From b2efd36e79be3e8855ea58d2502213911a19fc62 Mon Sep 17 00:00:00 2001 From: Lukas Geiger Date: Sat, 13 Jan 2018 02:48:46 +0100 Subject: [PATCH 001/112] Convert git-repository-provider to JS --- src/git-repository-provider.coffee | 84 ---------------------- src/git-repository-provider.js | 107 +++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+), 84 deletions(-) delete mode 100644 src/git-repository-provider.coffee create mode 100644 src/git-repository-provider.js diff --git a/src/git-repository-provider.coffee b/src/git-repository-provider.coffee deleted file mode 100644 index 593324d0c..000000000 --- a/src/git-repository-provider.coffee +++ /dev/null @@ -1,84 +0,0 @@ -fs = require 'fs' -{Directory} = require 'pathwatcher' -GitRepository = require './git-repository' - -# Returns the .gitdir path in the agnostic Git symlink .git file given, or -# null if the path is not a valid gitfile. -# -# * `gitFile` {String} path of gitfile to parse -gitFileRegex = RegExp "^gitdir: (.+)" -pathFromGitFile = (gitFile) -> - try - gitFileBuff = fs.readFileSync(gitFile, 'utf8') - return gitFileBuff?.match(gitFileRegex)[1] - -# Checks whether a valid `.git` directory is contained within the given -# directory or one of its ancestors. If so, a Directory that corresponds to the -# `.git` folder will be returned. Otherwise, returns `null`. -# -# * `directory` {Directory} to explore whether it is part of a Git repository. -findGitDirectorySync = (directory) -> - # TODO: Fix node-pathwatcher/src/directory.coffee so the following methods - # can return cached values rather than always returning new objects: - # getParent(), getFile(), getSubdirectory(). - gitDir = directory.getSubdirectory('.git') - gitDirPath = pathFromGitFile(gitDir.getPath?()) - if gitDirPath - gitDir = new Directory(directory.resolve(gitDirPath)) - if gitDir.existsSync?() and isValidGitDirectorySync gitDir - gitDir - else if directory.isRoot() - return null - else - findGitDirectorySync directory.getParent() - -# Returns a boolean indicating whether the specified directory represents a Git -# repository. -# -# * `directory` {Directory} whose base name is `.git`. -isValidGitDirectorySync = (directory) -> - # To decide whether a directory has a valid .git folder, we use - # the heuristic adopted by the valid_repository_path() function defined in - # node_modules/git-utils/deps/libgit2/src/repository.c. - return directory.getSubdirectory('objects').existsSync() and - directory.getFile('HEAD').existsSync() and - directory.getSubdirectory('refs').existsSync() - -# Provider that conforms to the atom.repository-provider@0.1.0 service. -module.exports = -class GitRepositoryProvider - - constructor: (@project, @config) -> - # Keys are real paths that end in `.git`. - # Values are the corresponding GitRepository objects. - @pathToRepository = {} - - # Returns a {Promise} that resolves with either: - # * {GitRepository} if the given directory has a Git repository. - # * `null` if the given directory does not have a Git repository. - repositoryForDirectory: (directory) -> - # TODO: Currently, this method is designed to be async, but it relies on a - # synchronous API. It should be rewritten to be truly async. - Promise.resolve(@repositoryForDirectorySync(directory)) - - # Returns either: - # * {GitRepository} if the given directory has a Git repository. - # * `null` if the given directory does not have a Git repository. - repositoryForDirectorySync: (directory) -> - # Only one GitRepository should be created for each .git folder. Therefore, - # we must check directory and its parent directories to find the nearest - # .git folder. - gitDir = findGitDirectorySync(directory) - unless gitDir - return null - - gitDirPath = gitDir.getPath() - repo = @pathToRepository[gitDirPath] - unless repo - repo = GitRepository.open(gitDirPath, {@project, @config}) - return null unless repo - repo.onDidDestroy(=> delete @pathToRepository[gitDirPath]) - @pathToRepository[gitDirPath] = repo - repo.refreshIndex() - repo.refreshStatus() - repo diff --git a/src/git-repository-provider.js b/src/git-repository-provider.js new file mode 100644 index 000000000..096e70c73 --- /dev/null +++ b/src/git-repository-provider.js @@ -0,0 +1,107 @@ +const fs = require('fs'); +const { Directory } = require('pathwatcher'); +const GitRepository = require('./git-repository'); + +// Returns the .gitdir path in the agnostic Git symlink .git file given, or +// null if the path is not a valid gitfile. +// +// * `gitFile` {String} path of gitfile to parse +const gitFileRegex = RegExp('^gitdir: (.+)'); +function pathFromGitFile(gitFile) { + try { + const gitFileBuff = fs.readFileSync(gitFile, 'utf8'); + return gitFileBuff != null ? gitFileBuff.match(gitFileRegex)[1] : undefined; + } catch (error) {} +} + +// Checks whether a valid `.git` directory is contained within the given +// directory or one of its ancestors. If so, a Directory that corresponds to the +// `.git` folder will be returned. Otherwise, returns `null`. +// +// * `directory` {Directory} to explore whether it is part of a Git repository. +function findGitDirectorySync(directory) { + // TODO: Fix node-pathwatcher/src/directory.coffee so the following methods + // can return cached values rather than always returning new objects: + // getParent(), getFile(), getSubdirectory(). + let gitDir = directory.getSubdirectory('.git'); + const gitDirPath = pathFromGitFile( + typeof gitDir.getPath === 'function' ? gitDir.getPath() : undefined + ); + if (gitDirPath) { + gitDir = new Directory(directory.resolve(gitDirPath)); + } + if ( + (typeof gitDir.existsSync === 'function' ? gitDir.existsSync() : undefined) && + isValidGitDirectorySync(gitDir) + ) { + return gitDir; + } else if (directory.isRoot()) { + return null; + } else { + return findGitDirectorySync(directory.getParent()); + } +} + +// Returns a boolean indicating whether the specified directory represents a Git +// repository. +// +// * `directory` {Directory} whose base name is `.git`. +function isValidGitDirectorySync(directory) { + // To decide whether a directory has a valid .git folder, we use + // the heuristic adopted by the valid_repository_path() function defined in + // node_modules/git-utils/deps/libgit2/src/repository.c. + return ( + directory.getSubdirectory('objects').existsSync() && + directory.getFile('HEAD').existsSync() && + directory.getSubdirectory('refs').existsSync() + ); +} + +// Provider that conforms to the atom.repository-provider@0.1.0 service. +class GitRepositoryProvider { + constructor(project, config) { + // Keys are real paths that end in `.git`. + // Values are the corresponding GitRepository objects. + this.project = project; + this.config = config; + this.pathToRepository = {}; + } + + // Returns a {Promise} that resolves with either: + // * {GitRepository} if the given directory has a Git repository. + // * `null` if the given directory does not have a Git repository. + repositoryForDirectory(directory) { + // TODO: Currently, this method is designed to be async, but it relies on a + // synchronous API. It should be rewritten to be truly async. + return Promise.resolve(this.repositoryForDirectorySync(directory)); + } + + // Returns either: + // * {GitRepository} if the given directory has a Git repository. + // * `null` if the given directory does not have a Git repository. + repositoryForDirectorySync(directory) { + // Only one GitRepository should be created for each .git folder. Therefore, + // we must check directory and its parent directories to find the nearest + // .git folder. + const gitDir = findGitDirectorySync(directory); + if (!gitDir) { + return null; + } + + const gitDirPath = gitDir.getPath(); + let repo = this.pathToRepository[gitDirPath]; + if (!repo) { + repo = GitRepository.open(gitDirPath, { project: this.project, config: this.config }); + if (!repo) { + return null; + } + repo.onDidDestroy(() => delete this.pathToRepository[gitDirPath]); + this.pathToRepository[gitDirPath] = repo; + repo.refreshIndex(); + repo.refreshStatus(); + } + return repo; + } +} + +module.exports = GitRepositoryProvider; From 3cfd2f8398fbf05bcaa84ab2f39942026a05aed2 Mon Sep 17 00:00:00 2001 From: Lukas Geiger Date: Sun, 14 Jan 2018 02:08:55 +0100 Subject: [PATCH 002/112] Add Async implementation for repositoryForDirectory --- src/git-repository-provider.js | 155 ++++++++++++++++++++++++--------- 1 file changed, 114 insertions(+), 41 deletions(-) diff --git a/src/git-repository-provider.js b/src/git-repository-provider.js index 096e70c73..9785a88ee 100644 --- a/src/git-repository-provider.js +++ b/src/git-repository-provider.js @@ -1,44 +1,93 @@ -const fs = require('fs'); -const { Directory } = require('pathwatcher'); -const GitRepository = require('./git-repository'); +const fs = require('fs') +const { Directory } = require('pathwatcher') +const GitRepository = require('./git-repository') + +const GIT_FILE_REGEX = RegExp('^gitdir: (.+)') // Returns the .gitdir path in the agnostic Git symlink .git file given, or // null if the path is not a valid gitfile. // // * `gitFile` {String} path of gitfile to parse -const gitFileRegex = RegExp('^gitdir: (.+)'); -function pathFromGitFile(gitFile) { +function pathFromGitFileSync (gitFile) { try { - const gitFileBuff = fs.readFileSync(gitFile, 'utf8'); - return gitFileBuff != null ? gitFileBuff.match(gitFileRegex)[1] : undefined; + const gitFileBuff = fs.readFileSync(gitFile, 'utf8') + return gitFileBuff != null ? gitFileBuff.match(GIT_FILE_REGEX)[1] : null } catch (error) {} } +// Returns a {Promise} that resolves to the .gitdir path in the agnostic +// Git symlink .git file given, or null if the path is not a valid gitfile. +// +// * `gitFile` {String} path of gitfile to parse +function pathFromGitFile (gitFile) { + return new Promise(resolve => { + fs.readFile(gitFile, 'utf8', (err, gitFileBuff) => { + if (err == null && gitFileBuff != null) { + const result = gitFileBuff.toString().match(GIT_FILE_REGEX) + resolve(result != null ? result[1] : null) + } else { + resolve(null) + } + }) + }) +} + // Checks whether a valid `.git` directory is contained within the given // directory or one of its ancestors. If so, a Directory that corresponds to the // `.git` folder will be returned. Otherwise, returns `null`. // // * `directory` {Directory} to explore whether it is part of a Git repository. -function findGitDirectorySync(directory) { +function findGitDirectorySync (directory) { // TODO: Fix node-pathwatcher/src/directory.coffee so the following methods // can return cached values rather than always returning new objects: // getParent(), getFile(), getSubdirectory(). - let gitDir = directory.getSubdirectory('.git'); - const gitDirPath = pathFromGitFile( - typeof gitDir.getPath === 'function' ? gitDir.getPath() : undefined - ); - if (gitDirPath) { - gitDir = new Directory(directory.resolve(gitDirPath)); + let gitDir = directory.getSubdirectory('.git') + if (typeof gitDir.getPath === 'function') { + const gitDirPath = pathFromGitFileSync(gitDir.getPath()) + if (gitDirPath) { + gitDir = new Directory(directory.resolve(gitDirPath)) + } } if ( - (typeof gitDir.existsSync === 'function' ? gitDir.existsSync() : undefined) && + typeof gitDir.existsSync === 'function' && + gitDir.existsSync() && isValidGitDirectorySync(gitDir) ) { - return gitDir; + return gitDir } else if (directory.isRoot()) { - return null; + return null } else { - return findGitDirectorySync(directory.getParent()); + return findGitDirectorySync(directory.getParent()) + } +} + +// Checks whether a valid `.git` directory is contained within the given +// directory or one of its ancestors. If so, a Directory that corresponds to the +// `.git` folder will be returned. Otherwise, returns `null`. +// +// Returns a {Promise} that resolves to +// * `directory` {Directory} to explore whether it is part of a Git repository. +async function findGitDirectory (directory) { + // TODO: Fix node-pathwatcher/src/directory.coffee so the following methods + // can return cached values rather than always returning new objects: + // getParent(), getFile(), getSubdirectory(). + let gitDir = directory.getSubdirectory('.git') + if (typeof gitDir.getPath === 'function') { + const gitDirPath = await pathFromGitFile(gitDir.getPath()) + if (gitDirPath) { + gitDir = new Directory(directory.resolve(gitDirPath)) + } + } + if ( + typeof gitDir.exists === 'function' && + (await gitDir.exists()) && + isValidGitDirectory(gitDir) + ) { + return gitDir + } else if (directory.isRoot()) { + return null + } else { + return await findGitDirectory(directory.getParent()) } } @@ -46,7 +95,7 @@ function findGitDirectorySync(directory) { // repository. // // * `directory` {Directory} whose base name is `.git`. -function isValidGitDirectorySync(directory) { +function isValidGitDirectorySync (directory) { // To decide whether a directory has a valid .git folder, we use // the heuristic adopted by the valid_repository_path() function defined in // node_modules/git-utils/deps/libgit2/src/repository.c. @@ -54,54 +103,78 @@ function isValidGitDirectorySync(directory) { directory.getSubdirectory('objects').existsSync() && directory.getFile('HEAD').existsSync() && directory.getSubdirectory('refs').existsSync() - ); + ) +} + +// Returns a {Promise} that resolves to a {Boolean} indicating whether the +// specified directory represents a Git repository. +// +// * `directory` {Directory} whose base name is `.git`. +async function isValidGitDirectory (directory) { + // To decide whether a directory has a valid .git folder, we use + // the heuristic adopted by the valid_repository_path() function defined in + // node_modules/git-utils/deps/libgit2/src/repository.c. + return ( + (await directory.getSubdirectory('objects').exists()) && + (await directory.getFile('HEAD').exists()) && + (await directory.getSubdirectory('refs').exists()) + ) } // Provider that conforms to the atom.repository-provider@0.1.0 service. class GitRepositoryProvider { - constructor(project, config) { + constructor (project, config) { // Keys are real paths that end in `.git`. // Values are the corresponding GitRepository objects. - this.project = project; - this.config = config; - this.pathToRepository = {}; + this.project = project + this.config = config + this.pathToRepository = {} } // Returns a {Promise} that resolves with either: // * {GitRepository} if the given directory has a Git repository. // * `null` if the given directory does not have a Git repository. - repositoryForDirectory(directory) { - // TODO: Currently, this method is designed to be async, but it relies on a - // synchronous API. It should be rewritten to be truly async. - return Promise.resolve(this.repositoryForDirectorySync(directory)); + async repositoryForDirectory (directory) { + // Only one GitRepository should be created for each .git folder. Therefore, + // we must check directory and its parent directories to find the nearest + // .git folder. + const gitDir = await findGitDirectory(directory) + return this.repositoryForGitDirectory(gitDir) } // Returns either: // * {GitRepository} if the given directory has a Git repository. // * `null` if the given directory does not have a Git repository. - repositoryForDirectorySync(directory) { + repositoryForDirectorySync (directory) { // Only one GitRepository should be created for each .git folder. Therefore, // we must check directory and its parent directories to find the nearest // .git folder. - const gitDir = findGitDirectorySync(directory); + const gitDir = findGitDirectorySync(directory) + return this.repositoryForGitDirectory(gitDir) + } + + // Returns either: + // * {GitRepository} if the given Git directory has a Git repository. + // * `null` if the given directory does not have a Git repository. + repositoryForGitDirectory (gitDir) { if (!gitDir) { - return null; + return null } - const gitDirPath = gitDir.getPath(); - let repo = this.pathToRepository[gitDirPath]; + const gitDirPath = gitDir.getPath() + let repo = this.pathToRepository[gitDirPath] if (!repo) { - repo = GitRepository.open(gitDirPath, { project: this.project, config: this.config }); + repo = GitRepository.open(gitDirPath, { project: this.project, config: this.config }) if (!repo) { - return null; + return null } - repo.onDidDestroy(() => delete this.pathToRepository[gitDirPath]); - this.pathToRepository[gitDirPath] = repo; - repo.refreshIndex(); - repo.refreshStatus(); + repo.onDidDestroy(() => delete this.pathToRepository[gitDirPath]) + this.pathToRepository[gitDirPath] = repo + repo.refreshIndex() + repo.refreshStatus() } - return repo; + return repo } } -module.exports = GitRepositoryProvider; +module.exports = GitRepositoryProvider From 16b8c293a19f2d39166ecfd6e9bd76070a600754 Mon Sep 17 00:00:00 2001 From: Lukas Geiger Date: Sun, 14 Jan 2018 15:20:58 +0100 Subject: [PATCH 003/112] :white_check_mark: Add tests for repositoryForDirectorySync Since `repositoryForDirectory` and `repositoryForDirectorySync` don't share the same implementation anymore. --- spec/git-repository-provider-spec.js | 88 ++++++++++++++++++++++++++-- 1 file changed, 82 insertions(+), 6 deletions(-) diff --git a/spec/git-repository-provider-spec.js b/spec/git-repository-provider-spec.js index 24993fe9b..2e679e755 100644 --- a/spec/git-repository-provider-spec.js +++ b/spec/git-repository-provider-spec.js @@ -82,6 +82,88 @@ describe('GitRepositoryProvider', () => { }) }) + describe('when specified a Directory without exists()', () => { + let directory + + beforeEach(() => { + // An implementation of Directory that does not implement existsSync(). + const subdirectory = {} + directory = { + getSubdirectory () {}, + isRoot () { return true } + } + spyOn(directory, 'getSubdirectory').andReturn(subdirectory) + }) + + it('returns a Promise that resolves to null', async () => { + const repo = await provider.repositoryForDirectory(directory) + expect(repo).toBe(null) + expect(directory.getSubdirectory).toHaveBeenCalledWith('.git') + }) + }) + }) + + describe('.repositoryForDirectorySync(directory)', () => { + describe('when specified a Directory with a Git repository', () => { + it('resolves with a GitRepository', async () => { + const directory = new Directory(path.join(__dirname, 'fixtures', 'git', 'master.git')) + const result = provider.repositoryForDirectorySync(directory) + expect(result).toBeInstanceOf(GitRepository) + expect(provider.pathToRepository[result.getPath()]).toBeTruthy() + expect(result.getType()).toBe('git') + + // Refresh should be started + await new Promise(resolve => result.onDidChangeStatuses(resolve)) + }) + + it('resolves with the same GitRepository for different Directory objects in the same repo', () => { + const firstRepo = provider.repositoryForDirectorySync( + new Directory(path.join(__dirname, 'fixtures', 'git', 'master.git')) + ) + const secondRepo = provider.repositoryForDirectorySync( + new Directory(path.join(__dirname, 'fixtures', 'git', 'master.git', 'objects')) + ) + + expect(firstRepo).toBeInstanceOf(GitRepository) + expect(firstRepo).toBe(secondRepo) + }) + }) + + describe('when specified a Directory without a Git repository', () => { + it('resolves with null', () => { + const directory = new Directory(temp.mkdirSync('dir')) + const repo = provider.repositoryForDirectorySync(directory) + expect(repo).toBe(null) + }) + }) + + describe('when specified a Directory with an invalid Git repository', () => { + it('resolves with null', () => { + const dirPath = temp.mkdirSync('dir') + fs.writeFileSync(path.join(dirPath, '.git', 'objects'), '') + fs.writeFileSync(path.join(dirPath, '.git', 'HEAD'), '') + fs.writeFileSync(path.join(dirPath, '.git', 'refs'), '') + + const directory = new Directory(dirPath) + const repo = provider.repositoryForDirectorySync(directory) + expect(repo).toBe(null) + }) + }) + + describe('when specified a Directory with a valid gitfile-linked repository', () => { + it('returns a Promise that resolves to a GitRepository', () => { + const gitDirPath = path.join(__dirname, 'fixtures', 'git', 'master.git') + const workDirPath = temp.mkdirSync('git-workdir') + fs.writeFileSync(path.join(workDirPath, '.git'), `gitdir: ${gitDirPath}\n`) + + const directory = new Directory(workDirPath) + const result = provider.repositoryForDirectorySync(directory) + expect(result).toBeInstanceOf(GitRepository) + expect(provider.pathToRepository[result.getPath()]).toBeTruthy() + expect(result.getType()).toBe('git') + }) + }) + describe('when specified a Directory without existsSync()', () => { let directory @@ -100,12 +182,6 @@ describe('GitRepositoryProvider', () => { expect(repo).toBe(null) expect(directory.getSubdirectory).toHaveBeenCalledWith('.git') }) - - it('returns a Promise that resolves to null for the async implementation', async () => { - const repo = await provider.repositoryForDirectory(directory) - expect(repo).toBe(null) - expect(directory.getSubdirectory).toHaveBeenCalledWith('.git') - }) }) }) }) From fe5bdeed2116a660482b7c1e26780c611d00e8bb Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 5 Feb 2019 14:28:35 -0500 Subject: [PATCH 004/112] Let's see if it magically works --- script/vsts/platforms/linux.yml | 8 ++++++++ script/vsts/platforms/macos.yml | 8 ++++++++ script/vsts/platforms/windows.yml | 8 ++++++++ 3 files changed, 24 insertions(+) diff --git a/script/vsts/platforms/linux.yml b/script/vsts/platforms/linux.yml index eb70878c7..b1f7bb688 100644 --- a/script/vsts/platforms/linux.yml +++ b/script/vsts/platforms/linux.yml @@ -25,9 +25,17 @@ jobs: CI: true CI_PROVIDER: VSTS ATOM_JASMINE_REPORTER: list + TEST_JUNIT_XML_PATH: $(Agent.HomeDirectory)/test-results displayName: Run tests condition: and(succeeded(), ne(variables['Atom.SkipTests'], 'true')) + - task: PublishTestResults@2 + inputs: + testResultsFormat: JUnit + testResultsFiles: $(Agent.HomeDirectory)/test-results/TEST-*.xml + testRunTitle: Linux + condition: succeededOrFailed() + - task: PublishBuildArtifacts@1 inputs: PathtoPublish: $(Build.SourcesDirectory)/out/atom.x86_64.rpm diff --git a/script/vsts/platforms/macos.yml b/script/vsts/platforms/macos.yml index 005f8b96f..e12e83747 100644 --- a/script/vsts/platforms/macos.yml +++ b/script/vsts/platforms/macos.yml @@ -45,9 +45,17 @@ jobs: CI: true CI_PROVIDER: VSTS ATOM_JASMINE_REPORTER: list + TEST_JUNIT_XML_PATH: $(Agent.HomeDirectory)/test-results displayName: Run tests condition: and(succeeded(), ne(variables['Atom.SkipTests'], 'true')) + - task: PublishTestResults@2 + inputs: + testResultsFormat: JUnit + testResultsFiles: $(Agent.HomeDirectory)/test-results/TEST-*.xml + testRunTitle: MacOS + condition: succeededOrFailed() + - script: | cp $(Build.SourcesDirectory)/out/*.zip $(Build.ArtifactStagingDirectory) displayName: Stage Artifacts diff --git a/script/vsts/platforms/windows.yml b/script/vsts/platforms/windows.yml index 8f490b77c..478c68fb1 100644 --- a/script/vsts/platforms/windows.yml +++ b/script/vsts/platforms/windows.yml @@ -70,10 +70,18 @@ jobs: CI: true CI_PROVIDER: VSTS ATOM_JASMINE_REPORTER: list + TEST_JUNIT_XML_PATH: $(Agent.HomeDirectory)/test-results BUILD_ARCH: $(buildArch) displayName: Run tests condition: and(succeeded(), ne(variables['Atom.SkipTests'], 'true')) + - task: PublishTestResults@2 + inputs: + testResultsFormat: JUnit + testResultsFiles: $(Agent.HomeDirectory)/test-results/TEST-*.xml + testRunTitle: Windows $(buildArch) + condition: succeededOrFailed() + - task: PublishBuildArtifacts@1 inputs: PathtoPublish: $(Build.SourcesDirectory)/out/atom-x64-windows.zip From 847f7aff4c68b57d80833e4e726dbe9d338b2985 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 5 Feb 2019 20:12:03 -0500 Subject: [PATCH 005/112] Use searchFolder and mergeTestResults --- script/vsts/platforms/linux.yml | 3 ++- script/vsts/platforms/macos.yml | 3 ++- script/vsts/platforms/windows.yml | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/script/vsts/platforms/linux.yml b/script/vsts/platforms/linux.yml index b1f7bb688..8b88d9273 100644 --- a/script/vsts/platforms/linux.yml +++ b/script/vsts/platforms/linux.yml @@ -32,7 +32,8 @@ jobs: - task: PublishTestResults@2 inputs: testResultsFormat: JUnit - testResultsFiles: $(Agent.HomeDirectory)/test-results/TEST-*.xml + searchFolder: $(Agent.HomeDirectory)/test-results + mergeTestResults: true testRunTitle: Linux condition: succeededOrFailed() diff --git a/script/vsts/platforms/macos.yml b/script/vsts/platforms/macos.yml index e12e83747..478a927a1 100644 --- a/script/vsts/platforms/macos.yml +++ b/script/vsts/platforms/macos.yml @@ -52,7 +52,8 @@ jobs: - task: PublishTestResults@2 inputs: testResultsFormat: JUnit - testResultsFiles: $(Agent.HomeDirectory)/test-results/TEST-*.xml + searchFolder: $(Agent.HomeDirectory)/test-results + mergeTestResults: true testRunTitle: MacOS condition: succeededOrFailed() diff --git a/script/vsts/platforms/windows.yml b/script/vsts/platforms/windows.yml index 478c68fb1..a5cc2e97b 100644 --- a/script/vsts/platforms/windows.yml +++ b/script/vsts/platforms/windows.yml @@ -78,7 +78,8 @@ jobs: - task: PublishTestResults@2 inputs: testResultsFormat: JUnit - testResultsFiles: $(Agent.HomeDirectory)/test-results/TEST-*.xml + searchFolder: $(Agent.HomeDirectory)\test-results + mergeTestResults: true testRunTitle: Windows $(buildArch) condition: succeededOrFailed() From 756f1196dafdc9f4cc6376df6840c189de511362 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 5 Feb 2019 20:12:25 -0500 Subject: [PATCH 006/112] Use backslashes on Windows in case something is being dumb --- script/vsts/platforms/windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/vsts/platforms/windows.yml b/script/vsts/platforms/windows.yml index a5cc2e97b..38a2dc120 100644 --- a/script/vsts/platforms/windows.yml +++ b/script/vsts/platforms/windows.yml @@ -70,7 +70,7 @@ jobs: CI: true CI_PROVIDER: VSTS ATOM_JASMINE_REPORTER: list - TEST_JUNIT_XML_PATH: $(Agent.HomeDirectory)/test-results + TEST_JUNIT_XML_PATH: $(Agent.HomeDirectory)\test-results BUILD_ARCH: $(buildArch) displayName: Run tests condition: and(succeeded(), ne(variables['Atom.SkipTests'], 'true')) From c6d0afb304b55e7d9994ee9da97ad453e4ebfd26 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 5 Feb 2019 20:12:37 -0500 Subject: [PATCH 007/112] Dump the test-results folder --- script/vsts/platforms/linux.yml | 6 ++++++ script/vsts/platforms/macos.yml | 6 ++++++ script/vsts/platforms/windows.yml | 5 +++++ 3 files changed, 17 insertions(+) diff --git a/script/vsts/platforms/linux.yml b/script/vsts/platforms/linux.yml index 8b88d9273..33cfa79c2 100644 --- a/script/vsts/platforms/linux.yml +++ b/script/vsts/platforms/linux.yml @@ -29,6 +29,12 @@ jobs: displayName: Run tests condition: and(succeeded(), ne(variables['Atom.SkipTests'], 'true')) + - script: ls -R "${TEST_JUNIT_XML_PATH}" + env: + TEST_JUNIT_XML_PATH: $(Agent.HomeDirectory)/test-results + displayName: Dump test results + condition: succeededOrFailed() + - task: PublishTestResults@2 inputs: testResultsFormat: JUnit diff --git a/script/vsts/platforms/macos.yml b/script/vsts/platforms/macos.yml index 478a927a1..22e2977d9 100644 --- a/script/vsts/platforms/macos.yml +++ b/script/vsts/platforms/macos.yml @@ -49,6 +49,12 @@ jobs: displayName: Run tests condition: and(succeeded(), ne(variables['Atom.SkipTests'], 'true')) + - script: ls -R "${TEST_JUNIT_XML_PATH}" + env: + TEST_JUNIT_XML_PATH: $(Agent.HomeDirectory)/test-results + displayName: Dump test results + condition: succeededOrFailed() + - task: PublishTestResults@2 inputs: testResultsFormat: JUnit diff --git a/script/vsts/platforms/windows.yml b/script/vsts/platforms/windows.yml index 38a2dc120..aeef0bb05 100644 --- a/script/vsts/platforms/windows.yml +++ b/script/vsts/platforms/windows.yml @@ -75,6 +75,11 @@ jobs: displayName: Run tests condition: and(succeeded(), ne(variables['Atom.SkipTests'], 'true')) + - ps: Get-ChildItem -Recurse %TEST_JUNIT_XML_PATH% + env: + TEST_JUNIT_XML_PATH: $(Agent.HomeDirectory)\test-results + displayName: Dump test results + - task: PublishTestResults@2 inputs: testResultsFormat: JUnit From 399a0b73631c0731dd60288a2d4da429b46f1efd Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 5 Feb 2019 20:15:39 -0500 Subject: [PATCH 008/112] I could swear you used to be able to shorten that --- script/vsts/platforms/windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/vsts/platforms/windows.yml b/script/vsts/platforms/windows.yml index aeef0bb05..a555b90e2 100644 --- a/script/vsts/platforms/windows.yml +++ b/script/vsts/platforms/windows.yml @@ -75,7 +75,7 @@ jobs: displayName: Run tests condition: and(succeeded(), ne(variables['Atom.SkipTests'], 'true')) - - ps: Get-ChildItem -Recurse %TEST_JUNIT_XML_PATH% + - powershell: Get-ChildItem -Recurse %TEST_JUNIT_XML_PATH% env: TEST_JUNIT_XML_PATH: $(Agent.HomeDirectory)\test-results displayName: Dump test results From 5945eca1489f4cc033cdab41df223f494a4f001b Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 5 Feb 2019 21:31:19 -0500 Subject: [PATCH 009/112] Configure JUnit noisily --- spec/jasmine-test-runner.coffee | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/spec/jasmine-test-runner.coffee b/spec/jasmine-test-runner.coffee index ef76d346d..b55a21caf 100644 --- a/spec/jasmine-test-runner.coffee +++ b/spec/jasmine-test-runner.coffee @@ -7,10 +7,6 @@ module.exports = ({logFile, headless, testPaths, buildAtomEnvironment}) -> window[key] = value for key, value of require '../vendor/jasmine' require 'jasmine-tagged' - if process.env.TEST_JUNIT_XML_PATH - require 'jasmine-reporters' - jasmine.getEnv().addReporter new jasmine.JUnitXmlReporter(process.env.TEST_JUNIT_XML_PATH, true, true) - # Allow document.title to be assigned in specs without screwing up spec window title documentTitle = null Object.defineProperty document, 'title', @@ -39,6 +35,14 @@ module.exports = ({logFile, headless, testPaths, buildAtomEnvironment}) -> jasmineEnv.addReporter(buildReporter({logFile, headless, resolveWithExitCode})) TimeReporter = require './time-reporter' jasmineEnv.addReporter(new TimeReporter()) + + if process.env.TEST_JUNIT_XML_PATH + require 'jasmine-reporters' + process.stderr.write "Outputting JUnit XML to <#{process.env.TEST_JUNIT_XML_PATH}>\n" + jasmineEnv.addReporter new jasmine.JUnitXmlReporter(process.env.TEST_JUNIT_XML_PATH, true, true) + else + process.stderr.write "No JUnit XML\n" + jasmineEnv.setIncludedTags([process.platform]) jasmineContent = document.createElement('div') From 69df3439f946d2f587b3b8560024621b9b8ca45a Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 6 Feb 2019 10:14:00 -0500 Subject: [PATCH 010/112] Use find instead of ls --- script/vsts/platforms/linux.yml | 2 +- script/vsts/platforms/macos.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/script/vsts/platforms/linux.yml b/script/vsts/platforms/linux.yml index 33cfa79c2..2d339ff6c 100644 --- a/script/vsts/platforms/linux.yml +++ b/script/vsts/platforms/linux.yml @@ -29,7 +29,7 @@ jobs: displayName: Run tests condition: and(succeeded(), ne(variables['Atom.SkipTests'], 'true')) - - script: ls -R "${TEST_JUNIT_XML_PATH}" + - script: find "${TEST_JUNIT_XML_PATH}" || true env: TEST_JUNIT_XML_PATH: $(Agent.HomeDirectory)/test-results displayName: Dump test results diff --git a/script/vsts/platforms/macos.yml b/script/vsts/platforms/macos.yml index 22e2977d9..f6021c77a 100644 --- a/script/vsts/platforms/macos.yml +++ b/script/vsts/platforms/macos.yml @@ -49,7 +49,7 @@ jobs: displayName: Run tests condition: and(succeeded(), ne(variables['Atom.SkipTests'], 'true')) - - script: ls -R "${TEST_JUNIT_XML_PATH}" + - script: find "${TEST_JUNIT_XML_PATH}" env: TEST_JUNIT_XML_PATH: $(Agent.HomeDirectory)/test-results displayName: Dump test results From ccc95917cdee1f7a20c5a7905b8570b1ef8fe4bb Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 6 Feb 2019 10:39:26 -0500 Subject: [PATCH 011/112] Use Common.TestResultsDirectory for test results --- script/vsts/platforms/linux.yml | 6 +++--- script/vsts/platforms/macos.yml | 6 +++--- script/vsts/platforms/windows.yml | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/script/vsts/platforms/linux.yml b/script/vsts/platforms/linux.yml index 2d339ff6c..400fb75cf 100644 --- a/script/vsts/platforms/linux.yml +++ b/script/vsts/platforms/linux.yml @@ -25,20 +25,20 @@ jobs: CI: true CI_PROVIDER: VSTS ATOM_JASMINE_REPORTER: list - TEST_JUNIT_XML_PATH: $(Agent.HomeDirectory)/test-results + TEST_JUNIT_XML_PATH: $(Common.TestResultsDirectory) displayName: Run tests condition: and(succeeded(), ne(variables['Atom.SkipTests'], 'true')) - script: find "${TEST_JUNIT_XML_PATH}" || true env: - TEST_JUNIT_XML_PATH: $(Agent.HomeDirectory)/test-results + TEST_JUNIT_XML_PATH: $(Common.TestResultsDirectory) displayName: Dump test results condition: succeededOrFailed() - task: PublishTestResults@2 inputs: testResultsFormat: JUnit - searchFolder: $(Agent.HomeDirectory)/test-results + searchFolder: $(Common.TestResultsDirectory) mergeTestResults: true testRunTitle: Linux condition: succeededOrFailed() diff --git a/script/vsts/platforms/macos.yml b/script/vsts/platforms/macos.yml index f6021c77a..3d4041fc8 100644 --- a/script/vsts/platforms/macos.yml +++ b/script/vsts/platforms/macos.yml @@ -45,20 +45,20 @@ jobs: CI: true CI_PROVIDER: VSTS ATOM_JASMINE_REPORTER: list - TEST_JUNIT_XML_PATH: $(Agent.HomeDirectory)/test-results + TEST_JUNIT_XML_PATH: $(Common.TestResultsDirectory) displayName: Run tests condition: and(succeeded(), ne(variables['Atom.SkipTests'], 'true')) - script: find "${TEST_JUNIT_XML_PATH}" env: - TEST_JUNIT_XML_PATH: $(Agent.HomeDirectory)/test-results + TEST_JUNIT_XML_PATH: $(Common.TestResultsDirectory) displayName: Dump test results condition: succeededOrFailed() - task: PublishTestResults@2 inputs: testResultsFormat: JUnit - searchFolder: $(Agent.HomeDirectory)/test-results + searchFolder: $(Common.TestResultsDirectory) mergeTestResults: true testRunTitle: MacOS condition: succeededOrFailed() diff --git a/script/vsts/platforms/windows.yml b/script/vsts/platforms/windows.yml index a555b90e2..7dfa4143a 100644 --- a/script/vsts/platforms/windows.yml +++ b/script/vsts/platforms/windows.yml @@ -70,14 +70,14 @@ jobs: CI: true CI_PROVIDER: VSTS ATOM_JASMINE_REPORTER: list - TEST_JUNIT_XML_PATH: $(Agent.HomeDirectory)\test-results + TEST_JUNIT_XML_PATH: $(Common.TestResultsDirectory) BUILD_ARCH: $(buildArch) displayName: Run tests condition: and(succeeded(), ne(variables['Atom.SkipTests'], 'true')) - powershell: Get-ChildItem -Recurse %TEST_JUNIT_XML_PATH% env: - TEST_JUNIT_XML_PATH: $(Agent.HomeDirectory)\test-results + TEST_JUNIT_XML_PATH: $(Common.TestResultsDirectory) displayName: Dump test results - task: PublishTestResults@2 From bef6edb34353e2b9f1cbf9bb3aa38b05e6bb4661 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 6 Feb 2019 10:39:59 -0500 Subject: [PATCH 012/112] Respect Atom.SkipTests --- script/vsts/platforms/linux.yml | 2 +- script/vsts/platforms/macos.yml | 2 +- script/vsts/platforms/windows.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/script/vsts/platforms/linux.yml b/script/vsts/platforms/linux.yml index 400fb75cf..f0273d7a8 100644 --- a/script/vsts/platforms/linux.yml +++ b/script/vsts/platforms/linux.yml @@ -41,7 +41,7 @@ jobs: searchFolder: $(Common.TestResultsDirectory) mergeTestResults: true testRunTitle: Linux - condition: succeededOrFailed() + condition: ne(variables['Atom.SkipTests'], 'true') - task: PublishBuildArtifacts@1 inputs: diff --git a/script/vsts/platforms/macos.yml b/script/vsts/platforms/macos.yml index 3d4041fc8..cdc9328e3 100644 --- a/script/vsts/platforms/macos.yml +++ b/script/vsts/platforms/macos.yml @@ -61,7 +61,7 @@ jobs: searchFolder: $(Common.TestResultsDirectory) mergeTestResults: true testRunTitle: MacOS - condition: succeededOrFailed() + condition: ne(variables['Atom.SkipTests'], 'true') - script: | cp $(Build.SourcesDirectory)/out/*.zip $(Build.ArtifactStagingDirectory) diff --git a/script/vsts/platforms/windows.yml b/script/vsts/platforms/windows.yml index 7dfa4143a..07d53bae2 100644 --- a/script/vsts/platforms/windows.yml +++ b/script/vsts/platforms/windows.yml @@ -86,7 +86,7 @@ jobs: searchFolder: $(Agent.HomeDirectory)\test-results mergeTestResults: true testRunTitle: Windows $(buildArch) - condition: succeededOrFailed() + condition: ne(variables['Atom.SkipTests'], 'true') - task: PublishBuildArtifacts@1 inputs: From d3eb451e5547dbf29d64ba1d5c659db31297ccef Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 6 Feb 2019 10:40:33 -0500 Subject: [PATCH 013/112] Fail less on empty or missing result directories --- script/vsts/platforms/macos.yml | 2 +- script/vsts/platforms/windows.yml | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/script/vsts/platforms/macos.yml b/script/vsts/platforms/macos.yml index cdc9328e3..b7d5ea1f8 100644 --- a/script/vsts/platforms/macos.yml +++ b/script/vsts/platforms/macos.yml @@ -49,7 +49,7 @@ jobs: displayName: Run tests condition: and(succeeded(), ne(variables['Atom.SkipTests'], 'true')) - - script: find "${TEST_JUNIT_XML_PATH}" + - script: find "${TEST_JUNIT_XML_PATH}" || true env: TEST_JUNIT_XML_PATH: $(Common.TestResultsDirectory) displayName: Dump test results diff --git a/script/vsts/platforms/windows.yml b/script/vsts/platforms/windows.yml index 07d53bae2..48d29420b 100644 --- a/script/vsts/platforms/windows.yml +++ b/script/vsts/platforms/windows.yml @@ -75,7 +75,9 @@ jobs: displayName: Run tests condition: and(succeeded(), ne(variables['Atom.SkipTests'], 'true')) - - powershell: Get-ChildItem -Recurse %TEST_JUNIT_XML_PATH% + - powershell: Get-ChildItem -Recurse $env:TEST_JUNIT_XML_PATH + failOnStderr: false + ignoreLASTEXITCODE: true env: TEST_JUNIT_XML_PATH: $(Common.TestResultsDirectory) displayName: Dump test results From 3b2f4bebcf3b14ca8b2f32a282a2e02659b653a6 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 6 Feb 2019 11:06:53 -0500 Subject: [PATCH 014/112] Write to stdout instead of stderr --- spec/jasmine-test-runner.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/jasmine-test-runner.coffee b/spec/jasmine-test-runner.coffee index 2e50891e5..1550fab3f 100644 --- a/spec/jasmine-test-runner.coffee +++ b/spec/jasmine-test-runner.coffee @@ -43,10 +43,10 @@ module.exports = ({logFile, headless, testPaths, buildAtomEnvironment}) -> if process.env.TEST_JUNIT_XML_PATH require 'jasmine-reporters' - process.stderr.write "Outputting JUnit XML to <#{process.env.TEST_JUNIT_XML_PATH}>\n" + process.stdout.write "Outputting JUnit XML to <#{process.env.TEST_JUNIT_XML_PATH}>\n" jasmineEnv.addReporter new jasmine.JUnitXmlReporter(process.env.TEST_JUNIT_XML_PATH, true, true) else - process.stderr.write "No JUnit XML\n" + process.stdout.write "No JUnit XML\n" jasmineEnv.setIncludedTags([process.platform]) From b118b910751041c0e693b82bed418a9a3f187262 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 6 Feb 2019 13:16:34 -0500 Subject: [PATCH 015/112] Use a subdirectory --- script/vsts/platforms/linux.yml | 4 ++-- script/vsts/platforms/macos.yml | 4 ++-- script/vsts/platforms/windows.yml | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/script/vsts/platforms/linux.yml b/script/vsts/platforms/linux.yml index f0273d7a8..31510e9ec 100644 --- a/script/vsts/platforms/linux.yml +++ b/script/vsts/platforms/linux.yml @@ -25,7 +25,7 @@ jobs: CI: true CI_PROVIDER: VSTS ATOM_JASMINE_REPORTER: list - TEST_JUNIT_XML_PATH: $(Common.TestResultsDirectory) + TEST_JUNIT_XML_PATH: $(Common.TestResultsDirectory)/junit displayName: Run tests condition: and(succeeded(), ne(variables['Atom.SkipTests'], 'true')) @@ -38,7 +38,7 @@ jobs: - task: PublishTestResults@2 inputs: testResultsFormat: JUnit - searchFolder: $(Common.TestResultsDirectory) + searchFolder: $(Common.TestResultsDirectory)/junit mergeTestResults: true testRunTitle: Linux condition: ne(variables['Atom.SkipTests'], 'true') diff --git a/script/vsts/platforms/macos.yml b/script/vsts/platforms/macos.yml index b7d5ea1f8..d97efe2a2 100644 --- a/script/vsts/platforms/macos.yml +++ b/script/vsts/platforms/macos.yml @@ -45,7 +45,7 @@ jobs: CI: true CI_PROVIDER: VSTS ATOM_JASMINE_REPORTER: list - TEST_JUNIT_XML_PATH: $(Common.TestResultsDirectory) + TEST_JUNIT_XML_PATH: $(Common.TestResultsDirectory)/junit displayName: Run tests condition: and(succeeded(), ne(variables['Atom.SkipTests'], 'true')) @@ -58,7 +58,7 @@ jobs: - task: PublishTestResults@2 inputs: testResultsFormat: JUnit - searchFolder: $(Common.TestResultsDirectory) + searchFolder: $(Common.TestResultsDirectory)/junit mergeTestResults: true testRunTitle: MacOS condition: ne(variables['Atom.SkipTests'], 'true') diff --git a/script/vsts/platforms/windows.yml b/script/vsts/platforms/windows.yml index 48d29420b..cbdd34ff7 100644 --- a/script/vsts/platforms/windows.yml +++ b/script/vsts/platforms/windows.yml @@ -70,7 +70,7 @@ jobs: CI: true CI_PROVIDER: VSTS ATOM_JASMINE_REPORTER: list - TEST_JUNIT_XML_PATH: $(Common.TestResultsDirectory) + TEST_JUNIT_XML_PATH: $(Common.TestResultsDirectory)\junit BUILD_ARCH: $(buildArch) displayName: Run tests condition: and(succeeded(), ne(variables['Atom.SkipTests'], 'true')) @@ -85,7 +85,7 @@ jobs: - task: PublishTestResults@2 inputs: testResultsFormat: JUnit - searchFolder: $(Agent.HomeDirectory)\test-results + searchFolder: $(Common.TestResultsDirectory)\junit mergeTestResults: true testRunTitle: Windows $(buildArch) condition: ne(variables['Atom.SkipTests'], 'true') From f42de37cbc2d441758c23256b22384256f81670c Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 6 Feb 2019 14:23:54 -0500 Subject: [PATCH 016/112] Set ROOT instead of PATH --- script/vsts/platforms/linux.yml | 6 +++--- script/vsts/platforms/macos.yml | 6 +++--- script/vsts/platforms/windows.yml | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/script/vsts/platforms/linux.yml b/script/vsts/platforms/linux.yml index 31510e9ec..4aa57774b 100644 --- a/script/vsts/platforms/linux.yml +++ b/script/vsts/platforms/linux.yml @@ -25,13 +25,13 @@ jobs: CI: true CI_PROVIDER: VSTS ATOM_JASMINE_REPORTER: list - TEST_JUNIT_XML_PATH: $(Common.TestResultsDirectory)/junit + TEST_JUNIT_XML_ROOT: $(Common.TestResultsDirectory)/junit displayName: Run tests condition: and(succeeded(), ne(variables['Atom.SkipTests'], 'true')) - - script: find "${TEST_JUNIT_XML_PATH}" || true + - script: find "${TEST_JUNIT_XML_ROOT}" || true env: - TEST_JUNIT_XML_PATH: $(Common.TestResultsDirectory) + TEST_JUNIT_XML_ROOT: $(Common.TestResultsDirectory) displayName: Dump test results condition: succeededOrFailed() diff --git a/script/vsts/platforms/macos.yml b/script/vsts/platforms/macos.yml index d97efe2a2..780f3e1ca 100644 --- a/script/vsts/platforms/macos.yml +++ b/script/vsts/platforms/macos.yml @@ -45,13 +45,13 @@ jobs: CI: true CI_PROVIDER: VSTS ATOM_JASMINE_REPORTER: list - TEST_JUNIT_XML_PATH: $(Common.TestResultsDirectory)/junit + TEST_JUNIT_XML_ROOT: $(Common.TestResultsDirectory)/junit displayName: Run tests condition: and(succeeded(), ne(variables['Atom.SkipTests'], 'true')) - - script: find "${TEST_JUNIT_XML_PATH}" || true + - script: find "${TEST_JUNIT_XML_ROOT}" || true env: - TEST_JUNIT_XML_PATH: $(Common.TestResultsDirectory) + TEST_JUNIT_XML_ROOT: $(Common.TestResultsDirectory) displayName: Dump test results condition: succeededOrFailed() diff --git a/script/vsts/platforms/windows.yml b/script/vsts/platforms/windows.yml index cbdd34ff7..ed55278d7 100644 --- a/script/vsts/platforms/windows.yml +++ b/script/vsts/platforms/windows.yml @@ -70,16 +70,16 @@ jobs: CI: true CI_PROVIDER: VSTS ATOM_JASMINE_REPORTER: list - TEST_JUNIT_XML_PATH: $(Common.TestResultsDirectory)\junit + TEST_JUNIT_XML_ROOT: $(Common.TestResultsDirectory)\junit BUILD_ARCH: $(buildArch) displayName: Run tests condition: and(succeeded(), ne(variables['Atom.SkipTests'], 'true')) - - powershell: Get-ChildItem -Recurse $env:TEST_JUNIT_XML_PATH + - powershell: Get-ChildItem -Recurse $env:TEST_JUNIT_XML_ROOT failOnStderr: false ignoreLASTEXITCODE: true env: - TEST_JUNIT_XML_PATH: $(Common.TestResultsDirectory) + TEST_JUNIT_XML_ROOT: $(Common.TestResultsDirectory) displayName: Dump test results - task: PublishTestResults@2 From 97df72a3c12cc71853ab3983e70d80c9515275cf Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 6 Feb 2019 15:56:28 -0500 Subject: [PATCH 017/112] Configure JUnit reporter to treat TEST_JUNIT_XML_PATH as a single file --- spec/jasmine-test-runner.coffee | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/spec/jasmine-test-runner.coffee b/spec/jasmine-test-runner.coffee index 1550fab3f..bd881c178 100644 --- a/spec/jasmine-test-runner.coffee +++ b/spec/jasmine-test-runner.coffee @@ -44,7 +44,10 @@ module.exports = ({logFile, headless, testPaths, buildAtomEnvironment}) -> if process.env.TEST_JUNIT_XML_PATH require 'jasmine-reporters' process.stdout.write "Outputting JUnit XML to <#{process.env.TEST_JUNIT_XML_PATH}>\n" - jasmineEnv.addReporter new jasmine.JUnitXmlReporter(process.env.TEST_JUNIT_XML_PATH, true, true) + outputDir = path.dirname(process.env.TEST_JUNIT_XML_PATH) + fileBase = path.basename(process.env.TEST_JUNIT_XML_PATH, '.xml') + + jasmineEnv.addReporter new jasmine.JUnitXmlReporter(outputDir, true, false, fileBase, true) else process.stdout.write "No JUnit XML\n" From c11442df5eb677ddc07445d61f12e938a535bccf Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 6 Feb 2019 19:45:41 -0500 Subject: [PATCH 018/112] Explicit test-results.xml glob --- script/vsts/platforms/linux.yml | 1 + script/vsts/platforms/macos.yml | 1 + script/vsts/platforms/windows.yml | 1 + 3 files changed, 3 insertions(+) diff --git a/script/vsts/platforms/linux.yml b/script/vsts/platforms/linux.yml index 4aa57774b..fa8bf6d0e 100644 --- a/script/vsts/platforms/linux.yml +++ b/script/vsts/platforms/linux.yml @@ -39,6 +39,7 @@ jobs: inputs: testResultsFormat: JUnit searchFolder: $(Common.TestResultsDirectory)/junit + testResultsFiles: **/test-results.xml mergeTestResults: true testRunTitle: Linux condition: ne(variables['Atom.SkipTests'], 'true') diff --git a/script/vsts/platforms/macos.yml b/script/vsts/platforms/macos.yml index 780f3e1ca..22a6c5f79 100644 --- a/script/vsts/platforms/macos.yml +++ b/script/vsts/platforms/macos.yml @@ -59,6 +59,7 @@ jobs: inputs: testResultsFormat: JUnit searchFolder: $(Common.TestResultsDirectory)/junit + testResultsFiles: **/test-results.xml mergeTestResults: true testRunTitle: MacOS condition: ne(variables['Atom.SkipTests'], 'true') diff --git a/script/vsts/platforms/windows.yml b/script/vsts/platforms/windows.yml index ed55278d7..e2293aabf 100644 --- a/script/vsts/platforms/windows.yml +++ b/script/vsts/platforms/windows.yml @@ -86,6 +86,7 @@ jobs: inputs: testResultsFormat: JUnit searchFolder: $(Common.TestResultsDirectory)\junit + testResultsFiles: **\test-results.xml mergeTestResults: true testRunTitle: Windows $(buildArch) condition: ne(variables['Atom.SkipTests'], 'true') From 73617203637908d119c46cf4281495f6d5952b12 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 6 Feb 2019 20:20:13 -0500 Subject: [PATCH 019/112] Quoting is a thing --- script/vsts/platforms/linux.yml | 2 +- script/vsts/platforms/macos.yml | 2 +- script/vsts/platforms/windows.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/script/vsts/platforms/linux.yml b/script/vsts/platforms/linux.yml index fa8bf6d0e..7038c13dc 100644 --- a/script/vsts/platforms/linux.yml +++ b/script/vsts/platforms/linux.yml @@ -39,7 +39,7 @@ jobs: inputs: testResultsFormat: JUnit searchFolder: $(Common.TestResultsDirectory)/junit - testResultsFiles: **/test-results.xml + testResultsFiles: "**/test-results.xml" mergeTestResults: true testRunTitle: Linux condition: ne(variables['Atom.SkipTests'], 'true') diff --git a/script/vsts/platforms/macos.yml b/script/vsts/platforms/macos.yml index 22a6c5f79..57dd01112 100644 --- a/script/vsts/platforms/macos.yml +++ b/script/vsts/platforms/macos.yml @@ -59,7 +59,7 @@ jobs: inputs: testResultsFormat: JUnit searchFolder: $(Common.TestResultsDirectory)/junit - testResultsFiles: **/test-results.xml + testResultsFiles: "**/test-results.xml" mergeTestResults: true testRunTitle: MacOS condition: ne(variables['Atom.SkipTests'], 'true') diff --git a/script/vsts/platforms/windows.yml b/script/vsts/platforms/windows.yml index e2293aabf..bab3df070 100644 --- a/script/vsts/platforms/windows.yml +++ b/script/vsts/platforms/windows.yml @@ -86,7 +86,7 @@ jobs: inputs: testResultsFormat: JUnit searchFolder: $(Common.TestResultsDirectory)\junit - testResultsFiles: **\test-results.xml + testResultsFiles: "**\test-results.xml" mergeTestResults: true testRunTitle: Windows $(buildArch) condition: ne(variables['Atom.SkipTests'], 'true') From 8dfdccbb10cce99026628641518c93377d1dc125 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 6 Feb 2019 20:21:19 -0500 Subject: [PATCH 020/112] One Mocha suite, one Jasmine suite --- script/test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/test b/script/test index 5270a3912..5c7991be8 100755 --- a/script/test +++ b/script/test @@ -216,7 +216,7 @@ function testSuitesForPlatform (platform) { suites = suites.filter(suite => suite !== runCoreMainProcessTests) } - return suites + return [runCoreMainProcessTests, runCoreRenderProcessTests] } async.series(testSuitesToRun, function (err, exitCodes) { From d99f2e6e79fe7801073667f3f762304e513ffaf5 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 6 Feb 2019 21:11:34 -0500 Subject: [PATCH 021/112] Subclass the Jasmine JUnit reporter to touch up the spec descriptions --- spec/jasmine-junit-reporter.js | 20 ++++++++++++++++++++ spec/jasmine-test-runner.coffee | 4 ++-- 2 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 spec/jasmine-junit-reporter.js diff --git a/spec/jasmine-junit-reporter.js b/spec/jasmine-junit-reporter.js new file mode 100644 index 000000000..19b31a54f --- /dev/null +++ b/spec/jasmine-junit-reporter.js @@ -0,0 +1,20 @@ +require('jasmine-reporters') + +class JasmineJUnitReporter extends jasmine.JUnitReporter { + fullDescription (spec) { + let fullDescription = spec.description + let currentSuite = spec.suite + while (currentSuite) { + fullDescription = currentSuite.description + ' ' + fullDescription + currentSuite = currentSuite.parentSuite + } + return fullDescription + } + + reportSpecResults (spec) { + spec.description = this.fullDescription(spec) + return super.reportSpecResults(spec) + } +} + +module.exports = { JasmineJUnitReporter } diff --git a/spec/jasmine-test-runner.coffee b/spec/jasmine-test-runner.coffee index bd881c178..200f03e38 100644 --- a/spec/jasmine-test-runner.coffee +++ b/spec/jasmine-test-runner.coffee @@ -42,12 +42,12 @@ module.exports = ({logFile, headless, testPaths, buildAtomEnvironment}) -> jasmineEnv.addReporter(new TimeReporter()) if process.env.TEST_JUNIT_XML_PATH - require 'jasmine-reporters' + {JasmineJUnitReporter} = require './jasmine-junit-reporter' process.stdout.write "Outputting JUnit XML to <#{process.env.TEST_JUNIT_XML_PATH}>\n" outputDir = path.dirname(process.env.TEST_JUNIT_XML_PATH) fileBase = path.basename(process.env.TEST_JUNIT_XML_PATH, '.xml') - jasmineEnv.addReporter new jasmine.JUnitXmlReporter(outputDir, true, false, fileBase, true) + jasmineEnv.addReporter new JasmineJUnitReporter(outputDir, true, false, fileBase, true) else process.stdout.write "No JUnit XML\n" From 4f575e034037d9eb2c2662cf38f282209ac6044c Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 6 Feb 2019 21:14:40 -0500 Subject: [PATCH 022/112] Does that expect a forward slash? --- script/vsts/platforms/windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/vsts/platforms/windows.yml b/script/vsts/platforms/windows.yml index bab3df070..554dcf0ea 100644 --- a/script/vsts/platforms/windows.yml +++ b/script/vsts/platforms/windows.yml @@ -86,7 +86,7 @@ jobs: inputs: testResultsFormat: JUnit searchFolder: $(Common.TestResultsDirectory)\junit - testResultsFiles: "**\test-results.xml" + testResultsFiles: "**/test-results.xml" mergeTestResults: true testRunTitle: Windows $(buildArch) condition: ne(variables['Atom.SkipTests'], 'true') From 584a1a317e6a965bf95203a1d5bd06f45d82590d Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Wed, 6 Feb 2019 21:31:58 -0500 Subject: [PATCH 023/112] Subclass the right class --- spec/jasmine-junit-reporter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/jasmine-junit-reporter.js b/spec/jasmine-junit-reporter.js index 19b31a54f..4e226e286 100644 --- a/spec/jasmine-junit-reporter.js +++ b/spec/jasmine-junit-reporter.js @@ -1,6 +1,6 @@ require('jasmine-reporters') -class JasmineJUnitReporter extends jasmine.JUnitReporter { +class JasmineJUnitReporter extends jasmine.JUnitXmlReporter { fullDescription (spec) { let fullDescription = spec.description let currentSuite = spec.suite From 284ae721c71250f56b33be31c83b3ce4e59089d0 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 7 Feb 2019 08:48:34 -0500 Subject: [PATCH 024/112] Run everything everywhere mwahahaha --- script/test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/test b/script/test index 5c7991be8..322ba18b5 100755 --- a/script/test +++ b/script/test @@ -216,7 +216,7 @@ function testSuitesForPlatform (platform) { suites = suites.filter(suite => suite !== runCoreMainProcessTests) } - return [runCoreMainProcessTests, runCoreRenderProcessTests] + return [runCoreMainProcessTests, runCoreRenderProcessTests].concat(packageTestSuites) } async.series(testSuitesToRun, function (err, exitCodes) { From 55874e8353321a7ef881abec59abce5e2f09a3f6 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 7 Feb 2019 08:49:03 -0500 Subject: [PATCH 025/112] Include suite name and optional run prefix in JUnit output filename --- script/test | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/script/test b/script/test index 322ba18b5..4167f8584 100755 --- a/script/test +++ b/script/test @@ -68,7 +68,8 @@ function prepareEnv (suiteName) { if (process.env.TEST_JUNIT_XML_ROOT) { // Tell Jasmine to output this suite's results as a JUnit XML file to a subdirectory of the root, so that a // CI system can interpret it. - const outputPath = path.join(process.env.TEST_JUNIT_XML_ROOT, suiteName, 'test-results.xml') + const runPrefix = process.env.TEST_JUNIT_XML_RUN || '' + const outputPath = path.join(process.env.TEST_JUNIT_XML_ROOT, suiteName, `TEST-${runPrefix}${suiteName}.xml`) env.TEST_JUNIT_XML_PATH = outputPath } From 65661ba8a3e60cbc24b1009cccc26819b1682cee Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Thu, 7 Feb 2019 08:49:42 -0500 Subject: [PATCH 026/112] Report test suites individually --- script/vsts/platforms/linux.yml | 5 ++--- script/vsts/platforms/macos.yml | 5 ++--- script/vsts/platforms/windows.yml | 5 ++--- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/script/vsts/platforms/linux.yml b/script/vsts/platforms/linux.yml index 7038c13dc..5dd6a22b0 100644 --- a/script/vsts/platforms/linux.yml +++ b/script/vsts/platforms/linux.yml @@ -26,6 +26,7 @@ jobs: CI_PROVIDER: VSTS ATOM_JASMINE_REPORTER: list TEST_JUNIT_XML_ROOT: $(Common.TestResultsDirectory)/junit + TEST_JUNIT_XML_RUN: Linux- displayName: Run tests condition: and(succeeded(), ne(variables['Atom.SkipTests'], 'true')) @@ -39,9 +40,7 @@ jobs: inputs: testResultsFormat: JUnit searchFolder: $(Common.TestResultsDirectory)/junit - testResultsFiles: "**/test-results.xml" - mergeTestResults: true - testRunTitle: Linux + testResultsFiles: "**/TEST-*.xml" condition: ne(variables['Atom.SkipTests'], 'true') - task: PublishBuildArtifacts@1 diff --git a/script/vsts/platforms/macos.yml b/script/vsts/platforms/macos.yml index 57dd01112..c0341c38e 100644 --- a/script/vsts/platforms/macos.yml +++ b/script/vsts/platforms/macos.yml @@ -46,6 +46,7 @@ jobs: CI_PROVIDER: VSTS ATOM_JASMINE_REPORTER: list TEST_JUNIT_XML_ROOT: $(Common.TestResultsDirectory)/junit + TEST_JUNIT_XML_RUN: MacOS- displayName: Run tests condition: and(succeeded(), ne(variables['Atom.SkipTests'], 'true')) @@ -59,9 +60,7 @@ jobs: inputs: testResultsFormat: JUnit searchFolder: $(Common.TestResultsDirectory)/junit - testResultsFiles: "**/test-results.xml" - mergeTestResults: true - testRunTitle: MacOS + testResultsFiles: "**/TEST-*.xml" condition: ne(variables['Atom.SkipTests'], 'true') - script: | diff --git a/script/vsts/platforms/windows.yml b/script/vsts/platforms/windows.yml index 554dcf0ea..0bc4cbd1c 100644 --- a/script/vsts/platforms/windows.yml +++ b/script/vsts/platforms/windows.yml @@ -71,6 +71,7 @@ jobs: CI_PROVIDER: VSTS ATOM_JASMINE_REPORTER: list TEST_JUNIT_XML_ROOT: $(Common.TestResultsDirectory)\junit + TEST_JUNIT_XML_RUN: Windows-$(buildArch)- BUILD_ARCH: $(buildArch) displayName: Run tests condition: and(succeeded(), ne(variables['Atom.SkipTests'], 'true')) @@ -86,9 +87,7 @@ jobs: inputs: testResultsFormat: JUnit searchFolder: $(Common.TestResultsDirectory)\junit - testResultsFiles: "**/test-results.xml" - mergeTestResults: true - testRunTitle: Windows $(buildArch) + testResultsFiles: "**/TEST-*.xml" condition: ne(variables['Atom.SkipTests'], 'true') - task: PublishBuildArtifacts@1 From 6696731fd5b58b5f092f2c10549cdca45e8e9629 Mon Sep 17 00:00:00 2001 From: David Wilson Date: Thu, 7 Feb 2019 10:15:06 -0800 Subject: [PATCH 027/112] :arrow_up: language-javascript@0.129.20 --- package-lock.json | 4 ++-- package.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1b239486b..278463567 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3293,8 +3293,8 @@ "integrity": "sha512-kdTsc2efREnuj72WsAfcx28h0RqrVUIGF7BQcS5zy+ZibqbvnaB5DiVunRFYLhefGoaKVkAyTdRkZWMKH/yIWg==" }, "language-javascript": { - "version": "https://www.atom.io/api/packages/language-javascript/versions/0.129.19/tarball", - "integrity": "sha512-ClPU0dc41WqagaPd+qy5DQ5ahDCVcfFxC1nwppyQSsSXzrzsiE2+FuYzG33OMaSGDA6/zZ6gBkHXnXXPFzWcNA==", + "version": "https://www.atom.io/api/packages/language-javascript/versions/0.129.20/tarball", + "integrity": "sha512-zHIaVdZYxxoabugCVDnOsrhy0oZC8hLPVKOZoT8EwPIWfRRNedTshFVhABUTH+dmiOUUS++izylwng2yWggpzA==", "requires": { "tree-sitter-javascript": "^0.13.10", "tree-sitter-jsdoc": "^0.13.4", diff --git a/package.json b/package.json index 6a84858c7..2d8ee106d 100644 --- a/package.json +++ b/package.json @@ -88,7 +88,7 @@ "language-html": "https://www.atom.io/api/packages/language-html/versions/0.52.0/tarball", "language-hyperlink": "https://www.atom.io/api/packages/language-hyperlink/versions/0.17.0/tarball", "language-java": "https://www.atom.io/api/packages/language-java/versions/0.31.1/tarball", - "language-javascript": "https://www.atom.io/api/packages/language-javascript/versions/0.129.19/tarball", + "language-javascript": "https://www.atom.io/api/packages/language-javascript/versions/0.129.20/tarball", "language-json": "https://www.atom.io/api/packages/language-json/versions/0.19.2/tarball", "language-less": "https://www.atom.io/api/packages/language-less/versions/0.34.3/tarball", "language-make": "https://www.atom.io/api/packages/language-make/versions/0.23.0/tarball", @@ -240,7 +240,7 @@ "language-html": "0.52.0", "language-hyperlink": "0.17.0", "language-java": "0.31.1", - "language-javascript": "0.129.19", + "language-javascript": "0.129.20", "language-json": "0.19.2", "language-less": "0.34.3", "language-make": "0.23.0", From bed9c6966ea67eb8ba83125d6aaacea6204d46d2 Mon Sep 17 00:00:00 2001 From: Nikolay Karev Date: Sun, 17 Jun 2018 10:34:37 +0500 Subject: [PATCH 028/112] File -> Open works without open windows --- src/main-process/atom-application.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/main-process/atom-application.js b/src/main-process/atom-application.js index 151845014..54e3dc646 100644 --- a/src/main-process/atom-application.js +++ b/src/main-process/atom-application.js @@ -23,6 +23,20 @@ const ConfigSchema = require('../config-schema') const LocationSuffixRegExp = /(:\d+)(:\d+)?$/ +const getDefaultPath = () => { + const editor = atom.workspace.getActiveTextEditor() + if (!editor) { + return undefined + } + if (!editor.getPath()) { + return undefined + } + const paths = atom.project.getPaths() + if (paths) { + return paths[0] + } +} + // The application's singleton class. // // It's the entry point into the Atom application and maintains the global state @@ -371,6 +385,9 @@ class AtomApplication extends EventEmitter { this.on('application:new-file', () => (this.focusedWindow() || this).openPath()) this.on('application:open-dev', () => this.promptForPathToOpen('all', {devMode: true})) this.on('application:open-safe', () => this.promptForPathToOpen('all', {safeMode: true})) + this.on('application:open', () => this.promptForPathToOpen('all', getLoadSettings(), getDefaultPath())) + this.on('application:open-file', () => this.promptForPathToOpen('file', getLoadSettings(), getDefaultPath())) + this.on('application:open-folder', () => this.promptForPathToOpen('file', getLoadSettings(), getDefaultPath())) this.on('application:inspect', ({x, y, atomWindow}) => { if (!atomWindow) atomWindow = this.focusedWindow() if (atomWindow) atomWindow.browserWindow.inspectElement(x, y) From 5e3f12857f36684cc98eb2353f9b030f6914e0fb Mon Sep 17 00:00:00 2001 From: Nikolay Karev Date: Mon, 18 Jun 2018 21:59:38 +0500 Subject: [PATCH 029/112] Shorter conditionals --- src/main-process/atom-application.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/main-process/atom-application.js b/src/main-process/atom-application.js index 54e3dc646..8edfdf39c 100644 --- a/src/main-process/atom-application.js +++ b/src/main-process/atom-application.js @@ -25,11 +25,8 @@ const LocationSuffixRegExp = /(:\d+)(:\d+)?$/ const getDefaultPath = () => { const editor = atom.workspace.getActiveTextEditor() - if (!editor) { - return undefined - } - if (!editor.getPath()) { - return undefined + if (!editor || !editor.getPath()) { + return } const paths = atom.project.getPaths() if (paths) { From 37ae5dde5af7fffad2e59f7cfea7103f3ee22577 Mon Sep 17 00:00:00 2001 From: David Wilson Date: Thu, 7 Feb 2019 12:52:01 -0800 Subject: [PATCH 030/112] Add a test for folder open behavior on after all windows have closed --- spec/main-process/atom-application.test.js | 25 ++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/spec/main-process/atom-application.test.js b/spec/main-process/atom-application.test.js index c271608c4..65503b682 100644 --- a/spec/main-process/atom-application.test.js +++ b/spec/main-process/atom-application.test.js @@ -638,6 +638,31 @@ describe('AtomApplication', function () { assert(atomApplication.getAllWindows().length === 0) }) + if (process.platform === 'darwin') { + it('allows opening a new folder after all windows are closed', async () => { + const atomApplication = buildAtomApplication() + sinon.stub(atomApplication, 'promptForPathToOpen') + + // Open a window and then close it, leaving the app running + const [window] = await atomApplication.launch(parseCommandLine([])) + await focusWindow(window) + window.close() + await window.closedPromise + + atomApplication.emit('application:open') + await conditionPromise(() => atomApplication.promptForPathToOpen.calledWith('all')) + atomApplication.promptForPathToOpen.reset() + + atomApplication.emit('application:open-file') + await conditionPromise(() => atomApplication.promptForPathToOpen.calledWith('file')) + atomApplication.promptForPathToOpen.reset() + + atomApplication.emit('application:open-folder') + await conditionPromise(() => atomApplication.promptForPathToOpen.calledWith('file')) + atomApplication.promptForPathToOpen.reset() + }) + } + function buildAtomApplication (params = {}) { const atomApplication = new AtomApplication(Object.assign({ resourcePath: ATOM_RESOURCE_PATH, From 2c8b8ef77ec792e5442c7cb775887237070eff9c Mon Sep 17 00:00:00 2001 From: David Wilson Date: Thu, 7 Feb 2019 15:03:23 -0800 Subject: [PATCH 031/112] Change chromedriver/mksnapshot version check to only lock major version --- script/lib/check-chromedriver-version.js | 12 ++++++------ script/package.json | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/script/lib/check-chromedriver-version.js b/script/lib/check-chromedriver-version.js index 1659f093c..f5cada045 100644 --- a/script/lib/check-chromedriver-version.js +++ b/script/lib/check-chromedriver-version.js @@ -5,17 +5,17 @@ const CONFIG = require('../config') const semver = require('semver') module.exports = function () { - // Chromedriver should be specified as ~x.y where x and y match Electron major/minor + // Chromedriver should be specified as ^n.x where n matches the Electron major version const chromedriverVer = buildMetadata.dependencies['electron-chromedriver'] const mksnapshotVer = buildMetadata.dependencies['electron-mksnapshot'] - // Always use tilde on electron-chromedriver so that it can pick up the best patch version - if (!chromedriverVer.startsWith('~')) { - throw new Error(`electron-chromedriver version in script/package.json should start with a tilde to match latest patch version.`) + // Always use caret on electron-chromedriver so that it can pick up the best minor/patch versions + if (!chromedriverVer.startsWith('^')) { + throw new Error(`electron-chromedriver version in script/package.json should start with a caret to match latest patch version.`) } - if (!mksnapshotVer.startsWith('~')) { - throw new Error(`electron-mksnapshot version in script/package.json should start with a tilde to match latest patch version.`) + if (!mksnapshotVer.startsWith('^')) { + throw new Error(`electron-mksnapshot version in script/package.json should start with a caret to match latest patch version.`) } const electronVer = CONFIG.appMetadata.electronVersion diff --git a/script/package.json b/script/package.json index 10c6494cc..d2fe4446e 100644 --- a/script/package.json +++ b/script/package.json @@ -9,9 +9,9 @@ "coffeelint": "1.15.7", "colors": "1.1.2", "donna": "1.0.16", - "electron-chromedriver": "~3.0.0-beta.1", + "electron-chromedriver": "^3.0.0-beta.1", "electron-link": "0.3.3", - "electron-mksnapshot": "~3.0.10", + "electron-mksnapshot": "^3.0.10", "electron-packager": "7.3.0", "electron-winstaller": "2.6.4", "fs-admin": "^0.1.5", From 505cf161fbbc4d24f01a9def984675b6ed4b9d11 Mon Sep 17 00:00:00 2001 From: David Wilson Date: Thu, 7 Feb 2019 15:03:40 -0800 Subject: [PATCH 032/112] :arrow_up: :electron: electron@3.1.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2d8ee106d..545bb3280 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "url": "https://github.com/atom/atom/issues" }, "license": "MIT", - "electronVersion": "3.0.14", + "electronVersion": "3.1.3", "dependencies": { "@atom/nsfw": "1.0.21", "@atom/source-map-support": "^0.3.4", From 7c56ae28a77ebc13f8d3d02451723e7b0ae254e4 Mon Sep 17 00:00:00 2001 From: David Wilson Date: Tue, 14 Aug 2018 10:56:29 -0700 Subject: [PATCH 033/112] Move release publishing script and deps under script/vsts --- script/package-lock.json | 358 ----- script/package.json | 2 - script/publish-release.cmd | 5 - script/{ => vsts}/lib/upload-to-s3.js | 0 script/vsts/nightly-release.yml | 4 +- script/vsts/package-lock.json | 1207 ++++++++--------- script/vsts/package.json | 3 + script/vsts/release-branch-build.yml | 3 +- .../upload-artifacts.js} | 2 +- 9 files changed, 551 insertions(+), 1033 deletions(-) delete mode 100644 script/publish-release.cmd rename script/{ => vsts}/lib/upload-to-s3.js (100%) rename script/{publish-release => vsts/upload-artifacts.js} (98%) diff --git a/script/package-lock.json b/script/package-lock.json index bc5efb6b2..9aa5dbf17 100644 --- a/script/package-lock.json +++ b/script/package-lock.json @@ -376,22 +376,6 @@ "postcss-value-parser": "^3.2.3" } }, - "aws-sdk": { - "version": "2.275.1", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.275.1.tgz", - "integrity": "sha512-lcpgoiHLhdcolUT7aJdg/CmlYO5ecf+3A+4dIceO72mFovCWZde1Rvr07QNbQ8gT0paqr5j2rs2b6c23Y/K0RQ==", - "requires": { - "buffer": "4.9.1", - "events": "1.1.1", - "ieee754": "1.1.8", - "jmespath": "0.15.0", - "querystring": "0.2.0", - "sax": "1.2.1", - "url": "0.10.3", - "uuid": "3.1.0", - "xml2js": "0.4.19" - } - }, "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", @@ -625,11 +609,6 @@ } } }, - "base64-js": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", - "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==" - }, "bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", @@ -737,16 +716,6 @@ "electron-to-chromium": "^1.3.47" } }, - "buffer": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", - "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" - } - }, "buffer-alloc": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", @@ -969,11 +938,6 @@ "restore-cursor": "^1.0.1" } }, - "cli-width": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-1.1.1.tgz", - "integrity": "sha1-pNKT72frt7iNSk1CwMzwDE0eNm0=" - }, "cliui": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", @@ -1668,14 +1632,6 @@ "is-obj": "^1.0.0" } }, - "duplexer2": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", - "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=", - "requires": { - "readable-stream": "~1.1.9" - } - }, "ecc-jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", @@ -1685,11 +1641,6 @@ "jsbn": "~0.1.0" } }, - "editor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/editor/-/editor-1.0.0.tgz", - "integrity": "sha1-YMf4e9YrzGqJT6jM1q+3gjok90I=" - }, "electron-chromedriver": { "version": "3.0.0-beta.1", "resolved": "https://registry.npmjs.org/electron-chromedriver/-/electron-chromedriver-3.0.0-beta.1.tgz", @@ -2236,11 +2187,6 @@ "es5-ext": "~0.10.14" } }, - "events": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", - "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=" - }, "execa": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/execa/-/execa-0.4.0.tgz", @@ -2991,49 +2937,6 @@ "assert-plus": "^1.0.0" } }, - "ghauth": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ghauth/-/ghauth-2.0.1.tgz", - "integrity": "sha1-ebfWiwvPjn0IUqI7FHU539MUrPY=", - "requires": { - "bl": "~0.9.4", - "hyperquest": "~1.2.0", - "mkdirp": "~0.5.0", - "read": "~1.0.5", - "xtend": "~4.0.0" - }, - "dependencies": { - "bl": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/bl/-/bl-0.9.5.tgz", - "integrity": "sha1-wGt5evCF6gC8Unr8jvzxHeIjIFQ=", - "requires": { - "readable-stream": "~1.0.26" - } - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "xtend": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" - } - } - }, "github-from-package": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", @@ -3049,14 +2952,6 @@ "resolved": "https://registry.npmjs.org/github-url-from-username-repo/-/github-url-from-username-repo-1.0.2.tgz", "integrity": "sha1-fdeTMNKr5pwQws73lxTJchV5Hfo=" }, - "github-url-to-object": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/github-url-to-object/-/github-url-to-object-1.6.0.tgz", - "integrity": "sha1-iR73+7+rqP7XFRCs2xtOk0apcNw=", - "requires": { - "is-url": "^1.1.0" - } - }, "glob": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.3.tgz", @@ -3345,47 +3240,6 @@ "sshpk": "^1.7.0" } }, - "hyperquest": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/hyperquest/-/hyperquest-1.2.0.tgz", - "integrity": "sha1-OeH+9miI3Hzg3sbA3YFPb8iUStU=", - "requires": { - "duplexer2": "~0.0.2", - "through2": "~0.6.3" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "through2": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", - "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", - "requires": { - "readable-stream": ">=1.0.33-1 <1.1.0-0", - "xtend": ">=4.0.0 <4.1.0-0" - } - }, - "xtend": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" - } - } - }, "iconv-lite": { "version": "0.4.23", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", @@ -3394,11 +3248,6 @@ "safer-buffer": ">= 2.1.2 < 3" } }, - "ieee754": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz", - "integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q=" - }, "ignore": { "version": "3.3.10", "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", @@ -3456,33 +3305,6 @@ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" }, - "inquirer": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.8.5.tgz", - "integrity": "sha1-29dAz2yjtzEpamPOb22WGFHzNt8=", - "requires": { - "ansi-regex": "^1.1.1", - "chalk": "^1.0.0", - "cli-width": "^1.0.1", - "figures": "^1.3.5", - "lodash": "^3.3.1", - "readline2": "^0.1.1", - "rx": "^2.4.3", - "through": "^2.3.6" - }, - "dependencies": { - "ansi-regex": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-1.1.1.tgz", - "integrity": "sha1-QchHGUZGN15qGl0Qw8oFTvn8mA0=" - }, - "lodash": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", - "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=" - } - } - }, "invert-kv": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", @@ -3746,11 +3568,6 @@ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" }, - "is-url": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", - "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==" - }, "is-utf8": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", @@ -3804,11 +3621,6 @@ "resolved": "https://registry.npmjs.org/jju/-/jju-1.3.0.tgz", "integrity": "sha1-2t2e8BkkvHKLA/L3l5vb1i96Kqo=" }, - "jmespath": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", - "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=" - }, "joanna": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/joanna/-/joanna-0.0.10.tgz", @@ -4463,11 +4275,6 @@ "regex-cache": "^0.4.2" } }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" - }, "mime-db": { "version": "1.33.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", @@ -4647,11 +4454,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, - "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=" - }, "mv": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz", @@ -7904,11 +7706,6 @@ } } }, - "pkginfo": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.3.1.tgz", - "integrity": "sha1-Wyn2qB9wcXFC4J52W76rl7T4HiE=" - }, "plist": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/plist/-/plist-1.2.0.tgz", @@ -8279,43 +8076,6 @@ "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" }, - "publish-release": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/publish-release/-/publish-release-1.6.0.tgz", - "integrity": "sha512-t+NFXTQN/VDTg9yJ8Uv5ZWQ7Ud1T5W1tPW+bmuo4g6uYVQTVNiwwRF6Td3EtXFTOafpEXJQEZqGG7IvIJwLwIg==", - "requires": { - "async": "^0.9.0", - "ghauth": "^2.0.0", - "github-url-to-object": "^1.4.2", - "inquirer": "^0.8.2", - "lodash": "^3.6.0", - "mime": "^1.3.4", - "minimist": "^1.1.1", - "pkginfo": "^0.3.0", - "pretty-bytes": "^1.0.4", - "progress-stream": "^1.0.1", - "request": "^2.54.0", - "single-line-log": "^0.4.1", - "string-editor": "^0.1.0" - }, - "dependencies": { - "async": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", - "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=" - }, - "lodash": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", - "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=" - }, - "single-line-log": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/single-line-log/-/single-line-log-0.4.1.tgz", - "integrity": "sha1-h6VWSfdJ14PsDc2AToFA2Yc8fO4=" - } - } - }, "pump": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", @@ -8408,14 +8168,6 @@ "resolved": "https://registry.npmjs.org/rcedit/-/rcedit-0.5.1.tgz", "integrity": "sha1-0L3PXSgKnRwp2m8RjMzizhU87x0=" }, - "read": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", - "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=", - "requires": { - "mute-stream": "~0.0.4" - } - }, "read-installed": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/read-installed/-/read-installed-3.1.3.tgz", @@ -8543,35 +8295,6 @@ "once": "^1.3.0" } }, - "readline2": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/readline2/-/readline2-0.1.1.tgz", - "integrity": "sha1-mUQ7pug7gw7zBRv9fcJBqCco1Wg=", - "requires": { - "mute-stream": "0.0.4", - "strip-ansi": "^2.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-1.1.1.tgz", - "integrity": "sha1-QchHGUZGN15qGl0Qw8oFTvn8mA0=" - }, - "mute-stream": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.4.tgz", - "integrity": "sha1-qSGZYKbV1dBGWXruUSUsZlX3F34=" - }, - "strip-ansi": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-2.0.1.tgz", - "integrity": "sha1-32LBqpTtLxFOHQ8h/R1QSCt5pg4=", - "requires": { - "ansi-regex": "^1.0.0" - } - } - } - }, "recast": { "version": "0.10.33", "resolved": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz", @@ -8788,24 +8511,6 @@ "uuid": "^3.1.0" } }, - "request-promise-core": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz", - "integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=", - "requires": { - "lodash": "^4.13.1" - } - }, - "request-promise-native": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.5.tgz", - "integrity": "sha1-UoF3D2jgyXGeUWP9P6tIIhX0/aU=", - "requires": { - "request-promise-core": "1.1.1", - "stealthy-require": "^1.1.0", - "tough-cookie": ">=2.3.3" - } - }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -8919,11 +8624,6 @@ "resolved": "https://registry.npmjs.org/run-series/-/run-series-1.1.8.tgz", "integrity": "sha512-+GztYEPRpIsQoCSraWHDBs9WVy4eVME16zhOtDB4H9J4xN0XRhknnmLOl+4gRgZtu8dpp9N/utSPjKH/xmDzXg==" }, - "rx": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/rx/-/rx-2.5.3.tgz", - "integrity": "sha1-Ia3H2A8CACr1Da6X/Z2/JIdV9WY=" - }, "rx-lite": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz", @@ -8947,11 +8647,6 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, - "sax": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", - "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=" - }, "season": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/season/-/season-5.3.0.tgz", @@ -9356,19 +9051,6 @@ } } }, - "stealthy-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", - "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=" - }, - "string-editor": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/string-editor/-/string-editor-0.1.2.tgz", - "integrity": "sha1-9f8bWsSu16xsL7jeI20VUbIPYdA=", - "requires": { - "editor": "^1.0.0" - } - }, "string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", @@ -9977,32 +9659,6 @@ } } }, - "terser": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-3.8.1.tgz", - "integrity": "sha512-FRin3gKQ0vm0xPPLuxw1FqpVgv1b2pBpYCaFb5qe6A7sD749Fnq1VbDiX3CEFM0BV0fqDzFtBfgmxhxCdzKQIg==", - "requires": { - "commander": "~2.16.0", - "source-map": "~0.6.1", - "source-map-support": "~0.5.6" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "source-map-support": { - "version": "0.5.9", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.9.tgz", - "integrity": "sha512-gR6Rw4MvUlYy83vP0vxoVNzM6t8MUXqNuRsuBmBHQDu1Fh6X015FrLdgoDKcNdkwGubozq0P4N0Q37UyFVr1EA==", - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - } - } - }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -10680,20 +10336,6 @@ "resolved": "https://registry.npmjs.org/x-is-string/-/x-is-string-0.1.0.tgz", "integrity": "sha1-R0tQhlrzpJqcRlfwWs0UVFj3fYI=" }, - "xml2js": { - "version": "0.4.19", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", - "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", - "requires": { - "sax": ">=0.6.0", - "xmlbuilder": "~9.0.1" - } - }, - "xmlbuilder": { - "version": "9.0.7", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", - "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=" - }, "xmldom": { "version": "0.1.27", "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz", diff --git a/script/package.json b/script/package.json index d2fe4446e..248efed4c 100644 --- a/script/package.json +++ b/script/package.json @@ -4,7 +4,6 @@ "dependencies": { "7zip-bin": "^4.0.2", "async": "2.0.1", - "aws-sdk": "^2.5.2", "babel-core": "5.8.38", "coffeelint": "1.15.7", "colors": "1.1.2", @@ -28,7 +27,6 @@ "npm": "6.2.0", "passwd-user": "2.1.0", "pegjs": "0.9.0", - "publish-release": "^1.6.0", "random-seed": "^0.3.0", "request": "^2.87.0", "request-promise-native": "^1.0.5", diff --git a/script/publish-release.cmd b/script/publish-release.cmd deleted file mode 100644 index 46e077a3c..000000000 --- a/script/publish-release.cmd +++ /dev/null @@ -1,5 +0,0 @@ -@IF EXIST "%~dp0\node.exe" ( - "%~dp0\node.exe" "%~dp0\publish-release" %* -) ELSE ( - node "%~dp0\publish-release" %* -) diff --git a/script/lib/upload-to-s3.js b/script/vsts/lib/upload-to-s3.js similarity index 100% rename from script/lib/upload-to-s3.js rename to script/vsts/lib/upload-to-s3.js diff --git a/script/vsts/nightly-release.yml b/script/vsts/nightly-release.yml index 0d0a84dbc..0d83405ac 100644 --- a/script/vsts/nightly-release.yml +++ b/script/vsts/nightly-release.yml @@ -43,7 +43,7 @@ jobs: # This has to be done separately because VSTS inexplicably # exits the script block after `npm install` completes. - script: | - cd script + cd script\vsts npm install displayName: npm install @@ -54,7 +54,7 @@ jobs: displayName: Download Release Artifacts - script: | - $(Build.SourcesDirectory)\script\publish-release.cmd --create-github-release --assets-path "$(System.ArtifactsDirectory)" + node $(Build.SourcesDirectory)\script\vsts\upload-artifacts.js --create-github-release --assets-path "$(System.ArtifactsDirectory)" env: GITHUB_TOKEN: $(GITHUB_TOKEN) ATOM_RELEASE_VERSION: $(ReleaseVersion) diff --git a/script/vsts/package-lock.json b/script/vsts/package-lock.json index a17d03b85..f38b34ff8 100644 --- a/script/vsts/package-lock.json +++ b/script/vsts/package-lock.json @@ -3,11 +3,6 @@ "requires": true, "lockfileVersion": 1, "dependencies": { - "@sindresorhus/is": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz", - "integrity": "sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==" - }, "ajv": { "version": "5.5.2", "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", @@ -24,20 +19,15 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" }, - "archive-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/archive-type/-/archive-type-4.0.0.tgz", - "integrity": "sha1-+S5yIzBW38aWlHJ0nCZ72wRrHXA=", - "requires": { - "file-type": "^4.2.0" - }, - "dependencies": { - "file-type": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-4.4.0.tgz", - "integrity": "sha1-G2AOX8ofvcboDApwxxyNul95BsU=" - } - } + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=" }, "asn1": { "version": "0.2.3", @@ -49,11 +39,39 @@ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" }, + "async": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", + "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=" + }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, + "aws-sdk": { + "version": "2.292.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.292.0.tgz", + "integrity": "sha512-1Btm3fPwyy/pILfKaByP1MmwrjHtmos1fSORDcbGdc7PGyA5w0Yo9Jh/eqZSqiXH1asQEX1ZzHfTbt69vl4EGQ==", + "requires": { + "buffer": "4.9.1", + "events": "1.1.1", + "ieee754": "1.1.8", + "jmespath": "0.15.0", + "querystring": "0.2.0", + "sax": "1.2.1", + "url": "0.10.3", + "uuid": "3.1.0", + "xml2js": "0.4.19" + }, + "dependencies": { + "uuid": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", + "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==" + } + } + }, "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", @@ -64,10 +82,15 @@ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz", "integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w==" }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, "base64-js": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz", - "integrity": "sha1-EQHpVE9KdrG8OybUUsqW16NeeXg=" + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", + "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==" }, "bcrypt-pbkdf": { "version": "1.0.1", @@ -79,95 +102,87 @@ } }, "bl": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", - "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/bl/-/bl-0.9.5.tgz", + "integrity": "sha1-wGt5evCF6gC8Unr8jvzxHeIjIFQ=", "requires": { - "readable-stream": "^2.3.5", - "safe-buffer": "^5.1.1" + "readable-stream": "~1.0.26" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, "buffer": { - "version": "3.6.0", - "resolved": "http://registry.npmjs.org/buffer/-/buffer-3.6.0.tgz", - "integrity": "sha1-pyyTb3e5a/UvX357RnGAYoVR3vs=", + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", + "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", "requires": { - "base64-js": "0.0.8", + "base64-js": "^1.0.2", "ieee754": "^1.1.4", "isarray": "^1.0.0" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + } } }, - "buffer-alloc": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", - "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", - "requires": { - "buffer-alloc-unsafe": "^1.1.0", - "buffer-fill": "^1.0.0" - } - }, - "buffer-alloc-unsafe": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", - "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==" - }, - "buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" - }, - "buffer-fill": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", - "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=" - }, "builtin-modules": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=" }, - "cacheable-request": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-2.1.4.tgz", - "integrity": "sha1-DYCIAbY0KtM8kd+dC0TcCbkeXD0=", - "requires": { - "clone-response": "1.0.2", - "get-stream": "3.0.0", - "http-cache-semantics": "3.8.1", - "keyv": "3.0.0", - "lowercase-keys": "1.0.0", - "normalize-url": "2.0.1", - "responselike": "1.0.2" - }, - "dependencies": { - "lowercase-keys": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz", - "integrity": "sha1-TjNms55/VFfjXxMkvfb4jQv8cwY=" - } - } - }, "camelcase": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=" }, + "camelcase-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", + "requires": { + "camelcase": "^2.0.0", + "map-obj": "^1.0.0" + }, + "dependencies": { + "camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=" + } + } + }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" }, - "caw": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/caw/-/caw-2.0.1.tgz", - "integrity": "sha512-Cg8/ZSBEa8ZVY9HspcGUYaK63d/bN7rqS3CYCzEGUxuYv6UlmcjzDUz2fCFFHyTvUW5Pk0I+3hkA3iXlIj6guA==", + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "requires": { - "get-proxy": "^2.0.0", - "isurl": "^1.0.0-alpha5", - "tunnel-agent": "^0.6.0", - "url-to-options": "^1.0.1" + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" } }, + "cli-width": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-1.1.1.tgz", + "integrity": "sha1-pNKT72frt7iNSk1CwMzwDE0eNm0=" + }, "cliui": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", @@ -178,14 +193,6 @@ "wrap-ansi": "^2.0.0" } }, - "clone-response": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", - "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", - "requires": { - "mimic-response": "^1.0.0" - } - }, "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -204,33 +211,24 @@ "delayed-stream": "~1.0.0" } }, - "commander": { - "version": "2.8.1", - "resolved": "http://registry.npmjs.org/commander/-/commander-2.8.1.tgz", - "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=", - "requires": { - "graceful-readlink": ">= 1.0.0" - } - }, - "config-chain": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", - "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==", - "requires": { - "ini": "^1.3.4", - "proto-list": "~1.2.1" - } - }, - "content-disposition": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", - "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, + "currently-unhandled": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "requires": { + "array-find-index": "^1.0.1" + } + }, "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", @@ -244,150 +242,32 @@ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" - }, - "decompress": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/decompress/-/decompress-4.2.0.tgz", - "integrity": "sha1-eu3YVCflqS2s/lVnSnxQXpbQH50=", - "requires": { - "decompress-tar": "^4.0.0", - "decompress-tarbz2": "^4.0.0", - "decompress-targz": "^4.0.0", - "decompress-unzip": "^4.0.1", - "graceful-fs": "^4.1.10", - "make-dir": "^1.0.0", - "pify": "^2.3.0", - "strip-dirs": "^2.0.0" - } - }, - "decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", - "requires": { - "mimic-response": "^1.0.0" - } - }, - "decompress-tar": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz", - "integrity": "sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==", - "requires": { - "file-type": "^5.2.0", - "is-stream": "^1.1.0", - "tar-stream": "^1.5.2" - }, - "dependencies": { - "file-type": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", - "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=" - } - } - }, - "decompress-tarbz2": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz", - "integrity": "sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A==", - "requires": { - "decompress-tar": "^4.1.0", - "file-type": "^6.1.0", - "is-stream": "^1.1.0", - "seek-bzip": "^1.0.5", - "unbzip2-stream": "^1.0.9" - }, - "dependencies": { - "file-type": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-6.2.0.tgz", - "integrity": "sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg==" - } - } - }, - "decompress-targz": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz", - "integrity": "sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==", - "requires": { - "decompress-tar": "^4.1.1", - "file-type": "^5.2.0", - "is-stream": "^1.1.0" - }, - "dependencies": { - "file-type": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", - "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=" - } - } - }, - "decompress-unzip": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-4.0.1.tgz", - "integrity": "sha1-3qrM39FK6vhVePczroIQ+bSEj2k=", - "requires": { - "file-type": "^3.8.0", - "get-stream": "^2.2.0", - "pify": "^2.3.0", - "yauzl": "^2.4.2" - }, - "dependencies": { - "file-type": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", - "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=" - }, - "get-stream": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz", - "integrity": "sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4=", - "requires": { - "object-assign": "^4.0.1", - "pinkie-promise": "^2.0.0" - } - } - } - }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, - "download": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/download/-/download-7.1.0.tgz", - "integrity": "sha512-xqnBTVd/E+GxJVrX5/eUJiLYjCGPwMpdL+jGhGU57BvtcA7wwhtHVbXBeUk51kOpW3S7Jn3BQbN9Q1R1Km2qDQ==", + "duplexer2": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", + "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=", "requires": { - "archive-type": "^4.0.0", - "caw": "^2.0.1", - "content-disposition": "^0.5.2", - "decompress": "^4.2.0", - "ext-name": "^5.0.0", - "file-type": "^8.1.0", - "filenamify": "^2.0.0", - "get-stream": "^3.0.0", - "got": "^8.3.1", - "make-dir": "^1.2.0", - "p-event": "^2.1.0", - "pify": "^3.0.0" + "readable-stream": "~1.1.9" }, "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } } } }, - "duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" - }, "ecc-jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", @@ -397,13 +277,10 @@ "jsbn": "~0.1.0" } }, - "end-of-stream": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", - "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", - "requires": { - "once": "^1.4.0" - } + "editor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/editor/-/editor-1.0.0.tgz", + "integrity": "sha1-YMf4e9YrzGqJT6jM1q+3gjok90I=" }, "error-ex": { "version": "1.3.2", @@ -418,22 +295,10 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, - "ext-list": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz", - "integrity": "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==", - "requires": { - "mime-db": "^1.28.0" - } - }, - "ext-name": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz", - "integrity": "sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==", - "requires": { - "ext-list": "^2.0.0", - "sort-keys-length": "^1.0.0" - } + "events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=" }, "extend": { "version": "3.0.1", @@ -455,32 +320,13 @@ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" }, - "fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", "requires": { - "pend": "~1.2.0" - } - }, - "file-type": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-8.1.0.tgz", - "integrity": "sha512-qyQ0pzAy78gVoJsmYeNgl8uH8yKhr1lVhW7JbzJmnlRi0I4R2eEDEJZVKG8agpDnLpacwNbDhLNG/LMdxHD2YQ==" - }, - "filename-reserved-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz", - "integrity": "sha1-q/c9+rc10EVECr/qLZHzieu/oik=" - }, - "filenamify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-2.1.0.tgz", - "integrity": "sha512-ICw7NTT6RsDp2rnYKVd8Fu4cr6ITzGy3+u4vUujPkabyaz+03F24NWEX7fs5fp+kBonlaqPH8fAO2NM+SXt/JA==", - "requires": { - "filename-reserved-regex": "^2.0.0", - "strip-outer": "^1.0.0", - "trim-repeated": "^1.0.0" + "escape-string-regexp": "^1.0.5", + "object-assign": "^4.1.0" } }, "find-up": { @@ -507,37 +353,15 @@ "mime-types": "^2.1.12" } }, - "from2": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", - "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", - "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" - } - }, - "fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" - }, "get-caller-file": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==" }, - "get-proxy": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/get-proxy/-/get-proxy-2.1.0.tgz", - "integrity": "sha512-zmZIaQTWnNQb4R4fJUEp/FC51eZsc6EkErspy3xtIYStaq8EB/hDIWipxsal+E8rz0qD7f2sL/NA9Xee4RInJw==", - "requires": { - "npm-conf": "^1.1.0" - } - }, - "get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" + "get-stdin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=" }, "getpass": { "version": "0.1.7", @@ -547,35 +371,36 @@ "assert-plus": "^1.0.0" } }, - "got": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/got/-/got-8.3.2.tgz", - "integrity": "sha512-qjUJ5U/hawxosMryILofZCkm3C84PLJS/0grRIpjAwu+Lkxxj5cxeCU25BG0/3mDSpXKTyZr8oh8wIgLaH0QCw==", + "ghauth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ghauth/-/ghauth-2.0.1.tgz", + "integrity": "sha1-ebfWiwvPjn0IUqI7FHU539MUrPY=", "requires": { - "@sindresorhus/is": "^0.7.0", - "cacheable-request": "^2.1.1", - "decompress-response": "^3.3.0", - "duplexer3": "^0.1.4", - "get-stream": "^3.0.0", - "into-stream": "^3.1.0", - "is-retry-allowed": "^1.1.0", - "isurl": "^1.0.0-alpha5", - "lowercase-keys": "^1.0.0", - "mimic-response": "^1.0.0", - "p-cancelable": "^0.4.0", - "p-timeout": "^2.0.1", - "pify": "^3.0.0", - "safe-buffer": "^5.1.1", - "timed-out": "^4.0.1", - "url-parse-lax": "^3.0.0", - "url-to-options": "^1.0.1" - }, - "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" - } + "bl": "~0.9.4", + "hyperquest": "~1.2.0", + "mkdirp": "~0.5.0", + "read": "~1.0.5", + "xtend": "~4.0.0" + } + }, + "github-url-to-object": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/github-url-to-object/-/github-url-to-object-1.6.0.tgz", + "integrity": "sha1-iR73+7+rqP7XFRCs2xtOk0apcNw=", + "requires": { + "is-url": "^1.1.0" + } + }, + "glob": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.3.tgz", + "integrity": "sha1-CqI1kxpKlqwT1g/6wvuHe9btT1g=", + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, "graceful-fs": { @@ -583,11 +408,6 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" }, - "graceful-readlink": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", - "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=" - }, "har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", @@ -602,17 +422,12 @@ "har-schema": "^2.0.0" } }, - "has-symbol-support-x": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz", - "integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==" - }, - "has-to-string-tag-x": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz", - "integrity": "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==", + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "requires": { - "has-symbol-support-x": "^1.4.1" + "ansi-regex": "^2.0.0" } }, "hosted-git-info": { @@ -620,11 +435,6 @@ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==" }, - "http-cache-semantics": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", - "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==" - }, "http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", @@ -635,28 +445,67 @@ "sshpk": "^1.7.0" } }, + "hyperquest": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/hyperquest/-/hyperquest-1.2.0.tgz", + "integrity": "sha1-OeH+9miI3Hzg3sbA3YFPb8iUStU=", + "requires": { + "duplexer2": "~0.0.2", + "through2": "~0.6.3" + } + }, "ieee754": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.12.tgz", - "integrity": "sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA==" + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz", + "integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q=" + }, + "indent-string": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", + "requires": { + "repeating": "^2.0.0" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } }, "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, - "ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" - }, - "into-stream": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-3.1.0.tgz", - "integrity": "sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY=", + "inquirer": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.8.5.tgz", + "integrity": "sha1-29dAz2yjtzEpamPOb22WGFHzNt8=", "requires": { - "from2": "^2.1.1", - "p-is-promise": "^1.1.0" + "ansi-regex": "^1.1.1", + "chalk": "^1.0.0", + "cli-width": "^1.0.1", + "figures": "^1.3.5", + "lodash": "^3.3.1", + "readline2": "^0.1.1", + "rx": "^2.4.3", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-regex": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-1.1.1.tgz", + "integrity": "sha1-QchHGUZGN15qGl0Qw8oFTvn8mA0=" + }, + "lodash": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", + "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=" + } } }, "invert-kv": { @@ -677,6 +526,14 @@ "builtin-modules": "^1.0.0" } }, + "is-finite": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", + "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", + "requires": { + "number-is-nan": "^1.0.0" + } + }, "is-fullwidth-code-point": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", @@ -685,59 +542,35 @@ "number-is-nan": "^1.0.0" } }, - "is-natural-number": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz", - "integrity": "sha1-q5124dtM7VHjXeDHLr7PCfc0zeg=" - }, - "is-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", - "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=" - }, - "is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=" - }, - "is-retry-allowed": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz", - "integrity": "sha1-EaBgVotnM5REAz0BJaYaINVk+zQ=" - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" - }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" }, + "is-url": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", + "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==" + }, "is-utf8": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=" }, "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" }, "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" }, - "isurl": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz", - "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==", - "requires": { - "has-to-string-tag-x": "^1.2.0", - "is-object": "^1.0.1" - } + "jmespath": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", + "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=" }, "jsbn": { "version": "0.1.1", @@ -745,11 +578,6 @@ "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", "optional": true }, - "json-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=" - }, "json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", @@ -776,14 +604,6 @@ "verror": "1.10.0" } }, - "keyv": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.0.0.tgz", - "integrity": "sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA==", - "requires": { - "json-buffer": "3.0.0" - } - }, "lcid": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", @@ -814,26 +634,42 @@ "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=" }, - "lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==" - }, - "make-dir": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "loud-rejection": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", "requires": { - "pify": "^3.0.0" - }, - "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" - } + "currently-unhandled": "^0.4.1", + "signal-exit": "^3.0.0" } }, + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=" + }, + "meow": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", + "requires": { + "camelcase-keys": "^2.0.0", + "decamelize": "^1.1.2", + "loud-rejection": "^1.0.0", + "map-obj": "^1.0.1", + "minimist": "^1.1.3", + "normalize-package-data": "^2.3.4", + "object-assign": "^4.0.1", + "read-pkg-up": "^1.0.1", + "redent": "^1.0.0", + "trim-newlines": "^1.0.0" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, "mime-db": { "version": "1.33.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", @@ -847,10 +683,38 @@ "mime-db": "~1.33.0" } }, - "mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + } + } + }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=" }, "normalize-package-data": { "version": "2.4.0", @@ -863,42 +727,6 @@ "validate-npm-package-license": "^3.0.1" } }, - "normalize-url": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-2.0.1.tgz", - "integrity": "sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw==", - "requires": { - "prepend-http": "^2.0.0", - "query-string": "^5.0.1", - "sort-keys": "^2.0.0" - }, - "dependencies": { - "sort-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz", - "integrity": "sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg=", - "requires": { - "is-plain-obj": "^1.0.0" - } - } - } - }, - "npm-conf": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/npm-conf/-/npm-conf-1.1.3.tgz", - "integrity": "sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw==", - "requires": { - "config-chain": "^1.1.11", - "pify": "^3.0.0" - }, - "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" - } - } - }, "number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", @@ -914,6 +742,11 @@ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, + "object-keys": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz", + "integrity": "sha1-KKaq50KN0sOpLz2V8hM13SBOAzY=" + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -930,37 +763,6 @@ "lcid": "^1.0.0" } }, - "p-cancelable": { - "version": "0.4.1", - "resolved": "http://registry.npmjs.org/p-cancelable/-/p-cancelable-0.4.1.tgz", - "integrity": "sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ==" - }, - "p-event": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-event/-/p-event-2.1.0.tgz", - "integrity": "sha512-sDEpDVnzLGlJj3k590uUdpfEUySP5yAYlvfTCu5hTDvSTXQVecYWKcEwdO49PrZlnJ5wkfAvtawnno/jyXeqvA==", - "requires": { - "p-timeout": "^2.0.1" - } - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" - }, - "p-is-promise": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz", - "integrity": "sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=" - }, - "p-timeout": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz", - "integrity": "sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA==", - "requires": { - "p-finally": "^1.0.0" - } - }, "parse-json": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", @@ -977,6 +779,11 @@ "pinkie-promise": "^2.0.0" } }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, "path-type": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", @@ -987,11 +794,6 @@ "pinkie-promise": "^2.0.0" } }, - "pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=" - }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", @@ -1015,20 +817,85 @@ "pinkie": "^2.0.0" } }, - "prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=" + "pkginfo": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.3.1.tgz", + "integrity": "sha1-Wyn2qB9wcXFC4J52W76rl7T4HiE=" }, - "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" + "pretty-bytes": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-1.0.4.tgz", + "integrity": "sha1-CiLoIQYJrTVUL4yNXSFZr/B1HIQ=", + "requires": { + "get-stdin": "^4.0.1", + "meow": "^3.1.0" + } }, - "proto-list": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=" + "progress-stream": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/progress-stream/-/progress-stream-1.2.0.tgz", + "integrity": "sha1-LNPP6jO6OonJwSHsM0er6asSX3c=", + "requires": { + "speedometer": "~0.1.2", + "through2": "~0.2.3" + }, + "dependencies": { + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "through2": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.2.3.tgz", + "integrity": "sha1-6zKE2k6jEbbMis42U3SKUqvyWj8=", + "requires": { + "readable-stream": "~1.1.9", + "xtend": "~2.1.1" + } + }, + "xtend": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz", + "integrity": "sha1-bv7MKk2tjmlixJAbM3znuoe10os=", + "requires": { + "object-keys": "~0.4.0" + } + } + } + }, + "publish-release": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/publish-release/-/publish-release-1.6.0.tgz", + "integrity": "sha512-t+NFXTQN/VDTg9yJ8Uv5ZWQ7Ud1T5W1tPW+bmuo4g6uYVQTVNiwwRF6Td3EtXFTOafpEXJQEZqGG7IvIJwLwIg==", + "requires": { + "async": "^0.9.0", + "ghauth": "^2.0.0", + "github-url-to-object": "^1.4.2", + "inquirer": "^0.8.2", + "lodash": "^3.6.0", + "mime": "^1.3.4", + "minimist": "^1.1.1", + "pkginfo": "^0.3.0", + "pretty-bytes": "^1.0.4", + "progress-stream": "^1.0.1", + "request": "^2.54.0", + "single-line-log": "^0.4.1", + "string-editor": "^0.1.0" + }, + "dependencies": { + "lodash": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", + "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=" + } + } }, "punycode": { "version": "1.4.1", @@ -1040,14 +907,17 @@ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" }, - "query-string": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", - "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" + }, + "read": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", + "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=", "requires": { - "decode-uri-component": "^0.2.0", - "object-assign": "^4.1.0", - "strict-uri-encode": "^1.0.0" + "mute-stream": "~0.0.4" } }, "read-pkg": { @@ -1070,17 +940,60 @@ } }, "readable-stream": { - "version": "2.3.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "requires": { "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "readline2": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/readline2/-/readline2-0.1.1.tgz", + "integrity": "sha1-mUQ7pug7gw7zBRv9fcJBqCco1Wg=", + "requires": { + "mute-stream": "0.0.4", + "strip-ansi": "^2.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-1.1.1.tgz", + "integrity": "sha1-QchHGUZGN15qGl0Qw8oFTvn8mA0=" + }, + "mute-stream": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.4.tgz", + "integrity": "sha1-qSGZYKbV1dBGWXruUSUsZlX3F34=" + }, + "strip-ansi": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-2.0.1.tgz", + "integrity": "sha1-32LBqpTtLxFOHQ8h/R1QSCt5pg4=", + "requires": { + "ansi-regex": "^1.0.0" + } + } + } + }, + "redent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", + "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", + "requires": { + "indent-string": "^2.1.0", + "strip-indent": "^1.0.1" + } + }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "requires": { + "is-finite": "^1.0.0" } }, "request": { @@ -1138,13 +1051,10 @@ "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" }, - "responselike": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", - "requires": { - "lowercase-keys": "^1.0.0" - } + "rx": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/rx/-/rx-2.5.3.tgz", + "integrity": "sha1-Ia3H2A8CACr1Da6X/Z2/JIdV9WY=" }, "safe-buffer": { "version": "5.1.2", @@ -1156,13 +1066,10 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, - "seek-bzip": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.5.tgz", - "integrity": "sha1-z+kXyz0nS8/6x5J1ivUxc+sfq9w=", - "requires": { - "commander": "~2.8.1" - } + "sax": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", + "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=" }, "semver": { "version": "5.5.0", @@ -1174,21 +1081,15 @@ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" }, - "sort-keys": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", - "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=", - "requires": { - "is-plain-obj": "^1.0.0" - } + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" }, - "sort-keys-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz", - "integrity": "sha1-nLb09OnkgVWmqgZx7dM2/xR5oYg=", - "requires": { - "sort-keys": "^1.0.0" - } + "single-line-log": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/single-line-log/-/single-line-log-0.4.1.tgz", + "integrity": "sha1-h6VWSfdJ14PsDc2AToFA2Yc8fO4=" }, "spdx-correct": { "version": "3.0.0", @@ -1218,6 +1119,11 @@ "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz", "integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA==" }, + "speedometer": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/speedometer/-/speedometer-0.1.4.tgz", + "integrity": "sha1-mHbb0qFp0xFUAtSObqYynIgWpQ0=" + }, "sshpk": { "version": "1.14.2", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz", @@ -1239,10 +1145,13 @@ "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=" }, - "strict-uri-encode": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", - "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=" + "string-editor": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/string-editor/-/string-editor-0.1.2.tgz", + "integrity": "sha1-9f8bWsSu16xsL7jeI20VUbIPYdA=", + "requires": { + "editor": "^1.0.0" + } }, "string-width": { "version": "1.0.2", @@ -1255,12 +1164,9 @@ } }, "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" }, "strip-ansi": { "version": "3.0.1", @@ -1278,50 +1184,32 @@ "is-utf8": "^0.2.0" } }, - "strip-dirs": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz", - "integrity": "sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g==", - "requires": { - "is-natural-number": "^4.0.1" - } - }, - "strip-outer": { + "strip-indent": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz", - "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", + "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", "requires": { - "escape-string-regexp": "^1.0.2" + "get-stdin": "^4.0.1" } }, - "tar-stream": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.1.tgz", - "integrity": "sha512-IFLM5wp3QrJODQFPm6/to3LJZrONdBY/otxcvDIQzu217zKye6yVR3hhi9lAjrC2Z+m/j5oDxMPb1qcd8cIvpA==", - "requires": { - "bl": "^1.0.0", - "buffer-alloc": "^1.1.0", - "end-of-stream": "^1.0.0", - "fs-constants": "^1.0.0", - "readable-stream": "^2.3.0", - "to-buffer": "^1.1.0", - "xtend": "^4.0.0" - } + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" }, "through": { "version": "2.3.8", - "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" }, - "timed-out": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", - "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=" - }, - "to-buffer": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", - "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==" + "through2": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", + "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", + "requires": { + "readable-stream": ">=1.0.33-1 <1.1.0-0", + "xtend": ">=4.0.0 <4.1.0-0" + } }, "tough-cookie": { "version": "2.3.4", @@ -1331,13 +1219,10 @@ "punycode": "^1.4.1" } }, - "trim-repeated": { + "trim-newlines": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", - "integrity": "sha1-42RqLqTokTEr9+rObPsFOAvAHCE=", - "requires": { - "escape-string-regexp": "^1.0.2" - } + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", + "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=" }, "tunnel-agent": { "version": "0.6.0", @@ -1353,33 +1238,22 @@ "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", "optional": true }, - "unbzip2-stream": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.2.5.tgz", - "integrity": "sha512-izD3jxT8xkzwtXRUZjtmRwKnZoeECrfZ8ra/ketwOcusbZEp4mjULMnJOCfTDZBgGQAAY1AJ/IgxcwkavcX9Og==", + "url": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", + "integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=", "requires": { - "buffer": "^3.0.1", - "through": "^2.3.6" + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" + } } }, - "url-parse-lax": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", - "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", - "requires": { - "prepend-http": "^2.0.0" - } - }, - "url-to-options": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz", - "integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=" - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, "uuid": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.0.tgz", @@ -1428,6 +1302,20 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, + "xml2js": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", + "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~9.0.1" + } + }, + "xmlbuilder": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", + "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=" + }, "xtend": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", @@ -1467,15 +1355,6 @@ "camelcase": "^3.0.0", "lodash.assign": "^4.0.6" } - }, - "yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", - "requires": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } } } } diff --git a/script/vsts/package.json b/script/vsts/package.json index 10d544292..051fd0286 100644 --- a/script/vsts/package.json +++ b/script/vsts/package.json @@ -3,6 +3,9 @@ "description": "Atom release scripts", "dependencies": { "download": "^7.1.0", + "aws-sdk": "^2.5.2", + "glob": "7.0.3", + "publish-release": "^1.6.0", "request": "^2.87.0", "request-promise-native": "^1.0.5", "yargs": "4.8.1" diff --git a/script/vsts/release-branch-build.yml b/script/vsts/release-branch-build.yml index 75e3ab627..7aea35c66 100644 --- a/script/vsts/release-branch-build.yml +++ b/script/vsts/release-branch-build.yml @@ -49,7 +49,7 @@ jobs: # This has to be done separately because VSTS inexplicably # exits the script block after `npm install` completes. - script: | - cd script + cd script\vsts npm install displayName: npm install @@ -61,6 +61,7 @@ jobs: - script: | $(Build.SourcesDirectory)\script\publish-release.cmd --assets-path "$(System.ArtifactsDirectory)" --s3-path "vsts-artifacts/$(Build.BuildId)/" + node $(Build.SourcesDirectory)\script\vsts\upload-artifacts.js --assets-path "$(System.ArtifactsDirectory)" --s3-path "vsts-artifacts/$(Build.BuildId)/" env: ATOM_RELEASE_VERSION: $(ReleaseVersion) ATOM_RELEASES_S3_KEY: $(ATOM_RELEASES_S3_KEY) diff --git a/script/publish-release b/script/vsts/upload-artifacts.js similarity index 98% rename from script/publish-release rename to script/vsts/upload-artifacts.js index a2d56b9a8..e9ce4e151 100644 --- a/script/publish-release +++ b/script/vsts/upload-artifacts.js @@ -8,7 +8,7 @@ const publishRelease = require('publish-release') const uploadToS3 = require('./lib/upload-to-s3') const uploadLinuxPackages = require('./lib/upload-linux-packages') -const CONFIG = require('./config') +const CONFIG = require('../config') const yargs = require('yargs') const argv = yargs From 1b3ad8ecbb1656cefc41516f6c00774976eec34a Mon Sep 17 00:00:00 2001 From: David Wilson Date: Tue, 14 Aug 2018 11:00:33 -0700 Subject: [PATCH 034/112] Create draft releases on successful release builds --- script/vsts/get-release-version.js | 7 ++++--- script/vsts/release-branch-build.yml | 12 +++++++++++- script/vsts/upload-artifacts.js | 2 +- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/script/vsts/get-release-version.js b/script/vsts/get-release-version.js index 13fbfbea5..6fc03a6c0 100644 --- a/script/vsts/get-release-version.js +++ b/script/vsts/get-release-version.js @@ -49,9 +49,10 @@ async function getReleaseVersion () { const buildBranch = process.env.BUILD_SOURCEBRANCHNAME const isReleaseBranch = process.env.IS_RELEASE_BRANCH || argv.nightly || buildBranch.match(/\d\.\d+-releases/) !== null const isSignedZipBranch = - process.env.IS_SIGNED_ZIP_BRANCH || - buildBranch.startsWith('electron-') || - buildBranch === 'master' && !process.env.SYSTEM_PULLREQUEST_PULLREQUESTNUMBER + !isReleaseBranch && + (process.env.IS_SIGNED_ZIP_BRANCH || + buildBranch.startsWith('electron-') || + buildBranch === 'master' && !process.env.SYSTEM_PULLREQUEST_PULLREQUESTNUMBER) console.log(`##vso[task.setvariable variable=IsReleaseBranch;isOutput=true]${isReleaseBranch}`) console.log(`##vso[task.setvariable variable=IsSignedZipBranch;isOutput=true]${isSignedZipBranch}`) } diff --git a/script/vsts/release-branch-build.yml b/script/vsts/release-branch-build.yml index 7aea35c66..fbd4e80da 100644 --- a/script/vsts/release-branch-build.yml +++ b/script/vsts/release-branch-build.yml @@ -60,7 +60,17 @@ jobs: displayName: Download Release Artifacts - script: | - $(Build.SourcesDirectory)\script\publish-release.cmd --assets-path "$(System.ArtifactsDirectory)" --s3-path "vsts-artifacts/$(Build.BuildId)/" + node $(Build.SourcesDirectory)\script\vsts\upload-artifacts.js --create-github-release --assets-path "$(System.ArtifactsDirectory)" + env: + GITHUB_TOKEN: $(GITHUB_TOKEN) + ATOM_RELEASE_VERSION: $(ReleaseVersion) + ATOM_RELEASES_S3_KEY: $(ATOM_RELEASES_S3_KEY) + ATOM_RELEASES_S3_SECRET: $(ATOM_RELEASES_S3_SECRET) + ATOM_RELEASES_S3_BUCKET: $(ATOM_RELEASES_S3_BUCKET) + displayName: Create Draft Release + condition: and(succeeded(), eq(variables['IsReleaseBranch'], 'true')) + + - script: | node $(Build.SourcesDirectory)\script\vsts\upload-artifacts.js --assets-path "$(System.ArtifactsDirectory)" --s3-path "vsts-artifacts/$(Build.BuildId)/" env: ATOM_RELEASE_VERSION: $(ReleaseVersion) diff --git a/script/vsts/upload-artifacts.js b/script/vsts/upload-artifacts.js index e9ce4e151..69e5dc66d 100644 --- a/script/vsts/upload-artifacts.js +++ b/script/vsts/upload-artifacts.js @@ -60,7 +60,7 @@ async function uploadRelease() { repo: CONFIG.channel !== 'nightly' ? 'atom' : 'atom-nightly-releases', name: CONFIG.computedAppVersion, tag: `v${CONFIG.computedAppVersion}`, - draft: false, + draft: CONFIG.channel !== 'nightly', prerelease: CONFIG.channel !== 'stable', reuseRelease: true, skipIfPublished: true, From 3d532e6b685f349bcbc2cfa6a5b30f19263e3fc5 Mon Sep 17 00:00:00 2001 From: David Wilson Date: Tue, 14 Aug 2018 11:37:25 -0700 Subject: [PATCH 035/112] Use Build.BuildId for more useful build versions --- script/vsts/get-release-version.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/vsts/get-release-version.js b/script/vsts/get-release-version.js index 6fc03a6c0..1e5aac558 100644 --- a/script/vsts/get-release-version.js +++ b/script/vsts/get-release-version.js @@ -42,7 +42,7 @@ async function getReleaseVersion () { if (!process.env.SYSTEM_PULLREQUEST_PULLREQUESTNUMBER) { // Only set the build number on non-PR builds as it causes build errors when // non-admins send PRs to the repo - console.log(`##vso[build.updatebuildnumber]${releaseVersion}+${process.env.BUILD_BUILDNUMBER}`) + console.log(`##vso[build.updatebuildnumber]${releaseVersion}+${process.env.BUILD_BUILDID}`) } // Write out some variables that indicate whether artifacts should be uploaded From 053955165d57e7b8e0e3dd1d2aa597284a704262 Mon Sep 17 00:00:00 2001 From: David Wilson Date: Tue, 14 Aug 2018 11:38:40 -0700 Subject: [PATCH 036/112] Allow release build version to be overridden by ATOM_RELEASE_VERSION --- script/vsts/get-release-version.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/vsts/get-release-version.js b/script/vsts/get-release-version.js index 1e5aac558..61d284d96 100644 --- a/script/vsts/get-release-version.js +++ b/script/vsts/get-release-version.js @@ -13,7 +13,7 @@ const argv = yargs .argv async function getReleaseVersion () { - let releaseVersion = appMetadata.version + let releaseVersion = process.env.ATOM_RELEASE_VERSION || appMetadata.version if (argv.nightly) { const releases = await request({ url: 'https://api.github.com/repos/atom/atom-nightly-releases/releases', From 944a017f70f7548bd8ba8728a3e99b6d92fedde3 Mon Sep 17 00:00:00 2001 From: David Wilson Date: Wed, 15 Aug 2018 16:21:45 -0700 Subject: [PATCH 037/112] WIP: Generate changelog --- script/vsts/lib/release-notes.js | 97 +++++ script/vsts/package-lock.json | 713 ++++++++++++++++++++++++++++++- script/vsts/package.json | 3 + script/vsts/upload-artifacts.js | 19 +- 4 files changed, 827 insertions(+), 5 deletions(-) create mode 100644 script/vsts/lib/release-notes.js diff --git a/script/vsts/lib/release-notes.js b/script/vsts/lib/release-notes.js new file mode 100644 index 000000000..640ebd2cf --- /dev/null +++ b/script/vsts/lib/release-notes.js @@ -0,0 +1,97 @@ +const semver = require('semver') +const changelog = require('pr-changelog') +const octokit = require('@octokit/rest')() + +module.exports.get = async function(releaseVersion, githubToken) { + if (githubToken) { + octokit.authenticate({ + type: 'oauth', + token: githubToken + }) + } + + let releases = await octokit.repos.getReleases({owner: 'atom', repo: 'atom'}) + let release = releases.data.find(r => semver.eq(r.name, releaseVersion)) + return release ? release.body : undefined +} + +module.exports.generate = async function(releaseVersion, githubToken) { + let oldVersion = null + let oldVersionName = null + const parsedVersion = semver.parse(releaseVersion) + const newVersionBranch = getBranchForVersion(parsedVersion) + + if (githubToken) { + changelog.setGithubAccessToken(githubToken) + octokit.authenticate({ + type: 'oauth', + token: githubToken + }) + } + + if (parsedVersion.prerelease && parsedVersion.prerelease[0] === 'beta0') { + // For beta0 releases, stable hasn't been released yet so compare against + // the stable version's release branch + oldVersion = `${parsedVersion.major}.${parsedVersion.minor - 1}-releases` + oldVersionName = `v${parsedVersion.major}.${parsedVersion.minor - 1}.0` + } else { + let releases = await octokit.repos.getReleases({owner: 'atom', repo: 'atom'}) + let versions = releases.data.map(r => r.name) + oldVersion = 'v' + getPreviousVersion(releaseVersion, versions) + oldVersionName = oldVersion + } + + const allChangesText = await changelog.getChangelog({ + owner: 'atom', + repo: 'atom', + fromTag: oldVersion, + toTag: newVersionBranch, + dependencyKey: 'packageDependencies', + changelogFormatter: function ({pullRequests, owner, repo, fromTag, toTag}) { + let prString = changelog.pullRequestsToString(pullRequests) + let title = repo + if (repo === 'atom') { + title = 'Atom Core' + fromTag = oldVersionName + toTag = releaseVersion + } + return `### [${title}](https://github.com/${owner}/${repo})\n\n${fromTag}...${toTag}\n\n${prString}` + } + }) + + return `## Notable Changes\n\n\ +**TODO**: Pull relevant changes here!\n\n\ +
+All Changes\n\n +${allChangesText}\n\n +
+` +} + +function getPreviousVersion (version, allVersions) { + const versionIsStable = semver.prerelease(version) === null + + // Make sure versions are sorted before using them + allVersions.sort(semver.rcompare) + + for (let otherVersion of allVersions) { + if (versionIsStable && semver.prerelease(otherVersion)) { + continue + } + + if (semver.lt(otherVersion, version)) { + return otherVersion + } + } + + return null +} + +function getBranchForVersion (version) { + let parsedVersion = version + if (!(version instanceof semver.SemVer)) { + parsedVersion = semver.parse(version) + } + + return `${parsedVersion.major}.${parsedVersion.minor}-releases` +} diff --git a/script/vsts/package-lock.json b/script/vsts/package-lock.json index f38b34ff8..ecf0130ae 100644 --- a/script/vsts/package-lock.json +++ b/script/vsts/package-lock.json @@ -3,6 +3,29 @@ "requires": true, "lockfileVersion": 1, "dependencies": { + "@octokit/rest": { + "version": "15.9.5", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-15.9.5.tgz", + "integrity": "sha512-vJEHSTnI4UAbCDTjVSQljPeX81zsQVNj2ruM5Oj5gxOttHD0TcfWeElcJYoITCMxQTgN6Y+bJFo6/+/0CqoacA==", + "requires": { + "before-after-hook": "^1.1.0", + "btoa-lite": "^1.0.0", + "debug": "^3.1.0", + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^2.2.0", + "lodash": "^4.17.4", + "node-fetch": "^2.1.1", + "url-template": "^2.0.8" + } + }, + "agent-base": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", + "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==", + "requires": { + "es6-promisify": "^5.0.0" + } + }, "ajv": { "version": "5.5.2", "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", @@ -82,6 +105,461 @@ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz", "integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w==" }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "requires": { + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + } + }, + "babel-helper-call-delegate": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz", + "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=", + "requires": { + "babel-helper-hoist-variables": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-helper-define-map": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz", + "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=", + "requires": { + "babel-helper-function-name": "^6.24.1", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "lodash": "^4.17.4" + } + }, + "babel-helper-function-name": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", + "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", + "requires": { + "babel-helper-get-function-arity": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-helper-get-function-arity": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz", + "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", + "requires": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-helper-hoist-variables": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz", + "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=", + "requires": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-helper-optimise-call-expression": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz", + "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=", + "requires": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-helper-regex": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz", + "integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=", + "requires": { + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "lodash": "^4.17.4" + } + }, + "babel-helper-replace-supers": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz", + "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=", + "requires": { + "babel-helper-optimise-call-expression": "^6.24.1", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-messages": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-check-es2015-constants": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz", + "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=", + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-syntax-async-functions": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", + "integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU=" + }, + "babel-plugin-transform-es2015-arrow-functions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz", + "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=", + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-block-scoped-functions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz", + "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=", + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-block-scoping": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz", + "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=", + "requires": { + "babel-runtime": "^6.26.0", + "babel-template": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "lodash": "^4.17.4" + } + }, + "babel-plugin-transform-es2015-classes": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz", + "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=", + "requires": { + "babel-helper-define-map": "^6.24.1", + "babel-helper-function-name": "^6.24.1", + "babel-helper-optimise-call-expression": "^6.24.1", + "babel-helper-replace-supers": "^6.24.1", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-computed-properties": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz", + "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=", + "requires": { + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-destructuring": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz", + "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=", + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-duplicate-keys": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz", + "integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=", + "requires": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-for-of": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz", + "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=", + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-function-name": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz", + "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=", + "requires": { + "babel-helper-function-name": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-literals": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz", + "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=", + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-modules-amd": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz", + "integrity": "sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=", + "requires": { + "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-modules-commonjs": { + "version": "6.26.2", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz", + "integrity": "sha512-CV9ROOHEdrjcwhIaJNBGMBCodN+1cfkwtM1SbUHmvyy35KGT7fohbpOxkE2uLz1o6odKK2Ck/tz47z+VqQfi9Q==", + "requires": { + "babel-plugin-transform-strict-mode": "^6.24.1", + "babel-runtime": "^6.26.0", + "babel-template": "^6.26.0", + "babel-types": "^6.26.0" + } + }, + "babel-plugin-transform-es2015-modules-systemjs": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz", + "integrity": "sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=", + "requires": { + "babel-helper-hoist-variables": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-modules-umd": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz", + "integrity": "sha1-rJl+YoXNGO1hdq22B9YCNErThGg=", + "requires": { + "babel-plugin-transform-es2015-modules-amd": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-object-super": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz", + "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=", + "requires": { + "babel-helper-replace-supers": "^6.24.1", + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-parameters": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz", + "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=", + "requires": { + "babel-helper-call-delegate": "^6.24.1", + "babel-helper-get-function-arity": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-shorthand-properties": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz", + "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=", + "requires": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-spread": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz", + "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=", + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-sticky-regex": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz", + "integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=", + "requires": { + "babel-helper-regex": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-template-literals": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz", + "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=", + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-typeof-symbol": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz", + "integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=", + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-unicode-regex": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz", + "integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=", + "requires": { + "babel-helper-regex": "^6.24.1", + "babel-runtime": "^6.22.0", + "regexpu-core": "^2.0.0" + } + }, + "babel-plugin-transform-regenerator": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz", + "integrity": "sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8=", + "requires": { + "regenerator-transform": "^0.10.0" + } + }, + "babel-plugin-transform-strict-mode": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz", + "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", + "requires": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-polyfill": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz", + "integrity": "sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=", + "requires": { + "babel-runtime": "^6.26.0", + "core-js": "^2.5.0", + "regenerator-runtime": "^0.10.5" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz", + "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=" + } + } + }, + "babel-preset-es2015": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz", + "integrity": "sha1-1EBQ1rwsn+6nAqrzjXJ6AhBTiTk=", + "requires": { + "babel-plugin-check-es2015-constants": "^6.22.0", + "babel-plugin-transform-es2015-arrow-functions": "^6.22.0", + "babel-plugin-transform-es2015-block-scoped-functions": "^6.22.0", + "babel-plugin-transform-es2015-block-scoping": "^6.24.1", + "babel-plugin-transform-es2015-classes": "^6.24.1", + "babel-plugin-transform-es2015-computed-properties": "^6.24.1", + "babel-plugin-transform-es2015-destructuring": "^6.22.0", + "babel-plugin-transform-es2015-duplicate-keys": "^6.24.1", + "babel-plugin-transform-es2015-for-of": "^6.22.0", + "babel-plugin-transform-es2015-function-name": "^6.24.1", + "babel-plugin-transform-es2015-literals": "^6.22.0", + "babel-plugin-transform-es2015-modules-amd": "^6.24.1", + "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1", + "babel-plugin-transform-es2015-modules-systemjs": "^6.24.1", + "babel-plugin-transform-es2015-modules-umd": "^6.24.1", + "babel-plugin-transform-es2015-object-super": "^6.24.1", + "babel-plugin-transform-es2015-parameters": "^6.24.1", + "babel-plugin-transform-es2015-shorthand-properties": "^6.24.1", + "babel-plugin-transform-es2015-spread": "^6.22.0", + "babel-plugin-transform-es2015-sticky-regex": "^6.24.1", + "babel-plugin-transform-es2015-template-literals": "^6.22.0", + "babel-plugin-transform-es2015-typeof-symbol": "^6.22.0", + "babel-plugin-transform-es2015-unicode-regex": "^6.24.1", + "babel-plugin-transform-regenerator": "^6.24.1" + } + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "requires": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + } + }, + "babel-template": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", + "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", + "requires": { + "babel-runtime": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "lodash": "^4.17.4" + } + }, + "babel-traverse": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", + "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", + "requires": { + "babel-code-frame": "^6.26.0", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "debug": "^2.6.8", + "globals": "^9.18.0", + "invariant": "^2.2.2", + "lodash": "^4.17.4" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "babel-types": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "requires": { + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" + } + }, + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==" + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -101,6 +579,11 @@ "tweetnacl": "^0.14.3" } }, + "before-after-hook": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-1.1.0.tgz", + "integrity": "sha512-VOMDtYPwLbIncTxNoSzRyvaMxtXmLWLUqr8k5AfC1BzLk34HvBXaQX8snOwQZ4c0aX8aSERqtJSiI9/m2u5kuA==" + }, "bl": { "version": "0.9.5", "resolved": "https://registry.npmjs.org/bl/-/bl-0.9.5.tgz", @@ -109,6 +592,11 @@ "readable-stream": "~1.0.26" } }, + "bluebird": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", + "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -118,6 +606,11 @@ "concat-map": "0.0.1" } }, + "btoa-lite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/btoa-lite/-/btoa-lite-1.0.0.tgz", + "integrity": "sha1-M3dm2hWAEhD92VbCLpxokaudAzc=" + }, "buffer": { "version": "4.9.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", @@ -216,6 +709,11 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, + "core-js": { + "version": "2.5.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", + "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==" + }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -237,6 +735,14 @@ "assert-plus": "^1.0.0" } }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, "decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", @@ -290,16 +796,39 @@ "is-arrayish": "^0.2.1" } }, + "es6-promise": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.4.tgz", + "integrity": "sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ==" + }, + "es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "requires": { + "es6-promise": "^4.0.3" + } + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" + }, "events": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=" }, + "expand-home-dir": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/expand-home-dir/-/expand-home-dir-0.0.3.tgz", + "integrity": "sha1-ct6KBIbMKKO71wRjU5iCW1tign0=" + }, "extend": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", @@ -383,6 +912,11 @@ "xtend": "~4.0.0" } }, + "github": { + "version": "0.1.16", + "resolved": "https://registry.npmjs.org/github/-/github-0.1.16.tgz", + "integrity": "sha1-iV0qhbD+t5gNiawM5PRNyqA/F7U=" + }, "github-url-to-object": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/github-url-to-object/-/github-url-to-object-1.6.0.tgz", @@ -403,6 +937,11 @@ "path-is-absolute": "^1.0.0" } }, + "globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==" + }, "graceful-fs": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", @@ -435,6 +974,15 @@ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==" }, + "http-proxy-agent": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", + "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", + "requires": { + "agent-base": "4", + "debug": "3.1.0" + } + }, "http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", @@ -445,6 +993,15 @@ "sshpk": "^1.7.0" } }, + "https-proxy-agent": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz", + "integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==", + "requires": { + "agent-base": "^4.1.0", + "debug": "^3.1.0" + } + }, "hyperquest": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/hyperquest/-/hyperquest-1.2.0.tgz", @@ -508,6 +1065,14 @@ } } }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "requires": { + "loose-envify": "^1.0.0" + } + }, "invert-kv": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", @@ -572,12 +1137,22 @@ "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=" }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" + }, "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", "optional": true }, + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=" + }, "json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", @@ -634,6 +1209,14 @@ "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=" }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, "loud-rejection": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", @@ -711,11 +1294,26 @@ } } }, + "moment": { + "version": "2.22.2", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.22.2.tgz", + "integrity": "sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y=" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, "mute-stream": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=" }, + "node-fetch": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.2.0.tgz", + "integrity": "sha512-OayFWziIxiHY8bCUyLX6sTpDH8Jsbp4FfYd1j1f7vZyfgkcOnAyM4oQR16f8a0s7Gl/viMGRey8eScYk4V4EZA==" + }, "normalize-package-data": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", @@ -771,6 +1369,14 @@ "error-ex": "^1.2.0" } }, + "parse-link-header": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/parse-link-header/-/parse-link-header-0.4.1.tgz", + "integrity": "sha1-9r1hXcZxP9QJNc6XlF5NP1Iu3xQ=", + "requires": { + "xtend": "~4.0.0" + } + }, "path-exists": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", @@ -822,6 +1428,49 @@ "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.3.1.tgz", "integrity": "sha1-Wyn2qB9wcXFC4J52W76rl7T4HiE=" }, + "pr-changelog": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/pr-changelog/-/pr-changelog-0.3.0.tgz", + "integrity": "sha1-e4nnchvH/EdhCjUwjY3MCJTtalk=", + "requires": { + "babel-plugin-syntax-async-functions": "^6.1.4", + "babel-plugin-transform-regenerator": "^6.1.4", + "babel-polyfill": "^6.1.4", + "babel-preset-es2015": "^6.1.4", + "bluebird": "^3.0.6", + "expand-home-dir": "0.0.3", + "github": "^0.1.16", + "moment": "^2.10.6", + "parse-link-header": "^0.4.1", + "yargs": "^3.31.0" + }, + "dependencies": { + "camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=" + }, + "window-size": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz", + "integrity": "sha1-+OGqHuWlPsW/FR/6CXQqatdpeHY=" + }, + "yargs": { + "version": "3.32.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.32.0.tgz", + "integrity": "sha1-AwiOnr+edWtpdRYR0qXvWRSCyZU=", + "requires": { + "camelcase": "^2.0.1", + "cliui": "^3.0.3", + "decamelize": "^1.1.1", + "os-locale": "^1.4.0", + "string-width": "^1.0.1", + "window-size": "^0.1.4", + "y18n": "^3.2.0" + } + } + } + }, "pretty-bytes": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-1.0.4.tgz", @@ -831,6 +1480,11 @@ "meow": "^3.1.0" } }, + "private": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==" + }, "progress-stream": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/progress-stream/-/progress-stream-1.2.0.tgz", @@ -988,6 +1642,49 @@ "strip-indent": "^1.0.1" } }, + "regenerate": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", + "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==" + }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + }, + "regenerator-transform": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz", + "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==", + "requires": { + "babel-runtime": "^6.18.0", + "babel-types": "^6.19.0", + "private": "^0.1.6" + } + }, + "regexpu-core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz", + "integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=", + "requires": { + "regenerate": "^1.2.1", + "regjsgen": "^0.2.0", + "regjsparser": "^0.1.4" + } + }, + "regjsgen": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", + "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=" + }, + "regjsparser": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", + "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", + "requires": { + "jsesc": "~0.5.0" + } + }, "repeating": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", @@ -1072,9 +1769,9 @@ "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=" }, "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=" }, "set-blocking": { "version": "2.0.0", @@ -1211,6 +1908,11 @@ "xtend": ">=4.0.0 <4.1.0-0" } }, + "to-fast-properties": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=" + }, "tough-cookie": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", @@ -1254,6 +1956,11 @@ } } }, + "url-template": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", + "integrity": "sha1-/FZaPMy/93MMd19WQflVV5FDnyE=" + }, "uuid": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.0.tgz", diff --git a/script/vsts/package.json b/script/vsts/package.json index 051fd0286..20483d0c5 100644 --- a/script/vsts/package.json +++ b/script/vsts/package.json @@ -3,11 +3,14 @@ "description": "Atom release scripts", "dependencies": { "download": "^7.1.0", + "@octokit/rest": "^15.9.5", "aws-sdk": "^2.5.2", "glob": "7.0.3", + "pr-changelog": "^0.3.0", "publish-release": "^1.6.0", "request": "^2.87.0", "request-promise-native": "^1.0.5", + "semver": "5.3.0", "yargs": "4.8.1" } } diff --git a/script/vsts/upload-artifacts.js b/script/vsts/upload-artifacts.js index 69e5dc66d..6514a1628 100644 --- a/script/vsts/upload-artifacts.js +++ b/script/vsts/upload-artifacts.js @@ -21,6 +21,7 @@ const argv = yargs .wrap(yargs.terminalWidth()) .argv +const isNightlyRelease = CONFIG.channel === 'nightly' const assetsPath = argv.assetsPath || path.join(CONFIG.repositoryRootPath, 'out') const assetsPattern = '/**/*(*.exe|*.zip|*.nupkg|*.tar.gz|*.rpm|*.deb|RELEASES*|atom-api.json)' const assets = glob.sync(assetsPattern, { root: assetsPath, nodir: true }) @@ -31,7 +32,7 @@ if (!assets || assets.length === 0) { process.exit(1) } -async function uploadRelease() { +async function uploadArtifacts() { console.log(`Uploading ${assets.length} release assets for ${CONFIG.computedAppVersion} to S3 under '${bucketPath}'`) await uploadToS3( @@ -61,6 +62,17 @@ async function uploadRelease() { name: CONFIG.computedAppVersion, tag: `v${CONFIG.computedAppVersion}`, draft: CONFIG.channel !== 'nightly', + + if (argv.createGithubRelease) { + console.log(`Creating GitHub release v${CONFIG.computedAppVersion}`) + const release = + await publishReleaseAsync({ + token: process.env.GITHUB_TOKEN, + owner: 'atom', + repo: !isNightlyRelease ? 'atom' : 'atom-nightly-releases', + name: CONFIG.computedAppVersion, + tag: `v${CONFIG.computedAppVersion}`, + draft: !isNightlyRelease, prerelease: CONFIG.channel !== 'stable', reuseRelease: true, skipIfPublished: true, @@ -85,7 +97,10 @@ async function publishReleaseAsync(options) { }) } -uploadRelease().catch((err) => { + +// Wrap the call the async function and catch errors from its promise because +// Node.js doesn't yet allow use of await at the script scope +uploadArtifacts().catch(err => { console.error('An error occurred while uploading the release:\n\n', err) process.exit(1) }) From 0fc3b34292837765eabe33279c1cf829a3541431 Mon Sep 17 00:00:00 2001 From: David Wilson Date: Tue, 30 Oct 2018 11:54:58 -0700 Subject: [PATCH 038/112] Move upload-linux-package.js to script/vsts/lib --- script/package.json | 2 -- script/{ => vsts}/lib/upload-linux-packages.js | 0 2 files changed, 2 deletions(-) rename script/{ => vsts}/lib/upload-linux-packages.js (100%) diff --git a/script/package.json b/script/package.json index 248efed4c..d8e44c849 100644 --- a/script/package.json +++ b/script/package.json @@ -28,8 +28,6 @@ "passwd-user": "2.1.0", "pegjs": "0.9.0", "random-seed": "^0.3.0", - "request": "^2.87.0", - "request-promise-native": "^1.0.5", "season": "5.3.0", "semver": "5.3.0", "standard": "8.4.0", diff --git a/script/lib/upload-linux-packages.js b/script/vsts/lib/upload-linux-packages.js similarity index 100% rename from script/lib/upload-linux-packages.js rename to script/vsts/lib/upload-linux-packages.js From 83b90df5fe7ebd25a5328b372a9e12376c48aaca Mon Sep 17 00:00:00 2001 From: David Wilson Date: Tue, 30 Oct 2018 11:55:50 -0700 Subject: [PATCH 039/112] Slight cleanup after rebase --- script/vsts/release-branch-build.yml | 2 +- script/vsts/upload-artifacts.js | 12 ------------ 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/script/vsts/release-branch-build.yml b/script/vsts/release-branch-build.yml index fbd4e80da..b48afebce 100644 --- a/script/vsts/release-branch-build.yml +++ b/script/vsts/release-branch-build.yml @@ -67,6 +67,7 @@ jobs: ATOM_RELEASES_S3_KEY: $(ATOM_RELEASES_S3_KEY) ATOM_RELEASES_S3_SECRET: $(ATOM_RELEASES_S3_SECRET) ATOM_RELEASES_S3_BUCKET: $(ATOM_RELEASES_S3_BUCKET) + PACKAGE_CLOUD_API_KEY: $(PACKAGE_CLOUD_API_KEY) displayName: Create Draft Release condition: and(succeeded(), eq(variables['IsReleaseBranch'], 'true')) @@ -77,6 +78,5 @@ jobs: ATOM_RELEASES_S3_KEY: $(ATOM_RELEASES_S3_KEY) ATOM_RELEASES_S3_SECRET: $(ATOM_RELEASES_S3_SECRET) ATOM_RELEASES_S3_BUCKET: $(ATOM_RELEASES_S3_BUCKET) - PACKAGE_CLOUD_API_KEY: $(PACKAGE_CLOUD_API_KEY) displayName: Upload CI Artifacts to S3 condition: and(succeeded(), eq(variables['IsSignedZipBranch'], 'true')) diff --git a/script/vsts/upload-artifacts.js b/script/vsts/upload-artifacts.js index 6514a1628..61af4ffcf 100644 --- a/script/vsts/upload-artifacts.js +++ b/script/vsts/upload-artifacts.js @@ -52,17 +52,6 @@ async function uploadArtifacts() { console.log("Skipping upload of Linux packages") } - if (argv.createGithubRelease) { - console.log(`Creating GitHub release v${CONFIG.computedAppVersion}`) - const release = - await publishReleaseAsync({ - token: process.env.GITHUB_TOKEN, - owner: 'atom', - repo: CONFIG.channel !== 'nightly' ? 'atom' : 'atom-nightly-releases', - name: CONFIG.computedAppVersion, - tag: `v${CONFIG.computedAppVersion}`, - draft: CONFIG.channel !== 'nightly', - if (argv.createGithubRelease) { console.log(`Creating GitHub release v${CONFIG.computedAppVersion}`) const release = @@ -97,7 +86,6 @@ async function publishReleaseAsync(options) { }) } - // Wrap the call the async function and catch errors from its promise because // Node.js doesn't yet allow use of await at the script scope uploadArtifacts().catch(err => { From 025c56f3c100b0c005017cee7c44ad86d2c16061 Mon Sep 17 00:00:00 2001 From: David Wilson Date: Tue, 30 Oct 2018 12:01:07 -0700 Subject: [PATCH 040/112] :lock: Update package-lock.json --- script/vsts/package-lock.json | 772 ++++++++++++++++++++++++++++++++++ 1 file changed, 772 insertions(+) diff --git a/script/vsts/package-lock.json b/script/vsts/package-lock.json index ecf0130ae..f4c30a270 100644 --- a/script/vsts/package-lock.json +++ b/script/vsts/package-lock.json @@ -18,6 +18,11 @@ "url-template": "^2.0.8" } }, + "@sindresorhus/is": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz", + "integrity": "sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==" + }, "agent-base": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", @@ -47,6 +52,21 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" }, + "archive-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/archive-type/-/archive-type-4.0.0.tgz", + "integrity": "sha1-+S5yIzBW38aWlHJ0nCZ72wRrHXA=", + "requires": { + "file-type": "^4.2.0" + }, + "dependencies": { + "file-type": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-4.4.0.tgz", + "integrity": "sha1-G2AOX8ofvcboDApwxxyNul95BsU=" + } + } + }, "array-find-index": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", @@ -628,11 +648,56 @@ } } }, + "buffer-alloc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", + "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "requires": { + "buffer-alloc-unsafe": "^1.1.0", + "buffer-fill": "^1.0.0" + } + }, + "buffer-alloc-unsafe": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==" + }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" + }, + "buffer-fill": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", + "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=" + }, "builtin-modules": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=" }, + "cacheable-request": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-2.1.4.tgz", + "integrity": "sha1-DYCIAbY0KtM8kd+dC0TcCbkeXD0=", + "requires": { + "clone-response": "1.0.2", + "get-stream": "3.0.0", + "http-cache-semantics": "3.8.1", + "keyv": "3.0.0", + "lowercase-keys": "1.0.0", + "normalize-url": "2.0.1", + "responselike": "1.0.2" + }, + "dependencies": { + "lowercase-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz", + "integrity": "sha1-TjNms55/VFfjXxMkvfb4jQv8cwY=" + } + } + }, "camelcase": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", @@ -659,6 +724,17 @@ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" }, + "caw": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/caw/-/caw-2.0.1.tgz", + "integrity": "sha512-Cg8/ZSBEa8ZVY9HspcGUYaK63d/bN7rqS3CYCzEGUxuYv6UlmcjzDUz2fCFFHyTvUW5Pk0I+3hkA3iXlIj6guA==", + "requires": { + "get-proxy": "^2.0.0", + "isurl": "^1.0.0-alpha5", + "tunnel-agent": "^0.6.0", + "url-to-options": "^1.0.1" + } + }, "chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", @@ -686,6 +762,14 @@ "wrap-ansi": "^2.0.0" } }, + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "requires": { + "mimic-response": "^1.0.0" + } + }, "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -704,11 +788,33 @@ "delayed-stream": "~1.0.0" } }, + "commander": { + "version": "2.8.1", + "resolved": "http://registry.npmjs.org/commander/-/commander-2.8.1.tgz", + "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=", + "requires": { + "graceful-readlink": ">= 1.0.0" + } + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, + "config-chain": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", + "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==", + "requires": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" + }, "core-js": { "version": "2.5.7", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", @@ -748,11 +854,145 @@ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" + }, + "decompress": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/decompress/-/decompress-4.2.0.tgz", + "integrity": "sha1-eu3YVCflqS2s/lVnSnxQXpbQH50=", + "requires": { + "decompress-tar": "^4.0.0", + "decompress-tarbz2": "^4.0.0", + "decompress-targz": "^4.0.0", + "decompress-unzip": "^4.0.1", + "graceful-fs": "^4.1.10", + "make-dir": "^1.0.0", + "pify": "^2.3.0", + "strip-dirs": "^2.0.0" + } + }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "requires": { + "mimic-response": "^1.0.0" + } + }, + "decompress-tar": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz", + "integrity": "sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==", + "requires": { + "file-type": "^5.2.0", + "is-stream": "^1.1.0", + "tar-stream": "^1.5.2" + }, + "dependencies": { + "file-type": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", + "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=" + } + } + }, + "decompress-tarbz2": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz", + "integrity": "sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A==", + "requires": { + "decompress-tar": "^4.1.0", + "file-type": "^6.1.0", + "is-stream": "^1.1.0", + "seek-bzip": "^1.0.5", + "unbzip2-stream": "^1.0.9" + }, + "dependencies": { + "file-type": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-6.2.0.tgz", + "integrity": "sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg==" + } + } + }, + "decompress-targz": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz", + "integrity": "sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==", + "requires": { + "decompress-tar": "^4.1.1", + "file-type": "^5.2.0", + "is-stream": "^1.1.0" + }, + "dependencies": { + "file-type": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", + "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=" + } + } + }, + "decompress-unzip": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-4.0.1.tgz", + "integrity": "sha1-3qrM39FK6vhVePczroIQ+bSEj2k=", + "requires": { + "file-type": "^3.8.0", + "get-stream": "^2.2.0", + "pify": "^2.3.0", + "yauzl": "^2.4.2" + }, + "dependencies": { + "file-type": { + "version": "3.9.0", + "resolved": "http://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", + "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=" + }, + "get-stream": { + "version": "2.3.1", + "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz", + "integrity": "sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4=", + "requires": { + "object-assign": "^4.0.1", + "pinkie-promise": "^2.0.0" + } + } + } + }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, + "download": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/download/-/download-7.1.0.tgz", + "integrity": "sha512-xqnBTVd/E+GxJVrX5/eUJiLYjCGPwMpdL+jGhGU57BvtcA7wwhtHVbXBeUk51kOpW3S7Jn3BQbN9Q1R1Km2qDQ==", + "requires": { + "archive-type": "^4.0.0", + "caw": "^2.0.1", + "content-disposition": "^0.5.2", + "decompress": "^4.2.0", + "ext-name": "^5.0.0", + "file-type": "^8.1.0", + "filenamify": "^2.0.0", + "get-stream": "^3.0.0", + "got": "^8.3.1", + "make-dir": "^1.2.0", + "p-event": "^2.1.0", + "pify": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" + } + } + }, "duplexer2": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", @@ -774,6 +1014,11 @@ } } }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" + }, "ecc-jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", @@ -788,6 +1033,14 @@ "resolved": "https://registry.npmjs.org/editor/-/editor-1.0.0.tgz", "integrity": "sha1-YMf4e9YrzGqJT6jM1q+3gjok90I=" }, + "end-of-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", + "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", + "requires": { + "once": "^1.4.0" + } + }, "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -829,6 +1082,23 @@ "resolved": "https://registry.npmjs.org/expand-home-dir/-/expand-home-dir-0.0.3.tgz", "integrity": "sha1-ct6KBIbMKKO71wRjU5iCW1tign0=" }, + "ext-list": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz", + "integrity": "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==", + "requires": { + "mime-db": "^1.28.0" + } + }, + "ext-name": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz", + "integrity": "sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==", + "requires": { + "ext-list": "^2.0.0", + "sort-keys-length": "^1.0.0" + } + }, "extend": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", @@ -849,6 +1119,14 @@ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" }, + "fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "requires": { + "pend": "~1.2.0" + } + }, "figures": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", @@ -858,6 +1136,26 @@ "object-assign": "^4.1.0" } }, + "file-type": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-8.1.0.tgz", + "integrity": "sha512-qyQ0pzAy78gVoJsmYeNgl8uH8yKhr1lVhW7JbzJmnlRi0I4R2eEDEJZVKG8agpDnLpacwNbDhLNG/LMdxHD2YQ==" + }, + "filename-reserved-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz", + "integrity": "sha1-q/c9+rc10EVECr/qLZHzieu/oik=" + }, + "filenamify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-2.1.0.tgz", + "integrity": "sha512-ICw7NTT6RsDp2rnYKVd8Fu4cr6ITzGy3+u4vUujPkabyaz+03F24NWEX7fs5fp+kBonlaqPH8fAO2NM+SXt/JA==", + "requires": { + "filename-reserved-regex": "^2.0.0", + "strip-outer": "^1.0.0", + "trim-repeated": "^1.0.0" + } + }, "find-up": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", @@ -882,16 +1180,72 @@ "mime-types": "^2.1.12" } }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, "get-caller-file": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==" }, + "get-proxy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/get-proxy/-/get-proxy-2.1.0.tgz", + "integrity": "sha512-zmZIaQTWnNQb4R4fJUEp/FC51eZsc6EkErspy3xtIYStaq8EB/hDIWipxsal+E8rz0qD7f2sL/NA9Xee4RInJw==", + "requires": { + "npm-conf": "^1.1.0" + } + }, "get-stdin": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=" }, + "get-stream": { + "version": "3.0.0", + "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" + }, "getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", @@ -942,11 +1296,47 @@ "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==" }, + "got": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/got/-/got-8.3.2.tgz", + "integrity": "sha512-qjUJ5U/hawxosMryILofZCkm3C84PLJS/0grRIpjAwu+Lkxxj5cxeCU25BG0/3mDSpXKTyZr8oh8wIgLaH0QCw==", + "requires": { + "@sindresorhus/is": "^0.7.0", + "cacheable-request": "^2.1.1", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "into-stream": "^3.1.0", + "is-retry-allowed": "^1.1.0", + "isurl": "^1.0.0-alpha5", + "lowercase-keys": "^1.0.0", + "mimic-response": "^1.0.0", + "p-cancelable": "^0.4.0", + "p-timeout": "^2.0.1", + "pify": "^3.0.0", + "safe-buffer": "^5.1.1", + "timed-out": "^4.0.1", + "url-parse-lax": "^3.0.0", + "url-to-options": "^1.0.1" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" + } + } + }, "graceful-fs": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" }, + "graceful-readlink": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=" + }, "har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", @@ -969,11 +1359,29 @@ "ansi-regex": "^2.0.0" } }, + "has-symbol-support-x": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz", + "integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==" + }, + "has-to-string-tag-x": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz", + "integrity": "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==", + "requires": { + "has-symbol-support-x": "^1.4.1" + } + }, "hosted-git-info": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==" }, + "http-cache-semantics": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", + "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==" + }, "http-proxy-agent": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", @@ -1038,6 +1446,11 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" + }, "inquirer": { "version": "0.8.5", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.8.5.tgz", @@ -1065,6 +1478,15 @@ } } }, + "into-stream": { + "version": "3.1.0", + "resolved": "http://registry.npmjs.org/into-stream/-/into-stream-3.1.0.tgz", + "integrity": "sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY=", + "requires": { + "from2": "^2.1.1", + "p-is-promise": "^1.1.0" + } + }, "invariant": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", @@ -1107,6 +1529,31 @@ "number-is-nan": "^1.0.0" } }, + "is-natural-number": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz", + "integrity": "sha1-q5124dtM7VHjXeDHLr7PCfc0zeg=" + }, + "is-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", + "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=" + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=" + }, + "is-retry-allowed": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz", + "integrity": "sha1-EaBgVotnM5REAz0BJaYaINVk+zQ=" + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" + }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", @@ -1132,6 +1579,15 @@ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" }, + "isurl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz", + "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==", + "requires": { + "has-to-string-tag-x": "^1.2.0", + "is-object": "^1.0.1" + } + }, "jmespath": { "version": "0.15.0", "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", @@ -1153,6 +1609,11 @@ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=" }, + "json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=" + }, "json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", @@ -1179,6 +1640,14 @@ "verror": "1.10.0" } }, + "keyv": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.0.0.tgz", + "integrity": "sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA==", + "requires": { + "json-buffer": "3.0.0" + } + }, "lcid": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", @@ -1226,6 +1695,26 @@ "signal-exit": "^3.0.0" } }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==" + }, + "make-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "requires": { + "pify": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" + } + } + }, "map-obj": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", @@ -1266,6 +1755,11 @@ "mime-db": "~1.33.0" } }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -1325,6 +1819,42 @@ "validate-npm-package-license": "^3.0.1" } }, + "normalize-url": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-2.0.1.tgz", + "integrity": "sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw==", + "requires": { + "prepend-http": "^2.0.0", + "query-string": "^5.0.1", + "sort-keys": "^2.0.0" + }, + "dependencies": { + "sort-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz", + "integrity": "sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg=", + "requires": { + "is-plain-obj": "^1.0.0" + } + } + } + }, + "npm-conf": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/npm-conf/-/npm-conf-1.1.3.tgz", + "integrity": "sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw==", + "requires": { + "config-chain": "^1.1.11", + "pify": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" + } + } + }, "number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", @@ -1361,6 +1891,37 @@ "lcid": "^1.0.0" } }, + "p-cancelable": { + "version": "0.4.1", + "resolved": "http://registry.npmjs.org/p-cancelable/-/p-cancelable-0.4.1.tgz", + "integrity": "sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ==" + }, + "p-event": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-event/-/p-event-2.1.0.tgz", + "integrity": "sha512-sDEpDVnzLGlJj3k590uUdpfEUySP5yAYlvfTCu5hTDvSTXQVecYWKcEwdO49PrZlnJ5wkfAvtawnno/jyXeqvA==", + "requires": { + "p-timeout": "^2.0.1" + } + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" + }, + "p-is-promise": { + "version": "1.1.0", + "resolved": "http://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz", + "integrity": "sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=" + }, + "p-timeout": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz", + "integrity": "sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA==", + "requires": { + "p-finally": "^1.0.0" + } + }, "parse-json": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", @@ -1400,6 +1961,11 @@ "pinkie-promise": "^2.0.0" } }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=" + }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", @@ -1471,6 +2037,11 @@ } } }, + "prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=" + }, "pretty-bytes": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-1.0.4.tgz", @@ -1485,6 +2056,11 @@ "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==" }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" + }, "progress-stream": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/progress-stream/-/progress-stream-1.2.0.tgz", @@ -1524,6 +2100,11 @@ } } }, + "proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=" + }, "publish-release": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/publish-release/-/publish-release-1.6.0.tgz", @@ -1561,6 +2142,16 @@ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" }, + "query-string": { + "version": "5.1.1", + "resolved": "http://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", + "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", + "requires": { + "decode-uri-component": "^0.2.0", + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + } + }, "querystring": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", @@ -1748,6 +2339,14 @@ "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" }, + "responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "requires": { + "lowercase-keys": "^1.0.0" + } + }, "rx": { "version": "2.5.3", "resolved": "https://registry.npmjs.org/rx/-/rx-2.5.3.tgz", @@ -1768,6 +2367,14 @@ "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=" }, + "seek-bzip": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.5.tgz", + "integrity": "sha1-z+kXyz0nS8/6x5J1ivUxc+sfq9w=", + "requires": { + "commander": "~2.8.1" + } + }, "semver": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", @@ -1788,6 +2395,22 @@ "resolved": "https://registry.npmjs.org/single-line-log/-/single-line-log-0.4.1.tgz", "integrity": "sha1-h6VWSfdJ14PsDc2AToFA2Yc8fO4=" }, + "sort-keys": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", + "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=", + "requires": { + "is-plain-obj": "^1.0.0" + } + }, + "sort-keys-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz", + "integrity": "sha1-nLb09OnkgVWmqgZx7dM2/xR5oYg=", + "requires": { + "sort-keys": "^1.0.0" + } + }, "spdx-correct": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", @@ -1842,6 +2465,11 @@ "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=" }, + "strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=" + }, "string-editor": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/string-editor/-/string-editor-0.1.2.tgz", @@ -1881,6 +2509,14 @@ "is-utf8": "^0.2.0" } }, + "strip-dirs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz", + "integrity": "sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g==", + "requires": { + "is-natural-number": "^4.0.1" + } + }, "strip-indent": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", @@ -1889,11 +2525,71 @@ "get-stdin": "^4.0.1" } }, + "strip-outer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz", + "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==", + "requires": { + "escape-string-regexp": "^1.0.2" + } + }, "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" }, + "tar-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", + "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", + "requires": { + "bl": "^1.0.0", + "buffer-alloc": "^1.2.0", + "end-of-stream": "^1.0.0", + "fs-constants": "^1.0.0", + "readable-stream": "^2.3.0", + "to-buffer": "^1.1.1", + "xtend": "^4.0.0" + }, + "dependencies": { + "bl": { + "version": "1.2.2", + "resolved": "http://registry.npmjs.org/bl/-/bl-1.2.2.tgz", + "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", + "requires": { + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", @@ -1908,6 +2604,16 @@ "xtend": ">=4.0.0 <4.1.0-0" } }, + "timed-out": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=" + }, + "to-buffer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", + "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==" + }, "to-fast-properties": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", @@ -1926,6 +2632,14 @@ "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=" }, + "trim-repeated": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", + "integrity": "sha1-42RqLqTokTEr9+rObPsFOAvAHCE=", + "requires": { + "escape-string-regexp": "^1.0.2" + } + }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -1940,6 +2654,37 @@ "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", "optional": true }, + "unbzip2-stream": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.3.1.tgz", + "integrity": "sha512-fIZnvdjblYs7Cru/xC6tCPVhz7JkYcVQQkePwMLyQELzYTds2Xn8QefPVnvdVhhZqubxNA1cASXEH5wcK0Bucw==", + "requires": { + "buffer": "^3.0.1", + "through": "^2.3.6" + }, + "dependencies": { + "base64-js": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz", + "integrity": "sha1-EQHpVE9KdrG8OybUUsqW16NeeXg=" + }, + "buffer": { + "version": "3.6.0", + "resolved": "http://registry.npmjs.org/buffer/-/buffer-3.6.0.tgz", + "integrity": "sha1-pyyTb3e5a/UvX357RnGAYoVR3vs=", + "requires": { + "base64-js": "0.0.8", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + } + } + }, "url": { "version": "0.10.3", "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", @@ -1956,11 +2701,29 @@ } } }, + "url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "requires": { + "prepend-http": "^2.0.0" + } + }, "url-template": { "version": "2.0.8", "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", "integrity": "sha1-/FZaPMy/93MMd19WQflVV5FDnyE=" }, + "url-to-options": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz", + "integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=" + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, "uuid": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.0.tgz", @@ -2062,6 +2825,15 @@ "camelcase": "^3.0.0", "lodash.assign": "^4.0.6" } + }, + "yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "requires": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } } } } From 3d85d5e5e2806640cf2f006215757b40c67fbc13 Mon Sep 17 00:00:00 2001 From: David Wilson Date: Tue, 30 Oct 2018 16:27:40 -0700 Subject: [PATCH 041/112] Bump pr-changelog --- script/vsts/package-lock.json | 18 +++++++++--------- script/vsts/package.json | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/script/vsts/package-lock.json b/script/vsts/package-lock.json index f4c30a270..f0de21de5 100644 --- a/script/vsts/package-lock.json +++ b/script/vsts/package-lock.json @@ -237,7 +237,7 @@ }, "babel-plugin-syntax-async-functions": { "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", + "resolved": "http://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", "integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU=" }, "babel-plugin-transform-es2015-arrow-functions": { @@ -613,9 +613,9 @@ } }, "bluebird": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", - "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.2.tgz", + "integrity": "sha512-dhHTWMI7kMx5whMQntl7Vr9C6BvV10lFXDAasnqnrMYhXVCzzk6IO9Fo2L75jXHT07WrOngL1WDXOp+yYS91Yg==" }, "brace-expansion": { "version": "1.1.11", @@ -1995,9 +1995,9 @@ "integrity": "sha1-Wyn2qB9wcXFC4J52W76rl7T4HiE=" }, "pr-changelog": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/pr-changelog/-/pr-changelog-0.3.0.tgz", - "integrity": "sha1-e4nnchvH/EdhCjUwjY3MCJTtalk=", + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/pr-changelog/-/pr-changelog-0.3.2.tgz", + "integrity": "sha512-CQayjupdJ4KB6EYzRuW7aXgXpRT0iOMuCn9DROC4ygqXpSgHW+eDzFz3l50icJq25yq1tnrLSBvh55aG+gy+MQ==", "requires": { "babel-plugin-syntax-async-functions": "^6.1.4", "babel-plugin-transform-regenerator": "^6.1.4", @@ -2023,7 +2023,7 @@ }, "yargs": { "version": "3.32.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.32.0.tgz", + "resolved": "http://registry.npmjs.org/yargs/-/yargs-3.32.0.tgz", "integrity": "sha1-AwiOnr+edWtpdRYR0qXvWRSCyZU=", "requires": { "camelcase": "^2.0.1", @@ -2265,7 +2265,7 @@ }, "regjsgen": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", + "resolved": "http://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=" }, "regjsparser": { diff --git a/script/vsts/package.json b/script/vsts/package.json index 20483d0c5..12f5d1449 100644 --- a/script/vsts/package.json +++ b/script/vsts/package.json @@ -2,11 +2,11 @@ "name": "atom-release-scripts", "description": "Atom release scripts", "dependencies": { - "download": "^7.1.0", "@octokit/rest": "^15.9.5", "aws-sdk": "^2.5.2", + "download": "^7.1.0", "glob": "7.0.3", - "pr-changelog": "^0.3.0", + "pr-changelog": "^0.3.2", "publish-release": "^1.6.0", "request": "^2.87.0", "request-promise-native": "^1.0.5", From cdc8a23bc39c45e84a16ff122e45b5172f58e5fd Mon Sep 17 00:00:00 2001 From: David Wilson Date: Tue, 30 Oct 2018 16:28:09 -0700 Subject: [PATCH 042/112] Remove shebang from upload-artifacts.js --- script/vsts/upload-artifacts.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/script/vsts/upload-artifacts.js b/script/vsts/upload-artifacts.js index 61af4ffcf..ad5fa8d05 100644 --- a/script/vsts/upload-artifacts.js +++ b/script/vsts/upload-artifacts.js @@ -1,5 +1,3 @@ -#!/usr/bin/env node - 'use strict' const path = require('path') From 120a2b37717d07e20a17ca4e87dc45e01e161024 Mon Sep 17 00:00:00 2001 From: David Wilson Date: Wed, 31 Oct 2018 13:42:03 -0700 Subject: [PATCH 043/112] Finish automated release notes generation --- script/vsts/lib/release-notes.js | 67 +++++++++++++++++++++------- script/vsts/release-branch-build.yml | 9 ++++ script/vsts/upload-artifacts.js | 45 ++++++++++++++++--- 3 files changed, 98 insertions(+), 23 deletions(-) diff --git a/script/vsts/lib/release-notes.js b/script/vsts/lib/release-notes.js index 640ebd2cf..d19df9c17 100644 --- a/script/vsts/lib/release-notes.js +++ b/script/vsts/lib/release-notes.js @@ -1,8 +1,9 @@ const semver = require('semver') -const changelog = require('pr-changelog') const octokit = require('@octokit/rest')() +const changelog = require('pr-changelog') +const childProcess = require('child_process') -module.exports.get = async function(releaseVersion, githubToken) { +module.exports.get = async function (releaseVersion, githubToken) { if (githubToken) { octokit.authenticate({ type: 'oauth', @@ -10,12 +11,12 @@ module.exports.get = async function(releaseVersion, githubToken) { }) } - let releases = await octokit.repos.getReleases({owner: 'atom', repo: 'atom'}) - let release = releases.data.find(r => semver.eq(r.name, releaseVersion)) + const releases = await octokit.repos.getReleases({owner: 'atom', repo: 'atom'}) + const release = releases.data.find(r => semver.eq(r.name, releaseVersion)) return release ? release.body : undefined } -module.exports.generate = async function(releaseVersion, githubToken) { +module.exports.generateForVersion = async function (releaseVersion, githubToken, oldReleaseNotes) { let oldVersion = null let oldVersionName = null const parsedVersion = semver.parse(releaseVersion) @@ -36,8 +37,7 @@ module.exports.generate = async function(releaseVersion, githubToken) { oldVersionName = `v${parsedVersion.major}.${parsedVersion.minor - 1}.0` } else { let releases = await octokit.repos.getReleases({owner: 'atom', repo: 'atom'}) - let versions = releases.data.map(r => r.name) - oldVersion = 'v' + getPreviousVersion(releaseVersion, versions) + oldVersion = 'v' + getPreviousRelease(releaseVersion, releases.data).name oldVersionName = oldVersion } @@ -59,28 +59,61 @@ module.exports.generate = async function(releaseVersion, githubToken) { } }) - return `## Notable Changes\n\n\ -**TODO**: Pull relevant changes here!\n\n\ + const writtenReleaseNotes = + extractWrittenReleaseNotes(oldReleaseNotes) || + '**TODO**: Pull relevant changes here!' + + return `## Notable Changes\n +${writtenReleaseNotes}\n
-All Changes\n\n -${allChangesText}\n\n +All Changes\n +${allChangesText}
` } -function getPreviousVersion (version, allVersions) { +module.exports.generateForNightly = async function(releaseVersion, githubToken) { + const releases = await octokit.repos.getReleases({owner: 'atom', repo: 'atom-nightly-releases'}) + const previousRelease = getPreviousRelease(releaseVersion, releases.data) + const oldReleaseNotes = previousRelease ? previousRelease.body : undefined + + const latestCommitResult = childProcess.spawnSync('git', ['rev-parse', '--short', 'HEAD']) + + if (latestCommitResult && oldReleaseNotes) { + const latestCommit = latestCommitResult.stdout.toString().trim() + const extractMatch = oldReleaseNotes.match(/atom\/atom\/compare\/([0-9a-f]{5,40})\.\.\.([0-9a-f]{5,40})/) + if (extractMatch) { + return `### Click [here](https://github.com/atom/atom/compare/${extractMatch[2]}...${latestCommit}) to see the changes included with this release! :atom: :night_with_stars:` + } + } + + return undefined +} + +function extractWrittenReleaseNotes (oldReleaseNotes) { + if (oldReleaseNotes) { + const extractMatch = oldReleaseNotes.match(/^## Notable Changes\r\n([\s\S]*)
/) + if (extractMatch && extractMatch[1]) { + return extractMatch[1].trim() + } + } + + return undefined +} + +function getPreviousRelease (version, allReleases) { const versionIsStable = semver.prerelease(version) === null // Make sure versions are sorted before using them - allVersions.sort(semver.rcompare) + allReleases.sort((v1, v2) => semver.rcompare(v1.name, v2.name)) - for (let otherVersion of allVersions) { - if (versionIsStable && semver.prerelease(otherVersion)) { + for (let release of allReleases) { + if (versionIsStable && semver.prerelease(release.name)) { continue } - if (semver.lt(otherVersion, version)) { - return otherVersion + if (semver.lt(release.name, version)) { + return release } } diff --git a/script/vsts/release-branch-build.yml b/script/vsts/release-branch-build.yml index b48afebce..e3dfdf16e 100644 --- a/script/vsts/release-branch-build.yml +++ b/script/vsts/release-branch-build.yml @@ -80,3 +80,12 @@ jobs: ATOM_RELEASES_S3_BUCKET: $(ATOM_RELEASES_S3_BUCKET) displayName: Upload CI Artifacts to S3 condition: and(succeeded(), eq(variables['IsSignedZipBranch'], 'true')) + + - task: PublishBuildArtifacts@1 + inputs: + PathtoPublish: $(Build.SourcesDirectory)/out/OLD_RELEASE_NOTES.md + ArtifactName: OLD_RELEASE_NOTES.md + ArtifactType: Container + displayName: Upload OLD_RELEASE_NOTES.md + condition: and(succeeded(), eq(variables['IsReleaseBranch'], 'true'), eq(variables['buildArch'], 'x86')) + continueOnError: true diff --git a/script/vsts/upload-artifacts.js b/script/vsts/upload-artifacts.js index ad5fa8d05..ea568e8e6 100644 --- a/script/vsts/upload-artifacts.js +++ b/script/vsts/upload-artifacts.js @@ -1,8 +1,10 @@ 'use strict' +const fs = require('fs') const path = require('path') const glob = require('glob') const publishRelease = require('publish-release') +const releaseNotes = require('./lib/release-notes') const uploadToS3 = require('./lib/upload-to-s3') const uploadLinuxPackages = require('./lib/upload-linux-packages') @@ -19,11 +21,12 @@ const argv = yargs .wrap(yargs.terminalWidth()) .argv +const releaseVersion = CONFIG.computedAppVersion const isNightlyRelease = CONFIG.channel === 'nightly' -const assetsPath = argv.assetsPath || path.join(CONFIG.repositoryRootPath, 'out') +const assetsPath = argv.assetsPath || CONFIG.buildOutputPath const assetsPattern = '/**/*(*.exe|*.zip|*.nupkg|*.tar.gz|*.rpm|*.deb|RELEASES*|atom-api.json)' const assets = glob.sync(assetsPattern, { root: assetsPath, nodir: true }) -const bucketPath = argv.s3Path || `releases/v${CONFIG.computedAppVersion}/` +const bucketPath = argv.s3Path || `releases/v${releaseVersion}/` if (!assets || assets.length === 0) { console.error(`No assets found under specified path: ${assetsPath}`) @@ -31,7 +34,7 @@ if (!assets || assets.length === 0) { } async function uploadArtifacts() { - console.log(`Uploading ${assets.length} release assets for ${CONFIG.computedAppVersion} to S3 under '${bucketPath}'`) + console.log(`Uploading ${assets.length} release assets for ${releaseVersion} to S3 under '${bucketPath}'`) await uploadToS3( process.env.ATOM_RELEASES_S3_KEY, @@ -44,20 +47,50 @@ async function uploadArtifacts() { await uploadLinuxPackages( argv.linuxRepoName, process.env.PACKAGE_CLOUD_API_KEY, - CONFIG.computedAppVersion, + releaseVersion, assets) } else { - console.log("Skipping upload of Linux packages") + console.log("Skipping upload of Linux packages") + } + + const oldReleaseNotes = + await releaseNotes.get( + releaseVersion, + process.env.GITHUB_TOKEN) + + if (oldReleaseNotes) { + const oldReleaseNotesPath = path.resolve(CONFIG.buildOutputPath, "OLD_RELEASE_NOTES.md") + console.log(`Saving existing ${releaseVersion} release notes to ${oldReleaseNotesPath}`) + fs.writeFileSync(oldReleaseNotesPath, oldReleaseNotes, 'utf8') } if (argv.createGithubRelease) { - console.log(`Creating GitHub release v${CONFIG.computedAppVersion}`) + console.log(`\nGenerating new release notes for ${releaseVersion}`) + let newReleaseNotes = '' + if (isNightlyRelease) { + newReleaseNotes = + await releaseNotes.generateForNightly( + releaseVersion, + process.env.GITHUB_TOKEN, + oldReleaseNotes) + } else { + newReleaseNotes = + await releaseNotes.generateForVersion( + releaseVersion, + process.env.GITHUB_TOKEN, + oldReleaseNotes) + } + + console.log(`New release notes:\n\n${newReleaseNotes}`) + + console.log(`Creating GitHub release v${releaseVersion}`) const release = await publishReleaseAsync({ token: process.env.GITHUB_TOKEN, owner: 'atom', repo: !isNightlyRelease ? 'atom' : 'atom-nightly-releases', name: CONFIG.computedAppVersion, + body: newReleaseNotes, tag: `v${CONFIG.computedAppVersion}`, draft: !isNightlyRelease, prerelease: CONFIG.channel !== 'stable', From 7c08366bacc3820e3279acc7102aff29bb6764e4 Mon Sep 17 00:00:00 2001 From: David Wilson Date: Wed, 31 Oct 2018 13:58:34 -0700 Subject: [PATCH 044/112] :shirt: --- script/vsts/lib/release-notes.js | 2 +- script/vsts/upload-artifacts.js | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/script/vsts/lib/release-notes.js b/script/vsts/lib/release-notes.js index d19df9c17..891cd2507 100644 --- a/script/vsts/lib/release-notes.js +++ b/script/vsts/lib/release-notes.js @@ -72,7 +72,7 @@ ${allChangesText} ` } -module.exports.generateForNightly = async function(releaseVersion, githubToken) { +module.exports.generateForNightly = async function (releaseVersion, githubToken) { const releases = await octokit.repos.getReleases({owner: 'atom', repo: 'atom-nightly-releases'}) const previousRelease = getPreviousRelease(releaseVersion, releases.data) const oldReleaseNotes = previousRelease ? previousRelease.body : undefined diff --git a/script/vsts/upload-artifacts.js b/script/vsts/upload-artifacts.js index ea568e8e6..9f139b468 100644 --- a/script/vsts/upload-artifacts.js +++ b/script/vsts/upload-artifacts.js @@ -33,7 +33,7 @@ if (!assets || assets.length === 0) { process.exit(1) } -async function uploadArtifacts() { +async function uploadArtifacts () { console.log(`Uploading ${assets.length} release assets for ${releaseVersion} to S3 under '${bucketPath}'`) await uploadToS3( @@ -50,7 +50,7 @@ async function uploadArtifacts() { releaseVersion, assets) } else { - console.log("Skipping upload of Linux packages") + console.log('Skipping upload of Linux packages') } const oldReleaseNotes = @@ -59,7 +59,7 @@ async function uploadArtifacts() { process.env.GITHUB_TOKEN) if (oldReleaseNotes) { - const oldReleaseNotesPath = path.resolve(CONFIG.buildOutputPath, "OLD_RELEASE_NOTES.md") + const oldReleaseNotesPath = path.resolve(CONFIG.buildOutputPath, 'OLD_RELEASE_NOTES.md') console.log(`Saving existing ${releaseVersion} release notes to ${oldReleaseNotesPath}`) fs.writeFileSync(oldReleaseNotesPath, oldReleaseNotes, 'utf8') } @@ -99,13 +99,13 @@ async function uploadArtifacts() { assets }) - console.log("Release published successfully: ", release.html_url) + console.log('Release published successfully: ', release.html_url) } else { - console.log("Skipping GitHub release creation") + console.log('Skipping GitHub release creation') } } -async function publishReleaseAsync(options) { +async function publishReleaseAsync (options) { return new Promise((resolve, reject) => { publishRelease(options, (err, release) => { if (err) { From e3661349b90f637d251f7e108e351a19fcc674d6 Mon Sep 17 00:00:00 2001 From: David Wilson Date: Wed, 31 Oct 2018 15:00:05 -0700 Subject: [PATCH 045/112] :lock: --- script/package-lock.json | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/script/package-lock.json b/script/package-lock.json index 9aa5dbf17..f157a9727 100644 --- a/script/package-lock.json +++ b/script/package-lock.json @@ -9659,6 +9659,37 @@ } } }, + "terser": { + "version": "3.10.8", + "resolved": "https://registry.npmjs.org/terser/-/terser-3.10.8.tgz", + "integrity": "sha512-GQJHWJ/vbx0EgRk+lBMONMmKaT+ifeo/XgT/hi3KpzEEFOERVyFuJSVXH8grcmJjiqKY35ds8rBCxvABUeyyuQ==", + "requires": { + "commander": "~2.17.1", + "source-map": "~0.6.1", + "source-map-support": "~0.5.6" + }, + "dependencies": { + "commander": { + "version": "2.17.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", + "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "source-map-support": { + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.9.tgz", + "integrity": "sha512-gR6Rw4MvUlYy83vP0vxoVNzM6t8MUXqNuRsuBmBHQDu1Fh6X015FrLdgoDKcNdkwGubozq0P4N0Q37UyFVr1EA==", + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + } + } + }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", From 9264a6606a5028f7271baf2b157e412b8cacf4e3 Mon Sep 17 00:00:00 2001 From: David Wilson Date: Fri, 8 Feb 2019 14:00:43 -0800 Subject: [PATCH 046/112] Remove unnecessary clause in release notes upload task --- script/vsts/release-branch-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/vsts/release-branch-build.yml b/script/vsts/release-branch-build.yml index e3dfdf16e..0b4485666 100644 --- a/script/vsts/release-branch-build.yml +++ b/script/vsts/release-branch-build.yml @@ -87,5 +87,5 @@ jobs: ArtifactName: OLD_RELEASE_NOTES.md ArtifactType: Container displayName: Upload OLD_RELEASE_NOTES.md - condition: and(succeeded(), eq(variables['IsReleaseBranch'], 'true'), eq(variables['buildArch'], 'x86')) + condition: and(succeeded(), eq(variables['IsReleaseBranch'], 'true')) continueOnError: true From 929e5f50f7de5fbd4825af87f50bf92668e54afa Mon Sep 17 00:00:00 2001 From: Hubot Date: Fri, 8 Feb 2019 17:38:17 -0600 Subject: [PATCH 047/112] 1.37.0-dev --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 545bb3280..2d7673c03 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "atom", "productName": "Atom", - "version": "1.36.0-dev", + "version": "1.37.0-dev", "description": "A hackable text editor for the 21st Century.", "main": "./src/main-process/main.js", "repository": { From f4f3d12719d0b44cac7f01bbc200496660c73992 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 11 Feb 2019 10:13:10 -0500 Subject: [PATCH 048/112] Remove intermediate directory and TEST- prefix --- script/test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/test b/script/test index 4167f8584..c5206db74 100755 --- a/script/test +++ b/script/test @@ -69,7 +69,7 @@ function prepareEnv (suiteName) { // Tell Jasmine to output this suite's results as a JUnit XML file to a subdirectory of the root, so that a // CI system can interpret it. const runPrefix = process.env.TEST_JUNIT_XML_RUN || '' - const outputPath = path.join(process.env.TEST_JUNIT_XML_ROOT, suiteName, `TEST-${runPrefix}${suiteName}.xml`) + const outputPath = path.join(process.env.TEST_JUNIT_XML_ROOT, `${runPrefix}${suiteName}.xml`) env.TEST_JUNIT_XML_PATH = outputPath } From da891bd120106ff0b2f734a7006530505ca94dad Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 11 Feb 2019 10:13:31 -0500 Subject: [PATCH 049/112] Use spaces in TEST_JUNIT_XML_RUN --- script/vsts/platforms/linux.yml | 4 ++-- script/vsts/platforms/macos.yml | 4 ++-- script/vsts/platforms/windows.yml | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/script/vsts/platforms/linux.yml b/script/vsts/platforms/linux.yml index 5dd6a22b0..3ecc2e96e 100644 --- a/script/vsts/platforms/linux.yml +++ b/script/vsts/platforms/linux.yml @@ -26,7 +26,7 @@ jobs: CI_PROVIDER: VSTS ATOM_JASMINE_REPORTER: list TEST_JUNIT_XML_ROOT: $(Common.TestResultsDirectory)/junit - TEST_JUNIT_XML_RUN: Linux- + TEST_JUNIT_XML_RUN: "Linux " displayName: Run tests condition: and(succeeded(), ne(variables['Atom.SkipTests'], 'true')) @@ -40,7 +40,7 @@ jobs: inputs: testResultsFormat: JUnit searchFolder: $(Common.TestResultsDirectory)/junit - testResultsFiles: "**/TEST-*.xml" + testResultsFiles: "**/*.xml" condition: ne(variables['Atom.SkipTests'], 'true') - task: PublishBuildArtifacts@1 diff --git a/script/vsts/platforms/macos.yml b/script/vsts/platforms/macos.yml index c0341c38e..db9562b35 100644 --- a/script/vsts/platforms/macos.yml +++ b/script/vsts/platforms/macos.yml @@ -46,7 +46,7 @@ jobs: CI_PROVIDER: VSTS ATOM_JASMINE_REPORTER: list TEST_JUNIT_XML_ROOT: $(Common.TestResultsDirectory)/junit - TEST_JUNIT_XML_RUN: MacOS- + TEST_JUNIT_XML_RUN: "MacOS " displayName: Run tests condition: and(succeeded(), ne(variables['Atom.SkipTests'], 'true')) @@ -60,7 +60,7 @@ jobs: inputs: testResultsFormat: JUnit searchFolder: $(Common.TestResultsDirectory)/junit - testResultsFiles: "**/TEST-*.xml" + testResultsFiles: "**/*.xml" condition: ne(variables['Atom.SkipTests'], 'true') - script: | diff --git a/script/vsts/platforms/windows.yml b/script/vsts/platforms/windows.yml index 0bc4cbd1c..4c5fa1eb4 100644 --- a/script/vsts/platforms/windows.yml +++ b/script/vsts/platforms/windows.yml @@ -71,7 +71,7 @@ jobs: CI_PROVIDER: VSTS ATOM_JASMINE_REPORTER: list TEST_JUNIT_XML_ROOT: $(Common.TestResultsDirectory)\junit - TEST_JUNIT_XML_RUN: Windows-$(buildArch)- + TEST_JUNIT_XML_RUN: "Windows $(buildArch) " BUILD_ARCH: $(buildArch) displayName: Run tests condition: and(succeeded(), ne(variables['Atom.SkipTests'], 'true')) @@ -87,7 +87,7 @@ jobs: inputs: testResultsFormat: JUnit searchFolder: $(Common.TestResultsDirectory)\junit - testResultsFiles: "**/TEST-*.xml" + testResultsFiles: "**/*.xml" condition: ne(variables['Atom.SkipTests'], 'true') - task: PublishBuildArtifacts@1 From 65c0cc31226c0de5db231ffe7c16a599dd5af3d8 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 11 Feb 2019 10:14:58 -0500 Subject: [PATCH 050/112] Use spaces in prepareEnv() calls --- script/test | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/script/test b/script/test index c5206db74..760d4e55e 100755 --- a/script/test +++ b/script/test @@ -82,7 +82,7 @@ function runCoreMainProcessTests (callback) { '--resource-path', resourcePath, '--test', '--main-process', testPath ] - const testEnv = Object.assign({}, prepareEnv('core-main-process'), {ATOM_GITHUB_INLINE_GIT_EXEC: 'true'}) + const testEnv = Object.assign({}, prepareEnv('core main process'), {ATOM_GITHUB_INLINE_GIT_EXEC: 'true'}) console.log('Executing core main process tests'.bold.green) const cp = childProcess.spawn(executablePath, testArguments, {stdio: 'inherit', env: testEnv}) @@ -96,7 +96,7 @@ function runCoreRenderProcessTests (callback) { '--resource-path', resourcePath, '--test', testPath ] - const testEnv = prepareEnv('core-render-process') + const testEnv = prepareEnv('core render process') console.log('Executing core render process tests'.bold.green) const cp = childProcess.spawn(executablePath, testArguments, {stdio: 'inherit', env: testEnv}) @@ -130,7 +130,7 @@ for (let packageName in CONFIG.appMetadata.packageDependencies) { '--resource-path', resourcePath, '--test', testFolder ] - const testEnv = prepareEnv(`bundled-package-${packageName}`) + const testEnv = prepareEnv(`bundled package ${packageName}`) const pkgJsonPath = path.join(repositoryPackagePath, 'package.json') const nodeModulesPath = path.join(repositoryPackagePath, 'node_modules') From a6cb715a1a62f64220b36ae34d7f7a5de08e3f40 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 11 Feb 2019 10:44:41 -0500 Subject: [PATCH 051/112] Temporary spec that crashes, to test crash handling --- spec/goes-boom-spec.js | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 spec/goes-boom-spec.js diff --git a/spec/goes-boom-spec.js b/spec/goes-boom-spec.js new file mode 100644 index 000000000..41d93ed5d --- /dev/null +++ b/spec/goes-boom-spec.js @@ -0,0 +1,5 @@ +describe('crash handler', () => { + it('goes boom', () => { + process.crash() + }) +}) From 6e69bc0d7dea32282790147045fe149a6534ca74 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 11 Feb 2019 10:44:51 -0500 Subject: [PATCH 052/112] Upload crash reports on macOS --- script/vsts/platforms/macos.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/script/vsts/platforms/macos.yml b/script/vsts/platforms/macos.yml index 005f8b96f..b1e34610f 100644 --- a/script/vsts/platforms/macos.yml +++ b/script/vsts/platforms/macos.yml @@ -52,6 +52,12 @@ jobs: cp $(Build.SourcesDirectory)/out/*.zip $(Build.ArtifactStagingDirectory) displayName: Stage Artifacts + - script: | + mkdir -p $(Build.ArtifactStagingDirectory)/crash-reports + cp ${HOME}/Library/Logs/DiagnosticReports/*.crash $(Build.ArtifactStagingDirectory)/crash-reports + displayName: Stage Crash Reports + condition: failed() + - task: PublishBuildArtifacts@1 inputs: PathtoPublish: $(Build.ArtifactStagingDirectory)/atom-mac.zip @@ -75,3 +81,10 @@ jobs: ArtifactType: Container displayName: Upload atom-api.json condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) + + - task: PublishBuildArtifacts@1 + inputs: + PathtoPublish: $(Build.ArtifactStagingDirectory)/crash-reports + ArtifactName: crash-reports.zip + displayName: Upload Crash Reports + condition: failed() From 3b7ac36becdf5f8f86c19e61b37bcc078b970947 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 11 Feb 2019 13:31:53 -0500 Subject: [PATCH 053/112] Azure doesn't like trailing whitespace --- script/test | 3 ++- script/vsts/platforms/linux.yml | 2 +- script/vsts/platforms/macos.yml | 2 +- script/vsts/platforms/windows.yml | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/script/test b/script/test index 760d4e55e..da389cedc 100755 --- a/script/test +++ b/script/test @@ -69,7 +69,8 @@ function prepareEnv (suiteName) { // Tell Jasmine to output this suite's results as a JUnit XML file to a subdirectory of the root, so that a // CI system can interpret it. const runPrefix = process.env.TEST_JUNIT_XML_RUN || '' - const outputPath = path.join(process.env.TEST_JUNIT_XML_ROOT, `${runPrefix}${suiteName}.xml`) + const filePath = (runPrefix.length > 0 ? runPrefix + ' ' : '') + suiteName + '.xml' + const outputPath = path.join(process.env.TEST_JUNIT_XML_ROOT, filePath) env.TEST_JUNIT_XML_PATH = outputPath } diff --git a/script/vsts/platforms/linux.yml b/script/vsts/platforms/linux.yml index 3ecc2e96e..f5afabaff 100644 --- a/script/vsts/platforms/linux.yml +++ b/script/vsts/platforms/linux.yml @@ -26,7 +26,7 @@ jobs: CI_PROVIDER: VSTS ATOM_JASMINE_REPORTER: list TEST_JUNIT_XML_ROOT: $(Common.TestResultsDirectory)/junit - TEST_JUNIT_XML_RUN: "Linux " + TEST_JUNIT_XML_RUN: Linux displayName: Run tests condition: and(succeeded(), ne(variables['Atom.SkipTests'], 'true')) diff --git a/script/vsts/platforms/macos.yml b/script/vsts/platforms/macos.yml index db9562b35..8afc8aaee 100644 --- a/script/vsts/platforms/macos.yml +++ b/script/vsts/platforms/macos.yml @@ -46,7 +46,7 @@ jobs: CI_PROVIDER: VSTS ATOM_JASMINE_REPORTER: list TEST_JUNIT_XML_ROOT: $(Common.TestResultsDirectory)/junit - TEST_JUNIT_XML_RUN: "MacOS " + TEST_JUNIT_XML_RUN: MacOS displayName: Run tests condition: and(succeeded(), ne(variables['Atom.SkipTests'], 'true')) diff --git a/script/vsts/platforms/windows.yml b/script/vsts/platforms/windows.yml index 4c5fa1eb4..37ca64168 100644 --- a/script/vsts/platforms/windows.yml +++ b/script/vsts/platforms/windows.yml @@ -71,7 +71,7 @@ jobs: CI_PROVIDER: VSTS ATOM_JASMINE_REPORTER: list TEST_JUNIT_XML_ROOT: $(Common.TestResultsDirectory)\junit - TEST_JUNIT_XML_RUN: "Windows $(buildArch) " + TEST_JUNIT_XML_RUN: Windows $(buildArch) BUILD_ARCH: $(buildArch) displayName: Run tests condition: and(succeeded(), ne(variables['Atom.SkipTests'], 'true')) From e1be511851cc00f910eb4e4a2900d03ee3eabcc2 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Mon, 11 Feb 2019 13:33:35 -0500 Subject: [PATCH 054/112] Unconditionally dump results --- script/vsts/platforms/windows.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/script/vsts/platforms/windows.yml b/script/vsts/platforms/windows.yml index 37ca64168..038c79847 100644 --- a/script/vsts/platforms/windows.yml +++ b/script/vsts/platforms/windows.yml @@ -82,6 +82,7 @@ jobs: env: TEST_JUNIT_XML_ROOT: $(Common.TestResultsDirectory) displayName: Dump test results + condition: succeededOrFailed() - task: PublishTestResults@2 inputs: From 1571175eea557b81fba71e45a021c51fc06aa53f Mon Sep 17 00:00:00 2001 From: David Wilson Date: Fri, 8 Feb 2019 22:34:46 -0800 Subject: [PATCH 055/112] Minor fixes to draft release creation - Don't upload artifacts for a release that is already published - Fix release notes on draft releases - Fix Linux package uploading for draft releases --- script/vsts/lib/release-notes.js | 9 +++++++-- script/vsts/release-branch-build.yml | 2 +- script/vsts/upload-artifacts.js | 20 +++++++++++++------- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/script/vsts/lib/release-notes.js b/script/vsts/lib/release-notes.js index 891cd2507..c7c9e7d41 100644 --- a/script/vsts/lib/release-notes.js +++ b/script/vsts/lib/release-notes.js @@ -3,7 +3,7 @@ const octokit = require('@octokit/rest')() const changelog = require('pr-changelog') const childProcess = require('child_process') -module.exports.get = async function (releaseVersion, githubToken) { +module.exports.getRelease = async function (releaseVersion, githubToken) { if (githubToken) { octokit.authenticate({ type: 'oauth', @@ -13,7 +13,12 @@ module.exports.get = async function (releaseVersion, githubToken) { const releases = await octokit.repos.getReleases({owner: 'atom', repo: 'atom'}) const release = releases.data.find(r => semver.eq(r.name, releaseVersion)) - return release ? release.body : undefined + + return { + exists: release !== undefined, + isDraft: release && release.draft, + releaseNotes: release ? release.body : undefined + } } module.exports.generateForVersion = async function (releaseVersion, githubToken, oldReleaseNotes) { diff --git a/script/vsts/release-branch-build.yml b/script/vsts/release-branch-build.yml index 0b4485666..f802e94d9 100644 --- a/script/vsts/release-branch-build.yml +++ b/script/vsts/release-branch-build.yml @@ -60,7 +60,7 @@ jobs: displayName: Download Release Artifacts - script: | - node $(Build.SourcesDirectory)\script\vsts\upload-artifacts.js --create-github-release --assets-path "$(System.ArtifactsDirectory)" + node $(Build.SourcesDirectory)\script\vsts\upload-artifacts.js --create-github-release --assets-path "$(System.ArtifactsDirectory)" --linux-repo-name "atom-staging" env: GITHUB_TOKEN: $(GITHUB_TOKEN) ATOM_RELEASE_VERSION: $(ReleaseVersion) diff --git a/script/vsts/upload-artifacts.js b/script/vsts/upload-artifacts.js index 9f139b468..89abff429 100644 --- a/script/vsts/upload-artifacts.js +++ b/script/vsts/upload-artifacts.js @@ -34,6 +34,16 @@ if (!assets || assets.length === 0) { } async function uploadArtifacts () { + let releaseForVersion = + await releaseNotes.getRelease() + releaseVersion, + process.env.GITHUB_TOKEN + + if (releaseForVersion.exists && !releaseForVersion.isDraft) { + console.log(`Published release already exists for ${releaseVersion}, skipping upload.`) + return + } + console.log(`Uploading ${assets.length} release assets for ${releaseVersion} to S3 under '${bucketPath}'`) await uploadToS3( @@ -50,14 +60,10 @@ async function uploadArtifacts () { releaseVersion, assets) } else { - console.log('Skipping upload of Linux packages') + console.log('\nNo Linux package repo name specified, skipping Linux package upload.') } - const oldReleaseNotes = - await releaseNotes.get( - releaseVersion, - process.env.GITHUB_TOKEN) - + const oldReleaseNotes = releaseForVersion.releaseNotes if (oldReleaseNotes) { const oldReleaseNotesPath = path.resolve(CONFIG.buildOutputPath, 'OLD_RELEASE_NOTES.md') console.log(`Saving existing ${releaseVersion} release notes to ${oldReleaseNotesPath}`) @@ -90,7 +96,7 @@ async function uploadArtifacts () { owner: 'atom', repo: !isNightlyRelease ? 'atom' : 'atom-nightly-releases', name: CONFIG.computedAppVersion, - body: newReleaseNotes, + notes: newReleaseNotes, tag: `v${CONFIG.computedAppVersion}`, draft: !isNightlyRelease, prerelease: CONFIG.channel !== 'stable', From 2ac4beea636ab73d15512c0a0c389f05f03530f8 Mon Sep 17 00:00:00 2001 From: David Wilson Date: Sat, 9 Feb 2019 10:21:58 -0800 Subject: [PATCH 056/112] Update release notes when creating another draft for same version --- script/vsts/upload-artifacts.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/script/vsts/upload-artifacts.js b/script/vsts/upload-artifacts.js index 89abff429..a4672720f 100644 --- a/script/vsts/upload-artifacts.js +++ b/script/vsts/upload-artifacts.js @@ -35,9 +35,9 @@ if (!assets || assets.length === 0) { async function uploadArtifacts () { let releaseForVersion = - await releaseNotes.getRelease() + await releaseNotes.getRelease( releaseVersion, - process.env.GITHUB_TOKEN + process.env.GITHUB_TOKEN) if (releaseForVersion.exists && !releaseForVersion.isDraft) { console.log(`Published release already exists for ${releaseVersion}, skipping upload.`) @@ -100,6 +100,7 @@ async function uploadArtifacts () { tag: `v${CONFIG.computedAppVersion}`, draft: !isNightlyRelease, prerelease: CONFIG.channel !== 'stable', + editRelease: true, reuseRelease: true, skipIfPublished: true, assets From 363741a88fd88efbb1c6cd0e6ba7c55e69a03d73 Mon Sep 17 00:00:00 2001 From: David Wilson Date: Sun, 10 Feb 2019 13:21:32 -0800 Subject: [PATCH 057/112] Fix artifact upload of OLD_RELEASE_NOTES.md --- script/vsts/release-branch-build.yml | 9 --------- script/vsts/upload-artifacts.js | 6 +++++- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/script/vsts/release-branch-build.yml b/script/vsts/release-branch-build.yml index f802e94d9..05bfd2d76 100644 --- a/script/vsts/release-branch-build.yml +++ b/script/vsts/release-branch-build.yml @@ -80,12 +80,3 @@ jobs: ATOM_RELEASES_S3_BUCKET: $(ATOM_RELEASES_S3_BUCKET) displayName: Upload CI Artifacts to S3 condition: and(succeeded(), eq(variables['IsSignedZipBranch'], 'true')) - - - task: PublishBuildArtifacts@1 - inputs: - PathtoPublish: $(Build.SourcesDirectory)/out/OLD_RELEASE_NOTES.md - ArtifactName: OLD_RELEASE_NOTES.md - ArtifactType: Container - displayName: Upload OLD_RELEASE_NOTES.md - condition: and(succeeded(), eq(variables['IsReleaseBranch'], 'true')) - continueOnError: true diff --git a/script/vsts/upload-artifacts.js b/script/vsts/upload-artifacts.js index a4672720f..08fb27024 100644 --- a/script/vsts/upload-artifacts.js +++ b/script/vsts/upload-artifacts.js @@ -1,6 +1,7 @@ 'use strict' const fs = require('fs') +const os = require('os') const path = require('path') const glob = require('glob') const publishRelease = require('publish-release') @@ -65,9 +66,12 @@ async function uploadArtifacts () { const oldReleaseNotes = releaseForVersion.releaseNotes if (oldReleaseNotes) { - const oldReleaseNotesPath = path.resolve(CONFIG.buildOutputPath, 'OLD_RELEASE_NOTES.md') + const oldReleaseNotesPath = path.resolve(os.tmpdir(), 'OLD_RELEASE_NOTES.md') console.log(`Saving existing ${releaseVersion} release notes to ${oldReleaseNotesPath}`) fs.writeFileSync(oldReleaseNotesPath, oldReleaseNotes, 'utf8') + + // This line instructs VSTS to upload the file as an artifact + console.log(`##vso[artifact.upload containerfolder=OldReleaseNotes;artifactname=OldReleaseNotes;]${oldReleaseNotesPath}`) } if (argv.createGithubRelease) { From 8b16801296d8adc70c79382fdfb7dcf379fff6e3 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 12 Feb 2019 11:29:20 -0500 Subject: [PATCH 058/112] Revert "Temporary spec that crashes, to test crash handling" This reverts commit a6cb715a1a62f64220b36ae34d7f7a5de08e3f40. --- spec/goes-boom-spec.js | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 spec/goes-boom-spec.js diff --git a/spec/goes-boom-spec.js b/spec/goes-boom-spec.js deleted file mode 100644 index 41d93ed5d..000000000 --- a/spec/goes-boom-spec.js +++ /dev/null @@ -1,5 +0,0 @@ -describe('crash handler', () => { - it('goes boom', () => { - process.crash() - }) -}) From fea3286ca8e182461bbe3aba547ac1d11a7df864 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 12 Feb 2019 11:59:11 -0500 Subject: [PATCH 059/112] Prefix test descriptions with TEST_JUNIT_RUN --- spec/jasmine-junit-reporter.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/spec/jasmine-junit-reporter.js b/spec/jasmine-junit-reporter.js index 4e226e286..9618edc24 100644 --- a/spec/jasmine-junit-reporter.js +++ b/spec/jasmine-junit-reporter.js @@ -8,6 +8,11 @@ class JasmineJUnitReporter extends jasmine.JUnitXmlReporter { fullDescription = currentSuite.description + ' ' + fullDescription currentSuite = currentSuite.parentSuite } + + if (process.env.TEST_JUNIT_RUN) { + fullDescription = `[${process.env.TEST_JUNIT_RUN}] ` + fullDescription + } + return fullDescription } From 50b8dad3b94c24b97ccdc79aeb74ddbbcb4871ce Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 12 Feb 2019 11:59:20 -0500 Subject: [PATCH 060/112] Set TEST_JUNIT_RUN to the current suite name --- script/test | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/script/test b/script/test index da389cedc..22d945a11 100755 --- a/script/test +++ b/script/test @@ -68,9 +68,9 @@ function prepareEnv (suiteName) { if (process.env.TEST_JUNIT_XML_ROOT) { // Tell Jasmine to output this suite's results as a JUnit XML file to a subdirectory of the root, so that a // CI system can interpret it. - const runPrefix = process.env.TEST_JUNIT_XML_RUN || '' - const filePath = (runPrefix.length > 0 ? runPrefix + ' ' : '') + suiteName + '.xml' - const outputPath = path.join(process.env.TEST_JUNIT_XML_ROOT, filePath) + env.TEST_JUNIT_RUN = suiteName + const fileName = suiteName.replace(/\W+/g, '-') + '.xml' + const outputPath = path.join(process.env.TEST_JUNIT_XML_ROOT, fileName) env.TEST_JUNIT_XML_PATH = outputPath } From 4d090b8f1ea159d62625eda89c1994f7d4566a63 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 12 Feb 2019 11:59:38 -0500 Subject: [PATCH 061/112] Set test run titles in PublishTestResults tasks --- script/vsts/platforms/linux.yml | 3 ++- script/vsts/platforms/macos.yml | 3 ++- script/vsts/platforms/windows.yml | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/script/vsts/platforms/linux.yml b/script/vsts/platforms/linux.yml index f5afabaff..477b3dbe0 100644 --- a/script/vsts/platforms/linux.yml +++ b/script/vsts/platforms/linux.yml @@ -26,7 +26,6 @@ jobs: CI_PROVIDER: VSTS ATOM_JASMINE_REPORTER: list TEST_JUNIT_XML_ROOT: $(Common.TestResultsDirectory)/junit - TEST_JUNIT_XML_RUN: Linux displayName: Run tests condition: and(succeeded(), ne(variables['Atom.SkipTests'], 'true')) @@ -41,6 +40,8 @@ jobs: testResultsFormat: JUnit searchFolder: $(Common.TestResultsDirectory)/junit testResultsFiles: "**/*.xml" + mergeTestResults: true + testRunTitle: Linux condition: ne(variables['Atom.SkipTests'], 'true') - task: PublishBuildArtifacts@1 diff --git a/script/vsts/platforms/macos.yml b/script/vsts/platforms/macos.yml index 8afc8aaee..1264efe4a 100644 --- a/script/vsts/platforms/macos.yml +++ b/script/vsts/platforms/macos.yml @@ -46,7 +46,6 @@ jobs: CI_PROVIDER: VSTS ATOM_JASMINE_REPORTER: list TEST_JUNIT_XML_ROOT: $(Common.TestResultsDirectory)/junit - TEST_JUNIT_XML_RUN: MacOS displayName: Run tests condition: and(succeeded(), ne(variables['Atom.SkipTests'], 'true')) @@ -61,6 +60,8 @@ jobs: testResultsFormat: JUnit searchFolder: $(Common.TestResultsDirectory)/junit testResultsFiles: "**/*.xml" + mergeTestResults: true + testRunTitle: MacOS condition: ne(variables['Atom.SkipTests'], 'true') - script: | diff --git a/script/vsts/platforms/windows.yml b/script/vsts/platforms/windows.yml index 038c79847..748da853f 100644 --- a/script/vsts/platforms/windows.yml +++ b/script/vsts/platforms/windows.yml @@ -71,7 +71,6 @@ jobs: CI_PROVIDER: VSTS ATOM_JASMINE_REPORTER: list TEST_JUNIT_XML_ROOT: $(Common.TestResultsDirectory)\junit - TEST_JUNIT_XML_RUN: Windows $(buildArch) BUILD_ARCH: $(buildArch) displayName: Run tests condition: and(succeeded(), ne(variables['Atom.SkipTests'], 'true')) @@ -89,6 +88,8 @@ jobs: testResultsFormat: JUnit searchFolder: $(Common.TestResultsDirectory)\junit testResultsFiles: "**/*.xml" + mergeTestResults: true + testRunTitle: Windows $(buildArch) condition: ne(variables['Atom.SkipTests'], 'true') - task: PublishBuildArtifacts@1 From 24ed380e786fa23af761a51e5afded58fe3ca1b5 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Tue, 12 Feb 2019 12:29:17 -0500 Subject: [PATCH 062/112] :arrow_up: @atom/watcher --- package-lock.json | 139 +++++----------------------------------------- package.json | 2 +- 2 files changed, 16 insertions(+), 125 deletions(-) diff --git a/package-lock.json b/package-lock.json index 278463567..8dd7b8c88 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "atom", - "version": "1.36.0-dev", + "version": "1.37.0-dev", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -34,33 +34,30 @@ } }, "@atom/watcher": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@atom/watcher/-/watcher-1.0.8.tgz", - "integrity": "sha512-53un+vGSaY7Fsbvmg8gerYOA3ISipMWR3qiYR9hZWqSfvFsksXJfGrmFsfbBj3uqGRQ3gPTi6wpxcFSWjbWVFQ==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@atom/watcher/-/watcher-1.3.1.tgz", + "integrity": "sha512-UjGisruWlcRLMzddE3pwvOx6wQCFN/+gg6Z4cJZvH1kjT5QT5eA04hUDs8QXF/QH8ZxMiOtP8x9SWTw0hCNelg==", "requires": { - "event-kit": "^2.5.0", - "fs-extra": "^6.0.0", - "nan": "^2.10.0", - "node-pre-gyp": "^0.10.0" + "event-kit": "2.5.3", + "fs-extra": "7.0.1", + "nan": "2.12.1", + "prebuild-install": "5.2.4" }, "dependencies": { "fs-extra": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz", - "integrity": "sha512-GnyIkKhhzXZUWFCaJzvyDLEEgDkPfb4/TPvJCJVuS8MWZgoSsErf++QpiAlDnKFcqhRlm+tIOcencCjyJE6ZCA==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", "requires": { "graceful-fs": "^4.1.2", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "requires": { - "graceful-fs": "^4.1.6" - } + "nan": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.12.1.tgz", + "integrity": "sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw==" } } }, @@ -78,11 +75,6 @@ "resolved": "https://registry.npmjs.org/CSSwhat/-/CSSwhat-0.4.7.tgz", "integrity": "sha1-hn2g/zn3eGEyQsRM/qg/CqTr35s=" }, - "abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" - }, "about": { "version": "file:packages/about", "requires": { @@ -2825,14 +2817,6 @@ "safer-buffer": ">= 2.1.2 < 3" } }, - "ignore-walk": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz", - "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", - "requires": { - "minimatch": "^3.0.4" - } - }, "image-size": { "version": "0.5.5", "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", @@ -3884,14 +3868,6 @@ "yallist": "^3.0.0" } }, - "minizlib": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.1.0.tgz", - "integrity": "sha1-EeE2WM5GvDpwomeqxYNZ0eDCnOs=", - "requires": { - "minipass": "^2.2.1" - } - }, "mixto": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/mixto/-/mixto-1.0.0.tgz", @@ -4070,16 +4046,6 @@ "underscore": ">=1.3.1" } }, - "needle": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/needle/-/needle-2.2.2.tgz", - "integrity": "sha512-mW7W8dKuVYefCpNzE3Z7xUmPI9wSrSL/1qH31YGMxmSOAnjatS3S9Zv3cmiHrhx3Jkp1SrWWBdOFXjfF48Uq3A==", - "requires": { - "debug": "^2.1.2", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - } - }, "next-tick": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", @@ -4117,30 +4083,6 @@ "is-stream": "^1.0.1" } }, - "node-pre-gyp": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.10.0.tgz", - "integrity": "sha512-G7kEonQLRbcA/mOoFoxvlMrw6Q6dPf92+t/l0DFSMuSlDoWaI9JWIyPwK0jyE1bph//CUEL65/Fz1m2vJbmjQQ==", - "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.0", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.1.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4" - }, - "dependencies": { - "semver": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.1.tgz", - "integrity": "sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw==" - } - } - }, "node-uuid": { "version": "1.4.8", "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz", @@ -4159,15 +4101,6 @@ "resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz", "integrity": "sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI=" }, - "nopt": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", - "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, "normalize-package-data": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", @@ -4192,20 +4125,6 @@ "temp": "^0.8.1" } }, - "npm-bundled": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.5.tgz", - "integrity": "sha512-m/e6jgWu8/v5niCUKQi9qQl8QdeEduFA96xHDDzFGqly0OOjI7c+60KM/2sppfnUU9JJagf+zs+yGhqSOFj71g==" - }, - "npm-packlist": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.1.11.tgz", - "integrity": "sha512-CxKlZ24urLkJk+9kCm48RTQ7L4hsmgSVzEk0TLGPzzyuFxD7VNgy5Sl24tOLMzQv773a/NeJ1ce1DKeacqffEA==", - "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1" - } - }, "npmlog": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", @@ -4299,15 +4218,6 @@ "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" }, - "osenv": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, "output-file-sync": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/output-file-sync/-/output-file-sync-1.1.2.tgz", @@ -4920,11 +4830,6 @@ "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.1.2.tgz", "integrity": "sha1-vsEf3IOp/aBjQBIQ5AF2wwJNFWc=" }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" - }, "scandal": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/scandal/-/scandal-3.1.0.tgz", @@ -5518,20 +5423,6 @@ "underscore-plus": "1.x" } }, - "tar": { - "version": "4.4.6", - "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.6.tgz", - "integrity": "sha512-tMkTnh9EdzxyfW+6GK6fCahagXsnYk6kE6S9Gr9pjVdys769+laCTbodXDhPAjzVtEBazRgP0gYqOjnk9dQzLg==", - "requires": { - "chownr": "^1.0.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.3.3", - "minizlib": "^1.1.0", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.2" - } - }, "tar-fs": { "version": "1.16.3", "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.3.tgz", diff --git a/package.json b/package.json index 2d7673c03..5375c855b 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "dependencies": { "@atom/nsfw": "1.0.21", "@atom/source-map-support": "^0.3.4", - "@atom/watcher": "1.0.8", + "@atom/watcher": "1.3.1", "about": "file:packages/about", "archive-view": "https://www.atom.io/api/packages/archive-view/versions/0.65.1/tarball", "async": "0.2.6", From 89184442a8ca59f2078200b41ac12048e76787c9 Mon Sep 17 00:00:00 2001 From: simurai Date: Thu, 14 Feb 2019 14:03:34 +0900 Subject: [PATCH 063/112] Left align diff icons --- packages/git-diff/styles/git-diff.less | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/git-diff/styles/git-diff.less b/packages/git-diff/styles/git-diff.less index cbff36467..625400622 100644 --- a/packages/git-diff/styles/git-diff.less +++ b/packages/git-diff/styles/git-diff.less @@ -37,15 +37,15 @@ atom-text-editor { } .gutter.git-diff-icon .line-number { - width: 100%; - border-left: none; - padding-left: 0.4em; + border-left-width: 0; + padding-left: 1.4em; // space for diff icon &:before { .octicon-font(); display: inline-block; - position: relative; + position: absolute; top: -.05em; + left: .4em; // make sure it doesnt affect the gutter line height. height: 0px; @@ -70,13 +70,12 @@ atom-text-editor { border: none; // reset triangle content: @dash; color: @syntax-color-removed; - position: relative; } &.git-line-removed:before { - top: .6em; + top: 1em; } &.git-previous-line-removed:before { - top: -.6em; + top: 0; } } } From 7ade4bcc8ebb9dc9b7f174499ab7ea52ae39d9f2 Mon Sep 17 00:00:00 2001 From: simurai Date: Thu, 14 Feb 2019 14:49:27 +0900 Subject: [PATCH 064/112] Reduce font size --- packages/git-diff/styles/git-diff.less | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/packages/git-diff/styles/git-diff.less b/packages/git-diff/styles/git-diff.less index 625400622..0a725be22 100644 --- a/packages/git-diff/styles/git-diff.less +++ b/packages/git-diff/styles/git-diff.less @@ -21,7 +21,7 @@ atom-text-editor { left: 0; height: 0; width: 0; - content: " "; + content: ""; border: solid transparent; border-left-color: @syntax-color-removed; border-width: @size; @@ -41,18 +41,15 @@ atom-text-editor { padding-left: 1.4em; // space for diff icon &:before { - .octicon-font(); + .octicon-font(); + content: ""; display: inline-block; position: absolute; - top: -.05em; + top: .2em; left: .4em; - - // make sure it doesnt affect the gutter line height. - height: 0px; + height: 0px; // make sure it doesnt affect the gutter line height. width: 1em; - content: " "; - padding-right: 0.4em; - font-size: .95em; + font-size: .75em; } &.git-line-modified:before { From 5e236d6ad16a57454f7bf8b8d4bc18cc20cc37bd Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 15 Feb 2019 08:35:35 -0500 Subject: [PATCH 065/112] Use cheerio for XML parsing and serializing --- script/package-lock.json | 66 ++++++++++++++++++++++++++++++++++++++++ script/package.json | 1 + 2 files changed, 67 insertions(+) diff --git a/script/package-lock.json b/script/package-lock.json index bc5efb6b2..065a4cd35 100644 --- a/script/package-lock.json +++ b/script/package-lock.json @@ -22,6 +22,11 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.0.tgz", "integrity": "sha512-LAQ1d4OPfSJ/BMbI2DuizmYrrkD9JMaTdi2hQTlI53lQ4kRQPyZQRS4CYQ7O66bnBBnP/oYdRxbk++X0xuFU6A==" }, + "@types/node": { + "version": "11.9.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-11.9.4.tgz", + "integrity": "sha512-Zl8dGvAcEmadgs1tmSPcvwzO1YRsz38bVJQvH1RvRqSR9/5n61Q1ktcDL0ht3FXWR+ZpVmXVwN1LuH4Ax23NsA==" + }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -691,6 +696,11 @@ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", "integrity": "sha1-U0uQM8AiyVecVro7Plpcqvu2UOE=" }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" + }, "boom": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/boom/-/boom-0.4.2.tgz", @@ -920,6 +930,19 @@ "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.2.tgz", "integrity": "sha512-7I/xceXfKyUJmSAn/jw8ve/9DyOP7XxufNYLI9Px7CmsKgEUaZLUTax6nZxGQtaoiZCjpu6cHPj20xC/vqRReQ==" }, + "cheerio": { + "version": "1.0.0-rc.2", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.2.tgz", + "integrity": "sha1-S59TqBsn5NXawxwP/Qz6A8xoMNs=", + "requires": { + "css-select": "~1.2.0", + "dom-serializer": "~0.1.0", + "entities": "~1.1.1", + "htmlparser2": "^3.9.1", + "lodash": "^4.15.0", + "parse5": "^3.0.1" + } + }, "chownr": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz", @@ -1259,11 +1282,38 @@ "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-1.7.0.tgz", "integrity": "sha1-Mh9s9zeCpv91ERE5D8BeLGV9jJs=" }, + "css-select": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", + "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", + "requires": { + "boolbase": "~1.0.0", + "css-what": "2.1", + "domutils": "1.5.1", + "nth-check": "~1.0.1" + }, + "dependencies": { + "domutils": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + } + } + }, "css-value": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/css-value/-/css-value-0.0.1.tgz", "integrity": "sha1-Xv1sLupeof1rasV+wEJ7GEUkJOo=" }, + "css-what": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", + "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==" + }, "ctype": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz", @@ -7572,6 +7622,14 @@ "set-blocking": "~2.0.0" } }, + "nth-check": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", + "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "requires": { + "boolbase": "~1.0.0" + } + }, "nugget": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/nugget/-/nugget-2.0.1.tgz", @@ -7800,6 +7858,14 @@ "error-ex": "^1.2.0" } }, + "parse5": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-3.0.3.tgz", + "integrity": "sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA==", + "requires": { + "@types/node": "*" + } + }, "pascalcase": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", diff --git a/script/package.json b/script/package.json index 10c6494cc..7bef66e97 100644 --- a/script/package.json +++ b/script/package.json @@ -6,6 +6,7 @@ "async": "2.0.1", "aws-sdk": "^2.5.2", "babel-core": "5.8.38", + "cheerio": "1.0.0-rc.2", "coffeelint": "1.15.7", "colors": "1.1.2", "donna": "1.0.16", From aa02ac8daa4c23d1f0d923f3d20b0575d930b04b Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 15 Feb 2019 10:01:15 -0500 Subject: [PATCH 066/112] Script to post-process JUnit XML output --- script/postprocess-junit-results | 87 ++++++++++++++++++++++++++++++++ spec/jasmine-junit-reporter.js | 4 -- 2 files changed, 87 insertions(+), 4 deletions(-) create mode 100755 script/postprocess-junit-results diff --git a/script/postprocess-junit-results b/script/postprocess-junit-results new file mode 100755 index 000000000..bd7cbb4f8 --- /dev/null +++ b/script/postprocess-junit-results @@ -0,0 +1,87 @@ +#!/usr/bin/env node + +const yargs = require('yargs') + +const argv = yargs + .usage('Usage: $0 [options]') + .help('help') + .option('search-folder', { + string: true, + demandOption: true, + requiresArg: true, + describe: 'Directory to search for JUnit XML results' + }) + .option('test-results-files', { + string: true, + demandOption: true, + requiresArg: true, + describe: 'Glob that matches JUnit XML files within searchFolder' + }) + .wrap(yargs.terminalWidth()) + .argv + +const fs = require('fs') +const path = require('path') +const glob = require('glob') +const cheerio = require('cheerio') + +function discoverTestFiles() { + return new Promise((resolve, reject) => { + glob(argv.testResultsFiles, {cwd: argv.searchFolder}, (err, paths) => { + if (err) { + reject(err) + } else { + resolve(paths) + } + }) + }) +} + +async function postProcessJUnitXML(junitXmlPath) { + const fullPath = path.resolve(argv.searchFolder, junitXmlPath) + const friendlyName = path.basename(junitXmlPath, '.xml').replace(/-+/g, ' ') + + console.log(`${fullPath}: loading`) + + const original = await new Promise((resolve, reject) => { + fs.readFile(fullPath, {encoding: 'utf8'}, (err, content) => { + if (err) { + reject(err) + } else { + resolve(content) + } + }) + }) + + const $ = cheerio.load(original, { xmlMode: true }) + $('testcase').attr('name', (i, oldName) => `[${friendlyName}] ${oldName}`) + const modified = $.xml() + + await new Promise((resolve, reject) => { + fs.writeFile(fullPath, modified, {encoding: 'utf8'}, err => { + if (err) { + reject(err) + } else { + resolve() + } + }) + }) + console.log(`${fullPath}: complete`) +} + +;(async function() { + const testResultFiles = await discoverTestFiles() + console.log(`Post-processing ${testResultFiles.length} JUnit XML files`) + + await Promise.all( + testResultFiles.map(postProcessJUnitXML) + ) + + console.log(`${testResultFiles.length} JUnit XML files complete`) +})().then( + () => process.exit(0), + err => { + console.error(err.stack || err) + process.exit(1) + } +) diff --git a/spec/jasmine-junit-reporter.js b/spec/jasmine-junit-reporter.js index 9618edc24..14a4969b7 100644 --- a/spec/jasmine-junit-reporter.js +++ b/spec/jasmine-junit-reporter.js @@ -9,10 +9,6 @@ class JasmineJUnitReporter extends jasmine.JUnitXmlReporter { currentSuite = currentSuite.parentSuite } - if (process.env.TEST_JUNIT_RUN) { - fullDescription = `[${process.env.TEST_JUNIT_RUN}] ` + fullDescription - } - return fullDescription } From 9d76594060662889c8a3587655824889fbeae3b0 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 15 Feb 2019 10:06:07 -0500 Subject: [PATCH 067/112] Windows entry point for postprocess-junit-results script --- script/postprocess-junit-results.cmd | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 script/postprocess-junit-results.cmd diff --git a/script/postprocess-junit-results.cmd b/script/postprocess-junit-results.cmd new file mode 100644 index 000000000..50ee48f37 --- /dev/null +++ b/script/postprocess-junit-results.cmd @@ -0,0 +1,5 @@ +@IF EXIST "%~dp0\node.exe" ( + "%~dp0\node.exe" "%~dp0\postprocess-junit-results" %* +) ELSE ( + node "%~dp0\postprocess-junit-results" %* +) From 57ff580d66adac309ae474b6b6db32626cad8c70 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 15 Feb 2019 10:09:36 -0500 Subject: [PATCH 068/112] Invoke the postprocessing script from CI --- script/vsts/platforms/linux.yml | 6 +++--- script/vsts/platforms/macos.yml | 6 +++--- script/vsts/platforms/windows.yml | 10 +++++----- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/script/vsts/platforms/linux.yml b/script/vsts/platforms/linux.yml index 477b3dbe0..aaee52410 100644 --- a/script/vsts/platforms/linux.yml +++ b/script/vsts/platforms/linux.yml @@ -29,10 +29,10 @@ jobs: displayName: Run tests condition: and(succeeded(), ne(variables['Atom.SkipTests'], 'true')) - - script: find "${TEST_JUNIT_XML_ROOT}" || true + - script: script/postprocess-junit-results --search-folder "${TEST_JUNIT_XML_ROOT}" --test-results-files "**/*.xml" env: - TEST_JUNIT_XML_ROOT: $(Common.TestResultsDirectory) - displayName: Dump test results + TEST_JUNIT_XML_ROOT: $(Common.TestResultsDirectory)/junit + displayName: Post-process test results condition: succeededOrFailed() - task: PublishTestResults@2 diff --git a/script/vsts/platforms/macos.yml b/script/vsts/platforms/macos.yml index 1264efe4a..a8def1732 100644 --- a/script/vsts/platforms/macos.yml +++ b/script/vsts/platforms/macos.yml @@ -49,10 +49,10 @@ jobs: displayName: Run tests condition: and(succeeded(), ne(variables['Atom.SkipTests'], 'true')) - - script: find "${TEST_JUNIT_XML_ROOT}" || true + - script: script/postprocess-junit-results --search-folder "${TEST_JUNIT_XML_ROOT}" --test-results-files "**/*.xml" env: - TEST_JUNIT_XML_ROOT: $(Common.TestResultsDirectory) - displayName: Dump test results + TEST_JUNIT_XML_ROOT: $(Common.TestResultsDirectory)/junit + displayName: Post-process test results condition: succeededOrFailed() - task: PublishTestResults@2 diff --git a/script/vsts/platforms/windows.yml b/script/vsts/platforms/windows.yml index 748da853f..d057ed348 100644 --- a/script/vsts/platforms/windows.yml +++ b/script/vsts/platforms/windows.yml @@ -75,12 +75,12 @@ jobs: displayName: Run tests condition: and(succeeded(), ne(variables['Atom.SkipTests'], 'true')) - - powershell: Get-ChildItem -Recurse $env:TEST_JUNIT_XML_ROOT - failOnStderr: false - ignoreLASTEXITCODE: true + - script: > + node script\vsts\windows-run.js script\postprocess-junit-results.cmd + --search-folder "${TEST_JUNIT_XML_ROOT}" --test-results-files "**/*.xml" env: - TEST_JUNIT_XML_ROOT: $(Common.TestResultsDirectory) - displayName: Dump test results + TEST_JUNIT_XML_ROOT: $(Common.TestResultsDirectory)/junit + displayName: Post-process test results condition: succeededOrFailed() - task: PublishTestResults@2 From 536c582e2bc1883a0c890be677207d26eccb27d1 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 15 Feb 2019 11:16:19 -0500 Subject: [PATCH 069/112] Respect Atom.SkipTests --- script/vsts/platforms/linux.yml | 2 +- script/vsts/platforms/macos.yml | 2 +- script/vsts/platforms/windows.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/script/vsts/platforms/linux.yml b/script/vsts/platforms/linux.yml index aaee52410..3ebb2a6bd 100644 --- a/script/vsts/platforms/linux.yml +++ b/script/vsts/platforms/linux.yml @@ -33,7 +33,7 @@ jobs: env: TEST_JUNIT_XML_ROOT: $(Common.TestResultsDirectory)/junit displayName: Post-process test results - condition: succeededOrFailed() + condition: ne(variables['Atom.SkipTests'], 'true') - task: PublishTestResults@2 inputs: diff --git a/script/vsts/platforms/macos.yml b/script/vsts/platforms/macos.yml index a8def1732..ef724f655 100644 --- a/script/vsts/platforms/macos.yml +++ b/script/vsts/platforms/macos.yml @@ -53,7 +53,7 @@ jobs: env: TEST_JUNIT_XML_ROOT: $(Common.TestResultsDirectory)/junit displayName: Post-process test results - condition: succeededOrFailed() + condition: ne(variables['Atom.SkipTests'], 'true') - task: PublishTestResults@2 inputs: diff --git a/script/vsts/platforms/windows.yml b/script/vsts/platforms/windows.yml index d057ed348..5ca4b9e23 100644 --- a/script/vsts/platforms/windows.yml +++ b/script/vsts/platforms/windows.yml @@ -81,7 +81,7 @@ jobs: env: TEST_JUNIT_XML_ROOT: $(Common.TestResultsDirectory)/junit displayName: Post-process test results - condition: succeededOrFailed() + condition: ne(variables['Atom.SkipTests'], 'true') - task: PublishTestResults@2 inputs: From a645a8e638a5a47c1f7ddcc948fe9017a56b96e2 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 15 Feb 2019 11:16:33 -0500 Subject: [PATCH 070/112] Windows path separator maybe --- script/vsts/platforms/windows.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/script/vsts/platforms/windows.yml b/script/vsts/platforms/windows.yml index 5ca4b9e23..4b973d760 100644 --- a/script/vsts/platforms/windows.yml +++ b/script/vsts/platforms/windows.yml @@ -77,9 +77,9 @@ jobs: - script: > node script\vsts\windows-run.js script\postprocess-junit-results.cmd - --search-folder "${TEST_JUNIT_XML_ROOT}" --test-results-files "**/*.xml" + --search-folder "${TEST_JUNIT_XML_ROOT}" --test-results-files "**\*.xml" env: - TEST_JUNIT_XML_ROOT: $(Common.TestResultsDirectory)/junit + TEST_JUNIT_XML_ROOT: $(Common.TestResultsDirectory)\junit displayName: Post-process test results condition: ne(variables['Atom.SkipTests'], 'true') From bf3502c4db46c42e516eac0c18658aa5a3cd8ade Mon Sep 17 00:00:00 2001 From: David Wilson Date: Sun, 10 Feb 2019 13:50:32 -0800 Subject: [PATCH 071/112] Fix "Open Folder" menu item on Windows --- spec/main-process/atom-application.test.js | 2 +- src/main-process/atom-application.js | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/main-process/atom-application.test.js b/spec/main-process/atom-application.test.js index 65503b682..296ffcad9 100644 --- a/spec/main-process/atom-application.test.js +++ b/spec/main-process/atom-application.test.js @@ -658,7 +658,7 @@ describe('AtomApplication', function () { atomApplication.promptForPathToOpen.reset() atomApplication.emit('application:open-folder') - await conditionPromise(() => atomApplication.promptForPathToOpen.calledWith('file')) + await conditionPromise(() => atomApplication.promptForPathToOpen.calledWith('folder')) atomApplication.promptForPathToOpen.reset() }) } diff --git a/src/main-process/atom-application.js b/src/main-process/atom-application.js index 8edfdf39c..00fef2d6f 100644 --- a/src/main-process/atom-application.js +++ b/src/main-process/atom-application.js @@ -382,9 +382,6 @@ class AtomApplication extends EventEmitter { this.on('application:new-file', () => (this.focusedWindow() || this).openPath()) this.on('application:open-dev', () => this.promptForPathToOpen('all', {devMode: true})) this.on('application:open-safe', () => this.promptForPathToOpen('all', {safeMode: true})) - this.on('application:open', () => this.promptForPathToOpen('all', getLoadSettings(), getDefaultPath())) - this.on('application:open-file', () => this.promptForPathToOpen('file', getLoadSettings(), getDefaultPath())) - this.on('application:open-folder', () => this.promptForPathToOpen('file', getLoadSettings(), getDefaultPath())) this.on('application:inspect', ({x, y, atomWindow}) => { if (!atomWindow) atomWindow = this.focusedWindow() if (atomWindow) atomWindow.browserWindow.inspectElement(x, y) @@ -406,6 +403,9 @@ class AtomApplication extends EventEmitter { this.on('application:check-for-update', () => this.autoUpdateManager.check()) if (process.platform === 'darwin') { + this.on('application:open', () => this.promptForPathToOpen('all', getLoadSettings(), getDefaultPath())) + this.on('application:open-file', () => this.promptForPathToOpen('file', getLoadSettings(), getDefaultPath())) + this.on('application:open-folder', () => this.promptForPathToOpen('folder', getLoadSettings(), getDefaultPath())) this.on('application:bring-all-windows-to-front', () => Menu.sendActionToFirstResponder('arrangeInFront:')) this.on('application:hide', () => Menu.sendActionToFirstResponder('hide:')) this.on('application:hide-other-applications', () => Menu.sendActionToFirstResponder('hideOtherApplications:')) From 60aaca8eccd3addbfea9a6e97e43001b729da636 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 15 Feb 2019 13:02:25 -0500 Subject: [PATCH 072/112] Er, maybe no separator at all? --- script/vsts/platforms/windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/vsts/platforms/windows.yml b/script/vsts/platforms/windows.yml index 4b973d760..85799b432 100644 --- a/script/vsts/platforms/windows.yml +++ b/script/vsts/platforms/windows.yml @@ -77,7 +77,7 @@ jobs: - script: > node script\vsts\windows-run.js script\postprocess-junit-results.cmd - --search-folder "${TEST_JUNIT_XML_ROOT}" --test-results-files "**\*.xml" + --search-folder "${TEST_JUNIT_XML_ROOT}" --test-results-files "*.xml" env: TEST_JUNIT_XML_ROOT: $(Common.TestResultsDirectory)\junit displayName: Post-process test results From 06a1a38d25771d265e64bd77629ba3039b606f7b Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 15 Feb 2019 14:56:39 -0500 Subject: [PATCH 073/112] Oh. Right. That's interpreted as a .bat file --- script/vsts/platforms/windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/vsts/platforms/windows.yml b/script/vsts/platforms/windows.yml index 85799b432..a57c1e1af 100644 --- a/script/vsts/platforms/windows.yml +++ b/script/vsts/platforms/windows.yml @@ -77,7 +77,7 @@ jobs: - script: > node script\vsts\windows-run.js script\postprocess-junit-results.cmd - --search-folder "${TEST_JUNIT_XML_ROOT}" --test-results-files "*.xml" + --search-folder %TEST_JUNIT_XML_ROOT% --test-results-files "**/*.xml" env: TEST_JUNIT_XML_ROOT: $(Common.TestResultsDirectory)\junit displayName: Post-process test results From efd9151589f64a0dd023926ae8820d71b535cb82 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 15 Feb 2019 16:09:27 -0500 Subject: [PATCH 074/112] Revert temporary script/test changes --- script/test | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/script/test b/script/test index 22d945a11..263858139 100755 --- a/script/test +++ b/script/test @@ -68,8 +68,7 @@ function prepareEnv (suiteName) { if (process.env.TEST_JUNIT_XML_ROOT) { // Tell Jasmine to output this suite's results as a JUnit XML file to a subdirectory of the root, so that a // CI system can interpret it. - env.TEST_JUNIT_RUN = suiteName - const fileName = suiteName.replace(/\W+/g, '-') + '.xml' + const fileName = suiteName + '.xml' const outputPath = path.join(process.env.TEST_JUNIT_XML_ROOT, fileName) env.TEST_JUNIT_XML_PATH = outputPath } @@ -83,7 +82,7 @@ function runCoreMainProcessTests (callback) { '--resource-path', resourcePath, '--test', '--main-process', testPath ] - const testEnv = Object.assign({}, prepareEnv('core main process'), {ATOM_GITHUB_INLINE_GIT_EXEC: 'true'}) + const testEnv = Object.assign({}, prepareEnv('core-main-process'), {ATOM_GITHUB_INLINE_GIT_EXEC: 'true'}) console.log('Executing core main process tests'.bold.green) const cp = childProcess.spawn(executablePath, testArguments, {stdio: 'inherit', env: testEnv}) @@ -97,7 +96,7 @@ function runCoreRenderProcessTests (callback) { '--resource-path', resourcePath, '--test', testPath ] - const testEnv = prepareEnv('core render process') + const testEnv = prepareEnv('core-render-process') console.log('Executing core render process tests'.bold.green) const cp = childProcess.spawn(executablePath, testArguments, {stdio: 'inherit', env: testEnv}) @@ -131,7 +130,7 @@ for (let packageName in CONFIG.appMetadata.packageDependencies) { '--resource-path', resourcePath, '--test', testFolder ] - const testEnv = prepareEnv(`bundled package ${packageName}`) + const testEnv = prepareEnv(`bundled-package-${packageName}`) const pkgJsonPath = path.join(repositoryPackagePath, 'package.json') const nodeModulesPath = path.join(repositoryPackagePath, 'node_modules') @@ -218,7 +217,7 @@ function testSuitesForPlatform (platform) { suites = suites.filter(suite => suite !== runCoreMainProcessTests) } - return [runCoreMainProcessTests, runCoreRenderProcessTests].concat(packageTestSuites) + return suites } async.series(testSuitesToRun, function (err, exitCodes) { From 13a6d43e615d637d275bd17efdaa0fc78c6e48a6 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 15 Feb 2019 16:10:21 -0500 Subject: [PATCH 075/112] Remove stdout noise --- spec/jasmine-test-runner.coffee | 2 -- 1 file changed, 2 deletions(-) diff --git a/spec/jasmine-test-runner.coffee b/spec/jasmine-test-runner.coffee index 200f03e38..5a11530b7 100644 --- a/spec/jasmine-test-runner.coffee +++ b/spec/jasmine-test-runner.coffee @@ -48,8 +48,6 @@ module.exports = ({logFile, headless, testPaths, buildAtomEnvironment}) -> fileBase = path.basename(process.env.TEST_JUNIT_XML_PATH, '.xml') jasmineEnv.addReporter new JasmineJUnitReporter(outputDir, true, false, fileBase, true) - else - process.stdout.write "No JUnit XML\n" jasmineEnv.setIncludedTags([process.platform]) From f0fb2888493de9320c883a2c57536d5500f80001 Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Sun, 17 Feb 2019 14:18:33 -0500 Subject: [PATCH 076/112] Override console.(log|error) and process.std(out|err) when headless --- src/initialize-test-window.coffee | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/initialize-test-window.coffee b/src/initialize-test-window.coffee index 4cbd02bfd..e80fc86a6 100644 --- a/src/initialize-test-window.coffee +++ b/src/initialize-test-window.coffee @@ -32,7 +32,17 @@ module.exports = ({blobStore}) -> {testRunnerPath, legacyTestRunnerPath, headless, logFile, testPaths, env} = getWindowLoadSettings() - unless headless + if headless + # Install console functions that output to stdout and stderr. + util = require 'util' + + Object.defineProperties process, + stdout: {value: remote.process.stdout} + stderr: {value: remote.process.stderr} + + console.log = (args...) -> process.stdout.write "#{util.format(args...)}\n" + console.error = (args...) -> process.stderr.write "#{util.format(args...)}\n" + else # Show window synchronously so a focusout doesn't fire on input elements # that are focused in the very first spec run. remote.getCurrentWindow().show() From ce4180e9f11ff1a96402419ab688cc7d86c0e02a Mon Sep 17 00:00:00 2001 From: David Wilson Date: Sun, 17 Feb 2019 11:26:04 -0800 Subject: [PATCH 077/112] Upload Windows delta nupkg artifacts in release builds --- script/vsts/platforms/windows.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/script/vsts/platforms/windows.yml b/script/vsts/platforms/windows.yml index a57c1e1af..019b59730 100644 --- a/script/vsts/platforms/windows.yml +++ b/script/vsts/platforms/windows.yml @@ -116,6 +116,15 @@ jobs: displayName: Upload atom-x64-$(ReleaseVersion)-full.nupkg condition: and(succeeded(), eq(variables['IsReleaseBranch'], 'true'), eq(variables['buildArch'], 'x64')) + - task: PublishBuildArtifacts@1 + inputs: + PathtoPublish: $(Build.SourcesDirectory)/out/atom-x64-$(ReleaseVersion)-delta.nupkg + ArtifactName: atom-x64-$(ReleaseVersion)-delta.nupkg + ArtifactType: Container + displayName: Upload atom-x64-$(ReleaseVersion)-delta.nupkg + condition: and(succeeded(), eq(variables['IsReleaseBranch'], 'true'), eq(variables['buildArch'], 'x64')) + continueOnError: true # Nightly builds don't produce delta packages yet, so don't fail the build + - task: PublishBuildArtifacts@1 inputs: PathtoPublish: $(Build.SourcesDirectory)/out/RELEASES-x64 @@ -148,6 +157,15 @@ jobs: displayName: Upload atom-$(ReleaseVersion)-full.nupkg condition: and(succeeded(), eq(variables['IsReleaseBranch'], 'true'), eq(variables['buildArch'], 'x86')) + - task: PublishBuildArtifacts@1 + inputs: + PathtoPublish: $(Build.SourcesDirectory)/out/atom-$(ReleaseVersion)-delta.nupkg + ArtifactName: atom-$(ReleaseVersion)-delta.nupkg + ArtifactType: Container + displayName: Upload atom-$(ReleaseVersion)-delta.nupkg + condition: and(succeeded(), eq(variables['IsReleaseBranch'], 'true'), eq(variables['buildArch'], 'x86')) + continueOnError: true # Nightly builds don't produce delta packages yet, so don't fail the build + - task: PublishBuildArtifacts@1 inputs: PathtoPublish: $(Build.SourcesDirectory)/out/RELEASES From 0a2ce1b38f92ee54d8cd031f89a830b5fb24a621 Mon Sep 17 00:00:00 2001 From: David Wilson Date: Sun, 17 Feb 2019 17:58:05 -0800 Subject: [PATCH 078/112] :arrow_up: atom-keymap@8.2.13 --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8dd7b8c88..2fa905550 100644 --- a/package-lock.json +++ b/package-lock.json @@ -306,9 +306,9 @@ } }, "atom-keymap": { - "version": "8.2.12", - "resolved": "https://registry.npmjs.org/atom-keymap/-/atom-keymap-8.2.12.tgz", - "integrity": "sha512-qAXylPa/uysvYhZC1zJR7yG7QFs2RqU+2646JYGeiqgm0nMxLpdJpJ9ABIXbDNxzjhlRXNmZkr5V6N22RWjh4Q==", + "version": "8.2.13", + "resolved": "https://registry.npmjs.org/atom-keymap/-/atom-keymap-8.2.13.tgz", + "integrity": "sha512-RNf+5KbAiXpNV2KZT0+XYpTRFE8rhq7NrBryghJAOlwayY3g3z6Kp9tMfaPJ05BkPo9mChcaFO6SKUL8LTQcBg==", "requires": { "clear-cut": "^2", "emissary": "^1.1.0", diff --git a/package.json b/package.json index 5375c855b..f34ed3302 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "async": "0.2.6", "atom-dark-syntax": "file:packages/atom-dark-syntax", "atom-dark-ui": "file:packages/atom-dark-ui", - "atom-keymap": "8.2.12", + "atom-keymap": "8.2.13", "atom-light-syntax": "file:packages/atom-light-syntax", "atom-light-ui": "file:packages/atom-light-ui", "atom-select-list": "^0.7.2", From 1a79b39b2d212191fabd1ce58915361e10310d91 Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Fri, 22 Feb 2019 17:40:48 +0100 Subject: [PATCH 079/112] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20=20fuzzy-finder@1.?= =?UTF-8?q?9.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 4 ++-- package.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2fa905550..43712b315 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2464,8 +2464,8 @@ "integrity": "sha1-gy9kifvodnaUWVmckUpnDsIpR+4=" }, "fuzzy-finder": { - "version": "https://www.atom.io/api/packages/fuzzy-finder/versions/1.9.0/tarball", - "integrity": "sha512-YJTPPMZLQmDiUa6eoONhHF7sOvAPQqrXNFLfPGAUItDUoJxvJBwkPcxh+ryCHLlO8MuoJdDvAKHsU0mGzb/JeQ==", + "version": "https://www.atom.io/api/packages/fuzzy-finder/versions/1.9.1/tarball", + "integrity": "sha512-UHyWdvhaiosjg4Rf3OKIWHew7kAB3T6ZQkaTJKMfBoARAdV3t6TvifRKYFICUjERWCHsx2fB+AZ1QwtMYuDiHA==", "requires": { "async": "0.2.6", "atom-select-list": "^0.7.0", diff --git a/package.json b/package.json index f34ed3302..99358f59d 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "fs-plus": "^3.1.1", "fstream": "0.1.24", "fuzzaldrin": "^2.1", - "fuzzy-finder": "https://www.atom.io/api/packages/fuzzy-finder/versions/1.9.0/tarball", + "fuzzy-finder": "https://www.atom.io/api/packages/fuzzy-finder/versions/1.9.1/tarball", "git-diff": "file:packages/git-diff", "git-utils": "5.2.1", "github": "https://www.atom.io/api/packages/github/versions/0.26.0/tarball", @@ -201,7 +201,7 @@ "encoding-selector": "0.23.9", "exception-reporting": "file:./packages/exception-reporting", "find-and-replace": "0.218.0", - "fuzzy-finder": "1.9.0", + "fuzzy-finder": "1.9.1", "github": "0.26.0", "git-diff": "file:./packages/git-diff", "go-to-line": "file:./packages/go-to-line", From b5898b8e0728bb6807da4900523eaa8908b4ba5b Mon Sep 17 00:00:00 2001 From: Ash Wilson Date: Fri, 22 Feb 2019 15:02:47 -0500 Subject: [PATCH 080/112] Actually dump minidump contents to the file --- script/lib/dump-symbols.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/lib/dump-symbols.js b/script/lib/dump-symbols.js index 6b0b10bef..9b7492ed7 100644 --- a/script/lib/dump-symbols.js +++ b/script/lib/dump-symbols.js @@ -35,7 +35,7 @@ function dumpSymbol (binaryPath) { const symbolDirPath = path.join(CONFIG.symbolsPath, filename, moduleLine[1]) const symbolFilePath = path.join(symbolDirPath, `${filename}.sym`) fs.mkdirpSync(symbolDirPath) - fs.writeFileSync(symbolFilePath) + fs.writeFileSync(symbolFilePath, content) resolve() } } From 07a0842c67e2c346798a8680d5aea5dae98acd1d Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Fri, 22 Feb 2019 16:26:14 +0100 Subject: [PATCH 081/112] =?UTF-8?q?=E2=AC=86=20find-and-replace@0.218.9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 4 ++-- package.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 43712b315..b1560214b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2219,8 +2219,8 @@ } }, "find-and-replace": { - "version": "https://www.atom.io/api/packages/find-and-replace/versions/0.218.0/tarball", - "integrity": "sha512-c77OpEcgce8cfPgjPQStEvK016AVmNMUfKIuCYgzYbjTik2lCSU+QAEG3q6MitIzqoFiSW6WW3FL502HFyZwKg==", + "version": "https://www.atom.io/api/packages/find-and-replace/versions/0.218.9/tarball", + "integrity": "sha512-j1KWRa8Ki9P3G3//kP9sWUqa8vva3+HiWfZJAR8kAaOJFUqy9EGOp6SR3Xs6ChQbk8kHmQBnIcYUjCz/gDoJ/g==", "requires": { "binary-search": "^1.3.3", "element-resize-detector": "^1.1.10", diff --git a/package.json b/package.json index 99358f59d..3ca3b9c61 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "etch": "^0.12.6", "event-kit": "^2.5.3", "exception-reporting": "file:packages/exception-reporting", - "find-and-replace": "https://www.atom.io/api/packages/find-and-replace/versions/0.218.0/tarball", + "find-and-replace": "https://www.atom.io/api/packages/find-and-replace/versions/0.218.9/tarball", "find-parent-dir": "^0.3.0", "first-mate": "7.1.3", "focus-trap": "2.4.5", @@ -200,7 +200,7 @@ "dev-live-reload": "file:./packages/dev-live-reload", "encoding-selector": "0.23.9", "exception-reporting": "file:./packages/exception-reporting", - "find-and-replace": "0.218.0", + "find-and-replace": "0.218.9", "fuzzy-finder": "1.9.1", "github": "0.26.0", "git-diff": "file:./packages/git-diff", From 64d63b9d4ab3c6f6d1f48c4e9f06010913f7970c Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Thu, 21 Feb 2019 14:49:43 +0100 Subject: [PATCH 082/112] Fix syntax error in fixture --- packages/go-to-line/spec/fixtures/sample.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/go-to-line/spec/fixtures/sample.js b/packages/go-to-line/spec/fixtures/sample.js index cb53d4078..e09a93919 100644 --- a/packages/go-to-line/spec/fixtures/sample.js +++ b/packages/go-to-line/spec/fixtures/sample.js @@ -14,7 +14,7 @@ var quicksort = function () { // adapted from: // https://github.com/nzakas/computer-science-in-javascript/tree/master/algorithms/sorting/merge-sort-recursive -var mergeSort function (items){ +var mergeSort = function (items){ var merge = function (left, right){ var result = []; var il = 0; From 7e23d4dc7a77bb5b226bfd2c2965fabab851d89c Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Thu, 21 Feb 2019 14:48:21 +0100 Subject: [PATCH 083/112] Run prettier on packages/ folder --- packages/about/lib/about.js | 30 +- .../about/lib/components/about-status-bar.js | 20 +- packages/about/lib/components/about-view.js | 159 ++++++--- packages/about/lib/components/atom-logo.js | 81 ++++- packages/about/lib/components/update-view.js | 142 +++++--- packages/about/lib/etch-component.js | 3 +- packages/about/lib/main.js | 35 +- packages/about/lib/update-manager.js | 17 +- packages/about/spec/about-spec.js | 11 +- packages/about/spec/about-status-bar-spec.js | 12 +- .../about/spec/helpers/async-spec-helpers.js | 6 +- packages/about/spec/mocks/updater.js | 4 +- packages/about/spec/update-manager-spec.js | 20 +- packages/about/spec/update-view-spec.js | 217 +++++++++--- packages/dalek/lib/dalek.js | 4 +- packages/dalek/test/dalek.test.js | 53 ++- packages/dalek/test/runner.js | 2 +- .../lib/deprecation-cop-view.js | 321 +++++++++++------ packages/deprecation-cop/lib/main.js | 39 ++- .../dev-live-reload/lib/base-theme-watcher.js | 11 +- packages/dev-live-reload/lib/main.js | 12 +- .../dev-live-reload/lib/package-watcher.js | 6 +- packages/dev-live-reload/lib/ui-watcher.js | 80 +++-- packages/dev-live-reload/lib/watcher.js | 12 +- .../spec/async-spec-helpers.js | 7 +- .../spec/dev-live-reload-spec.js | 28 +- .../dev-live-reload/spec/ui-watcher-spec.js | 111 ++++-- packages/exception-reporting/lib/main.js | 44 ++- packages/exception-reporting/lib/reporter.js | 122 ++++--- .../exception-reporting/spec/reporter-spec.js | 331 +++++++++++------- packages/git-diff/lib/diff-list-view.js | 30 +- packages/git-diff/lib/git-diff-view.js | 82 +++-- packages/git-diff/lib/main.js | 12 +- packages/git-diff/spec/diff-list-view-spec.js | 10 +- packages/git-diff/spec/git-diff-spec.js | 91 +++-- packages/go-to-line/lib/go-to-line-view.js | 18 +- packages/go-to-line/spec/go-to-line-spec.js | 8 +- .../grammar-selector/lib/grammar-list-view.js | 17 +- .../lib/grammar-status-view.js | 37 +- packages/grammar-selector/lib/main.js | 12 +- .../spec/async-spec-helpers.js | 5 +- .../spec/grammar-selector-spec.js | 101 ++++-- .../lib/incompatible-packages-component.js | 78 +++-- packages/incompatible-packages/lib/main.js | 30 +- .../lib/status-icon-component.js | 4 +- .../incompatible-packages-component-spec.js | 180 ++++++---- .../spec/incompatible-packages-spec.js | 10 +- packages/line-ending-selector/lib/main.js | 191 +++++----- .../lib/status-bar-item.js | 17 +- .../spec/line-ending-selector-spec.js | 100 ++++-- packages/link/lib/link.js | 36 +- packages/link/spec/async-spec-helpers.js | 7 +- packages/link/spec/link-spec.js | 28 +- packages/one-dark-ui/spec/theme-spec.js | 26 +- packages/one-light-ui/spec/theme-spec.js | 26 +- 55 files changed, 2077 insertions(+), 1019 deletions(-) diff --git a/packages/about/lib/about.js b/packages/about/lib/about.js index 1221bda6d..1fe660e9f 100644 --- a/packages/about/lib/about.js +++ b/packages/about/lib/about.js @@ -1,4 +1,4 @@ -const {CompositeDisposable, Emitter} = require('atom') +const { CompositeDisposable, Emitter } = require('atom') const AboutView = require('./components/about-view') // Deferred requires @@ -14,16 +14,22 @@ module.exports = class About { aboutView: null } - this.subscriptions.add(atom.workspace.addOpener((uriToOpen) => { - if (uriToOpen === this.state.uri) { - return this.deserialize() - } - })) + this.subscriptions.add( + atom.workspace.addOpener(uriToOpen => { + if (uriToOpen === this.state.uri) { + return this.deserialize() + } + }) + ) - this.subscriptions.add(atom.commands.add('atom-workspace', 'about:view-release-notes', () => { - shell = shell || require('electron').shell - shell.openExternal(this.state.updateManager.getReleaseNotesURLForCurrentVersion()) - })) + this.subscriptions.add( + atom.commands.add('atom-workspace', 'about:view-release-notes', () => { + shell = shell || require('electron').shell + shell.openExternal( + this.state.updateManager.getReleaseNotesURLForCurrentVersion() + ) + }) + ) } destroy () { @@ -31,14 +37,14 @@ module.exports = class About { this.views.aboutView = null if (this.state.updateManager) this.state.updateManager.dispose() - this.setState({updateManager: null}) + this.setState({ updateManager: null }) this.subscriptions.dispose() } setState (newState) { if (newState && typeof newState === 'object') { - let {state} = this + let { state } = this this.state = Object.assign({}, state, newState) this.didChange() diff --git a/packages/about/lib/components/about-status-bar.js b/packages/about/lib/components/about-status-bar.js index d55800f5d..4529b6ae8 100644 --- a/packages/about/lib/components/about-status-bar.js +++ b/packages/about/lib/components/about-status-bar.js @@ -1,16 +1,20 @@ -const {CompositeDisposable} = require('atom') +const { CompositeDisposable } = require('atom') const etch = require('etch') const EtchComponent = require('../etch-component') const $ = etch.dom -module.exports = -class AboutStatusBar extends EtchComponent { +module.exports = class AboutStatusBar extends EtchComponent { constructor () { super() this.subscriptions = new CompositeDisposable() - this.subscriptions.add(atom.tooltips.add(this.element, {title: 'An update will be installed the next time Atom is relaunched.

Click the squirrel icon for more information.'})) + this.subscriptions.add( + atom.tooltips.add(this.element, { + title: + 'An update will be installed the next time Atom is relaunched.

Click the squirrel icon for more information.' + }) + ) } handleClick () { @@ -18,8 +22,12 @@ class AboutStatusBar extends EtchComponent { } render () { - return $.div({className: 'about-release-notes inline-block', onclick: this.handleClick.bind(this)}, - $.span({type: 'button', className: 'icon icon-squirrel'}) + return $.div( + { + className: 'about-release-notes inline-block', + onclick: this.handleClick.bind(this) + }, + $.span({ type: 'button', className: 'icon icon-squirrel' }) ) } diff --git a/packages/about/lib/components/about-view.js b/packages/about/lib/components/about-view.js index 3e370b171..34fb7cba9 100644 --- a/packages/about/lib/components/about-view.js +++ b/packages/about/lib/components/about-view.js @@ -1,4 +1,4 @@ -const {Disposable} = require('atom') +const { Disposable } = require('atom') const etch = require('etch') const shell = require('shell') const AtomLogo = require('./atom-logo') @@ -7,8 +7,7 @@ const UpdateView = require('./update-view') const $ = etch.dom -module.exports = -class AboutView extends EtchComponent { +module.exports = class AboutView extends EtchComponent { handleAtomVersionClick (e) { e.preventDefault() atom.clipboard.write(this.props.currentAtomVersion) @@ -31,12 +30,17 @@ class AboutView extends EtchComponent { handleReleaseNotesClick (e) { e.preventDefault() - shell.openExternal(this.props.updateManager.getReleaseNotesURLForAvailableVersion()) + shell.openExternal( + this.props.updateManager.getReleaseNotesURLForAvailableVersion() + ) } handleLicenseClick (e) { e.preventDefault() - atom.commands.dispatch(atom.views.getView(atom.workspace), 'application:open-license') + atom.commands.dispatch( + atom.views.getView(atom.workspace), + 'application:open-license' + ) } handleTermsOfUseClick (e) { @@ -46,7 +50,9 @@ class AboutView extends EtchComponent { handleHowToUpdateClick (e) { e.preventDefault() - shell.openExternal('https://flight-manual.atom.io/getting-started/sections/installing-atom/') + shell.openExternal( + 'https://flight-manual.atom.io/getting-started/sections/installing-atom/' + ) } handleShowMoreClick (e) { @@ -66,39 +72,87 @@ class AboutView extends EtchComponent { } render () { - return $.div({className: 'pane-item native-key-bindings about'}, - $.div({className: 'about-container'}, - $.header({className: 'about-header'}, - $.a({className: 'about-atom-io', href: 'https://atom.io'}, + return $.div( + { className: 'pane-item native-key-bindings about' }, + $.div( + { className: 'about-container' }, + $.header( + { className: 'about-header' }, + $.a( + { className: 'about-atom-io', href: 'https://atom.io' }, $(AtomLogo) ), - $.div({className: 'about-header-info'}, - $.span({className: 'about-version-container inline-block atom', onclick: this.handleAtomVersionClick.bind(this)}, - $.span({className: 'about-version'}, `${this.props.currentAtomVersion} ${process.arch}`), - $.span({className: 'icon icon-clippy about-copy-version'}) + $.div( + { className: 'about-header-info' }, + $.span( + { + className: 'about-version-container inline-block atom', + onclick: this.handleAtomVersionClick.bind(this) + }, + $.span( + { className: 'about-version' }, + `${this.props.currentAtomVersion} ${process.arch}` + ), + $.span({ className: 'icon icon-clippy about-copy-version' }) ), - $.a({className: 'about-header-release-notes', onclick: this.handleReleaseNotesClick.bind(this)}, 'Release Notes') + $.a( + { + className: 'about-header-release-notes', + onclick: this.handleReleaseNotesClick.bind(this) + }, + 'Release Notes' + ) ), - $.span({className: 'about-version-container inline-block show-more-expand', onclick: this.handleShowMoreClick.bind(this)}, - $.span({className: 'about-more-expand'}, 'Show more') + $.span( + { + className: + 'about-version-container inline-block show-more-expand', + onclick: this.handleShowMoreClick.bind(this) + }, + $.span({ className: 'about-more-expand' }, 'Show more') ), - $.div({className: 'show-more hidden about-more-info'}, - $.div({className: 'about-more-info'}, - $.span({className: 'about-version-container inline-block electron', onclick: this.handleElectronVersionClick.bind(this)}, - $.span({className: 'about-more-version'}, `Electron: ${this.props.currentElectronVersion} `), - $.span({className: 'icon icon-clippy about-copy-version'}) + $.div( + { className: 'show-more hidden about-more-info' }, + $.div( + { className: 'about-more-info' }, + $.span( + { + className: 'about-version-container inline-block electron', + onclick: this.handleElectronVersionClick.bind(this) + }, + $.span( + { className: 'about-more-version' }, + `Electron: ${this.props.currentElectronVersion} ` + ), + $.span({ className: 'icon icon-clippy about-copy-version' }) ) ), - $.div({className: 'about-more-info'}, - $.span({className: 'about-version-container inline-block chrome', onclick: this.handleChromeVersionClick.bind(this)}, - $.span({className: 'about-more-version'}, `Chrome: ${this.props.currentChromeVersion} `), - $.span({className: 'icon icon-clippy about-copy-version'}) + $.div( + { className: 'about-more-info' }, + $.span( + { + className: 'about-version-container inline-block chrome', + onclick: this.handleChromeVersionClick.bind(this) + }, + $.span( + { className: 'about-more-version' }, + `Chrome: ${this.props.currentChromeVersion} ` + ), + $.span({ className: 'icon icon-clippy about-copy-version' }) ) ), - $.div({className: 'about-more-info'}, - $.span({className: 'about-version-container inline-block node', onclick: this.handleNodeVersionClick.bind(this)}, - $.span({className: 'about-more-version'}, `Node: ${this.props.currentNodeVersion} `), - $.span({className: 'icon icon-clippy about-copy-version'}) + $.div( + { className: 'about-more-info' }, + $.span( + { + className: 'about-version-container inline-block node', + onclick: this.handleNodeVersionClick.bind(this) + }, + $.span( + { className: 'about-more-version' }, + `Node: ${this.props.currentNodeVersion} ` + ), + $.span({ className: 'icon icon-clippy about-copy-version' }) ) ) ) @@ -112,24 +166,43 @@ class AboutView extends EtchComponent { viewUpdateInstructions: this.handleHowToUpdateClick.bind(this) }), - $.div({className: 'about-actions group-item'}, - $.div({className: 'btn-group'}, - $.button({className: 'btn view-license', onclick: this.handleLicenseClick.bind(this)}, 'License'), - $.button({className: 'btn terms-of-use', onclick: this.handleTermsOfUseClick.bind(this)}, 'Terms of Use') + $.div( + { className: 'about-actions group-item' }, + $.div( + { className: 'btn-group' }, + $.button( + { + className: 'btn view-license', + onclick: this.handleLicenseClick.bind(this) + }, + 'License' + ), + $.button( + { + className: 'btn terms-of-use', + onclick: this.handleTermsOfUseClick.bind(this) + }, + 'Terms of Use' + ) ) ), - $.div({className: 'about-love group-start'}, - $.span({className: 'icon icon-code'}), - $.span({className: 'inline'}, ' with '), - $.span({className: 'icon icon-heart'}), - $.span({className: 'inline'}, ' by '), - $.a({className: 'icon icon-logo-github', href: 'https://github.com'}) + $.div( + { className: 'about-love group-start' }, + $.span({ className: 'icon icon-code' }), + $.span({ className: 'inline' }, ' with '), + $.span({ className: 'icon icon-heart' }), + $.span({ className: 'inline' }, ' by '), + $.a({ className: 'icon icon-logo-github', href: 'https://github.com' }) ), - $.div({className: 'about-credits group-item'}, - $.span({className: 'inline'}, 'And the awesome '), - $.a({href: 'https://github.com/atom/atom/contributors'}, 'Atom Community') + $.div( + { className: 'about-credits group-item' }, + $.span({ className: 'inline' }, 'And the awesome '), + $.a( + { href: 'https://github.com/atom/atom/contributors' }, + 'Atom Community' + ) ) ) } diff --git a/packages/about/lib/components/atom-logo.js b/packages/about/lib/components/atom-logo.js index f8b620ce1..bd50fc7a2 100644 --- a/packages/about/lib/components/atom-logo.js +++ b/packages/about/lib/components/atom-logo.js @@ -3,23 +3,74 @@ const EtchComponent = require('../etch-component') const $ = etch.dom -module.exports = -class AtomLogo extends EtchComponent { +module.exports = class AtomLogo extends EtchComponent { render () { - return $.svg({className: 'about-logo', width: '330px', height: '68px', viewBox: '0 0 330 68'}, - $.g({stroke: 'none', 'stroke-width': '1', fill: 'none', 'fill-rule': 'evenodd'}, - $.g({transform: 'translate(2.000000, 1.000000)'}, - $.g({transform: 'translate(96.000000, 8.000000)', fill: 'currentColor'}, - $.path({d: 'M185.498,3.399 C185.498,2.417 186.34,1.573 187.324,1.573 L187.674,1.573 C188.447,1.573 189.01,1.995 189.5,2.628 L208.676,30.862 L227.852,2.628 C228.272,1.995 228.905,1.573 229.676,1.573 L230.028,1.573 C231.01,1.573 231.854,2.417 231.854,3.399 L231.854,49.403 C231.854,50.387 231.01,51.231 230.028,51.231 C229.044,51.231 228.202,50.387 228.202,49.403 L228.202,8.246 L210.151,34.515 C209.729,35.148 209.237,35.428 208.606,35.428 C207.973,35.428 207.481,35.148 207.061,34.515 L189.01,8.246 L189.01,49.475 C189.01,50.457 188.237,51.231 187.254,51.231 C186.27,51.231 185.498,50.458 185.498,49.475 L185.498,3.399 L185.498,3.399 Z'}), - $.path({d: 'M113.086,26.507 L113.086,26.367 C113.086,12.952 122.99,0.941 137.881,0.941 C152.77,0.941 162.533,12.811 162.533,26.225 L162.533,26.367 C162.533,39.782 152.629,51.792 137.74,51.792 C122.85,51.792 113.086,39.923 113.086,26.507 M158.74,26.507 L158.74,26.367 C158.74,14.216 149.89,4.242 137.74,4.242 C125.588,4.242 116.879,14.075 116.879,26.225 L116.879,26.367 C116.879,38.518 125.729,48.491 137.881,48.491 C150.031,48.491 158.74,38.658 158.74,26.507'}), - $.path({d: 'M76.705,5.155 L60.972,5.155 C60.06,5.155 59.287,4.384 59.287,3.469 C59.287,2.556 60.059,1.783 60.972,1.783 L96.092,1.783 C97.004,1.783 97.778,2.555 97.778,3.469 C97.778,4.383 97.005,5.155 96.092,5.155 L80.358,5.155 L80.358,49.405 C80.358,50.387 79.516,51.231 78.532,51.231 C77.55,51.231 76.706,50.387 76.706,49.405 L76.706,5.155 L76.705,5.155 Z'}), - $.path({d: 'M0.291,48.562 L21.291,3.05 C21.783,1.995 22.485,1.292 23.75,1.292 L23.891,1.292 C25.155,1.292 25.858,1.995 26.348,3.05 L47.279,48.421 C47.49,48.843 47.56,49.194 47.56,49.546 C47.56,50.458 46.788,51.231 45.803,51.231 C44.961,51.231 44.329,50.599 43.978,49.826 L38.219,37.183 L9.21,37.183 L3.45,49.897 C3.099,50.739 2.538,51.231 1.694,51.231 C0.781,51.231 0.008,50.529 0.008,49.685 C0.009,49.404 0.08,48.983 0.291,48.562 L0.291,48.562 Z M36.673,33.882 L23.749,5.437 L10.755,33.882 L36.673,33.882 L36.673,33.882 Z'}) + return $.svg( + { + className: 'about-logo', + width: '330px', + height: '68px', + viewBox: '0 0 330 68' + }, + $.g( + { + stroke: 'none', + 'stroke-width': '1', + fill: 'none', + 'fill-rule': 'evenodd' + }, + $.g( + { transform: 'translate(2.000000, 1.000000)' }, + $.g( + { + transform: 'translate(96.000000, 8.000000)', + fill: 'currentColor' + }, + $.path({ + d: + 'M185.498,3.399 C185.498,2.417 186.34,1.573 187.324,1.573 L187.674,1.573 C188.447,1.573 189.01,1.995 189.5,2.628 L208.676,30.862 L227.852,2.628 C228.272,1.995 228.905,1.573 229.676,1.573 L230.028,1.573 C231.01,1.573 231.854,2.417 231.854,3.399 L231.854,49.403 C231.854,50.387 231.01,51.231 230.028,51.231 C229.044,51.231 228.202,50.387 228.202,49.403 L228.202,8.246 L210.151,34.515 C209.729,35.148 209.237,35.428 208.606,35.428 C207.973,35.428 207.481,35.148 207.061,34.515 L189.01,8.246 L189.01,49.475 C189.01,50.457 188.237,51.231 187.254,51.231 C186.27,51.231 185.498,50.458 185.498,49.475 L185.498,3.399 L185.498,3.399 Z' + }), + $.path({ + d: + 'M113.086,26.507 L113.086,26.367 C113.086,12.952 122.99,0.941 137.881,0.941 C152.77,0.941 162.533,12.811 162.533,26.225 L162.533,26.367 C162.533,39.782 152.629,51.792 137.74,51.792 C122.85,51.792 113.086,39.923 113.086,26.507 M158.74,26.507 L158.74,26.367 C158.74,14.216 149.89,4.242 137.74,4.242 C125.588,4.242 116.879,14.075 116.879,26.225 L116.879,26.367 C116.879,38.518 125.729,48.491 137.881,48.491 C150.031,48.491 158.74,38.658 158.74,26.507' + }), + $.path({ + d: + 'M76.705,5.155 L60.972,5.155 C60.06,5.155 59.287,4.384 59.287,3.469 C59.287,2.556 60.059,1.783 60.972,1.783 L96.092,1.783 C97.004,1.783 97.778,2.555 97.778,3.469 C97.778,4.383 97.005,5.155 96.092,5.155 L80.358,5.155 L80.358,49.405 C80.358,50.387 79.516,51.231 78.532,51.231 C77.55,51.231 76.706,50.387 76.706,49.405 L76.706,5.155 L76.705,5.155 Z' + }), + $.path({ + d: + 'M0.291,48.562 L21.291,3.05 C21.783,1.995 22.485,1.292 23.75,1.292 L23.891,1.292 C25.155,1.292 25.858,1.995 26.348,3.05 L47.279,48.421 C47.49,48.843 47.56,49.194 47.56,49.546 C47.56,50.458 46.788,51.231 45.803,51.231 C44.961,51.231 44.329,50.599 43.978,49.826 L38.219,37.183 L9.21,37.183 L3.45,49.897 C3.099,50.739 2.538,51.231 1.694,51.231 C0.781,51.231 0.008,50.529 0.008,49.685 C0.009,49.404 0.08,48.983 0.291,48.562 L0.291,48.562 Z M36.673,33.882 L23.749,5.437 L10.755,33.882 L36.673,33.882 L36.673,33.882 Z' + }) ), - $.g({}, - $.path({d: 'M40.363,32.075 C40.874,34.44 39.371,36.77 37.006,37.282 C34.641,37.793 32.311,36.29 31.799,33.925 C31.289,31.56 32.791,29.23 35.156,28.718 C37.521,28.207 39.851,29.71 40.363,32.075', fill: 'currentColor'}), - $.path({d: 'M48.578,28.615 C56.851,45.587 58.558,61.581 52.288,64.778 C45.822,68.076 33.326,56.521 24.375,38.969 C15.424,21.418 13.409,4.518 19.874,1.221 C22.689,-0.216 26.648,1.166 30.959,4.629', stroke: 'currentColor', 'stroke-width': '3.08', 'stroke-linecap': 'round'}), - $.path({d: 'M7.64,39.45 C2.806,36.94 -0.009,33.915 0.154,30.79 C0.531,23.542 16.787,18.497 36.462,19.52 C56.137,20.544 71.781,27.249 71.404,34.497 C71.241,37.622 68.127,40.338 63.06,42.333', stroke: 'currentColor', 'stroke-width': '3.08', 'stroke-linecap': 'round'}), - $.path({d: 'M28.828,59.354 C23.545,63.168 18.843,64.561 15.902,62.653 C9.814,58.702 13.572,42.102 24.296,25.575 C35.02,9.048 48.649,-1.149 54.736,2.803 C57.566,4.639 58.269,9.208 57.133,15.232', stroke: 'currentColor', 'stroke-width': '3.08', 'stroke-linecap': 'round'}) + $.g( + {}, + $.path({ + d: + 'M40.363,32.075 C40.874,34.44 39.371,36.77 37.006,37.282 C34.641,37.793 32.311,36.29 31.799,33.925 C31.289,31.56 32.791,29.23 35.156,28.718 C37.521,28.207 39.851,29.71 40.363,32.075', + fill: 'currentColor' + }), + $.path({ + d: + 'M48.578,28.615 C56.851,45.587 58.558,61.581 52.288,64.778 C45.822,68.076 33.326,56.521 24.375,38.969 C15.424,21.418 13.409,4.518 19.874,1.221 C22.689,-0.216 26.648,1.166 30.959,4.629', + stroke: 'currentColor', + 'stroke-width': '3.08', + 'stroke-linecap': 'round' + }), + $.path({ + d: + 'M7.64,39.45 C2.806,36.94 -0.009,33.915 0.154,30.79 C0.531,23.542 16.787,18.497 36.462,19.52 C56.137,20.544 71.781,27.249 71.404,34.497 C71.241,37.622 68.127,40.338 63.06,42.333', + stroke: 'currentColor', + 'stroke-width': '3.08', + 'stroke-linecap': 'round' + }), + $.path({ + d: + 'M28.828,59.354 C23.545,63.168 18.843,64.561 15.902,62.653 C9.814,58.702 13.572,42.102 24.296,25.575 C35.02,9.048 48.649,-1.149 54.736,2.803 C57.566,4.639 58.269,9.208 57.133,15.232', + stroke: 'currentColor', + 'stroke-width': '3.08', + 'stroke-linecap': 'round' + }) ) ) ) diff --git a/packages/about/lib/components/update-view.js b/packages/about/lib/components/update-view.js index a4e97e74d..4399b58b4 100644 --- a/packages/about/lib/components/update-view.js +++ b/packages/about/lib/components/update-view.js @@ -4,12 +4,14 @@ const UpdateManager = require('../update-manager') const $ = etch.dom -module.exports = -class UpdateView extends EtchComponent { +module.exports = class UpdateView extends EtchComponent { constructor (props) { super(props) - if (this.props.updateManager.getAutoUpdatesEnabled() && this.props.updateManager.getState() === UpdateManager.State.Idle) { + if ( + this.props.updateManager.getAutoUpdatesEnabled() && + this.props.updateManager.getState() === UpdateManager.State.Idle + ) { this.props.updateManager.checkForUpdate() } } @@ -19,12 +21,18 @@ class UpdateView extends EtchComponent { } shouldUpdateActionButtonBeDisabled () { - let {state} = this.props.updateManager - return state === UpdateManager.State.CheckingForUpdate || state === UpdateManager.State.DownloadingUpdate + let { state } = this.props.updateManager + return ( + state === UpdateManager.State.CheckingForUpdate || + state === UpdateManager.State.DownloadingUpdate + ) } executeUpdateAction () { - if (this.props.updateManager.state === UpdateManager.State.UpdateAvailableToInstall) { + if ( + this.props.updateManager.state === + UpdateManager.State.UpdateAvailableToInstall + ) { this.props.updateManager.restartAndInstallUpdate() } else { this.props.updateManager.checkForUpdate() @@ -36,44 +44,86 @@ class UpdateView extends EtchComponent { switch (this.props.updateManager.state) { case UpdateManager.State.Idle: - updateStatus = $.div({className: 'about-updates-item is-shown about-default-update-message'}, - this.props.updateManager.getAutoUpdatesEnabled() ? 'Atom will check for updates automatically' : 'Automatic updates are disabled please check manually' + updateStatus = $.div( + { + className: + 'about-updates-item is-shown about-default-update-message' + }, + this.props.updateManager.getAutoUpdatesEnabled() + ? 'Atom will check for updates automatically' + : 'Automatic updates are disabled please check manually' ) break case UpdateManager.State.CheckingForUpdate: - updateStatus = $.div({className: 'about-updates-item app-checking-for-updates'}, - $.span({className: 'about-updates-label icon icon-search'}, 'Checking for updates...') + updateStatus = $.div( + { className: 'about-updates-item app-checking-for-updates' }, + $.span( + { className: 'about-updates-label icon icon-search' }, + 'Checking for updates...' + ) ) break case UpdateManager.State.DownloadingUpdate: - updateStatus = $.div({className: 'about-updates-item app-downloading-update'}, - $.span({className: 'loading loading-spinner-tiny inline-block'}), - $.span({className: 'about-updates-label'}, 'Downloading update') + updateStatus = $.div( + { className: 'about-updates-item app-downloading-update' }, + $.span({ className: 'loading loading-spinner-tiny inline-block' }), + $.span({ className: 'about-updates-label' }, 'Downloading update') ) break case UpdateManager.State.UpdateAvailableToInstall: - updateStatus = $.div({className: 'about-updates-item app-update-available-to-install'}, - $.span({className: 'about-updates-label icon icon-squirrel'}, 'New update'), - $.span({className: 'about-updates-version'}, this.props.availableVersion), - $.a({className: 'about-updates-release-notes', onclick: this.props.viewUpdateReleaseNotes}, 'Release Notes') + updateStatus = $.div( + { className: 'about-updates-item app-update-available-to-install' }, + $.span( + { className: 'about-updates-label icon icon-squirrel' }, + 'New update' + ), + $.span( + { className: 'about-updates-version' }, + this.props.availableVersion + ), + $.a( + { + className: 'about-updates-release-notes', + onclick: this.props.viewUpdateReleaseNotes + }, + 'Release Notes' + ) ) break case UpdateManager.State.UpToDate: - updateStatus = $.div({className: 'about-updates-item app-up-to-date'}, - $.span({className: 'icon icon-check'}), - $.span({className: 'about-updates-label is-strong'}, 'Atom is up to date!') + updateStatus = $.div( + { className: 'about-updates-item app-up-to-date' }, + $.span({ className: 'icon icon-check' }), + $.span( + { className: 'about-updates-label is-strong' }, + 'Atom is up to date!' + ) ) break case UpdateManager.State.Unsupported: - updateStatus = $.div({className: 'about-updates-item app-unsupported'}, - $.span({className: 'about-updates-label is-strong'}, 'Your system does not support automatic updates'), - $.a({className: 'about-updates-instructions', onclick: this.props.viewUpdateInstructions}, 'How to update') + updateStatus = $.div( + { className: 'about-updates-item app-unsupported' }, + $.span( + { className: 'about-updates-label is-strong' }, + 'Your system does not support automatic updates' + ), + $.a( + { + className: 'about-updates-instructions', + onclick: this.props.viewUpdateInstructions + }, + 'How to update' + ) ) break case UpdateManager.State.Error: - updateStatus = $.div({className: 'about-updates-item app-update-error'}, - $.span({className: 'icon icon-x'}), - $.span({className: 'about-updates-label app-error-message is-strong'}, this.props.updateManager.getErrorMessage()) + updateStatus = $.div( + { className: 'about-updates-item app-update-error' }, + $.span({ className: 'icon icon-x' }), + $.span( + { className: 'about-updates-label app-error-message is-strong' }, + this.props.updateManager.getErrorMessage() + ) ) break } @@ -82,37 +132,47 @@ class UpdateView extends EtchComponent { } render () { - return $.div({className: 'about-updates group-start'}, - $.div({className: 'about-updates-box'}, - $.div({className: 'about-updates-status'}, this.renderUpdateStatus()), + return $.div( + { className: 'about-updates group-start' }, + $.div( + { className: 'about-updates-box' }, + $.div({ className: 'about-updates-status' }, this.renderUpdateStatus()), $.button( { className: 'btn about-update-action-button', disabled: this.shouldUpdateActionButtonBeDisabled(), onclick: this.executeUpdateAction.bind(this), style: { - display: this.props.updateManager.state === UpdateManager.State.Unsupported ? 'none' : 'block' + display: + this.props.updateManager.state === + UpdateManager.State.Unsupported + ? 'none' + : 'block' } }, - this.props.updateManager.state === 'update-available' ? 'Restart and install' : 'Check now' + this.props.updateManager.state === 'update-available' + ? 'Restart and install' + : 'Check now' ) ), $.div( { className: 'about-auto-updates', style: { - display: this.props.updateManager.state === UpdateManager.State.Unsupported ? 'none' : 'block' + display: + this.props.updateManager.state === UpdateManager.State.Unsupported + ? 'none' + : 'block' } }, - $.label({}, - $.input( - { - className: 'input-checkbox', - type: 'checkbox', - checked: this.props.updateManager.getAutoUpdatesEnabled(), - onchange: this.handleAutoUpdateCheckbox.bind(this) - } - ), + $.label( + {}, + $.input({ + className: 'input-checkbox', + type: 'checkbox', + checked: this.props.updateManager.getAutoUpdatesEnabled(), + onchange: this.handleAutoUpdateCheckbox.bind(this) + }), $.span({}, 'Automatically download updates') ) ) diff --git a/packages/about/lib/etch-component.js b/packages/about/lib/etch-component.js index f75edce94..71ea85c88 100644 --- a/packages/about/lib/etch-component.js +++ b/packages/about/lib/etch-component.js @@ -4,8 +4,7 @@ const etch = require('etch') Public: Abstract class for handling the initialization boilerplate of an Etch component. */ -module.exports = -class EtchComponent { +module.exports = class EtchComponent { constructor (props) { this.props = props diff --git a/packages/about/lib/main.js b/packages/about/lib/main.js index f0b855649..ec1420e7f 100644 --- a/packages/about/lib/main.js +++ b/packages/about/lib/main.js @@ -1,4 +1,4 @@ -const {CompositeDisposable} = require('atom') +const { CompositeDisposable } = require('atom') const semver = require('semver') const UpdateManager = require('./update-manager') const About = require('./about') @@ -16,20 +16,33 @@ module.exports = { this.createModel() let availableVersion = window.localStorage.getItem(AvailableUpdateVersion) - if (atom.getReleaseChannel() === 'dev' || (availableVersion && semver.lte(availableVersion, atom.getVersion()))) { + if ( + atom.getReleaseChannel() === 'dev' || + (availableVersion && semver.lte(availableVersion, atom.getVersion())) + ) { this.clearUpdateState() } - this.subscriptions.add(updateManager.onDidChange(() => { - if (updateManager.getState() === UpdateManager.State.UpdateAvailableToInstall) { - window.localStorage.setItem(AvailableUpdateVersion, updateManager.getAvailableVersion()) - this.showStatusBarIfNeeded() - } - })) + this.subscriptions.add( + updateManager.onDidChange(() => { + if ( + updateManager.getState() === + UpdateManager.State.UpdateAvailableToInstall + ) { + window.localStorage.setItem( + AvailableUpdateVersion, + updateManager.getAvailableVersion() + ) + this.showStatusBarIfNeeded() + } + }) + ) - this.subscriptions.add(atom.commands.add('atom-workspace', 'about:clear-update-state', () => { - this.clearUpdateState() - })) + this.subscriptions.add( + atom.commands.add('atom-workspace', 'about:clear-update-state', () => { + this.clearUpdateState() + }) + ) }, deactivate () { diff --git a/packages/about/lib/update-manager.js b/packages/about/lib/update-manager.js index 0db55f08d..bae72753d 100644 --- a/packages/about/lib/update-manager.js +++ b/packages/about/lib/update-manager.js @@ -1,4 +1,4 @@ -const {Emitter, CompositeDisposable} = require('atom') +const { Emitter, CompositeDisposable } = require('atom') const Unsupported = 'unsupported' const Idle = 'idle' @@ -27,7 +27,7 @@ let UpdateManager = class UpdateManager { atom.autoUpdater.onDidBeginDownloadingUpdate(() => { this.setState(DownloadingUpdate) }), - atom.autoUpdater.onDidCompleteDownloadingUpdate(({releaseVersion}) => { + atom.autoUpdater.onDidCompleteDownloadingUpdate(({ releaseVersion }) => { this.setAvailableVersion(releaseVersion) }), atom.autoUpdater.onUpdateNotAvailable(() => { @@ -36,7 +36,7 @@ let UpdateManager = class UpdateManager { atom.autoUpdater.onUpdateError(() => { this.setState(ErrorState) }), - atom.config.observe('core.automaticallyUpdate', (value) => { + atom.config.observe('core.automaticallyUpdate', value => { this.autoUpdatesEnabled = value this.emitDidChange() }) @@ -61,7 +61,9 @@ let UpdateManager = class UpdateManager { } getAutoUpdatesEnabled () { - return this.autoUpdatesEnabled && this.state !== UpdateManager.State.Unsupported + return ( + this.autoUpdatesEnabled && this.state !== UpdateManager.State.Unsupported + ) } setAutoUpdatesEnabled (enabled) { @@ -82,7 +84,9 @@ let UpdateManager = class UpdateManager { } resetState () { - this.state = atom.autoUpdater.platformSupportsUpdates() ? atom.autoUpdater.getState() : Unsupported + this.state = atom.autoUpdater.platformSupportsUpdates() + ? atom.autoUpdater.getState() + : Unsupported this.emitDidChange() } @@ -128,7 +132,8 @@ let UpdateManager = class UpdateManager { appVersion = `v${appVersion}` } - const releaseRepo = appVersion.indexOf('nightly') > -1 ? 'atom-nightly-releases' : 'atom' + const releaseRepo = + appVersion.indexOf('nightly') > -1 ? 'atom-nightly-releases' : 'atom' return `https://github.com/atom/${releaseRepo}/releases/tag/${appVersion}` } } diff --git a/packages/about/spec/about-spec.js b/packages/about/spec/about-spec.js index 60c4136d8..a991457ff 100644 --- a/packages/about/spec/about-spec.js +++ b/packages/about/spec/about-spec.js @@ -1,4 +1,11 @@ -const {it, fit, ffit, fffit, beforeEach, afterEach} = require('./helpers/async-spec-helpers') // eslint-disable-line no-unused-vars +const { + it, + fit, + ffit, + fffit, + beforeEach, + afterEach +} = require('./helpers/async-spec-helpers') // eslint-disable-line no-unused-vars describe('About', () => { let workspaceElement @@ -9,7 +16,7 @@ describe('About', () => { spyOn(window.localStorage, 'setItem').andCallFake((key, value) => { storage[key] = value }) - spyOn(window.localStorage, 'getItem').andCallFake((key) => { + spyOn(window.localStorage, 'getItem').andCallFake(key => { return storage[key] }) diff --git a/packages/about/spec/about-status-bar-spec.js b/packages/about/spec/about-status-bar-spec.js index a611af67a..99de30010 100644 --- a/packages/about/spec/about-status-bar-spec.js +++ b/packages/about/spec/about-status-bar-spec.js @@ -1,4 +1,12 @@ -const {it, fit, ffit, fffit, beforeEach, afterEach, conditionPromise} = require('./helpers/async-spec-helpers') // eslint-disable-line no-unused-vars +const { + it, + fit, + ffit, + fffit, + beforeEach, + afterEach, + conditionPromise +} = require('./helpers/async-spec-helpers') // eslint-disable-line no-unused-vars const MockUpdater = require('./mocks/updater') describe('the status bar', () => { @@ -11,7 +19,7 @@ describe('the status bar', () => { spyOn(window.localStorage, 'setItem').andCallFake((key, value) => { storage[key] = value }) - spyOn(window.localStorage, 'getItem').andCallFake((key) => { + spyOn(window.localStorage, 'getItem').andCallFake(key => { return storage[key] }) spyOn(atom, 'getVersion').andCallFake(() => { diff --git a/packages/about/spec/helpers/async-spec-helpers.js b/packages/about/spec/helpers/async-spec-helpers.js index 377024691..6d1d45963 100644 --- a/packages/about/spec/helpers/async-spec-helpers.js +++ b/packages/about/spec/helpers/async-spec-helpers.js @@ -1,7 +1,7 @@ /** @babel */ -const {now} = Date -const {setTimeout} = global +const { now } = Date +const { setTimeout } = global export function beforeEach (fn) { global.beforeEach(function () { @@ -21,7 +21,7 @@ export function afterEach (fn) { }) } -['it', 'fit', 'ffit', 'fffit'].forEach(function (name) { +;['it', 'fit', 'ffit', 'fffit'].forEach(function (name) { module.exports[name] = function (description, fn) { global[name](description, function () { const result = fn() diff --git a/packages/about/spec/mocks/updater.js b/packages/about/spec/mocks/updater.js index c96ea4ec1..6c5e1f19d 100644 --- a/packages/about/spec/mocks/updater.js +++ b/packages/about/spec/mocks/updater.js @@ -16,6 +16,8 @@ module.exports = { }, finishDownloadingUpdate (releaseVersion) { - atom.autoUpdater.emitter.emit('did-complete-downloading-update', {releaseVersion}) + atom.autoUpdater.emitter.emit('did-complete-downloading-update', { + releaseVersion + }) } } diff --git a/packages/about/spec/update-manager-spec.js b/packages/about/spec/update-manager-spec.js index 294e33b8b..cc395949e 100644 --- a/packages/about/spec/update-manager-spec.js +++ b/packages/about/spec/update-manager-spec.js @@ -9,14 +9,24 @@ describe('UpdateManager', () => { describe('::getReleaseNotesURLForVersion', () => { it('returns atom.io releases when dev version', () => { - expect(updateManager.getReleaseNotesURLForVersion('1.7.0-dev-e44b57d')).toContain('atom.io/releases') + expect( + updateManager.getReleaseNotesURLForVersion('1.7.0-dev-e44b57d') + ).toContain('atom.io/releases') }) it('returns the page for the release when not a dev version', () => { - expect(updateManager.getReleaseNotesURLForVersion('1.7.0')).toContain('atom/atom/releases/tag/v1.7.0') - expect(updateManager.getReleaseNotesURLForVersion('v1.7.0')).toContain('atom/atom/releases/tag/v1.7.0') - expect(updateManager.getReleaseNotesURLForVersion('1.7.0-beta10')).toContain('atom/atom/releases/tag/v1.7.0-beta10') - expect(updateManager.getReleaseNotesURLForVersion('1.7.0-nightly10')).toContain('atom/atom-nightly-releases/releases/tag/v1.7.0-nightly10') + expect(updateManager.getReleaseNotesURLForVersion('1.7.0')).toContain( + 'atom/atom/releases/tag/v1.7.0' + ) + expect(updateManager.getReleaseNotesURLForVersion('v1.7.0')).toContain( + 'atom/atom/releases/tag/v1.7.0' + ) + expect( + updateManager.getReleaseNotesURLForVersion('1.7.0-beta10') + ).toContain('atom/atom/releases/tag/v1.7.0-beta10') + expect( + updateManager.getReleaseNotesURLForVersion('1.7.0-nightly10') + ).toContain('atom/atom-nightly-releases/releases/tag/v1.7.0-nightly10') }) }) }) diff --git a/packages/about/spec/update-view-spec.js b/packages/about/spec/update-view-spec.js index 83ddf5ac1..fdb9a02b4 100644 --- a/packages/about/spec/update-view-spec.js +++ b/packages/about/spec/update-view-spec.js @@ -1,5 +1,12 @@ -const {shell} = require('electron') -const {it, fit, ffit, fffit, beforeEach, afterEach} = require('./helpers/async-spec-helpers') // eslint-disable-line no-unused-vars +const { shell } = require('electron') +const { + it, + fit, + ffit, + fffit, + beforeEach, + afterEach +} = require('./helpers/async-spec-helpers') // eslint-disable-line no-unused-vars const main = require('../lib/main') const AboutView = require('../lib/components/about-view') const UpdateView = require('../lib/components/update-view') @@ -17,7 +24,7 @@ describe('UpdateView', () => { spyOn(window.localStorage, 'setItem').andCallFake((key, value) => { storage[key] = value }) - spyOn(window.localStorage, 'getItem').andCallFake((key) => { + spyOn(window.localStorage, 'getItem').andCallFake(key => { return storage[key] }) @@ -45,13 +52,19 @@ describe('UpdateView', () => { }) it('hides the auto update UI and shows the update instructions link', async () => { - expect(aboutElement.querySelector('.about-update-action-button')).not.toBeVisible() - expect(aboutElement.querySelector('.about-auto-updates')).not.toBeVisible() + expect( + aboutElement.querySelector('.about-update-action-button') + ).not.toBeVisible() + expect( + aboutElement.querySelector('.about-auto-updates') + ).not.toBeVisible() }) it('opens the update instructions page when the instructions link is clicked', async () => { spyOn(shell, 'openExternal') - let link = aboutElement.querySelector('.app-unsupported .about-updates-instructions') + let link = aboutElement.querySelector( + '.app-unsupported .about-updates-instructions' + ) link.click() let args = shell.openExternal.mostRecentCall.args @@ -72,66 +85,116 @@ describe('UpdateView', () => { }) it('shows the correct panels when the app checks for updates and there is no update available', async () => { - expect(aboutElement.querySelector('.about-default-update-message')).toBeVisible() + expect( + aboutElement.querySelector('.about-default-update-message') + ).toBeVisible() MockUpdater.checkForUpdate() await scheduler.getNextUpdatePromise() expect(aboutElement.querySelector('.app-up-to-date')).not.toBeVisible() - expect(aboutElement.querySelector('.app-checking-for-updates')).toBeVisible() + expect( + aboutElement.querySelector('.app-checking-for-updates') + ).toBeVisible() MockUpdater.updateNotAvailable() await scheduler.getNextUpdatePromise() expect(aboutElement.querySelector('.app-up-to-date')).toBeVisible() - expect(aboutElement.querySelector('.app-checking-for-updates')).not.toBeVisible() + expect( + aboutElement.querySelector('.app-checking-for-updates') + ).not.toBeVisible() }) it('shows the correct panels when the app checks for updates and encounters an error', async () => { - expect(aboutElement.querySelector('.about-default-update-message')).toBeVisible() + expect( + aboutElement.querySelector('.about-default-update-message') + ).toBeVisible() MockUpdater.checkForUpdate() await scheduler.getNextUpdatePromise() expect(aboutElement.querySelector('.app-up-to-date')).not.toBeVisible() - expect(aboutElement.querySelector('.app-checking-for-updates')).toBeVisible() + expect( + aboutElement.querySelector('.app-checking-for-updates') + ).toBeVisible() spyOn(atom.autoUpdater, 'getErrorMessage').andReturn('an error message') MockUpdater.updateError() await scheduler.getNextUpdatePromise() expect(aboutElement.querySelector('.app-update-error')).toBeVisible() - expect(aboutElement.querySelector('.app-error-message').textContent).toBe('an error message') - expect(aboutElement.querySelector('.app-checking-for-updates')).not.toBeVisible() - expect(aboutElement.querySelector('.about-update-action-button').disabled).toBe(false) - expect(aboutElement.querySelector('.about-update-action-button').textContent).toBe('Check now') + expect( + aboutElement.querySelector('.app-error-message').textContent + ).toBe('an error message') + expect( + aboutElement.querySelector('.app-checking-for-updates') + ).not.toBeVisible() + expect( + aboutElement.querySelector('.about-update-action-button').disabled + ).toBe(false) + expect( + aboutElement.querySelector('.about-update-action-button').textContent + ).toBe('Check now') }) it('shows the correct panels and button states when the app checks for updates and an update is downloaded', async () => { - expect(aboutElement.querySelector('.about-default-update-message')).toBeVisible() - expect(aboutElement.querySelector('.about-update-action-button').disabled).toBe(false) - expect(aboutElement.querySelector('.about-update-action-button').textContent).toBe('Check now') + expect( + aboutElement.querySelector('.about-default-update-message') + ).toBeVisible() + expect( + aboutElement.querySelector('.about-update-action-button').disabled + ).toBe(false) + expect( + aboutElement.querySelector('.about-update-action-button').textContent + ).toBe('Check now') MockUpdater.checkForUpdate() await scheduler.getNextUpdatePromise() expect(aboutElement.querySelector('.app-up-to-date')).not.toBeVisible() - expect(aboutElement.querySelector('.app-checking-for-updates')).toBeVisible() - expect(aboutElement.querySelector('.about-update-action-button').disabled).toBe(true) - expect(aboutElement.querySelector('.about-update-action-button').textContent).toBe('Check now') + expect( + aboutElement.querySelector('.app-checking-for-updates') + ).toBeVisible() + expect( + aboutElement.querySelector('.about-update-action-button').disabled + ).toBe(true) + expect( + aboutElement.querySelector('.about-update-action-button').textContent + ).toBe('Check now') MockUpdater.downloadUpdate() await scheduler.getNextUpdatePromise() - expect(aboutElement.querySelector('.app-checking-for-updates')).not.toBeVisible() - expect(aboutElement.querySelector('.app-downloading-update')).toBeVisible() + expect( + aboutElement.querySelector('.app-checking-for-updates') + ).not.toBeVisible() + expect( + aboutElement.querySelector('.app-downloading-update') + ).toBeVisible() // TODO: at some point it would be nice to be able to cancel an update download, and then this would be a cancel button - expect(aboutElement.querySelector('.about-update-action-button').disabled).toBe(true) - expect(aboutElement.querySelector('.about-update-action-button').textContent).toBe('Check now') + expect( + aboutElement.querySelector('.about-update-action-button').disabled + ).toBe(true) + expect( + aboutElement.querySelector('.about-update-action-button').textContent + ).toBe('Check now') MockUpdater.finishDownloadingUpdate('42.0.0') await scheduler.getNextUpdatePromise() - expect(aboutElement.querySelector('.app-downloading-update')).not.toBeVisible() - expect(aboutElement.querySelector('.app-update-available-to-install')).toBeVisible() + expect( + aboutElement.querySelector('.app-downloading-update') + ).not.toBeVisible() + expect( + aboutElement.querySelector('.app-update-available-to-install') + ).toBeVisible() - expect(aboutElement.querySelector('.app-update-available-to-install .about-updates-version').textContent).toBe('42.0.0') - expect(aboutElement.querySelector('.about-update-action-button').disabled).toBe(false) - expect(aboutElement.querySelector('.about-update-action-button').textContent).toBe('Restart and install') + expect( + aboutElement.querySelector( + '.app-update-available-to-install .about-updates-version' + ).textContent + ).toBe('42.0.0') + expect( + aboutElement.querySelector('.about-update-action-button').disabled + ).toBe(false) + expect( + aboutElement.querySelector('.about-update-action-button').textContent + ).toBe('Restart and install') }) it('opens the release notes for the downloaded release when the release notes link are clicked', async () => { @@ -139,7 +202,9 @@ describe('UpdateView', () => { await scheduler.getNextUpdatePromise() spyOn(shell, 'openExternal') - let link = aboutElement.querySelector('.app-update-available-to-install .about-updates-release-notes') + let link = aboutElement.querySelector( + '.app-update-available-to-install .about-updates-release-notes' + ) link.click() let args = shell.openExternal.mostRecentCall.args @@ -168,10 +233,18 @@ describe('UpdateView', () => { updateManager.resetState() await scheduler.getNextUpdatePromise() - expect(aboutElement.querySelector('.app-checking-for-updates')).not.toBeVisible() - expect(aboutElement.querySelector('.app-downloading-update')).toBeVisible() - expect(aboutElement.querySelector('.about-update-action-button').disabled).toBe(true) - expect(aboutElement.querySelector('.about-update-action-button').textContent).toBe('Check now') + expect( + aboutElement.querySelector('.app-checking-for-updates') + ).not.toBeVisible() + expect( + aboutElement.querySelector('.app-downloading-update') + ).toBeVisible() + expect( + aboutElement.querySelector('.about-update-action-button').disabled + ).toBe(true) + expect( + aboutElement.querySelector('.about-update-action-button').textContent + ).toBe('Check now') }) describe('when core.automaticallyUpdate is toggled', () => { @@ -181,36 +254,66 @@ describe('UpdateView', () => { }) it('shows the auto update UI', async () => { - expect(aboutElement.querySelector('.about-auto-updates input').checked).toBe(true) - expect(aboutElement.querySelector('.about-default-update-message')).toBeVisible() - expect(aboutElement.querySelector('.about-default-update-message').textContent).toBe('Atom will check for updates automatically') + expect( + aboutElement.querySelector('.about-auto-updates input').checked + ).toBe(true) + expect( + aboutElement.querySelector('.about-default-update-message') + ).toBeVisible() + expect( + aboutElement.querySelector('.about-default-update-message') + .textContent + ).toBe('Atom will check for updates automatically') atom.config.set('core.automaticallyUpdate', false) await scheduler.getNextUpdatePromise() - expect(aboutElement.querySelector('.about-auto-updates input').checked).toBe(false) - expect(aboutElement.querySelector('.about-default-update-message')).toBeVisible() - expect(aboutElement.querySelector('.about-default-update-message').textContent).toBe('Automatic updates are disabled please check manually') + expect( + aboutElement.querySelector('.about-auto-updates input').checked + ).toBe(false) + expect( + aboutElement.querySelector('.about-default-update-message') + ).toBeVisible() + expect( + aboutElement.querySelector('.about-default-update-message') + .textContent + ).toBe('Automatic updates are disabled please check manually') }) it('updates config and the UI when the checkbox is used to toggle', async () => { - expect(aboutElement.querySelector('.about-auto-updates input').checked).toBe(true) + expect( + aboutElement.querySelector('.about-auto-updates input').checked + ).toBe(true) aboutElement.querySelector('.about-auto-updates input').click() await scheduler.getNextUpdatePromise() expect(atom.config.get('core.automaticallyUpdate')).toBe(false) - expect(aboutElement.querySelector('.about-auto-updates input').checked).toBe(false) - expect(aboutElement.querySelector('.about-default-update-message')).toBeVisible() - expect(aboutElement.querySelector('.about-default-update-message').textContent).toBe('Automatic updates are disabled please check manually') + expect( + aboutElement.querySelector('.about-auto-updates input').checked + ).toBe(false) + expect( + aboutElement.querySelector('.about-default-update-message') + ).toBeVisible() + expect( + aboutElement.querySelector('.about-default-update-message') + .textContent + ).toBe('Automatic updates are disabled please check manually') aboutElement.querySelector('.about-auto-updates input').click() await scheduler.getNextUpdatePromise() expect(atom.config.get('core.automaticallyUpdate')).toBe(true) - expect(aboutElement.querySelector('.about-auto-updates input').checked).toBe(true) - expect(aboutElement.querySelector('.about-default-update-message')).toBeVisible() - expect(aboutElement.querySelector('.about-default-update-message').textContent).toBe('Atom will check for updates automatically') + expect( + aboutElement.querySelector('.about-auto-updates input').checked + ).toBe(true) + expect( + aboutElement.querySelector('.about-default-update-message') + ).toBeVisible() + expect( + aboutElement.querySelector('.about-default-update-message') + .textContent + ).toBe('Atom will check for updates automatically') }) describe('checking for updates', function () { @@ -271,10 +374,20 @@ describe('UpdateView', () => { updateManager = main.model.state.updateManager scheduler = AboutView.getScheduler() - expect(aboutElement.querySelector('.app-update-available-to-install')).toBeVisible() - expect(aboutElement.querySelector('.app-update-available-to-install .about-updates-version').textContent).toBe('42.0.0') - expect(aboutElement.querySelector('.about-update-action-button').disabled).toBe(false) - expect(aboutElement.querySelector('.about-update-action-button').textContent).toBe('Restart and install') + expect( + aboutElement.querySelector('.app-update-available-to-install') + ).toBeVisible() + expect( + aboutElement.querySelector( + '.app-update-available-to-install .about-updates-version' + ).textContent + ).toBe('42.0.0') + expect( + aboutElement.querySelector('.about-update-action-button').disabled + ).toBe(false) + expect( + aboutElement.querySelector('.about-update-action-button').textContent + ).toBe('Restart and install') }) }) }) diff --git a/packages/dalek/lib/dalek.js b/packages/dalek/lib/dalek.js index 8d322cc03..3f1944a0c 100644 --- a/packages/dalek/lib/dalek.js +++ b/packages/dalek/lib/dalek.js @@ -13,7 +13,9 @@ module.exports = { const names = atom.packages.getAvailablePackageNames() for (let name of names) { if (atom.packages.isBundledPackage(name)) { - const isDuplicatedPackage = await this.isInstalledAsCommunityPackage(name) + const isDuplicatedPackage = await this.isInstalledAsCommunityPackage( + name + ) if (isDuplicatedPackage) { duplicatePackages.push(name) } diff --git a/packages/dalek/test/dalek.test.js b/packages/dalek/test/dalek.test.js index 8b84dd29d..ff1ba394c 100644 --- a/packages/dalek/test/dalek.test.js +++ b/packages/dalek/test/dalek.test.js @@ -17,20 +17,49 @@ describe('dalek', function () { beforeEach(function () { availablePackages = { - 'an-unduplicated-installed-package': path.join('Users', 'username', '.atom', 'packages', 'an-unduplicated-installed-package'), - 'duplicated-package': path.join('Users', 'username', '.atom', 'packages', 'duplicated-package'), - 'unduplicated-package': path.join(`${atom.getLoadSettings().resourcePath}`, 'node_modules', 'unduplicated-package') + 'an-unduplicated-installed-package': path.join( + 'Users', + 'username', + '.atom', + 'packages', + 'an-unduplicated-installed-package' + ), + 'duplicated-package': path.join( + 'Users', + 'username', + '.atom', + 'packages', + 'duplicated-package' + ), + 'unduplicated-package': path.join( + `${atom.getLoadSettings().resourcePath}`, + 'node_modules', + 'unduplicated-package' + ) } atom.devMode = false bundledPackages = ['duplicated-package', 'unduplicated-package'] packageDirPaths = [path.join('Users', 'username', '.atom', 'packages')] sandbox = sinon.sandbox.create() - sandbox.stub(dalek, 'realpath').callsFake((filePath) => Promise.resolve(realPaths[filePath] || filePath)) - sandbox.stub(atom.packages, 'isBundledPackage').callsFake((packageName) => { return bundledPackages.includes(packageName) }) - sandbox.stub(atom.packages, 'getAvailablePackageNames').callsFake(() => Object.keys(availablePackages)) - sandbox.stub(atom.packages, 'getPackageDirPaths').callsFake(() => { return packageDirPaths }) - sandbox.stub(fs, 'existsSync').callsFake((candidate) => { return Object.values(availablePackages).includes(candidate) && !candidate.includes(atom.getLoadSettings().resourcePath) }) + sandbox + .stub(dalek, 'realpath') + .callsFake(filePath => Promise.resolve(realPaths[filePath] || filePath)) + sandbox.stub(atom.packages, 'isBundledPackage').callsFake(packageName => { + return bundledPackages.includes(packageName) + }) + sandbox + .stub(atom.packages, 'getAvailablePackageNames') + .callsFake(() => Object.keys(availablePackages)) + sandbox.stub(atom.packages, 'getPackageDirPaths').callsFake(() => { + return packageDirPaths + }) + sandbox.stub(fs, 'existsSync').callsFake(candidate => { + return ( + Object.values(availablePackages).includes(candidate) && + !candidate.includes(atom.getLoadSettings().resourcePath) + ) + }) }) afterEach(function () { @@ -54,7 +83,13 @@ describe('dalek', function () { describe('when a package is symlinked into the package directory', async function () { beforeEach(function () { const realPath = path.join('Users', 'username', 'duplicated-package') - const packagePath = path.join('Users', 'username', '.atom', 'packages', 'duplicated-package') + const packagePath = path.join( + 'Users', + 'username', + '.atom', + 'packages', + 'duplicated-package' + ) realPaths[packagePath] = realPath }) diff --git a/packages/dalek/test/runner.js b/packages/dalek/test/runner.js index 5688fc9c0..7b155fa67 100644 --- a/packages/dalek/test/runner.js +++ b/packages/dalek/test/runner.js @@ -1,2 +1,2 @@ const createRunner = require('atom-mocha-test-runner').createRunner -module.exports = createRunner({testSuffixes: ['test.js']}) +module.exports = createRunner({ testSuffixes: ['test.js'] }) diff --git a/packages/deprecation-cop/lib/deprecation-cop-view.js b/packages/deprecation-cop/lib/deprecation-cop-view.js index 01d8ad736..0531a2631 100644 --- a/packages/deprecation-cop/lib/deprecation-cop-view.js +++ b/packages/deprecation-cop/lib/deprecation-cop-view.js @@ -2,7 +2,7 @@ /** @jsx etch.dom */ import _ from 'underscore-plus' -import {CompositeDisposable} from 'atom' +import { CompositeDisposable } from 'atom' import etch from 'etch' import fs from 'fs-plus' import Grim from 'grim' @@ -11,23 +11,45 @@ import path from 'path' import shell from 'shell' export default class DeprecationCopView { - constructor ({uri}) { + constructor ({ uri }) { this.uri = uri - this.subscriptions = new CompositeDisposable - this.subscriptions.add(Grim.on('updated', () => { etch.update(this) })) + this.subscriptions = new CompositeDisposable() + this.subscriptions.add( + Grim.on('updated', () => { + etch.update(this) + }) + ) // TODO: Remove conditional when the new StyleManager deprecation APIs reach stable. if (atom.styles.onDidUpdateDeprecations) { - this.subscriptions.add(atom.styles.onDidUpdateDeprecations(() => { etch.update(this) })) + this.subscriptions.add( + atom.styles.onDidUpdateDeprecations(() => { + etch.update(this) + }) + ) } etch.initialize(this) - this.subscriptions.add(atom.commands.add(this.element, { - 'core:move-up': () => { this.scrollUp() }, - 'core:move-down': () => { this.scrollDown() }, - 'core:page-up': () => { this.pageUp() }, - 'core:page-down': () => { this.pageDown() }, - 'core:move-to-top': () => { this.scrollToTop() }, - 'core:move-to-bottom': () => { this.scrollToBottom() } - })) + this.subscriptions.add( + atom.commands.add(this.element, { + 'core:move-up': () => { + this.scrollUp() + }, + 'core:move-down': () => { + this.scrollDown() + }, + 'core:page-up': () => { + this.pageUp() + }, + 'core:page-down': () => { + this.pageDown() + }, + 'core:move-to-top': () => { + this.scrollToTop() + }, + 'core:move-to-bottom': () => { + this.scrollToBottom() + } + }) + ) } serialize () { @@ -49,25 +71,35 @@ export default class DeprecationCopView { render () { return ( -
+
+ }} + > + Check for Updates +
-
Deprecated calls
+
+ Deprecated calls +
    {this.renderDeprecatedCalls()}
-
Deprecated selectors
+
+ Deprecated selectors +
    {this.renderDeprecatedSelectors()}
@@ -82,37 +114,57 @@ export default class DeprecationCopView { if (packageNames.length === 0) { return
  • No deprecated calls
  • } else { - return packageNames.sort().map((packageName) => ( + return packageNames.sort().map(packageName => (
  • -
    event.target.parentElement.classList.toggle('collapsed')}> +
    + event.target.parentElement.classList.toggle('collapsed') + } + > {packageName || 'atom core'} - {` (${_.pluralize(deprecationsByPackageName[packageName].length, 'deprecation')})`} + {` (${_.pluralize( + deprecationsByPackageName[packageName].length, + 'deprecation' + )})`}
      {this.renderPackageActionsIfNeeded(packageName)} - {deprecationsByPackageName[packageName].map(({deprecation, stack}) => ( -
    • - -
      - {this.renderIssueURLIfNeeded(packageName, deprecation, this.buildIssueURL(packageName, deprecation, stack))} -
      - {stack.map(({functionName, location}) => ( -
      - {functionName} - - - { - event.preventDefault() - this.openLocation(location) - }}>{location} + {deprecationsByPackageName[packageName].map( + ({ deprecation, stack }) => ( +
    • + +
      + {this.renderIssueURLIfNeeded( + packageName, + deprecation, + this.buildIssueURL(packageName, deprecation, stack) + )} +
      + {stack.map(({ functionName, location }) => ( + + ))}
      - ))} -
      -
    • - ))} + + ) + )}
  • )) @@ -123,41 +175,61 @@ export default class DeprecationCopView { const deprecationsByPackageName = this.getDeprecatedSelectorsByPackageName() const packageNames = Object.keys(deprecationsByPackageName) if (packageNames.length === 0) { - return ( -
  • No deprecated selectors
  • - ) + return
  • No deprecated selectors
  • } else { - return packageNames.map((packageName) => ( + return packageNames.map(packageName => (
  • -
    event.target.parentElement.classList.toggle('collapsed')}> +
    + event.target.parentElement.classList.toggle('collapsed') + } + > {packageName}
      {this.renderPackageActionsIfNeeded(packageName)} - {deprecationsByPackageName[packageName].map(({packagePath, sourcePath, deprecation}) => { - const relativeSourcePath = path.relative(packagePath, sourcePath) - const issueTitle = `Deprecated selector in \`${relativeSourcePath}\`` - const issueBody = `In \`${relativeSourcePath}\`: \n\n${deprecation.message}` - return ( -
    • - { - event.preventDefault() - this.openLocation(sourcePath) - }}>{relativeSourcePath} -
        -
      • - -
        - {this.renderSelectorIssueURLIfNeeded(packageName, issueTitle, issueBody)} -
      • -
      -
    • - ) - })} + {deprecationsByPackageName[packageName].map( + ({ packagePath, sourcePath, deprecation }) => { + const relativeSourcePath = path.relative( + packagePath, + sourcePath + ) + const issueTitle = `Deprecated selector in \`${relativeSourcePath}\`` + const issueBody = `In \`${relativeSourcePath}\`: \n\n${ + deprecation.message + }` + return ( +
    • + { + event.preventDefault() + this.openLocation(sourcePath) + }} + > + {relativeSourcePath} + +
        +
      • + +
        + {this.renderSelectorIssueURLIfNeeded( + packageName, + issueTitle, + issueBody + )} +
      • +
      +
    • + ) + } + )}
  • )) @@ -171,17 +243,23 @@ export default class DeprecationCopView {
    + }} + > + Check for Update + + }} + > + Disable Package +
    ) @@ -191,13 +269,18 @@ export default class DeprecationCopView { } encodeURI (str) { - return encodeURI(str).replace(/#/g, '%23').replace(/;/g, '%3B').replace(/%20/g, '+') + return encodeURI(str) + .replace(/#/g, '%23') + .replace(/;/g, '%3B') + .replace(/%20/g, '+') } renderSelectorIssueURLIfNeeded (packageName, issueTitle, issueBody) { const repoURL = this.getRepoURL(packageName) if (repoURL) { - const issueURL = `${repoURL}/issues/new?title=${this.encodeURI(issueTitle)}&body=${this.encodeURI(issueBody)}` + const issueURL = `${repoURL}/issues/new?title=${this.encodeURI( + issueTitle + )}&body=${this.encodeURI(issueBody)}` return (
    + }} + > + Report Issue +
    ) } else { @@ -227,10 +313,13 @@ export default class DeprecationCopView { data-issue-title={issueTitle} data-repo-url={repoURL} data-issue-url={issueURL} - onclick={(event) => { + onclick={event => { event.preventDefault() this.openIssueURL(repoURL, issueURL, issueTitle) - }}>Report Issue + }} + > + Report Issue +
    ) } else { @@ -242,9 +331,13 @@ export default class DeprecationCopView { const repoURL = this.getRepoURL(packageName) if (repoURL) { const title = `${deprecation.getOriginName()} is deprecated.` - const stacktrace = stack.map(({functionName, location}) => `${functionName} (${location})`).join("\n") + const stacktrace = stack + .map(({ functionName, location }) => `${functionName} (${location})`) + .join('\n') const body = `${deprecation.getMessage()}\n\`\`\`\n${stacktrace}\n\`\`\`` - return `${repoURL}/issues/new?title=${encodeURI(title)}&body=${encodeURI(body)}` + return `${repoURL}/issues/new?title=${encodeURI(title)}&body=${encodeURI( + body + )}` } else { return null } @@ -266,13 +359,16 @@ export default class DeprecationCopView { const url = 'https://api.github.com/search/issues' const repo = repoURL.replace(/http(s)?:\/\/(\d+\.)?github.com\//gi, '') const query = `${issueTitle} repo:${repo}` - const response = await window.fetch(`${url}?q=${encodeURI(query)}&sort=created`, { - method: 'GET', - headers: { - 'Accept': 'application/vnd.github.v3+json', - 'Content-Type': 'application/json' + const response = await window.fetch( + `${url}?q=${encodeURI(query)}&sort=created`, + { + method: 'GET', + headers: { + Accept: 'application/vnd.github.v3+json', + 'Content-Type': 'application/json' + } } - }) + ) if (response.ok) { const data = await response.json() @@ -284,21 +380,25 @@ export default class DeprecationCopView { } } - return (issues.open || issues.closed) + return issues.open || issues.closed } } } async shortenURL (url) { let encodedUrl = encodeURIComponent(url).substr(0, 5000) // is.gd has 5000 char limit - let incompletePercentEncoding = encodedUrl.indexOf('%', encodedUrl.length - 2) - if (incompletePercentEncoding >= 0) { // Handle an incomplete % encoding cut-off + let incompletePercentEncoding = encodedUrl.indexOf( + '%', + encodedUrl.length - 2 + ) + if (incompletePercentEncoding >= 0) { + // Handle an incomplete % encoding cut-off encodedUrl = encodedUrl.substr(0, incompletePercentEncoding) } let result = await fetch('https://is.gd/create.php?format=simple', { method: 'POST', - headers: {'Content-Type': 'application/x-www-form-urlencoded'}, + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: `url=${encodedUrl}` }) @@ -307,8 +407,14 @@ export default class DeprecationCopView { getRepoURL (packageName) { const loadedPackage = atom.packages.getLoadedPackage(packageName) - if (loadedPackage && loadedPackage.metadata && loadedPackage.metadata.repository) { - const url = loadedPackage.metadata.repository.url || loadedPackage.metadata.repository + if ( + loadedPackage && + loadedPackage.metadata && + loadedPackage.metadata.repository + ) { + const url = + loadedPackage.metadata.repository.url || + loadedPackage.metadata.repository return url.replace(/\.git$/, '') } else { return null @@ -330,8 +436,9 @@ export default class DeprecationCopView { packageName = (this.getPackageName(stack) || '').toLowerCase() } - deprecatedCallsByPackageName[packageName] = deprecatedCallsByPackageName[packageName] || [] - deprecatedCallsByPackageName[packageName].push({deprecation, stack}) + deprecatedCallsByPackageName[packageName] = + deprecatedCallsByPackageName[packageName] || [] + deprecatedCallsByPackageName[packageName].push({ deprecation, stack }) } } return deprecatedCallsByPackageName @@ -352,11 +459,18 @@ export default class DeprecationCopView { packagePath = '' } else { packageName = components[packagesComponentIndex + 1] - packagePath = components.slice(0, packagesComponentIndex + 1).join(path.sep) + packagePath = components + .slice(0, packagesComponentIndex + 1) + .join(path.sep) } - deprecatedSelectorsByPackageName[packageName] = deprecatedSelectorsByPackageName[packageName] || [] - deprecatedSelectorsByPackageName[packageName].push({packagePath, sourcePath, deprecation}) + deprecatedSelectorsByPackageName[packageName] = + deprecatedSelectorsByPackageName[packageName] || [] + deprecatedSelectorsByPackageName[packageName].push({ + packagePath, + sourcePath, + deprecation + }) } } @@ -366,13 +480,16 @@ export default class DeprecationCopView { getPackageName (stack) { const packagePaths = this.getPackagePathsByPackageName() for (const [packageName, packagePath] of packagePaths) { - if (packagePath.includes('.atom/dev/packages') || packagePath.includes('.atom/packages')) { + if ( + packagePath.includes('.atom/dev/packages') || + packagePath.includes('.atom/packages') + ) { packagePaths.set(packageName, fs.absolute(packagePath)) } } for (let i = 1; i < stack.length; i++) { - const {fileName} = stack[i] + const { fileName } = stack[i] // Empty when it was run from the dev console if (!fileName) { @@ -426,7 +543,7 @@ export default class DeprecationCopView { if (process.platform === 'win32') { pathToOpen = pathToOpen.replace(/^\//, '') } - atom.open({pathsToOpen: [pathToOpen]}) + atom.open({ pathsToOpen: [pathToOpen] }) } getURI () { diff --git a/packages/deprecation-cop/lib/main.js b/packages/deprecation-cop/lib/main.js index 12da158b5..3dd94da6d 100644 --- a/packages/deprecation-cop/lib/main.js +++ b/packages/deprecation-cop/lib/main.js @@ -1,4 +1,4 @@ -const {Disposable, CompositeDisposable} = require('atom') +const { Disposable, CompositeDisposable } = require('atom') const DeprecationCopView = require('./deprecation-cop-view') const DeprecationCopStatusBarView = require('./deprecation-cop-status-bar-view') const ViewURI = 'atom://deprecation-cop' @@ -6,14 +6,18 @@ const ViewURI = 'atom://deprecation-cop' class DeprecationCopPackage { activate () { this.disposables = new CompositeDisposable() - this.disposables.add(atom.workspace.addOpener((uri) => { - if (uri === ViewURI) { - return this.deserializeDeprecationCopView({uri}) - } - })) - this.disposables.add(atom.commands.add('atom-workspace', 'deprecation-cop:view', () => { - atom.workspace.open(ViewURI) - })) + this.disposables.add( + atom.workspace.addOpener(uri => { + if (uri === ViewURI) { + return this.deserializeDeprecationCopView({ uri }) + } + }) + ) + this.disposables.add( + atom.commands.add('atom-workspace', 'deprecation-cop:view', () => { + atom.workspace.open(ViewURI) + }) + ) } deactivate () { @@ -30,9 +34,20 @@ class DeprecationCopPackage { consumeStatusBar (statusBar) { const statusBarView = new DeprecationCopStatusBarView() - const statusBarTile = statusBar.addRightTile({item: statusBarView, priority: 150}) - this.disposables.add(new Disposable(() => { statusBarView.destroy() })) - this.disposables.add(new Disposable(() => { statusBarTile.destroy() })) + const statusBarTile = statusBar.addRightTile({ + item: statusBarView, + priority: 150 + }) + this.disposables.add( + new Disposable(() => { + statusBarView.destroy() + }) + ) + this.disposables.add( + new Disposable(() => { + statusBarTile.destroy() + }) + ) } } diff --git a/packages/dev-live-reload/lib/base-theme-watcher.js b/packages/dev-live-reload/lib/base-theme-watcher.js index 8d8658a8c..e18a974f6 100644 --- a/packages/dev-live-reload/lib/base-theme-watcher.js +++ b/packages/dev-live-reload/lib/base-theme-watcher.js @@ -2,16 +2,19 @@ const fs = require('fs-plus') const path = require('path') const Watcher = require('./watcher') -module.exports = -class BaseThemeWatcher extends Watcher { +module.exports = class BaseThemeWatcher extends Watcher { constructor () { super() - this.stylesheetsPath = path.dirname(atom.themes.resolveStylesheet('../static/atom.less')) + this.stylesheetsPath = path.dirname( + atom.themes.resolveStylesheet('../static/atom.less') + ) this.watch() } watch () { - const filePaths = fs.readdirSync(this.stylesheetsPath).filter(filePath => path.extname(filePath).includes('less')) + const filePaths = fs + .readdirSync(this.stylesheetsPath) + .filter(filePath => path.extname(filePath).includes('less')) for (const filePath of filePaths) { this.watchFile(path.join(this.stylesheetsPath, filePath)) diff --git a/packages/dev-live-reload/lib/main.js b/packages/dev-live-reload/lib/main.js index 8e80de68f..a486231cf 100644 --- a/packages/dev-live-reload/lib/main.js +++ b/packages/dev-live-reload/lib/main.js @@ -5,7 +5,9 @@ module.exports = { if (atom.packages.hasActivatedInitialPackages()) { this.startWatching() } else { - this.activatedDisposable = atom.packages.onDidActivateInitialPackages(() => this.startWatching()) + this.activatedDisposable = atom.packages.onDidActivateInitialPackages( + () => this.startWatching() + ) } }, @@ -17,8 +19,12 @@ module.exports = { startWatching () { const UIWatcher = require('./ui-watcher') - this.uiWatcher = new UIWatcher({themeManager: atom.themes}) - this.commandDisposable = atom.commands.add('atom-workspace', 'dev-live-reload:reload-all', () => this.uiWatcher.reloadAll()) + this.uiWatcher = new UIWatcher({ themeManager: atom.themes }) + this.commandDisposable = atom.commands.add( + 'atom-workspace', + 'dev-live-reload:reload-all', + () => this.uiWatcher.reloadAll() + ) if (this.activatedDisposable) this.activatedDisposable.dispose() } } diff --git a/packages/dev-live-reload/lib/package-watcher.js b/packages/dev-live-reload/lib/package-watcher.js index 044b59719..a5be2337c 100644 --- a/packages/dev-live-reload/lib/package-watcher.js +++ b/packages/dev-live-reload/lib/package-watcher.js @@ -2,8 +2,7 @@ const fs = require('fs-plus') const Watcher = require('./watcher') -module.exports = -class PackageWatcher extends Watcher { +module.exports = class PackageWatcher extends Watcher { static supportsPackage (pack, type) { if (pack.getType() === type && pack.getStylesheetPaths().length) return true return false @@ -24,7 +23,8 @@ class PackageWatcher extends Watcher { const stylesheetsPath = this.pack.getStylesheetsPath() - if (fs.isDirectorySync(stylesheetsPath)) this.watchDirectory(stylesheetsPath) + if (fs.isDirectorySync(stylesheetsPath)) + this.watchDirectory(stylesheetsPath) const stylesheetPaths = new Set(this.pack.getStylesheetPaths()) const onFile = stylesheetPath => stylesheetPaths.add(stylesheetPath) diff --git a/packages/dev-live-reload/lib/ui-watcher.js b/packages/dev-live-reload/lib/ui-watcher.js index 458d31a78..9aa3eefde 100644 --- a/packages/dev-live-reload/lib/ui-watcher.js +++ b/packages/dev-live-reload/lib/ui-watcher.js @@ -1,10 +1,9 @@ -const {CompositeDisposable} = require('atom') +const { CompositeDisposable } = require('atom') const BaseThemeWatcher = require('./base-theme-watcher') const PackageWatcher = require('./package-watcher') -module.exports = -class UIWatcher { +module.exports = class UIWatcher { constructor () { this.subscriptions = new CompositeDisposable() this.reloadAll = this.reloadAll.bind(this) @@ -16,39 +15,61 @@ class UIWatcher { watchPackages () { this.watchedThemes = new Map() this.watchedPackages = new Map() - for (const theme of atom.themes.getActiveThemes()) { this.watchTheme(theme) } - for (const pack of atom.packages.getActivePackages()) { this.watchPackage(pack) } + for (const theme of atom.themes.getActiveThemes()) { + this.watchTheme(theme) + } + for (const pack of atom.packages.getActivePackages()) { + this.watchPackage(pack) + } this.watchForPackageChanges() } watchForPackageChanges () { - this.subscriptions.add(atom.themes.onDidChangeActiveThemes(() => { - // We need to destroy all theme watchers as all theme packages are destroyed - // when a theme changes. - for (const theme of this.watchedThemes.values()) { theme.destroy() } + this.subscriptions.add( + atom.themes.onDidChangeActiveThemes(() => { + // We need to destroy all theme watchers as all theme packages are destroyed + // when a theme changes. + for (const theme of this.watchedThemes.values()) { + theme.destroy() + } - this.watchedThemes.clear() + this.watchedThemes.clear() - // Rewatch everything! - for (const theme of atom.themes.getActiveThemes()) { this.watchTheme(theme) } - })) + // Rewatch everything! + for (const theme of atom.themes.getActiveThemes()) { + this.watchTheme(theme) + } + }) + ) - this.subscriptions.add(atom.packages.onDidActivatePackage(pack => this.watchPackage(pack))) + this.subscriptions.add( + atom.packages.onDidActivatePackage(pack => this.watchPackage(pack)) + ) - this.subscriptions.add(atom.packages.onDidDeactivatePackage(pack => { - // This only handles packages - onDidChangeActiveThemes handles themes - const watcher = this.watchedPackages.get(pack.name) - if (watcher) watcher.destroy() - this.watchedPackages.delete(pack.name) - })) + this.subscriptions.add( + atom.packages.onDidDeactivatePackage(pack => { + // This only handles packages - onDidChangeActiveThemes handles themes + const watcher = this.watchedPackages.get(pack.name) + if (watcher) watcher.destroy() + this.watchedPackages.delete(pack.name) + }) + ) } watchTheme (theme) { - if (PackageWatcher.supportsPackage(theme, 'theme')) this.watchedThemes.set(theme.name, this.createWatcher(new PackageWatcher(theme))) + if (PackageWatcher.supportsPackage(theme, 'theme')) + this.watchedThemes.set( + theme.name, + this.createWatcher(new PackageWatcher(theme)) + ) } watchPackage (pack) { - if (PackageWatcher.supportsPackage(pack, 'atom')) this.watchedPackages.set(pack.name, this.createWatcher(new PackageWatcher(pack))) + if (PackageWatcher.supportsPackage(pack, 'atom')) + this.watchedPackages.set( + pack.name, + this.createWatcher(new PackageWatcher(pack)) + ) } createWatcher (watcher) { @@ -56,7 +77,9 @@ class UIWatcher { console.log('Global changed, reloading all styles') this.reloadAll() }) - watcher.onDidDestroy(() => this.watchers.splice(this.watchers.indexOf(watcher), 1)) + watcher.onDidDestroy(() => + this.watchers.splice(this.watchers.indexOf(watcher), 1) + ) this.watchers.push(watcher) return watcher } @@ -68,14 +91,19 @@ class UIWatcher { } for (const theme of atom.themes.getActiveThemes()) { - if (PackageWatcher.supportsPackage(theme, 'theme')) theme.reloadStylesheets() + if (PackageWatcher.supportsPackage(theme, 'theme')) + theme.reloadStylesheets() } } destroy () { this.subscriptions.dispose() this.baseTheme.destroy() - for (const pack of this.watchedPackages.values()) { pack.destroy() } - for (const theme of this.watchedThemes.values()) { theme.destroy() } + for (const pack of this.watchedPackages.values()) { + pack.destroy() + } + for (const theme of this.watchedThemes.values()) { + theme.destroy() + } } } diff --git a/packages/dev-live-reload/lib/watcher.js b/packages/dev-live-reload/lib/watcher.js index 2ecde1eef..b1b3631a5 100644 --- a/packages/dev-live-reload/lib/watcher.js +++ b/packages/dev-live-reload/lib/watcher.js @@ -1,8 +1,7 @@ -const {CompositeDisposable, File, Directory, Emitter} = require('atom') +const { CompositeDisposable, File, Directory, Emitter } = require('atom') const path = require('path') -module.exports = -class Watcher { +module.exports = class Watcher { constructor () { this.destroy = this.destroy.bind(this) this.emitter = new Emitter() @@ -66,7 +65,10 @@ class Watcher { } isInAsarArchive (pathToCheck) { - const {resourcePath} = atom.getLoadSettings() - return pathToCheck.startsWith(`${resourcePath}${path.sep}`) && path.extname(resourcePath) === '.asar' + const { resourcePath } = atom.getLoadSettings() + return ( + pathToCheck.startsWith(`${resourcePath}${path.sep}`) && + path.extname(resourcePath) === '.asar' + ) } } diff --git a/packages/dev-live-reload/spec/async-spec-helpers.js b/packages/dev-live-reload/spec/async-spec-helpers.js index 73002c049..5a233973e 100644 --- a/packages/dev-live-reload/spec/async-spec-helpers.js +++ b/packages/dev-live-reload/spec/async-spec-helpers.js @@ -18,7 +18,7 @@ export function afterEach (fn) { }) } -['it', 'fit', 'ffit', 'fffit'].forEach(function (name) { +;['it', 'fit', 'ffit', 'fffit'].forEach(function (name) { module.exports[name] = function (description, fn) { if (fn === undefined) { global[name](description) @@ -34,7 +34,10 @@ export function afterEach (fn) { } }) -export async function conditionPromise (condition, description = 'anonymous condition') { +export async function conditionPromise ( + condition, + description = 'anonymous condition' +) { const startTime = Date.now() while (true) { diff --git a/packages/dev-live-reload/spec/dev-live-reload-spec.js b/packages/dev-live-reload/spec/dev-live-reload-spec.js index dec828b65..99b7fe261 100644 --- a/packages/dev-live-reload/spec/dev-live-reload-spec.js +++ b/packages/dev-live-reload/spec/dev-live-reload-spec.js @@ -1,4 +1,4 @@ -const {it, fit, ffit, afterEach, beforeEach} = require('./async-spec-helpers') // eslint-disable-line no-unused-vars +const { it, fit, ffit, afterEach, beforeEach } = require('./async-spec-helpers') // eslint-disable-line no-unused-vars describe('Dev Live Reload', () => { describe('package activation', () => { @@ -85,7 +85,9 @@ describe('Dev Live Reload', () => { it('stops watching all files', async () => { spyOn(atom.packages, 'hasActivatedInitialPackages').andReturn(true) - const {mainModule} = await atom.packages.activatePackage('dev-live-reload') + const { mainModule } = await atom.packages.activatePackage( + 'dev-live-reload' + ) expect(mainModule.uiWatcher).not.toBeNull() spyOn(mainModule.uiWatcher, 'destroy') @@ -95,7 +97,9 @@ describe('Dev Live Reload', () => { }) it('unsubscribes from the onDidActivateInitialPackages subscription if it is disabled before all initial packages are activated', async () => { - const {mainModule} = await atom.packages.activatePackage('dev-live-reload') + const { mainModule } = await atom.packages.activatePackage( + 'dev-live-reload' + ) expect(mainModule.activatedDisposable.disposed).toBe(false) await atom.packages.deactivatePackage('dev-live-reload') @@ -109,16 +113,18 @@ describe('Dev Live Reload', () => { it('removes its commands', async () => { spyOn(atom.packages, 'hasActivatedInitialPackages').andReturn(true) await atom.packages.activatePackage('dev-live-reload') - expect(atom.commands - .findCommands({target: atom.views.getView(atom.workspace)}) - .filter(command => command.name.startsWith('dev-live-reload')) - .length).toBeGreaterThan(0) + expect( + atom.commands + .findCommands({ target: atom.views.getView(atom.workspace) }) + .filter(command => command.name.startsWith('dev-live-reload')).length + ).toBeGreaterThan(0) await atom.packages.deactivatePackage('dev-live-reload') - expect(atom.commands - .findCommands({target: atom.views.getView(atom.workspace)}) - .filter(command => command.name.startsWith('dev-live-reload')) - .length).toBe(0) + expect( + atom.commands + .findCommands({ target: atom.views.getView(atom.workspace) }) + .filter(command => command.name.startsWith('dev-live-reload')).length + ).toBe(0) }) }) }) diff --git a/packages/dev-live-reload/spec/ui-watcher-spec.js b/packages/dev-live-reload/spec/ui-watcher-spec.js index c52ce35ab..0730619d8 100644 --- a/packages/dev-live-reload/spec/ui-watcher-spec.js +++ b/packages/dev-live-reload/spec/ui-watcher-spec.js @@ -2,25 +2,38 @@ const path = require('path') const UIWatcher = require('../lib/ui-watcher') -const {it, fit, ffit, afterEach, beforeEach, conditionPromise} = require('./async-spec-helpers') // eslint-disable-line no-unused-vars +const { + it, + fit, + ffit, + afterEach, + beforeEach, + conditionPromise +} = require('./async-spec-helpers') // eslint-disable-line no-unused-vars describe('UIWatcher', () => { let uiWatcher = null - beforeEach(() => atom.packages.packageDirPaths.push(path.join(__dirname, 'fixtures'))) + beforeEach(() => + atom.packages.packageDirPaths.push(path.join(__dirname, 'fixtures')) + ) afterEach(() => uiWatcher && uiWatcher.destroy()) describe("when a base theme's file changes", () => { beforeEach(() => { - spyOn(atom.themes, 'resolveStylesheet').andReturn(path.join(__dirname, 'fixtures', 'static', 'atom.less')) + spyOn(atom.themes, 'resolveStylesheet').andReturn( + path.join(__dirname, 'fixtures', 'static', 'atom.less') + ) uiWatcher = new UIWatcher() }) it('reloads all the base styles', () => { spyOn(atom.themes, 'reloadBaseStylesheets') - expect(uiWatcher.baseTheme.entities[0].getPath()).toContain(`${path.sep}static${path.sep}`) + expect(uiWatcher.baseTheme.entities[0].getPath()).toContain( + `${path.sep}static${path.sep}` + ) uiWatcher.baseTheme.entities[0].emitter.emit('did-change') expect(atom.themes.reloadBaseStylesheets).toHaveBeenCalled() @@ -28,7 +41,11 @@ describe('UIWatcher', () => { }) it("watches all the style sheets in the theme's styles folder", async () => { - const packagePath = path.join(__dirname, 'fixtures', 'package-with-styles-folder') + const packagePath = path.join( + __dirname, + 'fixtures', + 'package-with-styles-folder' + ) await atom.packages.activatePackage(packagePath) uiWatcher = new UIWatcher() @@ -36,15 +53,25 @@ describe('UIWatcher', () => { const lastWatcher = uiWatcher.watchers[uiWatcher.watchers.length - 1] expect(lastWatcher.entities.length).toBe(4) - expect(lastWatcher.entities[0].getPath()).toBe(path.join(packagePath, 'styles')) - expect(lastWatcher.entities[1].getPath()).toBe(path.join(packagePath, 'styles', '3.css')) - expect(lastWatcher.entities[2].getPath()).toBe(path.join(packagePath, 'styles', 'sub', '1.css')) - expect(lastWatcher.entities[3].getPath()).toBe(path.join(packagePath, 'styles', 'sub', '2.less')) + expect(lastWatcher.entities[0].getPath()).toBe( + path.join(packagePath, 'styles') + ) + expect(lastWatcher.entities[1].getPath()).toBe( + path.join(packagePath, 'styles', '3.css') + ) + expect(lastWatcher.entities[2].getPath()).toBe( + path.join(packagePath, 'styles', 'sub', '1.css') + ) + expect(lastWatcher.entities[3].getPath()).toBe( + path.join(packagePath, 'styles', 'sub', '2.less') + ) }) describe('when a package stylesheet file changes', async () => { beforeEach(async () => { - await atom.packages.activatePackage(path.join(__dirname, 'fixtures', 'package-with-styles-manifest')) + await atom.packages.activatePackage( + path.join(__dirname, 'fixtures', 'package-with-styles-manifest') + ) uiWatcher = new UIWatcher() }) @@ -52,7 +79,9 @@ describe('UIWatcher', () => { const pack = atom.packages.getActivePackages()[0] spyOn(pack, 'reloadStylesheets') - uiWatcher.watchers[uiWatcher.watchers.length - 1].entities[1].emitter.emit('did-change') + uiWatcher.watchers[ + uiWatcher.watchers.length - 1 + ].entities[1].emitter.emit('did-change') expect(pack.reloadStylesheets).toHaveBeenCalled() }) @@ -71,7 +100,10 @@ describe('UIWatcher', () => { describe('when a package global file changes', () => { beforeEach(async () => { - atom.config.set('core.themes', ['theme-with-ui-variables', 'theme-with-multiple-imported-files']) + atom.config.set('core.themes', [ + 'theme-with-ui-variables', + 'theme-with-multiple-imported-files' + ]) await atom.themes.activateThemes() uiWatcher = new UIWatcher() @@ -85,7 +117,9 @@ describe('UIWatcher', () => { spyOn(theme, 'reloadStylesheets') } - for (const entity of uiWatcher.watchedThemes.get('theme-with-multiple-imported-files').entities) { + for (const entity of uiWatcher.watchedThemes.get( + 'theme-with-multiple-imported-files' + ).entities) { if (entity.getPath().indexOf('variables') > -1) varEntity = entity } varEntity.emitter.emit('did-change') @@ -101,21 +135,31 @@ describe('UIWatcher', () => { uiWatcher = new UIWatcher() expect(uiWatcher.watchedPackages.size).toBe(0) - await atom.packages.activatePackage(path.join(__dirname, 'fixtures', 'package-with-styles-folder')) - expect(uiWatcher.watchedPackages.get('package-with-styles-folder')).not.toBeUndefined() + await atom.packages.activatePackage( + path.join(__dirname, 'fixtures', 'package-with-styles-folder') + ) + expect( + uiWatcher.watchedPackages.get('package-with-styles-folder') + ).not.toBeUndefined() }) it('unwatches a package after it is deactivated', async () => { - await atom.packages.activatePackage(path.join(__dirname, 'fixtures', 'package-with-styles-folder')) + await atom.packages.activatePackage( + path.join(__dirname, 'fixtures', 'package-with-styles-folder') + ) uiWatcher = new UIWatcher() - const watcher = uiWatcher.watchedPackages.get('package-with-styles-folder') + const watcher = uiWatcher.watchedPackages.get( + 'package-with-styles-folder' + ) expect(watcher).not.toBeUndefined() const watcherDestructionSpy = jasmine.createSpy('watcher-on-did-destroy') watcher.onDidDestroy(watcherDestructionSpy) await atom.packages.deactivatePackage('package-with-styles-folder') - expect(uiWatcher.watchedPackages.get('package-with-styles-folder')).toBeUndefined() + expect( + uiWatcher.watchedPackages.get('package-with-styles-folder') + ).toBeUndefined() expect(uiWatcher.watchedPackages.size).toBe(0) expect(watcherDestructionSpy).toHaveBeenCalled() }) @@ -124,7 +168,9 @@ describe('UIWatcher', () => { uiWatcher = new UIWatcher() uiWatcher.destroy() - await atom.packages.activatePackage(path.join(__dirname, 'fixtures', 'package-with-styles-folder')) + await atom.packages.activatePackage( + path.join(__dirname, 'fixtures', 'package-with-styles-folder') + ) expect(uiWatcher.watchedPackages.size).toBe(0) }) }) @@ -132,7 +178,10 @@ describe('UIWatcher', () => { describe('minimal theme packages', () => { let pack = null beforeEach(async () => { - atom.config.set('core.themes', ['theme-with-syntax-variables', 'theme-with-index-less']) + atom.config.set('core.themes', [ + 'theme-with-syntax-variables', + 'theme-with-index-less' + ]) await atom.themes.activateThemes() uiWatcher = new UIWatcher() pack = atom.themes.getActiveThemes()[0] @@ -157,7 +206,10 @@ describe('UIWatcher', () => { describe('theme packages', () => { let pack = null beforeEach(async () => { - atom.config.set('core.themes', ['theme-with-syntax-variables', 'theme-with-multiple-imported-files']) + atom.config.set('core.themes', [ + 'theme-with-syntax-variables', + 'theme-with-multiple-imported-files' + ]) await atom.themes.activateThemes() uiWatcher = new UIWatcher() @@ -170,7 +222,9 @@ describe('UIWatcher', () => { spyOn(pack, 'reloadStylesheets') spyOn(atom.themes, 'reloadBaseStylesheets') - const watcher = uiWatcher.watchedThemes.get('theme-with-multiple-imported-files') + const watcher = uiWatcher.watchedThemes.get( + 'theme-with-multiple-imported-files' + ) expect(watcher.entities.length).toBe(6) @@ -186,14 +240,21 @@ describe('UIWatcher', () => { jasmine.useRealClock() atom.config.set('core.themes', []) - await conditionPromise(() => !uiWatcher.watchedThemes['theme-with-multiple-imported-files']) + await conditionPromise( + () => !uiWatcher.watchedThemes['theme-with-multiple-imported-files'] + ) }) it('watches a new theme when it is deactivated', async () => { jasmine.useRealClock() - atom.config.set('core.themes', ['theme-with-syntax-variables', 'theme-with-package-file']) - await conditionPromise(() => uiWatcher.watchedThemes.get('theme-with-package-file')) + atom.config.set('core.themes', [ + 'theme-with-syntax-variables', + 'theme-with-package-file' + ]) + await conditionPromise(() => + uiWatcher.watchedThemes.get('theme-with-package-file') + ) pack = atom.themes.getActiveThemes()[0] spyOn(pack, 'reloadStylesheets') diff --git a/packages/exception-reporting/lib/main.js b/packages/exception-reporting/lib/main.js index 3909d5793..5893638f4 100644 --- a/packages/exception-reporting/lib/main.js +++ b/packages/exception-reporting/lib/main.js @@ -1,6 +1,6 @@ /** @babel */ -import {CompositeDisposable} from 'atom' +import { CompositeDisposable } from 'atom' let reporter @@ -13,36 +13,44 @@ function getReporter () { } export default { - activate() { + activate () { this.subscriptions = new CompositeDisposable() if (!atom.config.get('exception-reporting.userId')) { atom.config.set('exception-reporting.userId', require('node-uuid').v4()) } - this.subscriptions.add(atom.onDidThrowError(({message, url, line, column, originalError}) => { - try { - getReporter().reportUncaughtException(originalError) - } catch (secondaryException) { + this.subscriptions.add( + atom.onDidThrowError(({ message, url, line, column, originalError }) => { try { - console.error("Error reporting uncaught exception", secondaryException) - getReporter().reportUncaughtException(secondaryException) - } catch (error) { } - } - }) - ) - - if (atom.onDidFailAssertion != null) { - this.subscriptions.add(atom.onDidFailAssertion(error => { - try { - getReporter().reportFailedAssertion(error) + getReporter().reportUncaughtException(originalError) } catch (secondaryException) { try { - console.error("Error reporting assertion failure", secondaryException) + console.error( + 'Error reporting uncaught exception', + secondaryException + ) getReporter().reportUncaughtException(secondaryException) } catch (error) {} } }) + ) + + if (atom.onDidFailAssertion != null) { + this.subscriptions.add( + atom.onDidFailAssertion(error => { + try { + getReporter().reportFailedAssertion(error) + } catch (secondaryException) { + try { + console.error( + 'Error reporting assertion failure', + secondaryException + ) + getReporter().reportUncaughtException(secondaryException) + } catch (error) {} + } + }) ) } } diff --git a/packages/exception-reporting/lib/reporter.js b/packages/exception-reporting/lib/reporter.js index 42886c6ba..a702134a1 100644 --- a/packages/exception-reporting/lib/reporter.js +++ b/packages/exception-reporting/lib/reporter.js @@ -13,9 +13,15 @@ const StackTraceCache = new WeakMap() export default class Reporter { constructor (params = {}) { this.request = params.request || window.fetch - this.alwaysReport = params.hasOwnProperty('alwaysReport') ? params.alwaysReport : false - this.reportPreviousErrors = params.hasOwnProperty('reportPreviousErrors') ? params.reportPreviousErrors : true - this.resourcePath = this.normalizePath(params.resourcePath || process.resourcesPath) + this.alwaysReport = params.hasOwnProperty('alwaysReport') + ? params.alwaysReport + : false + this.reportPreviousErrors = params.hasOwnProperty('reportPreviousErrors') + ? params.reportPreviousErrors + : true + this.resourcePath = this.normalizePath( + params.resourcePath || process.resourcesPath + ) this.reportedErrors = [] this.reportedAssertionFailures = [] } @@ -28,22 +34,24 @@ export default class Reporter { version: LIB_VERSION, url: 'https://www.atom.io' }, - events: [{ - payloadVersion: "2", - exceptions: [this.buildExceptionJSON(error, params.projectRoot)], - severity: params.severity, - user: { - id: params.userId - }, - app: { - version: params.appVersion, - releaseStage: params.releaseStage - }, - device: { - osVersion: params.osVersion - }, - metaData: error.metadata - }] + events: [ + { + payloadVersion: '2', + exceptions: [this.buildExceptionJSON(error, params.projectRoot)], + severity: params.severity, + user: { + id: params.userId + }, + app: { + version: params.appVersion, + releaseStage: params.releaseStage + }, + device: { + osVersion: params.osVersion + }, + metaData: error.metadata + } + ] } } @@ -59,7 +67,8 @@ export default class Reporter { return this.parseStackTrace(error).map(callSite => { return { file: this.scrubPath(callSite.getFileName()), - method: callSite.getMethodName() || callSite.getFunctionName() || "none", + method: + callSite.getMethodName() || callSite.getFunctionName() || 'none', lineNumber: callSite.getLineNumber(), columnNumber: callSite.getColumnNumber(), inProject: !/node_modules/.test(callSite.getFileName()) @@ -69,8 +78,8 @@ export default class Reporter { normalizePath (pathToNormalize) { return pathToNormalize - .replace('file:///', '') // Sometimes it's a uri - .replace(/\\/g, '/') // Unify path separators across Win/macOS/Linux + .replace('file:///', '') // Sometimes it's a uri + .replace(/\\/g, '/') // Unify path separators across Win/macOS/Linux } scrubPath (pathToScrub) { @@ -96,17 +105,17 @@ export default class Reporter { } getReleaseChannel (version) { - return (version.indexOf('beta') > -1) + return version.indexOf('beta') > -1 ? 'beta' - : (version.indexOf('dev') > -1) - ? 'dev' - : 'stable' + : version.indexOf('dev') > -1 + ? 'dev' + : 'stable' } performRequest (json) { this.request.call(null, 'https://notify.bugsnag.com', { method: 'POST', - headers: new Headers({'Content-Type': 'application/json'}), + headers: new Headers({ 'Content-Type': 'application/json' }), body: JSON.stringify(json) }) } @@ -118,7 +127,10 @@ export default class Reporter { const topFrame = this.parseStackTrace(error)[0] const fileName = topFrame ? topFrame.getFileName() : null - return fileName && (this.isBundledFile(fileName) || this.isTeletypeFile(fileName)) + return ( + fileName && + (this.isBundledFile(fileName) || this.isTeletypeFile(fileName)) + ) } parseStackTrace (error) { @@ -169,21 +181,24 @@ export default class Reporter { notification = atom.notifications.addInfo(message, { detail: error.privateMetadataDescription, - description: "Are you willing to submit this information to a private server for debugging purposes?", + description: + 'Are you willing to submit this information to a private server for debugging purposes?', dismissable: true, buttons: [ { - text: "No", + text: 'No', onDidClick: reportWithoutPrivateMetadata }, { - text: "Yes, Submit for Debugging", + text: 'Yes, Submit for Debugging', onDidClick: reportWithPrivateMetadata } ] }) - dismissSubscription = notification.onDidDismiss(reportWithoutPrivateMetadata) + dismissSubscription = notification.onDidDismiss( + reportWithoutPrivateMetadata + ) } addPackageMetadata (error) { @@ -200,7 +215,9 @@ export default class Reporter { } } - if (error.metadata == null) { error.metadata = {} } + if (error.metadata == null) { + error.metadata = {} + } error.metadata.bundledPackages = bundledPackages error.metadata.userPackages = userPackages } @@ -209,8 +226,12 @@ export default class Reporter { addPreviousErrorsMetadata (error) { if (!this.reportPreviousErrors) return if (!error.metadata) error.metadata = {} - error.metadata.previousErrors = this.reportedErrors.map(error => error.message) - error.metadata.previousAssertionFailures = this.reportedAssertionFailures.map(error => error.message) + error.metadata.previousErrors = this.reportedErrors.map( + error => error.message + ) + error.metadata.previousAssertionFailures = this.reportedAssertionFailures.map( + error => error.message + ) } reportUncaughtException (error) { @@ -219,13 +240,20 @@ export default class Reporter { this.addPackageMetadata(error) this.addPreviousErrorsMetadata(error) - if ((error.privateMetadata != null) && (error.privateMetadataDescription != null)) { - this.requestPrivateMetadataConsent(error, "The Atom team would like to collect the following information to resolve this error:", error => this.reportUncaughtException(error)) + if ( + error.privateMetadata != null && + error.privateMetadataDescription != null + ) { + this.requestPrivateMetadataConsent( + error, + 'The Atom team would like to collect the following information to resolve this error:', + error => this.reportUncaughtException(error) + ) return } let params = this.getDefaultNotificationParams() - params.severity = "error" + params.severity = 'error' this.performRequest(this.buildNotificationJSON(error, params)) this.reportedErrors.push(error) } @@ -236,13 +264,20 @@ export default class Reporter { this.addPackageMetadata(error) this.addPreviousErrorsMetadata(error) - if ((error.privateMetadata != null) && (error.privateMetadataDescription != null)) { - this.requestPrivateMetadataConsent(error, "The Atom team would like to collect some information to resolve an unexpected condition:", error => this.reportFailedAssertion(error)) + if ( + error.privateMetadata != null && + error.privateMetadataDescription != null + ) { + this.requestPrivateMetadataConsent( + error, + 'The Atom team would like to collect some information to resolve an unexpected condition:', + error => this.reportFailedAssertion(error) + ) return } let params = this.getDefaultNotificationParams() - params.severity = "warning" + params.severity = 'warning' this.performRequest(this.buildNotificationJSON(error, params)) this.reportedAssertionFailures.push(error) } @@ -258,10 +293,11 @@ export default class Reporter { isTeletypeFile (fileName) { const teletypePath = atom.packages.resolvePackagePath('teletype') - return teletypePath && this.normalizePath(fileName).indexOf(teletypePath) === 0 + return ( + teletypePath && this.normalizePath(fileName).indexOf(teletypePath) === 0 + ) } } - Reporter.API_KEY = API_KEY Reporter.LIB_VERSION = LIB_VERSION diff --git a/packages/exception-reporting/spec/reporter-spec.js b/packages/exception-reporting/spec/reporter-spec.js index bcfdf8925..615868f3b 100644 --- a/packages/exception-reporting/spec/reporter-spec.js +++ b/packages/exception-reporting/spec/reporter-spec.js @@ -6,25 +6,31 @@ const fs = require('fs-plus') let osVersion = `${os.platform()}-${os.arch()}-${os.release()}` let getReleaseChannel = version => { - return (version.indexOf('beta') > -1) + return version.indexOf('beta') > -1 ? 'beta' - : (version.indexOf('dev') > -1) + : version.indexOf('dev') > -1 ? 'dev' : 'stable' } -describe("Reporter", () => { - let reporter, requests, initialStackTraceLimit, initialFsGetHomeDirectory, mockActivePackages +describe('Reporter', () => { + let reporter, + requests, + initialStackTraceLimit, + initialFsGetHomeDirectory, + mockActivePackages beforeEach(() => { reporter = new Reporter({ - request: (url, options) => requests.push(Object.assign({url}, options)), + request: (url, options) => requests.push(Object.assign({ url }, options)), alwaysReport: true, reportPreviousErrors: false }) requests = [] mockActivePackages = [] - spyOn(atom.packages, 'getActivePackages').andCallFake(() => mockActivePackages) + spyOn(atom.packages, 'getActivePackages').andCallFake( + () => mockActivePackages + ) initialStackTraceLimit = Error.stackTraceLimit Error.stackTraceLimit = 1 @@ -37,11 +43,12 @@ describe("Reporter", () => { Error.stackTraceLimit = initialStackTraceLimit }) - describe(".reportUncaughtException(error)", () => { - it("posts errors originated inside Atom Core to BugSnag", () => { + describe('.reportUncaughtException(error)', () => { + it('posts errors originated inside Atom Core to BugSnag', () => { const repositoryRootPath = path.join(__dirname, '..') reporter = new Reporter({ - request: (url, options) => requests.push(Object.assign({url}, options)), + request: (url, options) => + requests.push(Object.assign({ url }, options)), alwaysReport: true, reportPreviousErrors: false, resourcePath: repositoryRootPath @@ -50,111 +57,123 @@ describe("Reporter", () => { let error = new Error() Error.captureStackTrace(error) reporter.reportUncaughtException(error) - let [lineNumber, columnNumber] = error.stack.match(/.js:(\d+):(\d+)/).slice(1).map(s => parseInt(s)) + let [lineNumber, columnNumber] = error.stack + .match(/.js:(\d+):(\d+)/) + .slice(1) + .map(s => parseInt(s)) expect(requests.length).toBe(1) let [request] = requests - expect(request.method).toBe("POST") - expect(request.url).toBe("https://notify.bugsnag.com") - expect(request.headers.get("Content-Type")).toBe("application/json") + expect(request.method).toBe('POST') + expect(request.url).toBe('https://notify.bugsnag.com') + expect(request.headers.get('Content-Type')).toBe('application/json') let body = JSON.parse(request.body) // Delete `inProject` field because tests may fail when run as part of Atom core // (i.e. when this test file will be located under `node_modules/exception-reporting/spec`) delete body.events[0].exceptions[0].stacktrace[0].inProject expect(body).toEqual({ - "apiKey": Reporter.API_KEY, - "notifier": { - "name": "Atom", - "version": Reporter.LIB_VERSION, - "url": "https://www.atom.io" + apiKey: Reporter.API_KEY, + notifier: { + name: 'Atom', + version: Reporter.LIB_VERSION, + url: 'https://www.atom.io' }, - "events": [ + events: [ { - "payloadVersion": "2", - "exceptions": [ + payloadVersion: '2', + exceptions: [ { - "errorClass": "Error", - "message": "", - "stacktrace": [ + errorClass: 'Error', + message: '', + stacktrace: [ { - "method": semver.gt(process.versions.electron, '1.6.0') ? 'Spec.it' : 'it', - "file": "spec/reporter-spec.js", - "lineNumber": lineNumber, - "columnNumber": columnNumber + method: semver.gt(process.versions.electron, '1.6.0') + ? 'Spec.it' + : 'it', + file: 'spec/reporter-spec.js', + lineNumber: lineNumber, + columnNumber: columnNumber } ] } ], - "severity": "error", - "user": {}, - "app": { - "version": atom.getVersion(), - "releaseStage": getReleaseChannel(atom.getVersion()) + severity: 'error', + user: {}, + app: { + version: atom.getVersion(), + releaseStage: getReleaseChannel(atom.getVersion()) }, - "device": { - "osVersion": osVersion + device: { + osVersion: osVersion } } ] - });}) + }) + }) - it("posts errors originated outside Atom Core to BugSnag", () => { + it('posts errors originated outside Atom Core to BugSnag', () => { fs.getHomeDirectory = () => path.join(__dirname, '..', '..') let error = new Error() Error.captureStackTrace(error) reporter.reportUncaughtException(error) - let [lineNumber, columnNumber] = error.stack.match(/.js:(\d+):(\d+)/).slice(1).map(s => parseInt(s)) + let [lineNumber, columnNumber] = error.stack + .match(/.js:(\d+):(\d+)/) + .slice(1) + .map(s => parseInt(s)) expect(requests.length).toBe(1) let [request] = requests - expect(request.method).toBe("POST") - expect(request.url).toBe("https://notify.bugsnag.com") - expect(request.headers.get("Content-Type")).toBe("application/json") + expect(request.method).toBe('POST') + expect(request.url).toBe('https://notify.bugsnag.com') + expect(request.headers.get('Content-Type')).toBe('application/json') let body = JSON.parse(request.body) // Delete `inProject` field because tests may fail when run as part of Atom core // (i.e. when this test file will be located under `node_modules/exception-reporting/spec`) delete body.events[0].exceptions[0].stacktrace[0].inProject expect(body).toEqual({ - "apiKey": Reporter.API_KEY, - "notifier": { - "name": "Atom", - "version": Reporter.LIB_VERSION, - "url": "https://www.atom.io" + apiKey: Reporter.API_KEY, + notifier: { + name: 'Atom', + version: Reporter.LIB_VERSION, + url: 'https://www.atom.io' }, - "events": [ + events: [ { - "payloadVersion": "2", - "exceptions": [ + payloadVersion: '2', + exceptions: [ { - "errorClass": "Error", - "message": "", - "stacktrace": [ + errorClass: 'Error', + message: '', + stacktrace: [ { - "method": semver.gt(process.versions.electron, '1.6.0') ? 'Spec.it' : 'it', - "file": '~/exception-reporting/spec/reporter-spec.js', - "lineNumber": lineNumber, - "columnNumber": columnNumber + method: semver.gt(process.versions.electron, '1.6.0') + ? 'Spec.it' + : 'it', + file: '~/exception-reporting/spec/reporter-spec.js', + lineNumber: lineNumber, + columnNumber: columnNumber } ] } ], - "severity": "error", - "user": {}, - "app": { - "version": atom.getVersion(), - "releaseStage": getReleaseChannel(atom.getVersion()) + severity: 'error', + user: {}, + app: { + version: atom.getVersion(), + releaseStage: getReleaseChannel(atom.getVersion()) }, - "device": { - "osVersion": osVersion + device: { + osVersion: osVersion } } ] - });}) + }) + }) - describe("when the error object has `privateMetadata` and `privateMetadataDescription` fields", () => { + describe('when the error object has `privateMetadata` and `privateMetadataDescription` fields', () => { let [error, notification] = [] beforeEach(() => { @@ -164,17 +183,17 @@ describe("Reporter", () => { error = new Error() Error.captureStackTrace(error) - error.metadata = {foo: "bar"} - error.privateMetadata = {baz: "quux"} - error.privateMetadataDescription = "The contents of baz" + error.metadata = { foo: 'bar' } + error.privateMetadata = { baz: 'quux' } + error.privateMetadataDescription = 'The contents of baz' }) - it("posts a notification asking for consent", () => { + it('posts a notification asking for consent', () => { reporter.reportUncaughtException(error) expect(atom.notifications.addInfo).toHaveBeenCalled() }) - it("submits the error with the private metadata if the user consents", () => { + it('submits the error with the private metadata if the user consents', () => { spyOn(reporter, 'reportUncaughtException').andCallThrough() reporter.reportUncaughtException(error) reporter.reportUncaughtException.reset() @@ -189,12 +208,12 @@ describe("Reporter", () => { expect(reporter.reportUncaughtException.callCount).toBe(1) expect(error.privateMetadata).toBeUndefined() expect(error.privateMetadataDescription).toBeUndefined() - expect(error.metadata).toEqual({foo: "bar", baz: "quux"}) + expect(error.metadata).toEqual({ foo: 'bar', baz: 'quux' }) expect(notification.isDismissed()).toBe(true) }) - it("submits the error without the private metadata if the user does not consent", () => { + it('submits the error without the private metadata if the user does not consent', () => { spyOn(reporter, 'reportUncaughtException').andCallThrough() reporter.reportUncaughtException(error) reporter.reportUncaughtException.reset() @@ -209,12 +228,12 @@ describe("Reporter", () => { expect(reporter.reportUncaughtException.callCount).toBe(1) expect(error.privateMetadata).toBeUndefined() expect(error.privateMetadataDescription).toBeUndefined() - expect(error.metadata).toEqual({foo: "bar"}) + expect(error.metadata).toEqual({ foo: 'bar' }) expect(notification.isDismissed()).toBe(true) }) - it("submits the error without the private metadata if the user dismisses the notification", () => { + it('submits the error without the private metadata if the user dismisses the notification', () => { spyOn(reporter, 'reportUncaughtException').andCallThrough() reporter.reportUncaughtException(error) reporter.reportUncaughtException.reset() @@ -226,14 +245,34 @@ describe("Reporter", () => { expect(reporter.reportUncaughtException.callCount).toBe(1) expect(error.privateMetadata).toBeUndefined() expect(error.privateMetadataDescription).toBeUndefined() - expect(error.metadata).toEqual({foo: "bar"});});}) + expect(error.metadata).toEqual({ foo: 'bar' }) + }) + }) it('treats packages located in atom.packages.getPackageDirPaths as user packages', () => { mockActivePackages = [ - {name: 'user-1', path: '/Users/user/.atom/packages/user-1', metadata: {version: '1.0.0'}}, - {name: 'user-2', path: '/Users/user/.atom/packages/user-2', metadata: {version: '1.2.0'}}, - {name: 'bundled-1', path: '/Applications/Atom.app/Contents/Resources/app.asar/node_modules/bundled-1', metadata: {version: '1.0.0'}}, - {name: 'bundled-2', path: '/Applications/Atom.app/Contents/Resources/app.asar/node_modules/bundled-2', metadata: {version: '1.2.0'}}, + { + name: 'user-1', + path: '/Users/user/.atom/packages/user-1', + metadata: { version: '1.0.0' } + }, + { + name: 'user-2', + path: '/Users/user/.atom/packages/user-2', + metadata: { version: '1.2.0' } + }, + { + name: 'bundled-1', + path: + '/Applications/Atom.app/Contents/Resources/app.asar/node_modules/bundled-1', + metadata: { version: '1.0.0' } + }, + { + name: 'bundled-2', + path: + '/Applications/Atom.app/Contents/Resources/app.asar/node_modules/bundled-2', + metadata: { version: '1.2.0' } + } ] const packageDirPaths = ['/Users/user/.atom/packages'] @@ -269,69 +308,78 @@ describe("Reporter", () => { const lastRequest = requests[requests.length - 1] const body = JSON.parse(lastRequest.body) - console.log(body); + console.log(body) expect(body.events[0].metaData.previousErrors).toEqual(['A', 'B']) - expect(body.events[0].metaData.previousAssertionFailures).toEqual(['X', 'Y']) + expect(body.events[0].metaData.previousAssertionFailures).toEqual([ + 'X', + 'Y' + ]) }) }) - describe(".reportFailedAssertion(error)", () => { - it("posts warnings to bugsnag", () => { + describe('.reportFailedAssertion(error)', () => { + it('posts warnings to bugsnag', () => { fs.getHomeDirectory = () => path.join(__dirname, '..', '..') let error = new Error() Error.captureStackTrace(error) reporter.reportFailedAssertion(error) - let [lineNumber, columnNumber] = error.stack.match(/.js:(\d+):(\d+)/).slice(1).map(s => parseInt(s)) + let [lineNumber, columnNumber] = error.stack + .match(/.js:(\d+):(\d+)/) + .slice(1) + .map(s => parseInt(s)) expect(requests.length).toBe(1) let [request] = requests - expect(request.method).toBe("POST") - expect(request.url).toBe("https://notify.bugsnag.com") - expect(request.headers.get("Content-Type")).toBe("application/json") + expect(request.method).toBe('POST') + expect(request.url).toBe('https://notify.bugsnag.com') + expect(request.headers.get('Content-Type')).toBe('application/json') let body = JSON.parse(request.body) // Delete `inProject` field because tests may fail when run as part of Atom core // (i.e. when this test file will be located under `node_modules/exception-reporting/spec`) delete body.events[0].exceptions[0].stacktrace[0].inProject expect(body).toEqual({ - "apiKey": Reporter.API_KEY, - "notifier": { - "name": "Atom", - "version": Reporter.LIB_VERSION, - "url": "https://www.atom.io" + apiKey: Reporter.API_KEY, + notifier: { + name: 'Atom', + version: Reporter.LIB_VERSION, + url: 'https://www.atom.io' }, - "events": [ + events: [ { - "payloadVersion": "2", - "exceptions": [ + payloadVersion: '2', + exceptions: [ { - "errorClass": "Error", - "message": "", - "stacktrace": [ + errorClass: 'Error', + message: '', + stacktrace: [ { - "method": semver.gt(process.versions.electron, '1.6.0') ? 'Spec.it' : 'it', - "file": '~/exception-reporting/spec/reporter-spec.js', - "lineNumber": lineNumber, - "columnNumber": columnNumber + method: semver.gt(process.versions.electron, '1.6.0') + ? 'Spec.it' + : 'it', + file: '~/exception-reporting/spec/reporter-spec.js', + lineNumber: lineNumber, + columnNumber: columnNumber } ] } ], - "severity": "warning", - "user": {}, - "app": { - "version": atom.getVersion(), - "releaseStage": getReleaseChannel(atom.getVersion()) + severity: 'warning', + user: {}, + app: { + version: atom.getVersion(), + releaseStage: getReleaseChannel(atom.getVersion()) }, - "device": { - "osVersion": osVersion + device: { + osVersion: osVersion } } ] - });}) + }) + }) - describe("when the error object has `privateMetadata` and `privateMetadataDescription` fields", () => { + describe('when the error object has `privateMetadata` and `privateMetadataDescription` fields', () => { let [error, notification] = [] beforeEach(() => { @@ -341,17 +389,17 @@ describe("Reporter", () => { error = new Error() Error.captureStackTrace(error) - error.metadata = {foo: "bar"} - error.privateMetadata = {baz: "quux"} - error.privateMetadataDescription = "The contents of baz" + error.metadata = { foo: 'bar' } + error.privateMetadata = { baz: 'quux' } + error.privateMetadataDescription = 'The contents of baz' }) - it("posts a notification asking for consent", () => { + it('posts a notification asking for consent', () => { reporter.reportFailedAssertion(error) expect(atom.notifications.addInfo).toHaveBeenCalled() }) - it("submits the error with the private metadata if the user consents", () => { + it('submits the error with the private metadata if the user consents', () => { spyOn(reporter, 'reportFailedAssertion').andCallThrough() reporter.reportFailedAssertion(error) reporter.reportFailedAssertion.reset() @@ -366,12 +414,12 @@ describe("Reporter", () => { expect(reporter.reportFailedAssertion.callCount).toBe(1) expect(error.privateMetadata).toBeUndefined() expect(error.privateMetadataDescription).toBeUndefined() - expect(error.metadata).toEqual({foo: "bar", baz: "quux"}) + expect(error.metadata).toEqual({ foo: 'bar', baz: 'quux' }) expect(notification.isDismissed()).toBe(true) }) - it("submits the error without the private metadata if the user does not consent", () => { + it('submits the error without the private metadata if the user does not consent', () => { spyOn(reporter, 'reportFailedAssertion').andCallThrough() reporter.reportFailedAssertion(error) reporter.reportFailedAssertion.reset() @@ -386,12 +434,12 @@ describe("Reporter", () => { expect(reporter.reportFailedAssertion.callCount).toBe(1) expect(error.privateMetadata).toBeUndefined() expect(error.privateMetadataDescription).toBeUndefined() - expect(error.metadata).toEqual({foo: "bar"}) + expect(error.metadata).toEqual({ foo: 'bar' }) expect(notification.isDismissed()).toBe(true) }) - it("submits the error without the private metadata if the user dismisses the notification", () => { + it('submits the error without the private metadata if the user dismisses the notification', () => { spyOn(reporter, 'reportFailedAssertion').andCallThrough() reporter.reportFailedAssertion(error) reporter.reportFailedAssertion.reset() @@ -403,13 +451,17 @@ describe("Reporter", () => { expect(reporter.reportFailedAssertion.callCount).toBe(1) expect(error.privateMetadata).toBeUndefined() expect(error.privateMetadataDescription).toBeUndefined() - expect(error.metadata).toEqual({foo: "bar"}) + expect(error.metadata).toEqual({ foo: 'bar' }) }) it("only notifies the user once for a given 'privateMetadataRequestName'", () => { let fakeStorage = {} - spyOn(global.localStorage, 'setItem').andCallFake((key, value) => fakeStorage[key] = value) - spyOn(global.localStorage, 'getItem').andCallFake(key => fakeStorage[key]) + spyOn(global.localStorage, 'setItem').andCallFake( + (key, value) => (fakeStorage[key] = value) + ) + spyOn(global.localStorage, 'getItem').andCallFake( + key => fakeStorage[key] + ) error.privateMetadataRequestName = 'foo' @@ -423,7 +475,7 @@ describe("Reporter", () => { let error2 = new Error() Error.captureStackTrace(error2) error2.privateMetadataDescription = 'Something about you' - error2.privateMetadata = {baz: 'quux'} + error2.privateMetadata = { baz: 'quux' } error2.privateMetadataRequestName = 'bar' reporter.reportFailedAssertion(error2) @@ -433,10 +485,28 @@ describe("Reporter", () => { it('treats packages located in atom.packages.getPackageDirPaths as user packages', () => { mockActivePackages = [ - {name: 'user-1', path: '/Users/user/.atom/packages/user-1', metadata: {version: '1.0.0'}}, - {name: 'user-2', path: '/Users/user/.atom/packages/user-2', metadata: {version: '1.2.0'}}, - {name: 'bundled-1', path: '/Applications/Atom.app/Contents/Resources/app.asar/node_modules/bundled-1', metadata: {version: '1.0.0'}}, - {name: 'bundled-2', path: '/Applications/Atom.app/Contents/Resources/app.asar/node_modules/bundled-2', metadata: {version: '1.2.0'}}, + { + name: 'user-1', + path: '/Users/user/.atom/packages/user-1', + metadata: { version: '1.0.0' } + }, + { + name: 'user-2', + path: '/Users/user/.atom/packages/user-2', + metadata: { version: '1.2.0' } + }, + { + name: 'bundled-1', + path: + '/Applications/Atom.app/Contents/Resources/app.asar/node_modules/bundled-1', + metadata: { version: '1.0.0' } + }, + { + name: 'bundled-2', + path: + '/Applications/Atom.app/Contents/Resources/app.asar/node_modules/bundled-2', + metadata: { version: '1.2.0' } + } ] const packageDirPaths = ['/Users/user/.atom/packages'] @@ -473,7 +543,10 @@ describe("Reporter", () => { const body = JSON.parse(lastRequest.body) expect(body.events[0].metaData.previousErrors).toEqual(['A', 'B']) - expect(body.events[0].metaData.previousAssertionFailures).toEqual(['X', 'Y']) + expect(body.events[0].metaData.previousAssertionFailures).toEqual([ + 'X', + 'Y' + ]) }) }) }) diff --git a/packages/git-diff/lib/diff-list-view.js b/packages/git-diff/lib/diff-list-view.js index 38e50880f..22f7c7d23 100644 --- a/packages/git-diff/lib/diff-list-view.js +++ b/packages/git-diff/lib/diff-list-view.js @@ -1,14 +1,13 @@ const SelectListView = require('atom-select-list') -const {repositoryForPath} = require('./helpers') +const { repositoryForPath } = require('./helpers') -module.exports = -class DiffListView { +module.exports = class DiffListView { constructor () { this.selectListView = new SelectListView({ emptyMessage: 'No diffs in file', items: [], - filterKeyForItem: (diff) => diff.lineText, - elementForItem: (diff) => { + filterKeyForItem: diff => diff.lineText, + elementForItem: diff => { const li = document.createElement('li') li.classList.add('two-lines') @@ -19,15 +18,19 @@ class DiffListView { const secondaryLine = document.createElement('div') secondaryLine.classList.add('secondary-line') - secondaryLine.textContent = `-${diff.oldStart},${diff.oldLines} +${diff.newStart},${diff.newLines}` + secondaryLine.textContent = `-${diff.oldStart},${diff.oldLines} +${ + diff.newStart + },${diff.newLines}` li.appendChild(secondaryLine) return li }, - didConfirmSelection: (diff) => { + didConfirmSelection: diff => { this.cancel() const bufferRow = diff.newStart > 0 ? diff.newStart - 1 : diff.newStart - this.editor.setCursorBufferPosition([bufferRow, 0], {autoscroll: true}) + this.editor.setCursorBufferPosition([bufferRow, 0], { + autoscroll: true + }) this.editor.moveToFirstCharacterOfLine() }, didCancelSelection: () => { @@ -35,7 +38,10 @@ class DiffListView { } }) this.selectListView.element.classList.add('diff-list-view') - this.panel = atom.workspace.addModalPanel({item: this.selectListView, visible: false}) + this.panel = atom.workspace.addModalPanel({ + item: this.selectListView, + visible: false + }) } attach () { @@ -66,7 +72,9 @@ class DiffListView { } else if (editor) { this.editor = editor const repository = repositoryForPath(this.editor.getPath()) - let diffs = repository ? repository.getLineDiffs(this.editor.getPath(), this.editor.getText()) : [] + let diffs = repository + ? repository.getLineDiffs(this.editor.getPath(), this.editor.getText()) + : [] if (!diffs) diffs = [] for (let diff of diffs) { const bufferRow = diff.newStart > 0 ? diff.newStart - 1 : diff.newStart @@ -74,7 +82,7 @@ class DiffListView { diff.lineText = lineText ? lineText.trim() : '' } - await this.selectListView.update({items: diffs}) + await this.selectListView.update({ items: diffs }) this.attach() } } diff --git a/packages/git-diff/lib/git-diff-view.js b/packages/git-diff/lib/git-diff-view.js index 1f1913eab..99d57b483 100644 --- a/packages/git-diff/lib/git-diff-view.js +++ b/packages/git-diff/lib/git-diff-view.js @@ -1,10 +1,9 @@ -const {CompositeDisposable} = require('atom') -const {repositoryForPath} = require('./helpers') +const { CompositeDisposable } = require('atom') +const { repositoryForPath } = require('./helpers') const MAX_BUFFER_LENGTH_TO_DIFF = 2 * 1024 * 1024 -module.exports = -class GitDiffView { +module.exports = class GitDiffView { constructor (editor) { this.updateDiffs = this.updateDiffs.bind(this) this.editor = editor @@ -22,10 +21,18 @@ class GitDiffView { this.editor.onDidStopChanging(this.updateDiffs), this.editor.onDidChangePath(this.updateDiffs), atom.project.onDidChangePaths(() => this.subscribeToRepository()), - atom.commands.add(editorElement, 'git-diff:move-to-next-diff', () => this.moveToNextDiff()), - atom.commands.add(editorElement, 'git-diff:move-to-previous-diff', () => this.moveToPreviousDiff()), - atom.config.onDidChange('git-diff.showIconsInEditorGutter', () => this.updateIconDecoration()), - atom.config.onDidChange('editor.showLineNumbers', () => this.updateIconDecoration()), + atom.commands.add(editorElement, 'git-diff:move-to-next-diff', () => + this.moveToNextDiff() + ), + atom.commands.add(editorElement, 'git-diff:move-to-previous-diff', () => + this.moveToPreviousDiff() + ), + atom.config.onDidChange('git-diff.showIconsInEditorGutter', () => + this.updateIconDecoration() + ), + atom.config.onDidChange('editor.showLineNumbers', () => + this.updateIconDecoration() + ), editorElement.onDidAttach(() => this.updateIconDecoration()), this.editor.onDidDestroy(() => { this.cancelUpdate() @@ -43,7 +50,7 @@ class GitDiffView { let nextDiffLineNumber = null let firstDiffLineNumber = null if (this.diffs) { - for (const {newStart} of this.diffs) { + for (const { newStart } of this.diffs) { if (newStart > cursorLineNumber) { if (nextDiffLineNumber == null) nextDiffLineNumber = newStart - 1 nextDiffLineNumber = Math.min(newStart - 1, nextDiffLineNumber) @@ -55,7 +62,10 @@ class GitDiffView { } // Wrap around to the first diff in the file - if (atom.config.get('git-diff.wrapAroundOnMoveToDiff') && nextDiffLineNumber == null) { + if ( + atom.config.get('git-diff.wrapAroundOnMoveToDiff') && + nextDiffLineNumber == null + ) { nextDiffLineNumber = firstDiffLineNumber } @@ -65,7 +75,10 @@ class GitDiffView { updateIconDecoration () { const gutter = this.editor.getElement().querySelector('.gutter') if (gutter) { - if (atom.config.get('editor.showLineNumbers') && atom.config.get('git-diff.showIconsInEditorGutter')) { + if ( + atom.config.get('editor.showLineNumbers') && + atom.config.get('git-diff.showIconsInEditorGutter') + ) { gutter.classList.add('git-diff-icon') } else { gutter.classList.remove('git-diff-icon') @@ -78,16 +91,22 @@ class GitDiffView { let previousDiffLineNumber = -1 let lastDiffLineNumber = -1 if (this.diffs) { - for (const {newStart} of this.diffs) { + for (const { newStart } of this.diffs) { if (newStart < cursorLineNumber) { - previousDiffLineNumber = Math.max(newStart - 1, previousDiffLineNumber) + previousDiffLineNumber = Math.max( + newStart - 1, + previousDiffLineNumber + ) } lastDiffLineNumber = Math.max(newStart - 1, lastDiffLineNumber) } } // Wrap around to the last diff in the file - if (atom.config.get('git-diff.wrapAroundOnMoveToDiff') && previousDiffLineNumber === -1) { + if ( + atom.config.get('git-diff.wrapAroundOnMoveToDiff') && + previousDiffLineNumber === -1 + ) { previousDiffLineNumber = lastDiffLineNumber } @@ -104,12 +123,16 @@ class GitDiffView { subscribeToRepository () { this.repository = repositoryForPath(this.editor.getPath()) if (this.repository) { - this.subscriptions.add(this.repository.onDidChangeStatuses(() => { - this.scheduleUpdate() - })) - this.subscriptions.add(this.repository.onDidChangeStatus(changedPath => { - if (changedPath === this.editor.getPath()) this.scheduleUpdate() - })) + this.subscriptions.add( + this.repository.onDidChangeStatuses(() => { + this.scheduleUpdate() + }) + ) + this.subscriptions.add( + this.repository.onDidChangeStatus(changedPath => { + if (changedPath === this.editor.getPath()) this.scheduleUpdate() + }) + ) } } @@ -126,16 +149,21 @@ class GitDiffView { if (this.editor.isDestroyed()) return this.removeDecorations() const path = this.editor && this.editor.getPath() - if (path && this.editor.getBuffer().getLength() < MAX_BUFFER_LENGTH_TO_DIFF) { - this.diffs = this.repository && this.repository.getLineDiffs(path, this.editor.getText()) + if ( + path && + this.editor.getBuffer().getLength() < MAX_BUFFER_LENGTH_TO_DIFF + ) { + this.diffs = + this.repository && + this.repository.getLineDiffs(path, this.editor.getText()) if (this.diffs) this.addDecorations(this.diffs) } } addDecorations (diffs) { - for (const {newStart, oldLines, newLines} of diffs) { + for (const { newStart, oldLines, newLines } of diffs) { const startRow = newStart - 1 - const endRow = (newStart + newLines) - 1 + const endRow = newStart + newLines - 1 if (oldLines === 0 && newLines > 0) { this.markRange(startRow, endRow, 'git-line-added') } else if (newLines === 0 && oldLines > 0) { @@ -156,8 +184,10 @@ class GitDiffView { } markRange (startRow, endRow, klass) { - const marker = this.editor.markBufferRange([[startRow, 0], [endRow, 0]], {invalidate: 'never'}) - this.editor.decorateMarker(marker, {type: 'line-number', class: klass}) + const marker = this.editor.markBufferRange([[startRow, 0], [endRow, 0]], { + invalidate: 'never' + }) + this.editor.decorateMarker(marker, { type: 'line-number', class: klass }) this.markers.push(marker) } } diff --git a/packages/git-diff/lib/main.js b/packages/git-diff/lib/main.js index d5162139b..72597b93c 100644 --- a/packages/git-diff/lib/main.js +++ b/packages/git-diff/lib/main.js @@ -11,10 +11,14 @@ module.exports = { if (watchedEditors.has(editor)) return new GitDiffView(editor).start() - atom.commands.add(atom.views.getView(editor), 'git-diff:toggle-diff-list', () => { - if (diffListView == null) diffListView = new DiffListView() - diffListView.toggle() - }) + atom.commands.add( + atom.views.getView(editor), + 'git-diff:toggle-diff-list', + () => { + if (diffListView == null) diffListView = new DiffListView() + diffListView.toggle() + } + ) watchedEditors.add(editor) editor.onDidDestroy(() => watchedEditors.delete(editor)) diff --git a/packages/git-diff/spec/diff-list-view-spec.js b/packages/git-diff/spec/diff-list-view-spec.js index 36ca97b05..5fba8eba1 100644 --- a/packages/git-diff/spec/diff-list-view-spec.js +++ b/packages/git-diff/spec/diff-list-view-spec.js @@ -8,7 +8,10 @@ describe('git-diff:toggle-diff-list', () => { beforeEach(() => { const projectPath = temp.mkdirSync('git-diff-spec-') fs.copySync(path.join(__dirname, 'fixtures', 'working-dir'), projectPath) - fs.moveSync(path.join(projectPath, 'git.git'), path.join(projectPath, '.git')) + fs.moveSync( + path.join(projectPath, 'git.git'), + path.join(projectPath, '.git') + ) atom.project.setPaths([projectPath]) jasmine.attachToDOM(atom.workspace.getElement()) @@ -37,7 +40,10 @@ describe('git-diff:toggle-diff-list', () => { it('moves the cursor to the selected hunk', () => { editor.setCursorBufferPosition([0, 0]) - atom.commands.dispatch(document.querySelector('.diff-list-view'), 'core:confirm') + atom.commands.dispatch( + document.querySelector('.diff-list-view'), + 'core:confirm' + ) expect(editor.getCursorBufferPosition()).toEqual([4, 4]) }) }) diff --git a/packages/git-diff/spec/git-diff-spec.js b/packages/git-diff/spec/git-diff-spec.js index 397693c89..badb15f76 100644 --- a/packages/git-diff/spec/git-diff-spec.js +++ b/packages/git-diff/spec/git-diff-spec.js @@ -12,12 +12,17 @@ describe('GitDiff package', () => { const otherPath = temp.mkdirSync('some-other-path-') fs.copySync(path.join(__dirname, 'fixtures', 'working-dir'), projectPath) - fs.moveSync(path.join(projectPath, 'git.git'), path.join(projectPath, '.git')) + fs.moveSync( + path.join(projectPath, 'git.git'), + path.join(projectPath, '.git') + ) atom.project.setPaths([otherPath, projectPath]) jasmine.attachToDOM(atom.workspace.getElement()) - waitsForPromise(() => atom.workspace.open(path.join(projectPath, 'sample.js'))) + waitsForPromise(() => + atom.workspace.open(path.join(projectPath, 'sample.js')) + ) runs(() => { editor = atom.workspace.getActiveTextEditor() @@ -29,11 +34,18 @@ describe('GitDiff package', () => { describe('when the editor has modified lines', () => { it('highlights the modified lines', () => { - expect(editorElement.querySelectorAll('.git-line-modified').length).toBe(0) + expect(editorElement.querySelectorAll('.git-line-modified').length).toBe( + 0 + ) editor.insertText('a') advanceClock(editor.getBuffer().stoppedChangingDelay) - expect(editorElement.querySelectorAll('.git-line-modified').length).toBe(1) - expect(editorElement.querySelector('.git-line-modified')).toHaveData('buffer-row', 0) + expect(editorElement.querySelectorAll('.git-line-modified').length).toBe( + 1 + ) + expect(editorElement.querySelector('.git-line-modified')).toHaveData( + 'buffer-row', + 0 + ) }) }) @@ -45,7 +57,10 @@ describe('GitDiff package', () => { editor.insertText('a') advanceClock(editor.getBuffer().stoppedChangingDelay) expect(editorElement.querySelectorAll('.git-line-added').length).toBe(1) - expect(editorElement.querySelector('.git-line-added')).toHaveData('buffer-row', 1) + expect(editorElement.querySelector('.git-line-added')).toHaveData( + 'buffer-row', + 1 + ) }) }) @@ -56,7 +71,10 @@ describe('GitDiff package', () => { editor.deleteLine() advanceClock(editor.getBuffer().stoppedChangingDelay) expect(editorElement.querySelectorAll('.git-line-removed').length).toBe(1) - expect(editorElement.querySelector('.git-line-removed')).toHaveData('buffer-row', 4) + expect(editorElement.querySelector('.git-line-removed')).toHaveData( + 'buffer-row', + 4 + ) }) }) @@ -66,29 +84,44 @@ describe('GitDiff package', () => { editor.setCursorBufferPosition([0, 0]) editor.deleteLine() advanceClock(editor.getBuffer().stoppedChangingDelay) - expect(editorElement.querySelectorAll('.git-previous-line-removed').length).toBe(1) - expect(editorElement.querySelector('.git-previous-line-removed')).toHaveData('buffer-row', 0) + expect( + editorElement.querySelectorAll('.git-previous-line-removed').length + ).toBe(1) + expect( + editorElement.querySelector('.git-previous-line-removed') + ).toHaveData('buffer-row', 0) }) }) describe('when a modified line is restored to the HEAD version contents', () => { it('removes the diff highlight', () => { - expect(editorElement.querySelectorAll('.git-line-modified').length).toBe(0) + expect(editorElement.querySelectorAll('.git-line-modified').length).toBe( + 0 + ) editor.insertText('a') advanceClock(editor.getBuffer().stoppedChangingDelay) - expect(editorElement.querySelectorAll('.git-line-modified').length).toBe(1) + expect(editorElement.querySelectorAll('.git-line-modified').length).toBe( + 1 + ) editor.backspace() advanceClock(editor.getBuffer().stoppedChangingDelay) - expect(editorElement.querySelectorAll('.git-line-modified').length).toBe(0) + expect(editorElement.querySelectorAll('.git-line-modified').length).toBe( + 0 + ) }) }) describe('when a modified file is opened', () => { it('highlights the changed lines', () => { - fs.writeFileSync(path.join(projectPath, 'sample.txt'), 'Some different text.') + fs.writeFileSync( + path.join(projectPath, 'sample.txt'), + 'Some different text.' + ) let nextTick = false - waitsForPromise(() => atom.workspace.open(path.join(projectPath, 'sample.txt'))) + waitsForPromise(() => + atom.workspace.open(path.join(projectPath, 'sample.txt')) + ) runs(() => { editorElement = atom.workspace.getActiveTextEditor().getElement() @@ -101,8 +134,13 @@ describe('GitDiff package', () => { waitsFor(() => nextTick) runs(() => { - expect(editorElement.querySelectorAll('.git-line-modified').length).toBe(1) - expect(editorElement.querySelector('.git-line-modified')).toHaveData('buffer-row', 0) + expect( + editorElement.querySelectorAll('.git-line-modified').length + ).toBe(1) + expect(editorElement.querySelector('.git-line-modified')).toHaveData( + 'buffer-row', + 0 + ) }) }) }) @@ -148,7 +186,9 @@ describe('GitDiff package', () => { }) describe('when the wrapAroundOnMoveToDiff config option is false', () => { - beforeEach(() => atom.config.set('git-diff.wrapAroundOnMoveToDiff', false)) + beforeEach(() => + atom.config.set('git-diff.wrapAroundOnMoveToDiff', false) + ) it('does not wraps around to the first/last diff in the file', () => { editor.insertText('a') @@ -177,19 +217,28 @@ describe('GitDiff package', () => { atom.config.set('git-diff.showIconsInEditorGutter', true) }) - it('the gutter has a git-diff-icon class', () => expect(editorElement.querySelector('.gutter')).toHaveClass('git-diff-icon')) + it('the gutter has a git-diff-icon class', () => + expect(editorElement.querySelector('.gutter')).toHaveClass( + 'git-diff-icon' + )) it('keeps the git-diff-icon class when editor.showLineNumbers is toggled', () => { atom.config.set('editor.showLineNumbers', false) - expect(editorElement.querySelector('.gutter')).not.toHaveClass('git-diff-icon') + expect(editorElement.querySelector('.gutter')).not.toHaveClass( + 'git-diff-icon' + ) atom.config.set('editor.showLineNumbers', true) - expect(editorElement.querySelector('.gutter')).toHaveClass('git-diff-icon') + expect(editorElement.querySelector('.gutter')).toHaveClass( + 'git-diff-icon' + ) }) it('removes the git-diff-icon class when the showIconsInEditorGutter config option set to false', () => { atom.config.set('git-diff.showIconsInEditorGutter', false) - expect(editorElement.querySelector('.gutter')).not.toHaveClass('git-diff-icon') + expect(editorElement.querySelector('.gutter')).not.toHaveClass( + 'git-diff-icon' + ) }) }) }) diff --git a/packages/go-to-line/lib/go-to-line-view.js b/packages/go-to-line/lib/go-to-line-view.js index 66759f9d9..93d174dbc 100644 --- a/packages/go-to-line/lib/go-to-line-view.js +++ b/packages/go-to-line/lib/go-to-line-view.js @@ -29,13 +29,13 @@ class GoToLineView { atom.commands.add(this.miniEditor.element, 'core:cancel', () => { this.close() }) - this.miniEditor.onWillInsertText((arg) => { + this.miniEditor.onWillInsertText(arg => { if (arg.text.match(/[^0-9:]/)) { arg.cancel() } }) this.miniEditor.onDidChange(() => { - this.navigate({keepOpen: true}) + this.navigate({ keepOpen: true }) }) } @@ -62,9 +62,11 @@ class GoToLineView { const currentRow = editor.getCursorBufferPosition().row const rowLineNumber = lineNumber.split(/:+/)[0] || '' - const row = rowLineNumber.length > 0 ? parseInt(rowLineNumber) - 1 : currentRow + const row = + rowLineNumber.length > 0 ? parseInt(rowLineNumber) - 1 : currentRow const columnLineNumber = lineNumber.split(/:+/)[1] || '' - const column = columnLineNumber.length > 0 ? parseInt(columnLineNumber) - 1 : -1 + const column = + columnLineNumber.length > 0 ? parseInt(columnLineNumber) - 1 : -1 const position = new Point(row, column) editor.setCursorBufferPosition(position) @@ -83,7 +85,10 @@ class GoToLineView { } restoreFocus () { - if (this.previouslyFocusedElement && this.previouslyFocusedElement.parentElement) { + if ( + this.previouslyFocusedElement && + this.previouslyFocusedElement.parentElement + ) { return this.previouslyFocusedElement.focus() } atom.views.getView(atom.workspace).focus() @@ -93,7 +98,8 @@ class GoToLineView { if (this.panel.isVisible() || !atom.workspace.getActiveTextEditor()) return this.storeFocusedElement() this.panel.show() - this.message.textContent = 'Enter a or : to go there. Examples: "3" for row 3 or "2:7" for row 2 and column 7' + this.message.textContent = + 'Enter a or : to go there. Examples: "3" for row 3 or "2:7" for row 2 and column 7' this.miniEditor.element.focus() } } diff --git a/packages/go-to-line/spec/go-to-line-spec.js b/packages/go-to-line/spec/go-to-line-spec.js index 8b9f3ba92..62551825e 100644 --- a/packages/go-to-line/spec/go-to-line-spec.js +++ b/packages/go-to-line/spec/go-to-line-spec.js @@ -76,8 +76,12 @@ describe('GoToLine', () => { atom.commands.dispatch(goToLine.miniEditor.element, 'core:confirm') const rowsPerPage = editor.getRowsPerPage() const currentRow = editor.getCursorBufferPosition().row - 1 - expect(editor.getFirstVisibleScreenRow()).toBe(currentRow - Math.ceil(rowsPerPage / 2)) - expect(editor.getLastVisibleScreenRow()).toBe(currentRow + Math.floor(rowsPerPage / 2)) + expect(editor.getFirstVisibleScreenRow()).toBe( + currentRow - Math.ceil(rowsPerPage / 2) + ) + expect(editor.getLastVisibleScreenRow()).toBe( + currentRow + Math.floor(rowsPerPage / 2) + ) }) }) diff --git a/packages/grammar-selector/lib/grammar-list-view.js b/packages/grammar-selector/lib/grammar-list-view.js index 557036af5..d6812fcfc 100644 --- a/packages/grammar-selector/lib/grammar-list-view.js +++ b/packages/grammar-selector/lib/grammar-list-view.js @@ -1,14 +1,13 @@ const SelectListView = require('atom-select-list') -module.exports = -class GrammarListView { +module.exports = class GrammarListView { constructor () { - this.autoDetect = {name: 'Auto Detect'} + this.autoDetect = { name: 'Auto Detect' } this.selectListView = new SelectListView({ itemsClassList: ['mark-active'], items: [], - filterKeyForItem: (grammar) => grammar.name, - elementForItem: (grammar) => { + filterKeyForItem: grammar => grammar.name, + elementForItem: grammar => { const grammarName = grammar.name || grammar.scopeName const element = document.createElement('li') if (grammar === this.currentGrammar) { @@ -29,7 +28,7 @@ class GrammarListView { return element }, - didConfirmSelection: (grammar) => { + didConfirmSelection: grammar => { this.cancel() if (grammar === this.autoDetect) { atom.textEditors.clearGrammarOverride(this.editor) @@ -64,7 +63,7 @@ class GrammarListView { attach () { this.previouslyFocusedElement = document.activeElement if (this.panel == null) { - this.panel = atom.workspace.addModalPanel({item: this.selectListView}) + this.panel = atom.workspace.addModalPanel({ item: this.selectListView }) } this.selectListView.focus() this.selectListView.reset() @@ -80,7 +79,7 @@ class GrammarListView { this.currentGrammar = this.autoDetect } - const grammars = atom.grammars.getGrammars().filter((grammar) => { + const grammars = atom.grammars.getGrammars().filter(grammar => { return grammar !== atom.grammars.nullGrammar && grammar.name }) grammars.sort((a, b) => { @@ -97,7 +96,7 @@ class GrammarListView { } }) grammars.unshift(this.autoDetect) - await this.selectListView.update({items: grammars}) + await this.selectListView.update({ items: grammars }) this.attach() } } diff --git a/packages/grammar-selector/lib/grammar-status-view.js b/packages/grammar-selector/lib/grammar-status-view.js index 45dab6cd1..d7f13930b 100644 --- a/packages/grammar-selector/lib/grammar-status-view.js +++ b/packages/grammar-selector/lib/grammar-status-view.js @@ -1,7 +1,6 @@ -const {Disposable} = require('atom') +const { Disposable } = require('atom') -module.exports = -class GrammarStatusView { +module.exports = class GrammarStatusView { constructor (statusBar) { this.statusBar = statusBar this.element = document.createElement('grammar-selector-status') @@ -10,15 +9,25 @@ class GrammarStatusView { this.grammarLink.classList.add('inline-block') this.element.appendChild(this.grammarLink) - this.activeItemSubscription = atom.workspace.observeActiveTextEditor(this.subscribeToActiveTextEditor.bind(this)) + this.activeItemSubscription = atom.workspace.observeActiveTextEditor( + this.subscribeToActiveTextEditor.bind(this) + ) - this.configSubscription = atom.config.observe('grammar-selector.showOnRightSideOfStatusBar', this.attach.bind(this)) - const clickHandler = (event) => { + this.configSubscription = atom.config.observe( + 'grammar-selector.showOnRightSideOfStatusBar', + this.attach.bind(this) + ) + const clickHandler = event => { event.preventDefault() - atom.commands.dispatch(atom.views.getView(atom.workspace.getActiveTextEditor()), 'grammar-selector:show') + atom.commands.dispatch( + atom.views.getView(atom.workspace.getActiveTextEditor()), + 'grammar-selector:show' + ) } this.element.addEventListener('click', clickHandler) - this.clickSubscription = new Disposable(() => { this.element.removeEventListener('click', clickHandler) }) + this.clickSubscription = new Disposable(() => { + this.element.removeEventListener('click', clickHandler) + }) } attach () { @@ -27,8 +36,8 @@ class GrammarStatusView { } this.tile = atom.config.get('grammar-selector.showOnRightSideOfStatusBar') - ? this.statusBar.addRightTile({item: this.element, priority: 10}) - : this.statusBar.addLeftTile({item: this.element, priority: 10}) + ? this.statusBar.addRightTile({ item: this.element, priority: 10 }) + : this.statusBar.addLeftTile({ item: this.element, priority: 10 }) } destroy () { @@ -65,7 +74,9 @@ class GrammarStatusView { const editor = atom.workspace.getActiveTextEditor() if (editor) { - this.grammarSubscription = editor.onDidChangeGrammar(this.updateGrammarText.bind(this)) + this.grammarSubscription = editor.onDidChangeGrammar( + this.updateGrammarText.bind(this) + ) } this.updateGrammarText() } @@ -92,7 +103,9 @@ class GrammarStatusView { this.grammarLink.dataset.grammar = grammarName this.element.style.display = '' - this.tooltip = atom.tooltips.add(this.element, {title: `File uses the ${grammarName} grammar`}) + this.tooltip = atom.tooltips.add(this.element, { + title: `File uses the ${grammarName} grammar` + }) } else { this.element.style.display = 'none' } diff --git a/packages/grammar-selector/lib/main.js b/packages/grammar-selector/lib/main.js index 6f95a44e6..428108dd4 100644 --- a/packages/grammar-selector/lib/main.js +++ b/packages/grammar-selector/lib/main.js @@ -7,10 +7,14 @@ let grammarStatusView = null module.exports = { activate () { - commandDisposable = atom.commands.add('atom-text-editor', 'grammar-selector:show', () => { - if (!grammarListView) grammarListView = new GrammarListView() - grammarListView.toggle() - }) + commandDisposable = atom.commands.add( + 'atom-text-editor', + 'grammar-selector:show', + () => { + if (!grammarListView) grammarListView = new GrammarListView() + grammarListView.toggle() + } + ) }, deactivate () { diff --git a/packages/grammar-selector/spec/async-spec-helpers.js b/packages/grammar-selector/spec/async-spec-helpers.js index 61eeaab39..5fe94e859 100644 --- a/packages/grammar-selector/spec/async-spec-helpers.js +++ b/packages/grammar-selector/spec/async-spec-helpers.js @@ -15,7 +15,6 @@ exports.afterEach = function afterEach (fn) { } }) } - ;['it', 'fit', 'ffit', 'fffit'].forEach(function (name) { exports[name] = function (description, fn) { if (fn === undefined) { @@ -33,8 +32,8 @@ exports.afterEach = function afterEach (fn) { }) function waitsForPromise (message, promise) { - global.waitsFor(message, (done) => { - promise.then(done, (error) => { + global.waitsFor(message, done => { + promise.then(done, error => { jasmine.getEnv().currentSpec.fail(error) done() }) diff --git a/packages/grammar-selector/spec/grammar-selector-spec.js b/packages/grammar-selector/spec/grammar-selector-spec.js index 21ea63d38..1c27d95a5 100644 --- a/packages/grammar-selector/spec/grammar-selector-spec.js +++ b/packages/grammar-selector/spec/grammar-selector-spec.js @@ -1,6 +1,6 @@ const path = require('path') const SelectListView = require('atom-select-list') -const {it, fit, ffit, beforeEach, afterEach} = require('./async-spec-helpers') // eslint-disable-line +const { it, fit, ffit, beforeEach, afterEach } = require('./async-spec-helpers') // eslint-disable-line describe('GrammarSelector', () => { let [editor, textGrammar, jsGrammar] = [] @@ -13,7 +13,9 @@ describe('GrammarSelector', () => { await atom.packages.activatePackage('grammar-selector') await atom.packages.activatePackage('language-text') await atom.packages.activatePackage('language-javascript') - await atom.packages.activatePackage(path.join(__dirname, 'fixtures', 'language-with-no-name')) + await atom.packages.activatePackage( + path.join(__dirname, 'fixtures', 'language-with-no-name') + ) editor = await atom.workspace.open('sample.js') @@ -33,15 +35,24 @@ describe('GrammarSelector', () => { // TODO: Remove once Atom 1.23 reaches stable if (parseFloat(atom.getVersion()) >= 1.23) { // Do not take into account the two JS regex grammars or language-with-no-name - expect(grammarView.querySelectorAll('li').length).toBe(atom.grammars.grammars.length - 3) + expect(grammarView.querySelectorAll('li').length).toBe( + atom.grammars.grammars.length - 3 + ) } else { - expect(grammarView.querySelectorAll('li').length).toBe(atom.grammars.grammars.length - 1) + expect(grammarView.querySelectorAll('li').length).toBe( + atom.grammars.grammars.length - 1 + ) } - expect(grammarView.querySelectorAll('li')[0].textContent).toBe('Auto Detect') + expect(grammarView.querySelectorAll('li')[0].textContent).toBe( + 'Auto Detect' + ) expect(grammarView.textContent.includes('source.a')).toBe(false) - grammarView.querySelectorAll('li').forEach(li => expect(li.textContent).not.toBe(atom.grammars.nullGrammar.name)) - }) - ) + grammarView + .querySelectorAll('li') + .forEach(li => + expect(li.textContent).not.toBe(atom.grammars.nullGrammar.name) + ) + })) describe('when a grammar is selected', () => it('sets the new grammar on the editor', async () => { @@ -51,8 +62,7 @@ describe('GrammarSelector', () => { const grammarView = atom.workspace.getModalPanels()[0].getItem() grammarView.props.didConfirmSelection(textGrammar) expect(editor.getGrammar()).toBe(textGrammar) - }) - ) + })) describe('when auto-detect is selected', () => it('restores the auto-detected grammar on the editor', async () => { @@ -69,8 +79,7 @@ describe('GrammarSelector', () => { grammarView = atom.workspace.getModalPanels()[0].getItem() grammarView.props.didConfirmSelection(grammarView.items[0]) expect(editor.getGrammar()).toBe(jsGrammar) - }) - ) + })) describe("when the editor's current grammar is the null grammar", () => it('displays Auto Detect as the selected grammar', async () => { @@ -79,9 +88,10 @@ describe('GrammarSelector', () => { await SelectListView.getScheduler().getNextUpdatePromise() const grammarView = atom.workspace.getModalPanels()[0].getItem().element - expect(grammarView.querySelector('li.active').textContent).toBe('Auto Detect') - }) - ) + expect(grammarView.querySelector('li.active').textContent).toBe( + 'Auto Detect' + ) + })) describe('when editor is untitled', () => it('sets the new grammar on the editor', async () => { @@ -94,8 +104,7 @@ describe('GrammarSelector', () => { const grammarView = atom.workspace.getModalPanels()[0].getItem() grammarView.props.didConfirmSelection(jsGrammar) expect(editor.getGrammar()).toBe(jsGrammar) - }) - ) + })) describe('Status bar grammar label', () => { let [grammarStatus, grammarTile, statusBar] = [] @@ -114,7 +123,9 @@ describe('GrammarSelector', () => { it('displays the name of the current grammar', () => { expect(grammarStatus.querySelector('a').textContent).toBe('JavaScript') - expect(getTooltipText(grammarStatus)).toBe('File uses the JavaScript grammar') + expect(getTooltipText(grammarStatus)).toBe( + 'File uses the JavaScript grammar' + ) }) it('displays Plain Text when the current grammar is the null grammar', async () => { @@ -123,7 +134,9 @@ describe('GrammarSelector', () => { expect(grammarStatus.querySelector('a').textContent).toBe('Plain Text') expect(grammarStatus).toBeVisible() - expect(getTooltipText(grammarStatus)).toBe('File uses the Plain Text grammar') + expect(getTooltipText(grammarStatus)).toBe( + 'File uses the Plain Text grammar' + ) editor.setGrammar(atom.grammars.grammarForScopeName('source.js')) await atom.views.getNextUpdatePromise() @@ -142,20 +155,31 @@ describe('GrammarSelector', () => { describe('when the grammar-selector.showOnRightSideOfStatusBar setting changes', () => it('moves the item to the preferred side of the status bar', () => { - expect(statusBar.getLeftTiles().map(tile => tile.getItem())).toContain(grammarStatus) - expect(statusBar.getRightTiles().map(tile => tile.getItem())).not.toContain(grammarStatus) + expect(statusBar.getLeftTiles().map(tile => tile.getItem())).toContain( + grammarStatus + ) + expect( + statusBar.getRightTiles().map(tile => tile.getItem()) + ).not.toContain(grammarStatus) atom.config.set('grammar-selector.showOnRightSideOfStatusBar', true) - expect(statusBar.getLeftTiles().map(tile => tile.getItem())).not.toContain(grammarStatus) - expect(statusBar.getRightTiles().map(tile => tile.getItem())).toContain(grammarStatus) + expect( + statusBar.getLeftTiles().map(tile => tile.getItem()) + ).not.toContain(grammarStatus) + expect(statusBar.getRightTiles().map(tile => tile.getItem())).toContain( + grammarStatus + ) atom.config.set('grammar-selector.showOnRightSideOfStatusBar', false) - expect(statusBar.getLeftTiles().map(tile => tile.getItem())).toContain(grammarStatus) - expect(statusBar.getRightTiles().map(tile => tile.getItem())).not.toContain(grammarStatus) - }) - ) + expect(statusBar.getLeftTiles().map(tile => tile.getItem())).toContain( + grammarStatus + ) + expect( + statusBar.getRightTiles().map(tile => tile.getItem()) + ).not.toContain(grammarStatus) + })) describe("when the editor's grammar changes", () => it('displays the new grammar of the editor', async () => { @@ -163,32 +187,37 @@ describe('GrammarSelector', () => { await atom.views.getNextUpdatePromise() expect(grammarStatus.querySelector('a').textContent).toBe('Plain Text') - expect(getTooltipText(grammarStatus)).toBe('File uses the Plain Text grammar') + expect(getTooltipText(grammarStatus)).toBe( + 'File uses the Plain Text grammar' + ) editor.setGrammar(atom.grammars.grammarForScopeName('source.a')) await atom.views.getNextUpdatePromise() expect(grammarStatus.querySelector('a').textContent).toBe('source.a') - expect(getTooltipText(grammarStatus)).toBe('File uses the source.a grammar') - }) - ) + expect(getTooltipText(grammarStatus)).toBe( + 'File uses the source.a grammar' + ) + })) describe('when clicked', () => it('shows the grammar selector modal', () => { const eventHandler = jasmine.createSpy('eventHandler') - atom.commands.add(editor.getElement(), 'grammar-selector:show', eventHandler) + atom.commands.add( + editor.getElement(), + 'grammar-selector:show', + eventHandler + ) grammarStatus.click() expect(eventHandler).toHaveBeenCalled() - }) - ) + })) describe('when the package is deactivated', () => it('removes the view', () => { spyOn(grammarTile, 'destroy') atom.packages.deactivatePackage('grammar-selector') expect(grammarTile.destroy).toHaveBeenCalled() - }) - ) + })) }) }) diff --git a/packages/incompatible-packages/lib/incompatible-packages-component.js b/packages/incompatible-packages/lib/incompatible-packages-component.js index 8eb6c62c6..0f7bd263c 100644 --- a/packages/incompatible-packages/lib/incompatible-packages-component.js +++ b/packages/incompatible-packages/lib/incompatible-packages-component.js @@ -1,7 +1,7 @@ /** @babel */ /** @jsx etch.dom */ -import {BufferedProcess} from 'atom' +import { BufferedProcess } from 'atom' import etch from 'etch' import VIEW_URI from './view-uri' @@ -11,8 +11,8 @@ const REBUILD_SUCCEEDED = 'rebuild-succeeded' export default class IncompatiblePackagesComponent { constructor (packageManager) { - this.rebuildStatuses = new Map - this.rebuildFailureOutputs = new Map + this.rebuildStatuses = new Map() + this.rebuildFailureOutputs = new Map() this.rebuildInProgress = false this.rebuiltPackageCount = 0 this.packageManager = packageManager @@ -25,13 +25,15 @@ export default class IncompatiblePackagesComponent { global.setImmediate(this.populateIncompatiblePackages.bind(this)) } - this.element.addEventListener('click', (event) => { + this.element.addEventListener('click', event => { if (event.target === this.refs.rebuildButton) { this.rebuildIncompatiblePackages() } else if (event.target === this.refs.reloadButton) { atom.reload() } else if (event.target.classList.contains('view-settings')) { - atom.workspace.open(`atom://config/packages/${event.target.package.name}`) + atom.workspace.open( + `atom://config/packages/${event.target.package.name}` + ) } }) } @@ -44,7 +46,10 @@ export default class IncompatiblePackagesComponent { } return ( -
    +
    {this.renderHeading()} {this.renderIncompatiblePackageList()}
    @@ -55,15 +60,14 @@ export default class IncompatiblePackagesComponent { if (this.incompatiblePackages.length > 0) { if (this.rebuiltPackageCount > 0) { let alertClass = - (this.rebuiltPackageCount === this.incompatiblePackages.length) + this.rebuiltPackageCount === this.incompatiblePackages.length ? 'alert-success icon-check' : 'alert-warning icon-bug' return (
    - {this.rebuiltPackageCount} of {this.incompatiblePackages.length} packages - were rebuilt successfully. Reload Atom to activate them. - + {this.rebuiltPackageCount} of {this.incompatiblePackages.length}{' '} + packages were rebuilt successfully. Reload Atom to activate them. @@ -72,10 +76,13 @@ export default class IncompatiblePackagesComponent { } else { return (
    - Some installed packages could not be loaded because they contain native - modules that were compiled for an earlier version of Atom. - -
    @@ -92,9 +99,11 @@ export default class IncompatiblePackagesComponent { renderIncompatiblePackageList () { return ( -
    { - this.incompatiblePackages.map(this.renderIncompatiblePackage.bind(this)) - }
    +
    + {this.incompatiblePackages.map( + this.renderIncompatiblePackage.bind(this) + )} +
    ) } @@ -104,15 +113,18 @@ export default class IncompatiblePackagesComponent { return (
    {this.renderRebuildStatusIndicator(rebuildStatus)} - +

    {pack.name} {pack.metadata.version}

    - { - rebuildStatus + {rebuildStatus ? this.renderRebuildOutput(pack) - : this.renderIncompatibleModules(pack) - } + : this.renderIncompatibleModules(pack)}
    ) } @@ -151,23 +163,23 @@ export default class IncompatiblePackagesComponent { renderIncompatibleModules (pack) { return ( -
      { - pack.incompatibleModules.map((nativeModule) => +
        + {pack.incompatibleModules.map(nativeModule => (
      • - {nativeModule.name}@{nativeModule.version || 'unknown'} – {nativeModule.error} + {nativeModule.name}@{nativeModule.version || 'unknown'} –{' '} + {nativeModule.error}
      • - ) - }
      + ))} +
    ) } populateIncompatiblePackages () { - this.incompatiblePackages = - this.packageManager - .getLoadedPackages() - .filter(pack => !pack.isCompatible()) + this.incompatiblePackages = this.packageManager + .getLoadedPackages() + .filter(pack => !pack.isCompatible()) for (let pack of this.incompatiblePackages) { let buildFailureOutput = pack.getBuildFailureOutput() @@ -186,7 +198,7 @@ export default class IncompatiblePackagesComponent { let rebuiltPackageCount = 0 for (let pack of this.incompatiblePackages) { this.setPackageStatus(pack, REBUILDING) - let {code, stderr} = await pack.rebuild() + let { code, stderr } = await pack.rebuild() if (code === 0) { this.setPackageStatus(pack, REBUILD_SUCCEEDED) rebuiltPackageCount++ @@ -223,6 +235,6 @@ export default class IncompatiblePackagesComponent { } serialize () { - return {deserializer: 'IncompatiblePackagesComponent'} + return { deserializer: 'IncompatiblePackagesComponent' } } } diff --git a/packages/incompatible-packages/lib/main.js b/packages/incompatible-packages/lib/main.js index b936cb880..f66549a7c 100644 --- a/packages/incompatible-packages/lib/main.js +++ b/packages/incompatible-packages/lib/main.js @@ -1,6 +1,6 @@ /** @babel */ -import {Disposable, CompositeDisposable} from 'atom' +import { Disposable, CompositeDisposable } from 'atom' import VIEW_URI from './view-uri' let disposables = null @@ -8,17 +8,21 @@ let disposables = null export function activate () { disposables = new CompositeDisposable() - disposables.add(atom.workspace.addOpener((uri) => { - if (uri === VIEW_URI) { - return deserializeIncompatiblePackagesComponent() - } - })) + disposables.add( + atom.workspace.addOpener(uri => { + if (uri === VIEW_URI) { + return deserializeIncompatiblePackagesComponent() + } + }) + ) - disposables.add(atom.commands.add('atom-workspace', { - 'incompatible-packages:view': () => { - atom.workspace.open(VIEW_URI) - } - })) + disposables.add( + atom.commands.add('atom-workspace', { + 'incompatible-packages:view': () => { + atom.workspace.open(VIEW_URI) + } + }) + ) } export function deactivate () { @@ -33,7 +37,7 @@ export function consumeStatusBar (statusBar) { if (incompatibleCount > 0) { let icon = createIcon(incompatibleCount) - let tile = statusBar.addRightTile({item: icon, priority: 200}) + let tile = statusBar.addRightTile({ item: icon, priority: 200 }) icon.element.addEventListener('click', () => { atom.commands.dispatch(icon.element, 'incompatible-packages:view') }) @@ -48,5 +52,5 @@ export function deserializeIncompatiblePackagesComponent () { function createIcon (count) { const StatusIconComponent = require('./status-icon-component') - return new StatusIconComponent({count}) + return new StatusIconComponent({ count }) } diff --git a/packages/incompatible-packages/lib/status-icon-component.js b/packages/incompatible-packages/lib/status-icon-component.js index 72653ca9b..21cc2a742 100644 --- a/packages/incompatible-packages/lib/status-icon-component.js +++ b/packages/incompatible-packages/lib/status-icon-component.js @@ -4,7 +4,7 @@ import etch from 'etch' export default class StatusIconComponent { - constructor ({count}) { + constructor ({ count }) { this.count = count etch.initialize(this) } @@ -14,7 +14,7 @@ export default class StatusIconComponent { render () { return (
    - + {this.count}
    ) diff --git a/packages/incompatible-packages/spec/incompatible-packages-component-spec.js b/packages/incompatible-packages/spec/incompatible-packages-component-spec.js index 88d46677e..1039cabe5 100644 --- a/packages/incompatible-packages/spec/incompatible-packages-component-spec.js +++ b/packages/incompatible-packages/spec/incompatible-packages-component-spec.js @@ -16,7 +16,7 @@ describe('IncompatiblePackagesComponent', () => { return false }, rebuild: function () { - return new Promise((resolve) => this.resolveRebuild = resolve) + return new Promise(resolve => (this.resolveRebuild = resolve)) }, getBuildFailureOutput () { return null @@ -27,8 +27,8 @@ describe('IncompatiblePackagesComponent', () => { version: '1.0.0' }, incompatibleModules: [ - {name: 'x', version: '1.0.0', error: 'Expected version X, got Y'}, - {name: 'y', version: '1.0.0', error: 'Expected version X, got Z'} + { name: 'x', version: '1.0.0', error: 'Expected version X, got Y' }, + { name: 'y', version: '1.0.0', error: 'Expected version X, got Z' } ] }, { @@ -37,7 +37,7 @@ describe('IncompatiblePackagesComponent', () => { return false }, rebuild () { - return new Promise((resolve) => this.resolveRebuild = resolve) + return new Promise(resolve => (this.resolveRebuild = resolve)) }, getBuildFailureOutput () { return null @@ -48,7 +48,7 @@ describe('IncompatiblePackagesComponent', () => { version: '1.0.0' }, incompatibleModules: [ - {name: 'z', version: '1.0.0', error: 'Expected version X, got Y'} + { name: 'z', version: '1.0.0', error: 'Expected version X, got Y' } ] }, { @@ -67,7 +67,7 @@ describe('IncompatiblePackagesComponent', () => { repository: 'https://github.com/atom/b', version: '1.0.0' }, - incompatibleModules: [], + incompatibleModules: [] } ] }) @@ -75,18 +75,21 @@ describe('IncompatiblePackagesComponent', () => { describe('when packages have not finished loading', () => { it('delays rendering incompatible packages until the end of the tick', () => { waitsForPromise(async () => { - let component = - new IncompatiblePackagesComponent({ - getActivePackages: () => [], - getLoadedPackages: () => packages - }) - let {element} = component + let component = new IncompatiblePackagesComponent({ + getActivePackages: () => [], + getLoadedPackages: () => packages + }) + let { element } = component - expect(element.querySelectorAll('.incompatible-package').length).toEqual(0) + expect( + element.querySelectorAll('.incompatible-package').length + ).toEqual(0) await etchScheduler.getNextUpdatePromise() - expect(element.querySelectorAll('.incompatible-package').length).toBeGreaterThan(0) + expect( + element.querySelectorAll('.incompatible-package').length + ).toBeGreaterThan(0) }) }) }) @@ -97,12 +100,11 @@ describe('IncompatiblePackagesComponent', () => { expect(packages[2].isCompatible()).toBe(true) let compatiblePackages = [packages[2]] - let component = - new IncompatiblePackagesComponent({ - getActivePackages: () => compatiblePackages, - getLoadedPackages: () => compatiblePackages - }) - let {element} = component + let component = new IncompatiblePackagesComponent({ + getActivePackages: () => compatiblePackages, + getLoadedPackages: () => compatiblePackages + }) + let { element } = component await etchScheduler.getNextUpdatePromise() @@ -119,18 +121,23 @@ describe('IncompatiblePackagesComponent', () => { return 'The build failed' } - let component = - new IncompatiblePackagesComponent({ - getActivePackages: () => packages, - getLoadedPackages: () => packages - }) - let {element} = component + let component = new IncompatiblePackagesComponent({ + getActivePackages: () => packages, + getLoadedPackages: () => packages + }) + let { element } = component await etchScheduler.getNextUpdatePromise() - let packageElement = element.querySelector('.incompatible-package:nth-child(2)') + let packageElement = element.querySelector( + '.incompatible-package:nth-child(2)' + ) - expect(packageElement.querySelector('.badge').textContent).toBe('Rebuild Failed') - expect(packageElement.querySelector('pre').textContent).toBe('The build failed') + expect(packageElement.querySelector('.badge').textContent).toBe( + 'Rebuild Failed' + ) + expect(packageElement.querySelector('pre').textContent).toBe( + 'The build failed' + ) }) }) }) @@ -138,75 +145,101 @@ describe('IncompatiblePackagesComponent', () => { describe('when there are incompatible packages', () => { it('renders incompatible packages and the rebuild button', () => { waitsForPromise(async () => { - let component = - new IncompatiblePackagesComponent({ - getActivePackages: () => packages, - getLoadedPackages: () => packages - }) - let {element} = component + let component = new IncompatiblePackagesComponent({ + getActivePackages: () => packages, + getLoadedPackages: () => packages + }) + let { element } = component await etchScheduler.getNextUpdatePromise() - expect(element.querySelectorAll('.incompatible-package').length).toEqual(2) + expect( + element.querySelectorAll('.incompatible-package').length + ).toEqual(2) expect(element.querySelector('button')).not.toBeNull() }) }) describe('when the "Rebuild All" button is clicked', () => { - it('rebuilds every incompatible package, updating each package\'s view with status', () => { + it("rebuilds every incompatible package, updating each package's view with status", () => { waitsForPromise(async () => { - let component = - new IncompatiblePackagesComponent({ - getActivePackages: () => packages, - getLoadedPackages: () => packages - }) - let {element} = component + let component = new IncompatiblePackagesComponent({ + getActivePackages: () => packages, + getLoadedPackages: () => packages + }) + let { element } = component jasmine.attachToDOM(element) await etchScheduler.getNextUpdatePromise() - component.refs.rebuildButton.dispatchEvent(new CustomEvent('click', {bubbles: true})) + component.refs.rebuildButton.dispatchEvent( + new CustomEvent('click', { bubbles: true }) + ) await etchScheduler.getNextUpdatePromise() // view update expect(component.refs.rebuildButton.disabled).toBe(true) expect(packages[0].resolveRebuild).toBeDefined() - expect(element.querySelector('.incompatible-package:nth-child(1) .badge').textContent).toBe('Rebuilding') - expect(element.querySelector('.incompatible-package:nth-child(2) .badge')).toBeNull() + expect( + element.querySelector('.incompatible-package:nth-child(1) .badge') + .textContent + ).toBe('Rebuilding') + expect( + element.querySelector('.incompatible-package:nth-child(2) .badge') + ).toBeNull() - packages[0].resolveRebuild({code: 0}) // simulate rebuild success + packages[0].resolveRebuild({ code: 0 }) // simulate rebuild success await etchScheduler.getNextUpdatePromise() // view update expect(packages[1].resolveRebuild).toBeDefined() - expect(element.querySelector('.incompatible-package:nth-child(1) .badge').textContent).toBe('Rebuild Succeeded') - expect(element.querySelector('.incompatible-package:nth-child(2) .badge').textContent).toBe('Rebuilding') + expect( + element.querySelector('.incompatible-package:nth-child(1) .badge') + .textContent + ).toBe('Rebuild Succeeded') + expect( + element.querySelector('.incompatible-package:nth-child(2) .badge') + .textContent + ).toBe('Rebuilding') - packages[1].resolveRebuild({code: 12, stderr: 'This is an error from the test!'}) // simulate rebuild failure + packages[1].resolveRebuild({ + code: 12, + stderr: 'This is an error from the test!' + }) // simulate rebuild failure await etchScheduler.getNextUpdatePromise() // view update - expect(element.querySelector('.incompatible-package:nth-child(1) .badge').textContent).toBe('Rebuild Succeeded') - expect(element.querySelector('.incompatible-package:nth-child(2) .badge').textContent).toBe('Rebuild Failed') - expect(element.querySelector('.incompatible-package:nth-child(2) pre').textContent).toBe('This is an error from the test!') + expect( + element.querySelector('.incompatible-package:nth-child(1) .badge') + .textContent + ).toBe('Rebuild Succeeded') + expect( + element.querySelector('.incompatible-package:nth-child(2) .badge') + .textContent + ).toBe('Rebuild Failed') + expect( + element.querySelector('.incompatible-package:nth-child(2) pre') + .textContent + ).toBe('This is an error from the test!') }) }) it('displays a prompt to reload Atom when the packages finish rebuilding', () => { waitsForPromise(async () => { - let component = - new IncompatiblePackagesComponent({ - getActivePackages: () => packages, - getLoadedPackages: () => packages - }) - let {element} = component + let component = new IncompatiblePackagesComponent({ + getActivePackages: () => packages, + getLoadedPackages: () => packages + }) + let { element } = component jasmine.attachToDOM(element) await etchScheduler.getNextUpdatePromise() // view update - component.refs.rebuildButton.dispatchEvent(new CustomEvent('click', {bubbles: true})) - expect(packages[0].resolveRebuild({code: 0})) + component.refs.rebuildButton.dispatchEvent( + new CustomEvent('click', { bubbles: true }) + ) + expect(packages[0].resolveRebuild({ code: 0 })) await new Promise(global.setImmediate) - expect(packages[1].resolveRebuild({code: 0})) + expect(packages[1].resolveRebuild({ code: 0 })) await etchScheduler.getNextUpdatePromise() // view update @@ -214,7 +247,9 @@ describe('IncompatiblePackagesComponent', () => { expect(element.querySelector('.alert').textContent).toMatch(/2 of 2/) spyOn(atom, 'reload') - component.refs.reloadButton.dispatchEvent(new CustomEvent('click', {bubbles: true})) + component.refs.reloadButton.dispatchEvent( + new CustomEvent('click', { bubbles: true }) + ) expect(atom.reload).toHaveBeenCalled() }) }) @@ -223,19 +258,22 @@ describe('IncompatiblePackagesComponent', () => { describe('when the "Package Settings" button is clicked', () => { it('opens the settings panel for the package', () => { waitsForPromise(async () => { - let component = - new IncompatiblePackagesComponent({ - getActivePackages: () => packages, - getLoadedPackages: () => packages - }) - let {element} = component + let component = new IncompatiblePackagesComponent({ + getActivePackages: () => packages, + getLoadedPackages: () => packages + }) + let { element } = component jasmine.attachToDOM(element) await etchScheduler.getNextUpdatePromise() spyOn(atom.workspace, 'open') - element.querySelector('.incompatible-package:nth-child(2) button').dispatchEvent(new CustomEvent('click', {bubbles: true})) - expect(atom.workspace.open).toHaveBeenCalledWith('atom://config/packages/incompatible-2') + element + .querySelector('.incompatible-package:nth-child(2) button') + .dispatchEvent(new CustomEvent('click', { bubbles: true })) + expect(atom.workspace.open).toHaveBeenCalledWith( + 'atom://config/packages/incompatible-2' + ) }) }) }) diff --git a/packages/incompatible-packages/spec/incompatible-packages-spec.js b/packages/incompatible-packages/spec/incompatible-packages-spec.js index fa6e7e76a..c4e3587d8 100644 --- a/packages/incompatible-packages/spec/incompatible-packages-spec.js +++ b/packages/incompatible-packages/spec/incompatible-packages-spec.js @@ -36,7 +36,9 @@ describe('Incompatible packages', () => { ) spyOn(incompatiblePackage, 'isCompatible').andReturn(false) incompatiblePackage.incompatibleModules = [] - waitsForPromise(() => atom.packages.activatePackage("incompatible-packages")) + waitsForPromise(() => + atom.packages.activatePackage('incompatible-packages') + ) waits(1) }) @@ -63,13 +65,15 @@ describe('Incompatible packages', () => { describe('when there are no packages with incompatible native modules', () => { beforeEach(() => { - waitsForPromise(() => atom.packages.activatePackage("incompatible-packages")) + waitsForPromise(() => + atom.packages.activatePackage('incompatible-packages') + ) }) it('does not add an icon to the status bar', () => { let statusBarItemClasses = statusBar .getRightTiles() - .map((tile) => tile.getItem().className) + .map(tile => tile.getItem().className) expect(statusBarItemClasses).not.toContain('incompatible-packages') }) diff --git a/packages/line-ending-selector/lib/main.js b/packages/line-ending-selector/lib/main.js index 5945ed24f..74b1d44c0 100644 --- a/packages/line-ending-selector/lib/main.js +++ b/packages/line-ending-selector/lib/main.js @@ -1,7 +1,7 @@ 'use babel' import _ from 'underscore-plus' -import {CompositeDisposable, Disposable} from 'atom' +import { CompositeDisposable, Disposable } from 'atom' import SelectListView from 'atom-select-list' import StatusBarItem from './status-bar-item' import helpers from './helpers' @@ -17,48 +17,60 @@ let lineEndingListView = null export function activate () { disposables = new CompositeDisposable() - disposables.add(atom.commands.add('atom-text-editor', { - 'line-ending-selector:show': (event) => { - if (!modalPanel) { - lineEndingListView = new SelectListView({ - items: [{name: 'LF', value: '\n'}, {name: 'CRLF', value: '\r\n'}], - filterKeyForItem: (lineEnding) => lineEnding.name, - didConfirmSelection: (lineEnding) => { - setLineEnding(atom.workspace.getActiveTextEditor(), lineEnding.value) - modalPanel.hide() - }, - didCancelSelection: () => { - modalPanel.hide() - }, - elementForItem: (lineEnding) => { - const element = document.createElement('li') - element.textContent = lineEnding.name - return element - } - }) - modalPanel = atom.workspace.addModalPanel({item: lineEndingListView}) - disposables.add(new Disposable(() => { - lineEndingListView.destroy() - modalPanel.destroy() - modalPanel = null - })) + disposables.add( + atom.commands.add('atom-text-editor', { + 'line-ending-selector:show': event => { + if (!modalPanel) { + lineEndingListView = new SelectListView({ + items: [ + { name: 'LF', value: '\n' }, + { name: 'CRLF', value: '\r\n' } + ], + filterKeyForItem: lineEnding => lineEnding.name, + didConfirmSelection: lineEnding => { + setLineEnding( + atom.workspace.getActiveTextEditor(), + lineEnding.value + ) + modalPanel.hide() + }, + didCancelSelection: () => { + modalPanel.hide() + }, + elementForItem: lineEnding => { + const element = document.createElement('li') + element.textContent = lineEnding.name + return element + } + }) + modalPanel = atom.workspace.addModalPanel({ + item: lineEndingListView + }) + disposables.add( + new Disposable(() => { + lineEndingListView.destroy() + modalPanel.destroy() + modalPanel = null + }) + ) + } + + lineEndingListView.reset() + modalPanel.show() + lineEndingListView.focus() + }, + + 'line-ending-selector:convert-to-LF': event => { + const editorElement = event.target.closest('atom-text-editor') + setLineEnding(editorElement.getModel(), '\n') + }, + + 'line-ending-selector:convert-to-CRLF': event => { + const editorElement = event.target.closest('atom-text-editor') + setLineEnding(editorElement.getModel(), '\r\n') } - - lineEndingListView.reset() - modalPanel.show() - lineEndingListView.focus() - }, - - 'line-ending-selector:convert-to-LF': (event) => { - const editorElement = event.target.closest('atom-text-editor') - setLineEnding(editorElement.getModel(), '\n') - }, - - 'line-ending-selector:convert-to-CRLF': (event) => { - const editorElement = event.target.closest('atom-text-editor') - setLineEnding(editorElement.getModel(), '\r\n') - } - })) + }) + ) } export function deactivate () { @@ -70,8 +82,8 @@ export function consumeStatusBar (statusBar) { let currentBufferDisposable = null let tooltipDisposable = null - const updateTile = _.debounce((buffer) => { - getLineEndings(buffer).then((lineEndings) => { + const updateTile = _.debounce(buffer => { + getLineEndings(buffer).then(lineEndings => { if (lineEndings.size === 0) { let defaultLineEnding = getDefaultLineEnding() buffer.setPreferredLineEnding(defaultLineEnding) @@ -81,45 +93,49 @@ export function consumeStatusBar (statusBar) { }) }, 0) - disposables.add(atom.workspace.observeActiveTextEditor((editor) => { - if (currentBufferDisposable) currentBufferDisposable.dispose() + disposables.add( + atom.workspace.observeActiveTextEditor(editor => { + if (currentBufferDisposable) currentBufferDisposable.dispose() - if (editor && editor.getBuffer) { - let buffer = editor.getBuffer() - updateTile(buffer) - currentBufferDisposable = buffer.onDidChange(({oldText, newText}) => { - if (!statusBarItem.hasLineEnding('\n')) { - if (newText.indexOf('\n') >= 0) { + if (editor && editor.getBuffer) { + let buffer = editor.getBuffer() + updateTile(buffer) + currentBufferDisposable = buffer.onDidChange(({ oldText, newText }) => { + if (!statusBarItem.hasLineEnding('\n')) { + if (newText.indexOf('\n') >= 0) { + updateTile(buffer) + } + } else if (!statusBarItem.hasLineEnding('\r\n')) { + if (newText.indexOf('\r\n') >= 0) { + updateTile(buffer) + } + } else if (oldText.indexOf('\n')) { updateTile(buffer) } - } else if (!statusBarItem.hasLineEnding('\r\n')) { - if (newText.indexOf('\r\n') >= 0) { - updateTile(buffer) - } - } else if (oldText.indexOf('\n')) { - updateTile(buffer) + }) + } else { + statusBarItem.setLineEndings(new Set()) + currentBufferDisposable = null + } + + if (tooltipDisposable) { + disposables.remove(tooltipDisposable) + tooltipDisposable.dispose() + } + tooltipDisposable = atom.tooltips.add(statusBarItem.element, { + title () { + return `File uses ${statusBarItem.description()} line endings` } }) - } else { - statusBarItem.setLineEndings(new Set()) - currentBufferDisposable = null - } - - if (tooltipDisposable) { - disposables.remove(tooltipDisposable) - tooltipDisposable.dispose() - } - tooltipDisposable = atom.tooltips.add(statusBarItem.element, { - title () { - return `File uses ${statusBarItem.description()} line endings` - } + disposables.add(tooltipDisposable) }) - disposables.add(tooltipDisposable) - })) + ) - disposables.add(new Disposable(() => { - if (currentBufferDisposable) currentBufferDisposable.dispose() - })) + disposables.add( + new Disposable(() => { + if (currentBufferDisposable) currentBufferDisposable.dispose() + }) + ) statusBarItem.onClick(() => { const editor = atom.workspace.getActiveTextEditor() @@ -129,7 +145,7 @@ export function consumeStatusBar (statusBar) { ) }) - let tile = statusBar.addRightTile({item: statusBarItem, priority: 200}) + let tile = statusBar.addRightTile({ item: statusBarItem, priority: 200 }) disposables.add(new Disposable(() => tile.destroy())) } @@ -141,23 +157,22 @@ function getDefaultLineEnding () { return '\r\n' case 'OS Default': default: - return (helpers.getProcessPlatform() === 'win32') ? '\r\n' : '\n' + return helpers.getProcessPlatform() === 'win32' ? '\r\n' : '\n' } } function getLineEndings (buffer) { if (typeof buffer.find === 'function') { - return Promise.all([ - buffer.find(LFRegExp), - buffer.find(CRLFRegExp) - ]).then(([hasLF, hasCRLF]) => { - const result = new Set() - if (hasLF) result.add('\n') - if (hasCRLF) result.add('\r\n') - return result - }) + return Promise.all([buffer.find(LFRegExp), buffer.find(CRLFRegExp)]).then( + ([hasLF, hasCRLF]) => { + const result = new Set() + if (hasLF) result.add('\n') + if (hasCRLF) result.add('\r\n') + return result + } + ) } else { - return new Promise((resolve) => { + return new Promise(resolve => { const result = new Set() for (let i = 0; i < buffer.getLineCount() - 1; i++) { result.add(buffer.lineEndingForRow(i)) diff --git a/packages/line-ending-selector/lib/status-bar-item.js b/packages/line-ending-selector/lib/status-bar-item.js index da2f033c9..1684bc370 100644 --- a/packages/line-ending-selector/lib/status-bar-item.js +++ b/packages/line-ending-selector/lib/status-bar-item.js @@ -1,7 +1,6 @@ -const {Emitter} = require('atom') +const { Emitter } = require('atom') -module.exports = -class StatusBarItem { +module.exports = class StatusBarItem { constructor () { this.element = document.createElement('a') this.element.className = 'line-ending-tile inline-block' @@ -46,9 +45,13 @@ function lineEndingName (lineEndings) { function lineEndingDescription (lineEndings) { switch (lineEndingName(lineEndings)) { - case 'Mixed': return 'mixed' - case 'LF': return 'LF (Unix)' - case 'CRLF': return 'CRLF (Windows)' - default: return 'unknown' + case 'Mixed': + return 'mixed' + case 'LF': + return 'LF (Unix)' + case 'CRLF': + return 'CRLF (Windows)' + default: + return 'unknown' } } diff --git a/packages/line-ending-selector/spec/line-ending-selector-spec.js b/packages/line-ending-selector/spec/line-ending-selector-spec.js index 263f43c62..afc8f9db0 100644 --- a/packages/line-ending-selector/spec/line-ending-selector-spec.js +++ b/packages/line-ending-selector/spec/line-ending-selector-spec.js @@ -1,5 +1,5 @@ const helpers = require('../lib/helpers') -const {TextEditor} = require('atom') +const { TextEditor } = require('atom') describe('line ending selector', () => { let lineEndingTile @@ -30,7 +30,7 @@ describe('line ending selector', () => { beforeEach(() => { waitsForPromise(() => { - return atom.workspace.open('mixed-endings.md').then((e) => { + return atom.workspace.open('mixed-endings.md').then(e => { editor = e editorElement = atom.views.getView(editor) jasmine.attachToDOM(editorElement) @@ -41,7 +41,10 @@ describe('line ending selector', () => { describe('When "line-ending-selector:convert-to-LF" is run', () => { it('converts the file to LF line endings', () => { editorElement.focus() - atom.commands.dispatch(document.activeElement, 'line-ending-selector:convert-to-LF') + atom.commands.dispatch( + document.activeElement, + 'line-ending-selector:convert-to-LF' + ) expect(editor.getText()).toBe('Hello\nGoodbye\nMixed\n') }) }) @@ -49,7 +52,10 @@ describe('line ending selector', () => { describe('When "line-ending-selector:convert-to-LF" is run', () => { it('converts the file to CRLF line endings', () => { editorElement.focus() - atom.commands.dispatch(document.activeElement, 'line-ending-selector:convert-to-CRLF') + atom.commands.dispatch( + document.activeElement, + 'line-ending-selector:convert-to-CRLF' + ) expect(editor.getText()).toBe('Hello\r\nGoodbye\r\nMixed\r\n') }) }) @@ -58,30 +64,34 @@ describe('line ending selector', () => { describe('Status bar tile', () => { describe('when an empty file is opened', () => { it('uses the default line endings for the platform', () => { - waitsFor((done) => { + waitsFor(done => { spyOn(helpers, 'getProcessPlatform').andReturn('win32') - atom.workspace.open('').then((editor) => { + atom.workspace.open('').then(editor => { const subscription = lineEndingTile.onDidChange(() => { subscription.dispose() expect(lineEndingTile.element.textContent).toBe('CRLF') expect(editor.getBuffer().getPreferredLineEnding()).toBe('\r\n') - expect(getTooltipText(lineEndingTile.element)).toBe('File uses CRLF (Windows) line endings') + expect(getTooltipText(lineEndingTile.element)).toBe( + 'File uses CRLF (Windows) line endings' + ) done() }) }) }) - waitsFor((done) => { + waitsFor(done => { helpers.getProcessPlatform.andReturn('darwin') - atom.workspace.open('').then((editor) => { + atom.workspace.open('').then(editor => { const subscription = lineEndingTile.onDidChange(() => { subscription.dispose() expect(lineEndingTile.element.textContent).toBe('LF') expect(editor.getBuffer().getPreferredLineEnding()).toBe('\n') - expect(getTooltipText(lineEndingTile.element)).toBe('File uses LF (Unix) line endings') + expect(getTooltipText(lineEndingTile.element)).toBe( + 'File uses LF (Unix) line endings' + ) done() }) @@ -95,10 +105,10 @@ describe('line ending selector', () => { }) it('uses LF line endings, regardless of the platform', () => { - waitsFor((done) => { + waitsFor(done => { spyOn(helpers, 'getProcessPlatform').andReturn('win32') - atom.workspace.open('').then((editor) => { + atom.workspace.open('').then(editor => { lineEndingTile.onDidChange(() => { expect(lineEndingTile.element.textContent).toBe('LF') expect(editor.getBuffer().getPreferredLineEnding()).toBe('\n') @@ -115,8 +125,8 @@ describe('line ending selector', () => { }) it('uses CRLF line endings, regardless of the platform', () => { - waitsFor((done) => { - atom.workspace.open('').then((editor) => { + waitsFor(done => { + atom.workspace.open('').then(editor => { lineEndingTile.onDidChange(() => { expect(lineEndingTile.element.textContent).toBe('CRLF') expect(editor.getBuffer().getPreferredLineEnding()).toBe('\r\n') @@ -130,7 +140,7 @@ describe('line ending selector', () => { describe('when a file is opened that contains only CRLF line endings', () => { it('displays "CRLF" as the line ending', () => { - waitsFor((done) => { + waitsFor(done => { atom.workspace.open('windows-endings.md').then(() => { lineEndingTile.onDidChange(() => { expect(lineEndingTile.element.textContent).toBe('CRLF') @@ -143,8 +153,8 @@ describe('line ending selector', () => { describe('when a file is opened that contains only LF line endings', () => { it('displays "LF" as the line ending', () => { - waitsFor((done) => { - atom.workspace.open('unix-endings.md').then((editor) => { + waitsFor(done => { + atom.workspace.open('unix-endings.md').then(editor => { lineEndingTile.onDidChange(() => { expect(lineEndingTile.element.textContent).toBe('LF') expect(editor.getBuffer().getPreferredLineEnding()).toBe(null) @@ -157,7 +167,7 @@ describe('line ending selector', () => { describe('when a file is opened that contains mixed line endings', () => { it('displays "Mixed" as the line ending', () => { - waitsFor((done) => { + waitsFor(done => { atom.workspace.open('mixed-endings.md').then(() => { lineEndingTile.onDidChange(() => { expect(lineEndingTile.element.textContent).toBe('Mixed') @@ -174,10 +184,10 @@ describe('line ending selector', () => { beforeEach(() => { jasmine.attachToDOM(atom.views.getView(atom.workspace)) - waitsFor((done) => - atom.workspace.open('unix-endings.md').then(() => - lineEndingTile.onDidChange(done) - ) + waitsFor(done => + atom.workspace + .open('unix-endings.md') + .then(() => lineEndingTile.onDidChange(done)) ) }) @@ -192,7 +202,9 @@ describe('line ending selector', () => { lineEndingSelector = lineEndingModal.getItem() expect(lineEndingModal.isVisible()).toBe(true) - expect(lineEndingSelector.element.contains(document.activeElement)).toBe(true) + expect( + lineEndingSelector.element.contains(document.activeElement) + ).toBe(true) let listItems = lineEndingSelector.element.querySelectorAll('li') expect(listItems[0].textContent).toBe('LF') expect(listItems[1].textContent).toBe('CRLF') @@ -210,7 +222,9 @@ describe('line ending selector', () => { lineEndingSelector = lineEndingModal.getItem() expect(lineEndingModal.isVisible()).toBe(true) - expect(lineEndingSelector.element.contains(document.activeElement)).toBe(true) + expect( + lineEndingSelector.element.contains(document.activeElement) + ).toBe(true) let listItems = lineEndingSelector.element.querySelectorAll('li') expect(listItems[0].textContent).toBe('LF') expect(listItems[1].textContent).toBe('CRLF') @@ -264,12 +278,12 @@ describe('line ending selector', () => { }) }) - describe('when the buffer\'s line endings change', () => { + describe("when the buffer's line endings change", () => { let editor beforeEach(() => { - waitsFor((done) => { - atom.workspace.open('unix-endings.md').then((e) => { + waitsFor(done => { + atom.workspace.open('unix-endings.md').then(e => { editor = e lineEndingTile.onDidChange(done) }) @@ -291,33 +305,47 @@ describe('line ending selector', () => { }) expect(lineEndingTile.element.textContent).toBe('LF') - expect(getTooltipText(lineEndingTile.element)).toBe('File uses LF (Unix) line endings') + expect(getTooltipText(lineEndingTile.element)).toBe( + 'File uses LF (Unix) line endings' + ) - waitsFor((done) => { + waitsFor(done => { editor.setTextInBufferRange([[0, 0], [0, 0]], '... ') - editor.setTextInBufferRange([[0, Infinity], [1, 0]], '\r\n', {normalizeLineEndings: false}) + editor.setTextInBufferRange([[0, Infinity], [1, 0]], '\r\n', { + normalizeLineEndings: false + }) lineEndingTile.onDidChange(done) }) runs(() => { expect(tileUpdateCount).toBe(1) expect(lineEndingTile.element.textContent).toBe('Mixed') - expect(getTooltipText(lineEndingTile.element)).toBe('File uses mixed line endings') + expect(getTooltipText(lineEndingTile.element)).toBe( + 'File uses mixed line endings' + ) }) - waitsFor((done) => { - atom.commands.dispatch(editor.getElement(), 'line-ending-selector:convert-to-CRLF') + waitsFor(done => { + atom.commands.dispatch( + editor.getElement(), + 'line-ending-selector:convert-to-CRLF' + ) lineEndingTile.onDidChange(done) }) runs(() => { expect(tileUpdateCount).toBe(2) expect(lineEndingTile.element.textContent).toBe('CRLF') - expect(getTooltipText(lineEndingTile.element)).toBe('File uses CRLF (Windows) line endings') + expect(getTooltipText(lineEndingTile.element)).toBe( + 'File uses CRLF (Windows) line endings' + ) }) - waitsFor((done) => { - atom.commands.dispatch(editor.getElement(), 'line-ending-selector:convert-to-LF') + waitsFor(done => { + atom.commands.dispatch( + editor.getElement(), + 'line-ending-selector:convert-to-LF' + ) lineEndingTile.onDidChange(done) }) diff --git a/packages/link/lib/link.js b/packages/link/lib/link.js index 4b2443cfb..c7add2f63 100644 --- a/packages/link/lib/link.js +++ b/packages/link/lib/link.js @@ -1,12 +1,16 @@ const url = require('url') -const {shell} = require('electron') +const { shell } = require('electron') const _ = require('underscore-plus') const LINK_SCOPE_REGEX = /markup\.underline\.link/ module.exports = { activate () { - this.commandDisposable = atom.commands.add('atom-text-editor', 'link:open', () => this.openLink()) + this.commandDisposable = atom.commands.add( + 'atom-text-editor', + 'link:open', + () => this.openLink() + ) }, deactivate () { @@ -24,8 +28,9 @@ module.exports = { link = this.linkForName(editor, link) } - const {protocol} = url.parse(link) - if (protocol === 'http:' || protocol === 'https:' || protocol === 'atom:') shell.openExternal(link) + const { protocol } = url.parse(link) + if (protocol === 'http:' || protocol === 'https:' || protocol === 'atom:') + shell.openExternal(link) }, // Get the link under the cursor in the editor @@ -47,7 +52,11 @@ module.exports = { // Returns a {String} link or undefined if no link found. linkAtPosition (editor, bufferPosition) { const token = editor.tokenForBufferPosition(bufferPosition) - if (token && token.value && token.scopes.some(scope => LINK_SCOPE_REGEX.test(scope))) { + if ( + token && + token.value && + token.scopes.some(scope => LINK_SCOPE_REGEX.test(scope)) + ) { return token.value } }, @@ -65,11 +74,18 @@ module.exports = { // Returns a {String} link linkForName (editor, linkName) { let link = linkName - const regex = new RegExp(`^\\s*\\[${_.escapeRegExp(linkName)}\\]\\s*:\\s*(.+)$`, 'g') - editor.backwardsScanInBufferRange(regex, [[0, 0], [Infinity, Infinity]], ({match, stop}) => { - link = match[1] - stop() - }) + const regex = new RegExp( + `^\\s*\\[${_.escapeRegExp(linkName)}\\]\\s*:\\s*(.+)$`, + 'g' + ) + editor.backwardsScanInBufferRange( + regex, + [[0, 0], [Infinity, Infinity]], + ({ match, stop }) => { + link = match[1] + stop() + } + ) return link } } diff --git a/packages/link/spec/async-spec-helpers.js b/packages/link/spec/async-spec-helpers.js index 73002c049..5a233973e 100644 --- a/packages/link/spec/async-spec-helpers.js +++ b/packages/link/spec/async-spec-helpers.js @@ -18,7 +18,7 @@ export function afterEach (fn) { }) } -['it', 'fit', 'ffit', 'fffit'].forEach(function (name) { +;['it', 'fit', 'ffit', 'fffit'].forEach(function (name) { module.exports[name] = function (description, fn) { if (fn === undefined) { global[name](description) @@ -34,7 +34,10 @@ export function afterEach (fn) { } }) -export async function conditionPromise (condition, description = 'anonymous condition') { +export async function conditionPromise ( + condition, + description = 'anonymous condition' +) { const startTime = Date.now() while (true) { diff --git a/packages/link/spec/link-spec.js b/packages/link/spec/link-spec.js index 976261cd4..0c0b817a2 100644 --- a/packages/link/spec/link-spec.js +++ b/packages/link/spec/link-spec.js @@ -1,6 +1,6 @@ -const {shell} = require('electron') +const { shell } = require('electron') -const {it, fit, ffit, afterEach, beforeEach} = require('./async-spec-helpers') // eslint-disable-line no-unused-vars +const { it, fit, ffit, afterEach, beforeEach } = require('./async-spec-helpers') // eslint-disable-line no-unused-vars describe('link package', () => { beforeEach(async () => { @@ -47,13 +47,15 @@ describe('link package', () => { // only works in Atom >= 1.33.0 // https://github.com/atom/link/pull/33#issuecomment-419643655 const atomVersion = atom.getVersion().split('.') - console.error("atomVersion", atomVersion) + console.error('atomVersion', atomVersion) if (+atomVersion[0] > 1 || +atomVersion[1] >= 33) { it("opens an 'atom:' link", async () => { await atom.workspace.open('sample.md') const editor = atom.workspace.getActiveTextEditor() - editor.setText('// "atom://core/open/file?filename=sample.js&line=1&column=2"') + editor.setText( + '// "atom://core/open/file?filename=sample.js&line=1&column=2"' + ) spyOn(shell, 'openExternal') atom.commands.dispatch(atom.views.getView(editor), 'link:open') @@ -63,21 +65,27 @@ describe('link package', () => { atom.commands.dispatch(atom.views.getView(editor), 'link:open') expect(shell.openExternal).toHaveBeenCalled() - expect(shell.openExternal.argsForCall[0][0]).toBe('atom://core/open/file?filename=sample.js&line=1&column=2') + expect(shell.openExternal.argsForCall[0][0]).toBe( + 'atom://core/open/file?filename=sample.js&line=1&column=2' + ) shell.openExternal.reset() editor.setCursorBufferPosition([0, 8]) atom.commands.dispatch(atom.views.getView(editor), 'link:open') expect(shell.openExternal).toHaveBeenCalled() - expect(shell.openExternal.argsForCall[0][0]).toBe('atom://core/open/file?filename=sample.js&line=1&column=2') + expect(shell.openExternal.argsForCall[0][0]).toBe( + 'atom://core/open/file?filename=sample.js&line=1&column=2' + ) shell.openExternal.reset() editor.setCursorBufferPosition([0, 60]) atom.commands.dispatch(atom.views.getView(editor), 'link:open') expect(shell.openExternal).toHaveBeenCalled() - expect(shell.openExternal.argsForCall[0][0]).toBe('atom://core/open/file?filename=sample.js&line=1&column=2') + expect(shell.openExternal.argsForCall[0][0]).toBe( + 'atom://core/open/file?filename=sample.js&line=1&column=2' + ) }) } @@ -91,8 +99,7 @@ you should [click][here] you should not [click][her] [here]: http://github.com\ -` - ) +`) spyOn(shell, 'openExternal') editor.setCursorBufferPosition([0, 0]) @@ -110,8 +117,7 @@ you should not [click][her] atom.commands.dispatch(atom.views.getView(editor), 'link:open') expect(shell.openExternal).not.toHaveBeenCalled() - }) - ) + })) it('does not open non http/https/atom links', async () => { await atom.workspace.open('sample.md') diff --git a/packages/one-dark-ui/spec/theme-spec.js b/packages/one-dark-ui/spec/theme-spec.js index 5ff5aa3db..a43ea4f7c 100644 --- a/packages/one-dark-ui/spec/theme-spec.js +++ b/packages/one-dark-ui/spec/theme-spec.js @@ -14,31 +14,45 @@ describe(`${themeName} theme`, () => { it('allows the tab sizing to be set via config', () => { atom.config.set(`${themeName}.tabSizing`, 'Maximum') - expect(document.documentElement.getAttribute(`theme-${themeName}-tabsizing`)).toBe('maximum') + expect( + document.documentElement.getAttribute(`theme-${themeName}-tabsizing`) + ).toBe('maximum') }) it('allows the tab sizing to be set via config', () => { atom.config.set(`${themeName}.tabSizing`, 'Minimum') - expect(document.documentElement.getAttribute(`theme-${themeName}-tabsizing`)).toBe('minimum') + expect( + document.documentElement.getAttribute(`theme-${themeName}-tabsizing`) + ).toBe('minimum') }) it('allows the tab close button to be shown on the left via config', () => { atom.config.set(`${themeName}.tabCloseButton`, 'Left') - expect(document.documentElement.getAttribute(`theme-${themeName}-tab-close-button`)).toBe('left') + expect( + document.documentElement.getAttribute( + `theme-${themeName}-tab-close-button` + ) + ).toBe('left') }) it('allows the dock toggle buttons to be hidden via config', () => { atom.config.set(`${themeName}.hideDockButtons`, true) - expect(document.documentElement.getAttribute(`theme-${themeName}-dock-buttons`)).toBe('hidden') + expect( + document.documentElement.getAttribute(`theme-${themeName}-dock-buttons`) + ).toBe('hidden') }) it('allows the tree-view headers to be sticky via config', () => { atom.config.set(`${themeName}.stickyHeaders`, true) - expect(document.documentElement.getAttribute(`theme-${themeName}-sticky-headers`)).toBe('sticky') + expect( + document.documentElement.getAttribute(`theme-${themeName}-sticky-headers`) + ).toBe('sticky') }) it('allows the tree-view headers to not be sticky via config', () => { atom.config.set(`${themeName}.stickyHeaders`, false) - expect(document.documentElement.getAttribute(`theme-${themeName}-sticky-headers`)).toBe(null) + expect( + document.documentElement.getAttribute(`theme-${themeName}-sticky-headers`) + ).toBe(null) }) }) diff --git a/packages/one-light-ui/spec/theme-spec.js b/packages/one-light-ui/spec/theme-spec.js index a0e72875b..862d2ef5e 100644 --- a/packages/one-light-ui/spec/theme-spec.js +++ b/packages/one-light-ui/spec/theme-spec.js @@ -14,31 +14,45 @@ describe(`${themeName} theme`, () => { it('allows the tab sizing to be set via config', () => { atom.config.set(`${themeName}.tabSizing`, 'Maximum') - expect(document.documentElement.getAttribute(`theme-${themeName}-tabsizing`)).toBe('maximum') + expect( + document.documentElement.getAttribute(`theme-${themeName}-tabsizing`) + ).toBe('maximum') }) it('allows the tab sizing to be set via config', () => { atom.config.set(`${themeName}.tabSizing`, 'Minimum') - expect(document.documentElement.getAttribute(`theme-${themeName}-tabsizing`)).toBe('minimum') + expect( + document.documentElement.getAttribute(`theme-${themeName}-tabsizing`) + ).toBe('minimum') }) it('allows the tab close button to be shown on the left via config', () => { atom.config.set(`${themeName}.tabCloseButton`, 'Left') - expect(document.documentElement.getAttribute(`theme-${themeName}-tab-close-button`)).toBe('left') + expect( + document.documentElement.getAttribute( + `theme-${themeName}-tab-close-button` + ) + ).toBe('left') }) it('allows the dock toggle buttons to be hidden via config', () => { atom.config.set(`${themeName}.hideDockButtons`, true) - expect(document.documentElement.getAttribute(`theme-${themeName}-dock-buttons`)).toBe('hidden') + expect( + document.documentElement.getAttribute(`theme-${themeName}-dock-buttons`) + ).toBe('hidden') }) it('allows the tree-view headers to be sticky via config', () => { atom.config.set(`${themeName}.stickyHeaders`, true) - expect(document.documentElement.getAttribute(`theme-${themeName}-sticky-headers`)).toBe('sticky') + expect( + document.documentElement.getAttribute(`theme-${themeName}-sticky-headers`) + ).toBe('sticky') }) it('allows the tree-view headers to not be sticky via config', () => { atom.config.set(`${themeName}.stickyHeaders`, false) - expect(document.documentElement.getAttribute(`theme-${themeName}-sticky-headers`)).toBe(null) + expect( + document.documentElement.getAttribute(`theme-${themeName}-sticky-headers`) + ).toBe(null) }) }) From f6db819485e53a18df11be38c08286aa70d26932 Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Thu, 21 Feb 2019 15:05:44 +0100 Subject: [PATCH 084/112] Remove unused variables from specs --- packages/about/spec/about-spec.js | 9 +-------- packages/about/spec/about-status-bar-spec.js | 5 +---- packages/about/spec/update-view-spec.js | 9 +-------- packages/dev-live-reload/spec/ui-watcher-spec.js | 4 +--- 4 files changed, 4 insertions(+), 23 deletions(-) diff --git a/packages/about/spec/about-spec.js b/packages/about/spec/about-spec.js index a991457ff..f3352e806 100644 --- a/packages/about/spec/about-spec.js +++ b/packages/about/spec/about-spec.js @@ -1,11 +1,4 @@ -const { - it, - fit, - ffit, - fffit, - beforeEach, - afterEach -} = require('./helpers/async-spec-helpers') // eslint-disable-line no-unused-vars +const { it, beforeEach } = require('./helpers/async-spec-helpers') describe('About', () => { let workspaceElement diff --git a/packages/about/spec/about-status-bar-spec.js b/packages/about/spec/about-status-bar-spec.js index 99de30010..4190674df 100644 --- a/packages/about/spec/about-status-bar-spec.js +++ b/packages/about/spec/about-status-bar-spec.js @@ -1,12 +1,9 @@ const { it, - fit, - ffit, - fffit, beforeEach, afterEach, conditionPromise -} = require('./helpers/async-spec-helpers') // eslint-disable-line no-unused-vars +} = require('./helpers/async-spec-helpers') const MockUpdater = require('./mocks/updater') describe('the status bar', () => { diff --git a/packages/about/spec/update-view-spec.js b/packages/about/spec/update-view-spec.js index fdb9a02b4..2f593b5bd 100644 --- a/packages/about/spec/update-view-spec.js +++ b/packages/about/spec/update-view-spec.js @@ -1,12 +1,5 @@ const { shell } = require('electron') -const { - it, - fit, - ffit, - fffit, - beforeEach, - afterEach -} = require('./helpers/async-spec-helpers') // eslint-disable-line no-unused-vars +const { it, beforeEach, afterEach } = require('./helpers/async-spec-helpers') const main = require('../lib/main') const AboutView = require('../lib/components/about-view') const UpdateView = require('../lib/components/update-view') diff --git a/packages/dev-live-reload/spec/ui-watcher-spec.js b/packages/dev-live-reload/spec/ui-watcher-spec.js index 0730619d8..a8dd6e86d 100644 --- a/packages/dev-live-reload/spec/ui-watcher-spec.js +++ b/packages/dev-live-reload/spec/ui-watcher-spec.js @@ -4,12 +4,10 @@ const UIWatcher = require('../lib/ui-watcher') const { it, - fit, - ffit, afterEach, beforeEach, conditionPromise -} = require('./async-spec-helpers') // eslint-disable-line no-unused-vars +} = require('./async-spec-helpers') describe('UIWatcher', () => { let uiWatcher = null From 11206eca7659fb865c81e69c6510468461cf808d Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Thu, 21 Feb 2019 15:08:30 +0100 Subject: [PATCH 085/112] Add curly braces around if statements --- packages/dev-live-reload/lib/package-watcher.js | 3 ++- packages/dev-live-reload/lib/ui-watcher.js | 13 +++++++++---- packages/dev-live-reload/spec/ui-watcher-spec.js | 4 +--- packages/link/lib/link.js | 3 ++- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/packages/dev-live-reload/lib/package-watcher.js b/packages/dev-live-reload/lib/package-watcher.js index a5be2337c..2cb8096dd 100644 --- a/packages/dev-live-reload/lib/package-watcher.js +++ b/packages/dev-live-reload/lib/package-watcher.js @@ -23,8 +23,9 @@ module.exports = class PackageWatcher extends Watcher { const stylesheetsPath = this.pack.getStylesheetsPath() - if (fs.isDirectorySync(stylesheetsPath)) + if (fs.isDirectorySync(stylesheetsPath)) { this.watchDirectory(stylesheetsPath) + } const stylesheetPaths = new Set(this.pack.getStylesheetPaths()) const onFile = stylesheetPath => stylesheetPaths.add(stylesheetPath) diff --git a/packages/dev-live-reload/lib/ui-watcher.js b/packages/dev-live-reload/lib/ui-watcher.js index 9aa3eefde..eb5ac2635 100644 --- a/packages/dev-live-reload/lib/ui-watcher.js +++ b/packages/dev-live-reload/lib/ui-watcher.js @@ -57,19 +57,21 @@ module.exports = class UIWatcher { } watchTheme (theme) { - if (PackageWatcher.supportsPackage(theme, 'theme')) + if (PackageWatcher.supportsPackage(theme, 'theme')) { this.watchedThemes.set( theme.name, this.createWatcher(new PackageWatcher(theme)) ) + } } watchPackage (pack) { - if (PackageWatcher.supportsPackage(pack, 'atom')) + if (PackageWatcher.supportsPackage(pack, 'atom')) { this.watchedPackages.set( pack.name, this.createWatcher(new PackageWatcher(pack)) ) + } } createWatcher (watcher) { @@ -87,12 +89,15 @@ module.exports = class UIWatcher { reloadAll () { this.baseTheme.loadAllStylesheets() for (const pack of atom.packages.getActivePackages()) { - if (PackageWatcher.supportsPackage(pack, 'atom')) pack.reloadStylesheets() + if (PackageWatcher.supportsPackage(pack, 'atom')) { + pack.reloadStylesheets() + } } for (const theme of atom.themes.getActiveThemes()) { - if (PackageWatcher.supportsPackage(theme, 'theme')) + if (PackageWatcher.supportsPackage(theme, 'theme')) { theme.reloadStylesheets() + } } } diff --git a/packages/dev-live-reload/spec/ui-watcher-spec.js b/packages/dev-live-reload/spec/ui-watcher-spec.js index a8dd6e86d..ffce8034c 100644 --- a/packages/dev-live-reload/spec/ui-watcher-spec.js +++ b/packages/dev-live-reload/spec/ui-watcher-spec.js @@ -77,9 +77,7 @@ describe('UIWatcher', () => { const pack = atom.packages.getActivePackages()[0] spyOn(pack, 'reloadStylesheets') - uiWatcher.watchers[ - uiWatcher.watchers.length - 1 - ].entities[1].emitter.emit('did-change') + uiWatcher.watchers[uiWatcher.watchers.length - 1].entities[1].emitter.emit('did-change') expect(pack.reloadStylesheets).toHaveBeenCalled() }) diff --git a/packages/link/lib/link.js b/packages/link/lib/link.js index c7add2f63..005c9e614 100644 --- a/packages/link/lib/link.js +++ b/packages/link/lib/link.js @@ -29,8 +29,9 @@ module.exports = { } const { protocol } = url.parse(link) - if (protocol === 'http:' || protocol === 'https:' || protocol === 'atom:') + if (protocol === 'http:' || protocol === 'https:' || protocol === 'atom:') { shell.openExternal(link) + } }, // Get the link under the cursor in the editor From e734434811796adfc61cf1e917ee5930b456c9c8 Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Mon, 25 Feb 2019 12:48:41 +0100 Subject: [PATCH 086/112] Small linter fixes --- packages/exception-reporting/lib/reporter.js | 1 - .../incompatible-packages/lib/incompatible-packages-component.js | 1 - 2 files changed, 2 deletions(-) diff --git a/packages/exception-reporting/lib/reporter.js b/packages/exception-reporting/lib/reporter.js index a702134a1..e4becff04 100644 --- a/packages/exception-reporting/lib/reporter.js +++ b/packages/exception-reporting/lib/reporter.js @@ -1,6 +1,5 @@ /** @babel */ -import _ from 'underscore-plus' import os from 'os' import stackTrace from 'stack-trace' import fs from 'fs-plus' diff --git a/packages/incompatible-packages/lib/incompatible-packages-component.js b/packages/incompatible-packages/lib/incompatible-packages-component.js index 0f7bd263c..478e9682d 100644 --- a/packages/incompatible-packages/lib/incompatible-packages-component.js +++ b/packages/incompatible-packages/lib/incompatible-packages-component.js @@ -1,7 +1,6 @@ /** @babel */ /** @jsx etch.dom */ -import { BufferedProcess } from 'atom' import etch from 'etch' import VIEW_URI from './view-uri' From 20ec642da1779f86695f0955b16bbbfbf3f486a5 Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Mon, 25 Feb 2019 12:27:10 +0100 Subject: [PATCH 087/112] Lint fixture file from git-diff package --- packages/git-diff/spec/diff-list-view-spec.js | 6 ++-- .../working-dir/git.git/COMMIT_EDITMSG | 0 .../fixtures/working-dir/git.git/MERGE_RR | 0 .../spec/fixtures/working-dir/git.git/index | Bin 217 -> 217 bytes .../fixtures/working-dir/git.git/info/refs | 1 + .../fixtures/working-dir/git.git/logs/HEAD | 0 .../git.git/logs/refs/heads/master | 0 .../3e/715502b971d4f8282d1e05a8ccfad6f7037910 | Bin 27 -> 0 bytes .../90/820108a054b6f49c0d21031313244b6f7d69dc | 3 -- .../f1/4149b7b38a0a972c46557877caff6c9fe76476 | Bin 81 -> 0 bytes .../fb/33b0b43b20b7f9de1bca79e192fa2e30dbeb6b | Bin 227 -> 0 bytes .../working-dir/git.git/objects/info/packs | 2 ++ ...30b46ead026befe94c88f5591a6d3dfdca4e95.idx | Bin 0 -> 1380 bytes ...0b46ead026befe94c88f5591a6d3dfdca4e95.pack | Bin 0 -> 1127 bytes .../fixtures/working-dir/git.git/packed-refs | 2 ++ .../working-dir/git.git/refs/heads/master | 1 - .../spec/fixtures/working-dir/sample.js | 30 +++++++++++------- packages/git-diff/spec/git-diff-spec.js | 16 +++++----- 18 files changed, 34 insertions(+), 27 deletions(-) create mode 100644 packages/git-diff/spec/fixtures/working-dir/git.git/COMMIT_EDITMSG create mode 100644 packages/git-diff/spec/fixtures/working-dir/git.git/MERGE_RR create mode 100644 packages/git-diff/spec/fixtures/working-dir/git.git/info/refs create mode 100644 packages/git-diff/spec/fixtures/working-dir/git.git/logs/HEAD create mode 100644 packages/git-diff/spec/fixtures/working-dir/git.git/logs/refs/heads/master delete mode 100644 packages/git-diff/spec/fixtures/working-dir/git.git/objects/3e/715502b971d4f8282d1e05a8ccfad6f7037910 delete mode 100644 packages/git-diff/spec/fixtures/working-dir/git.git/objects/90/820108a054b6f49c0d21031313244b6f7d69dc delete mode 100644 packages/git-diff/spec/fixtures/working-dir/git.git/objects/f1/4149b7b38a0a972c46557877caff6c9fe76476 delete mode 100644 packages/git-diff/spec/fixtures/working-dir/git.git/objects/fb/33b0b43b20b7f9de1bca79e192fa2e30dbeb6b create mode 100644 packages/git-diff/spec/fixtures/working-dir/git.git/objects/info/packs create mode 100644 packages/git-diff/spec/fixtures/working-dir/git.git/objects/pack/pack-fb30b46ead026befe94c88f5591a6d3dfdca4e95.idx create mode 100644 packages/git-diff/spec/fixtures/working-dir/git.git/objects/pack/pack-fb30b46ead026befe94c88f5591a6d3dfdca4e95.pack create mode 100644 packages/git-diff/spec/fixtures/working-dir/git.git/packed-refs delete mode 100644 packages/git-diff/spec/fixtures/working-dir/git.git/refs/heads/master diff --git a/packages/git-diff/spec/diff-list-view-spec.js b/packages/git-diff/spec/diff-list-view-spec.js index 5fba8eba1..d78560acc 100644 --- a/packages/git-diff/spec/diff-list-view-spec.js +++ b/packages/git-diff/spec/diff-list-view-spec.js @@ -22,7 +22,7 @@ describe('git-diff:toggle-diff-list', () => { runs(() => { editor = atom.workspace.getActiveTextEditor() - editor.setCursorBufferPosition([4, 29]) + editor.setCursorBufferPosition([3, 28]) editor.insertText('a') atom.commands.dispatch(editor.getElement(), 'git-diff:toggle-diff-list') }) @@ -35,7 +35,7 @@ describe('git-diff:toggle-diff-list', () => { it('shows a list of all diff hunks', () => { diffListView = document.querySelector('.diff-list-view ol') - expect(diffListView.textContent).toBe('while(items.length > 0) {a-5,1 +5,1') + expect(diffListView.textContent).toBe('var pivot = items.shift(a)-4,1 +4,1') }) it('moves the cursor to the selected hunk', () => { @@ -44,6 +44,6 @@ describe('git-diff:toggle-diff-list', () => { document.querySelector('.diff-list-view'), 'core:confirm' ) - expect(editor.getCursorBufferPosition()).toEqual([4, 4]) + expect(editor.getCursorBufferPosition()).toEqual([3, 4]) }) }) diff --git a/packages/git-diff/spec/fixtures/working-dir/git.git/COMMIT_EDITMSG b/packages/git-diff/spec/fixtures/working-dir/git.git/COMMIT_EDITMSG new file mode 100644 index 000000000..e69de29bb diff --git a/packages/git-diff/spec/fixtures/working-dir/git.git/MERGE_RR b/packages/git-diff/spec/fixtures/working-dir/git.git/MERGE_RR new file mode 100644 index 000000000..e69de29bb diff --git a/packages/git-diff/spec/fixtures/working-dir/git.git/index b/packages/git-diff/spec/fixtures/working-dir/git.git/index index 7b94a97970cb53622608d2c0240f383c89e74d4e..17dcc2005c6d34768d09f5f9580968af969fd734 100644 GIT binary patch delta 176 zcmcb~c$2Z-#WTp6fq{Vugky@YO;A~v!VaSu85md@;>4R77#f!_Ffe`vsu2Owho1k9 zW{o|&YVz9txyh$`w;HpW3&b;U7ANKwr6>y0$}R_iss?tRs`mLt=r+F+en)Q>rRrQ4L&#tM~%e$ZpS{3Wd7fYjoE FDFA_iI(`5E delta 176 zcmcb~c$2Z-#WTp6fq{VugoDBbwShDPjAmqDU|~^GE@NP5T*AP>_!TH60;FgBHr}ws zT4DRod(x*WA5QwEXK?#AWiT`_Ff%bxC{D~R$Vt`9DrWd?ykU#A!uFr{q)$~oob*f2 n;P&fmR7E8fB@A|jp-ejqul&%^m1A9T=GV3F%#{KFDZn9!hz}*T diff --git a/packages/git-diff/spec/fixtures/working-dir/git.git/objects/fb/33b0b43b20b7f9de1bca79e192fa2e30dbeb6b b/packages/git-diff/spec/fixtures/working-dir/git.git/objects/fb/33b0b43b20b7f9de1bca79e192fa2e30dbeb6b deleted file mode 100644 index e9ffee6407bbb200388e6ccbecf97457892a94e9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 227 zcmV<90382#0bNkbP6Htnb=|KxOGqZ9OmjwG%cPIItCLU@jpTP(vxu>8wO-@v-dBxlIWm2!4c3W8{g~4?p^1@WLCCf* zb9fb*g@skT^J_EjtlV%oX`@Wvo~b2E(@oNre1Ev#@aX#W=QB?1V*lf8=Djo1`Rv@K zJ6k3{{~OI3dv?|2wf%FGPxWp!W;GXx|LEwseRCJrbRDQ4 zxZ7T-V`(Q_ws=00y!`UF@rEtd3fq6)lRj1XaMCY5gWIpOZT?98e{WFD6cP}xQoE+* zek*tO*~S&ir52h53TziV^il4`13jJIEqnz+0&{`cYc{Yr0EG_^ki8zrHUMTLcOd&W zki84YZUoA00MciF8*Is2%ar~8rBBD#NU2=gzo-1Bx@O6&*vWDE=!E@FAHr_=dGV}zx*WUY&swrE}GOGZ--2d3<%)5qLB zq8!)X+VXReqUHQW3-;PgQ_7#xsa`qvhwrBdjp8MrYuEJKmK4tP4~krUKsvqGW{W|G z+w+ZK|88$R_V~Q$^o_N5GUC+V&71v$L2|Y8{r4;lDiw38&-|DXxP6I+X{e&1uA#2w z*)vKvl{7CNu+hDFP3^2mku4dRI%t?j3>7hZF=H9@;LS!F|Jl+t|dgcU^2%lP2rYY1c&lSniV&=6~?1x;s4V zy`sk2lH0-eBc|O6dTS!(Jncjw$BSDJI87Hmh_=+%mic3QuHcD#Npj2EABq36%DrTk zpVD2)d^I99%Vo=ki7HDgu8Vko{4al`PC}u0m*2i!DGz=w|D^MXb@ytA*_&i4=HyQB z%{#0h(E8o-sE*^RfX!!WZrcB84 zYob91ChM=*X(#nY=<({+Mia|2YoqT@ebj$=mB6=Uo}t##TYf426P-8xVuIs8>B{2r z+zs2MG@bg|O#2U?p7SeuZNtWSxfefquGykruy9YX(Z;Sik?hi^pOSi0=T={^p16lg zvT5(86a%})C3gJ5C3B>Xo#mguwl~bWVh;DY^S+@Po@+HOK4xN&P-5P+nx$fnv5A3! zv0xz6rB(bhpJn>(&8m~xzn`nke|0zOOqQNNe#fE}OBS^pTxT#PGyUOI zd8u7RYqZb(+4XJi&L9Q`m1 z#6Q$-&KK|V55B$5!Rw0BLV2GToXx@@SJ*T|U9tb4OSQAx>rU39TUJ~rm%6&HtW>q) zg1g0v%XQ{UNr7#q)0qUOq^CSv;%Ae8B*S**#ETb2l_I#+x`VvEx<83@eeU)$aZt;6 zrTYB2s`|7Hk(6mql`9e|H*B0WOX2O-Ym?OtUu}vgz8b~Mux_!Q?QerEd25-n-@o+f O_!=pdYy0<<-&6o5ToB9v literal 0 HcmV?d00001 diff --git a/packages/git-diff/spec/fixtures/working-dir/git.git/packed-refs b/packages/git-diff/spec/fixtures/working-dir/git.git/packed-refs new file mode 100644 index 000000000..1a97c394d --- /dev/null +++ b/packages/git-diff/spec/fixtures/working-dir/git.git/packed-refs @@ -0,0 +1,2 @@ +# pack-refs with: peeled fully-peeled sorted +745ed7547d15a61bc4ee7e182615590f44aca201 refs/heads/master diff --git a/packages/git-diff/spec/fixtures/working-dir/git.git/refs/heads/master b/packages/git-diff/spec/fixtures/working-dir/git.git/refs/heads/master deleted file mode 100644 index 40efdd18b..000000000 --- a/packages/git-diff/spec/fixtures/working-dir/git.git/refs/heads/master +++ /dev/null @@ -1 +0,0 @@ -90820108a054b6f49c0d21031313244b6f7d69dc diff --git a/packages/git-diff/spec/fixtures/working-dir/sample.js b/packages/git-diff/spec/fixtures/working-dir/sample.js index fb33b0b43..e7fd5b055 100644 --- a/packages/git-diff/spec/fixtures/working-dir/sample.js +++ b/packages/git-diff/spec/fixtures/working-dir/sample.js @@ -1,13 +1,19 @@ -var quicksort = function () { - var sort = function(items) { - if (items.length <= 1) return items; - var pivot = items.shift(), current, left = [], right = []; - while(items.length > 0) { - current = items.shift(); - current < pivot ? left.push(current) : right.push(current); - } - return sort(left).concat(pivot).concat(sort(right)); - }; +module.exports.quicksort = function () { + var sort = function (items) { + if (items.length <= 1) return items + var pivot = items.shift() + var current + var left = [] + var right = [] - return sort(Array.apply(this, arguments)); -}; \ No newline at end of file + while (items.length > 0) { + current = items.shift() + current < pivot ? left.push(current) : right.push(current) + } + return sort(left) + .concat(pivot) + .concat(sort(right)) + } + + return sort(Array.apply(this, arguments)) +} diff --git a/packages/git-diff/spec/git-diff-spec.js b/packages/git-diff/spec/git-diff-spec.js index badb15f76..950fec71d 100644 --- a/packages/git-diff/spec/git-diff-spec.js +++ b/packages/git-diff/spec/git-diff-spec.js @@ -156,13 +156,13 @@ describe('GitDiff package', () => { describe('move-to-next-diff/move-to-previous-diff events', () => { it('moves the cursor to first character of the next/previous diff line', () => { editor.insertText('a') - editor.setCursorBufferPosition([5]) + editor.setCursorBufferPosition([9]) editor.deleteLine() advanceClock(editor.getBuffer().stoppedChangingDelay) editor.setCursorBufferPosition([0]) atom.commands.dispatch(editorElement, 'git-diff:move-to-next-diff') - expect(editor.getCursorBufferPosition()).toEqual([4, 4]) + expect(editor.getCursorBufferPosition()).toEqual([8, 4]) atom.commands.dispatch(editorElement, 'git-diff:move-to-previous-diff') expect(editor.getCursorBufferPosition()).toEqual([0, 0]) @@ -170,19 +170,19 @@ describe('GitDiff package', () => { it('wraps around to the first/last diff in the file', () => { editor.insertText('a') - editor.setCursorBufferPosition([5]) + editor.setCursorBufferPosition([9]) editor.deleteLine() advanceClock(editor.getBuffer().stoppedChangingDelay) editor.setCursorBufferPosition([0]) atom.commands.dispatch(editorElement, 'git-diff:move-to-next-diff') - expect(editor.getCursorBufferPosition()).toEqual([4, 4]) + expect(editor.getCursorBufferPosition()).toEqual([8, 4]) atom.commands.dispatch(editorElement, 'git-diff:move-to-next-diff') expect(editor.getCursorBufferPosition()).toEqual([0, 0]) atom.commands.dispatch(editorElement, 'git-diff:move-to-previous-diff') - expect(editor.getCursorBufferPosition()).toEqual([4, 4]) + expect(editor.getCursorBufferPosition()).toEqual([8, 4]) }) describe('when the wrapAroundOnMoveToDiff config option is false', () => { @@ -192,16 +192,16 @@ describe('GitDiff package', () => { it('does not wraps around to the first/last diff in the file', () => { editor.insertText('a') - editor.setCursorBufferPosition([5]) + editor.setCursorBufferPosition([9]) editor.deleteLine() advanceClock(editor.getBuffer().stoppedChangingDelay) editor.setCursorBufferPosition([0]) atom.commands.dispatch(editorElement, 'git-diff:move-to-next-diff') - expect(editor.getCursorBufferPosition()).toEqual([4, 4]) + expect(editor.getCursorBufferPosition()).toEqual([8, 4]) atom.commands.dispatch(editorElement, 'git-diff:move-to-next-diff') - expect(editor.getCursorBufferPosition()).toEqual([4, 4]) + expect(editor.getCursorBufferPosition()).toEqual([8, 4]) atom.commands.dispatch(editorElement, 'git-diff:move-to-previous-diff') expect(editor.getCursorBufferPosition()).toEqual([0, 0]) From 3f1b965343889626b32401a8b079cc5a50c2c1d6 Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Mon, 25 Feb 2019 11:51:02 +0100 Subject: [PATCH 088/112] Lint fixture file from go-to-line package The specs needed to be updated since they depended on the actual contents of the fixture. --- packages/go-to-line/spec/fixtures/sample.js | 108 +++++++++++--------- packages/go-to-line/spec/go-to-line-spec.js | 18 ++-- 2 files changed, 70 insertions(+), 56 deletions(-) diff --git a/packages/go-to-line/spec/fixtures/sample.js b/packages/go-to-line/spec/fixtures/sample.js index e09a93919..17845689a 100644 --- a/packages/go-to-line/spec/fixtures/sample.js +++ b/packages/go-to-line/spec/fixtures/sample.js @@ -1,70 +1,84 @@ var quicksort = function () { - var sort = function(items) { - if (items.length <= 1) return items; - var pivot = items.shift(), current, left = [], right = []; - while(items.length > 0) { - current = items.shift(); - current < pivot ? left.push(current) : right.push(current); - } - return sort(left).concat(pivot).concat(sort(right)); - }; + var sort = function (items) { + if (items.length <= 1) return items + var pivot = items.shift() + var current + var left = [] + var right = [] - return sort(Array.apply(this, arguments)); -}; + while (items.length > 0) { + current = items.shift() + current < pivot ? left.push(current) : right.push(current) + } + return sort(left) + .concat(pivot) + .concat(sort(right)) + } + + return sort(Array.apply(this, arguments)) +} // adapted from: // https://github.com/nzakas/computer-science-in-javascript/tree/master/algorithms/sorting/merge-sort-recursive -var mergeSort = function (items){ - var merge = function (left, right){ - var result = []; - var il = 0; - var ir = 0; +var mergeSort = function (items) { + var merge = function (left, right) { + var result = [] + var il = 0 + var ir = 0 - while (il < left.length && ir < right.length){ - if (left[il] < right[ir]){ - result.push(left[il++]); + while (il < left.length && ir < right.length) { + if (left[il] < right[ir]) { + result.push(left[il++]) } else { - result.push(right[ir++]); + result.push(right[ir++]) } } - return result.concat(left.slice(il)).concat(right.slice(ir)); - }; - - if (items.length < 2) { - return items; + return result.concat(left.slice(il)).concat(right.slice(ir)) } - var middle = Math.floor(items.length / 2), - left = items.slice(0, middle), - right = items.slice(middle), - params = merge(mergeSort(left), mergeSort(right)); + if (items.length < 2) { + return items + } + + var middle = Math.floor(items.length / 2) + var left = items.slice(0, middle) + var right = items.slice(middle) + var params = merge(mergeSort(left), mergeSort(right)) // Add the arguments to replace everything between 0 and last item in the array - params.unshift(0, items.length); - items.splice.apply(items, params); - return items; -}; + params.unshift(0, items.length) + items.splice.apply(items, params) + return items +} // adapted from: // https://github.com/nzakas/computer-science-in-javascript/blob/master/algorithms/sorting/bubble-sort/bubble-sort.js -var bubbleSort = function (items){ - var swap = function (items, firstIndex, secondIndex){ - var temp = items[firstIndex]; - items[firstIndex] = items[secondIndex]; - items[secondIndex] = temp; - }; +var bubbleSort = function (items) { + var swap = function (items, firstIndex, secondIndex) { + var temp = items[firstIndex] + items[firstIndex] = items[secondIndex] + items[secondIndex] = temp + } - var len = items.length, - i, j, stop; + var len = items.length + var i + var j + var stop - for (i=0; i < len; i++){ - for (j=0, stop=len-i; j < stop; j++){ - if (items[j] > items[j+1]){ - swap(items, j, j+1); + for (i = 0; i < len; i++) { + for (j = 0, stop = len - i; j < stop; j++) { + if (items[j] > items[j + 1]) { + swap(items, j, j + 1) } } } - return items; -}; + return items +} + +module.exports = { + bubbleSort, + mergeSort, + quicksort +} diff --git a/packages/go-to-line/spec/go-to-line-spec.js b/packages/go-to-line/spec/go-to-line-spec.js index 62551825e..b3440b00f 100644 --- a/packages/go-to-line/spec/go-to-line-spec.js +++ b/packages/go-to-line/spec/go-to-line-spec.js @@ -51,8 +51,8 @@ describe('GoToLine', () => { describe('when typing line numbers (auto-navigation)', () => { it('automatically scrolls to the desired line', () => { - goToLine.miniEditor.insertText('13') - expect(editor.getCursorBufferPosition()).toEqual([12, 0]) + goToLine.miniEditor.insertText('19') + expect(editor.getCursorBufferPosition()).toEqual([18, 0]) }) }) @@ -90,10 +90,10 @@ describe('GoToLine', () => { atom.commands.dispatch(editorView, 'go-to-line:toggle') expect(goToLine.panel.isVisible()).toBeTruthy() expect(goToLine.miniEditor.getText()).toBe('') - goToLine.miniEditor.insertText('71') + goToLine.miniEditor.insertText('78') atom.commands.dispatch(goToLine.miniEditor.element, 'core:confirm') expect(goToLine.panel.isVisible()).toBeFalsy() - expect(editor.getCursorBufferPosition()).toEqual([70, 0]) + expect(editor.getCursorBufferPosition()).toEqual([77, 0]) }) }) @@ -105,7 +105,7 @@ describe('GoToLine', () => { goToLine.miniEditor.insertText('3:43') atom.commands.dispatch(goToLine.miniEditor.element, 'core:confirm') expect(goToLine.panel.isVisible()).toBeFalsy() - expect(editor.getCursorBufferPosition()).toEqual([2, 40]) + expect(editor.getCursorBufferPosition()).toEqual([2, 39]) }) }) @@ -120,12 +120,12 @@ describe('GoToLine', () => { describe('when the line number entered is nested within foldes', () => { it('unfolds all folds containing the given row', () => { - expect(editor.indentationForBufferRow(6)).toEqual(3) + expect(editor.indentationForBufferRow(9)).toEqual(3) editor.foldAll() - expect(editor.screenRowForBufferRow(6)).toEqual(0) - goToLine.miniEditor.insertText('7') + expect(editor.screenRowForBufferRow(9)).toEqual(0) + goToLine.miniEditor.insertText('10') atom.commands.dispatch(goToLine.miniEditor.element, 'core:confirm') - expect(editor.getCursorBufferPosition()).toEqual([6, 6]) + expect(editor.getCursorBufferPosition()).toEqual([9, 6]) }) }) }) From ebf137954cbc0ea25dd10817f820de7840a92be7 Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Thu, 21 Feb 2019 15:23:07 +0100 Subject: [PATCH 089/112] Add comment and ignore rule on regular expression. --- packages/line-ending-selector/lib/main.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/line-ending-selector/lib/main.js b/packages/line-ending-selector/lib/main.js index 74b1d44c0..c3e07ff05 100644 --- a/packages/line-ending-selector/lib/main.js +++ b/packages/line-ending-selector/lib/main.js @@ -7,6 +7,11 @@ import StatusBarItem from './status-bar-item' import helpers from './helpers' const LineEndingRegExp = /\r\n|\n/g + +// the following regular expression is executed natively via the `substring` package, +// where `\A` corresponds to the beginning of the string. +// More info: https://github.com/atom/line-ending-selector/pull/56 +// eslint-disable-next-line no-useless-escape const LFRegExp = /(\A|[^\r])\n/g const CRLFRegExp = /\r\n/g From 034a05c8f48742cb6aeabbf1d3a40eb38593b1b1 Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Thu, 21 Feb 2019 15:24:07 +0100 Subject: [PATCH 090/112] Enable linter on packages/ folder --- script/lib/lint-java-script-paths.js | 1 + 1 file changed, 1 insertion(+) diff --git a/script/lib/lint-java-script-paths.js b/script/lib/lint-java-script-paths.js index 8086488dc..64ff22610 100644 --- a/script/lib/lint-java-script-paths.js +++ b/script/lib/lint-java-script-paths.js @@ -9,6 +9,7 @@ const CONFIG = require('../config') module.exports = function () { const globPathsToLint = [ path.join(CONFIG.repositoryRootPath, 'exports', '**', '*.js'), + path.join(CONFIG.repositoryRootPath, 'packages', '**', '*.js'), path.join(CONFIG.repositoryRootPath, 'script', '**', '*.js'), path.join(CONFIG.repositoryRootPath, 'src', '**', '*.js'), path.join(CONFIG.repositoryRootPath, 'static', '*.js') From 9cf34c0e893e3f8b04a90b41c80d6b91806563ac Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Mon, 25 Feb 2019 14:52:35 +0100 Subject: [PATCH 091/112] Fix git-diff package test --- packages/git-diff/spec/diff-list-view-spec.js | 6 +++--- .../fixtures/working-dir/git.git/COMMIT_EDITMSG | 0 .../spec/fixtures/working-dir/git.git/MERGE_RR | 0 .../spec/fixtures/working-dir/git.git/index | Bin 217 -> 217 bytes .../spec/fixtures/working-dir/git.git/info/refs | 1 - .../spec/fixtures/working-dir/git.git/logs/HEAD | 0 .../working-dir/git.git/logs/refs/heads/master | 0 .../06/5a272b55ec2ee84530dffd60b6869f7bf5d99c | Bin 0 -> 164 bytes .../3e/715502b971d4f8282d1e05a8ccfad6f7037910 | Bin 0 -> 27 bytes .../8e/ab2e81eb8dea81ad08694c7b30ae165af89c8e | Bin 0 -> 81 bytes .../90/820108a054b6f49c0d21031313244b6f7d69dc | 3 +++ .../e7/fd5b055dcdaa93ad8f9d63ca8db5330537105f | Bin 0 -> 236 bytes .../f1/4149b7b38a0a972c46557877caff6c9fe76476 | Bin 0 -> 81 bytes .../fb/33b0b43b20b7f9de1bca79e192fa2e30dbeb6b | Bin 0 -> 227 bytes .../working-dir/git.git/objects/info/packs | 2 -- ...fb30b46ead026befe94c88f5591a6d3dfdca4e95.idx | Bin 1380 -> 0 bytes ...b30b46ead026befe94c88f5591a6d3dfdca4e95.pack | Bin 1127 -> 0 bytes .../fixtures/working-dir/git.git/packed-refs | 2 -- .../working-dir/git.git/refs/heads/master | 1 + packages/git-diff/spec/git-diff-spec.js | 16 ++++++++-------- 20 files changed, 15 insertions(+), 16 deletions(-) delete mode 100644 packages/git-diff/spec/fixtures/working-dir/git.git/COMMIT_EDITMSG delete mode 100644 packages/git-diff/spec/fixtures/working-dir/git.git/MERGE_RR delete mode 100644 packages/git-diff/spec/fixtures/working-dir/git.git/info/refs delete mode 100644 packages/git-diff/spec/fixtures/working-dir/git.git/logs/HEAD delete mode 100644 packages/git-diff/spec/fixtures/working-dir/git.git/logs/refs/heads/master create mode 100644 packages/git-diff/spec/fixtures/working-dir/git.git/objects/06/5a272b55ec2ee84530dffd60b6869f7bf5d99c create mode 100644 packages/git-diff/spec/fixtures/working-dir/git.git/objects/3e/715502b971d4f8282d1e05a8ccfad6f7037910 create mode 100644 packages/git-diff/spec/fixtures/working-dir/git.git/objects/8e/ab2e81eb8dea81ad08694c7b30ae165af89c8e create mode 100644 packages/git-diff/spec/fixtures/working-dir/git.git/objects/90/820108a054b6f49c0d21031313244b6f7d69dc create mode 100644 packages/git-diff/spec/fixtures/working-dir/git.git/objects/e7/fd5b055dcdaa93ad8f9d63ca8db5330537105f create mode 100644 packages/git-diff/spec/fixtures/working-dir/git.git/objects/f1/4149b7b38a0a972c46557877caff6c9fe76476 create mode 100644 packages/git-diff/spec/fixtures/working-dir/git.git/objects/fb/33b0b43b20b7f9de1bca79e192fa2e30dbeb6b delete mode 100644 packages/git-diff/spec/fixtures/working-dir/git.git/objects/info/packs delete mode 100644 packages/git-diff/spec/fixtures/working-dir/git.git/objects/pack/pack-fb30b46ead026befe94c88f5591a6d3dfdca4e95.idx delete mode 100644 packages/git-diff/spec/fixtures/working-dir/git.git/objects/pack/pack-fb30b46ead026befe94c88f5591a6d3dfdca4e95.pack delete mode 100644 packages/git-diff/spec/fixtures/working-dir/git.git/packed-refs create mode 100644 packages/git-diff/spec/fixtures/working-dir/git.git/refs/heads/master diff --git a/packages/git-diff/spec/diff-list-view-spec.js b/packages/git-diff/spec/diff-list-view-spec.js index d78560acc..8f98e68c0 100644 --- a/packages/git-diff/spec/diff-list-view-spec.js +++ b/packages/git-diff/spec/diff-list-view-spec.js @@ -22,7 +22,7 @@ describe('git-diff:toggle-diff-list', () => { runs(() => { editor = atom.workspace.getActiveTextEditor() - editor.setCursorBufferPosition([3, 28]) + editor.setCursorBufferPosition([8, 30]) editor.insertText('a') atom.commands.dispatch(editor.getElement(), 'git-diff:toggle-diff-list') }) @@ -35,7 +35,7 @@ describe('git-diff:toggle-diff-list', () => { it('shows a list of all diff hunks', () => { diffListView = document.querySelector('.diff-list-view ol') - expect(diffListView.textContent).toBe('var pivot = items.shift(a)-4,1 +4,1') + expect(diffListView.textContent).toBe('while (items.length > 0) {a-9,1 +9,1') }) it('moves the cursor to the selected hunk', () => { @@ -44,6 +44,6 @@ describe('git-diff:toggle-diff-list', () => { document.querySelector('.diff-list-view'), 'core:confirm' ) - expect(editor.getCursorBufferPosition()).toEqual([3, 4]) + expect(editor.getCursorBufferPosition()).toEqual([8, 4]) }) }) diff --git a/packages/git-diff/spec/fixtures/working-dir/git.git/COMMIT_EDITMSG b/packages/git-diff/spec/fixtures/working-dir/git.git/COMMIT_EDITMSG deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/git-diff/spec/fixtures/working-dir/git.git/MERGE_RR b/packages/git-diff/spec/fixtures/working-dir/git.git/MERGE_RR deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/git-diff/spec/fixtures/working-dir/git.git/index b/packages/git-diff/spec/fixtures/working-dir/git.git/index index 17dcc2005c6d34768d09f5f9580968af969fd734..a15f269aafeb5e4c914ae5df79a4aadb82b636f0 100644 GIT binary patch delta 65 zcmcb~c#~1Z#WTp6fq{Vugky?7`!TUC*#M&%85md@;%3~QsIpMxi`t(vv*s>sv&>NL NFP&mhwR5MMGXRtm7exR7 delta 65 zcmcb~c#~1Z#WTp6fq{Vugky@YO;A~v!VaSu85md@;>4RLsw@;K-KMlQR;VoWgC6tc NFJTo2q!tHE0RU{76_x-1 diff --git a/packages/git-diff/spec/fixtures/working-dir/git.git/info/refs b/packages/git-diff/spec/fixtures/working-dir/git.git/info/refs deleted file mode 100644 index 99f414cef..000000000 --- a/packages/git-diff/spec/fixtures/working-dir/git.git/info/refs +++ /dev/null @@ -1 +0,0 @@ -745ed7547d15a61bc4ee7e182615590f44aca201 refs/heads/master diff --git a/packages/git-diff/spec/fixtures/working-dir/git.git/logs/HEAD b/packages/git-diff/spec/fixtures/working-dir/git.git/logs/HEAD deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/git-diff/spec/fixtures/working-dir/git.git/logs/refs/heads/master b/packages/git-diff/spec/fixtures/working-dir/git.git/logs/refs/heads/master deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/git-diff/spec/fixtures/working-dir/git.git/objects/06/5a272b55ec2ee84530dffd60b6869f7bf5d99c b/packages/git-diff/spec/fixtures/working-dir/git.git/objects/06/5a272b55ec2ee84530dffd60b6869f7bf5d99c new file mode 100644 index 0000000000000000000000000000000000000000..03673f8db597f3759be3e9104f9a18584f4299c7 GIT binary patch literal 164 zcmV;V09*ff0iBLP3c@fDMP26<*$ZVRP1^~GcmP5029so}mByAd-FSNA73A+8yw3|u zN>kCs42P0MGzohngyJa*6LJLVoehI;fd%`HM{<+=MNEa|MV>#+KORv+szs7h;Lk$+ru SooeI8X`Q8cZR!gR^G5c${!VrP literal 0 HcmV?d00001 diff --git a/packages/git-diff/spec/fixtures/working-dir/git.git/objects/3e/715502b971d4f8282d1e05a8ccfad6f7037910 b/packages/git-diff/spec/fixtures/working-dir/git.git/objects/3e/715502b971d4f8282d1e05a8ccfad6f7037910 new file mode 100644 index 0000000000000000000000000000000000000000..1cbeb30fc8cafbf2790a34fbf334eea0de778e71 GIT binary patch literal 27 jcmbAWiT`_Ff%bxC{D~R$Vt`9DrR{8H<~r}?5fFY`{yQ~>fLJ0 nYAz6us;H!*gu$*blxb(-l^+_qa;z)P{JQp?xl#ZC*t;KuqQNHb literal 0 HcmV?d00001 diff --git a/packages/git-diff/spec/fixtures/working-dir/git.git/objects/90/820108a054b6f49c0d21031313244b6f7d69dc b/packages/git-diff/spec/fixtures/working-dir/git.git/objects/90/820108a054b6f49c0d21031313244b6f7d69dc new file mode 100644 index 000000000..718602204 --- /dev/null +++ b/packages/git-diff/spec/fixtures/working-dir/git.git/objects/90/820108a054b6f49c0d21031313244b6f7d69dc @@ -0,0 +1,3 @@ +xÍM‚0†a×=Å\@ÒB;SbtíÒ ¥Õ +õçøbL<€Ëç]|Ÿ›RŠJi6yö‚ÒJ×-µ•eÉ5•N£1d‰‡€®žP +¾çË4ÃÑ?â'~F×Ghú—¯öçÄq(Ü”v *«L‰ˆ¶’¤k]³ÿAºN·Á×xü)¿²xmðCÛ \ No newline at end of file diff --git a/packages/git-diff/spec/fixtures/working-dir/git.git/objects/e7/fd5b055dcdaa93ad8f9d63ca8db5330537105f b/packages/git-diff/spec/fixtures/working-dir/git.git/objects/e7/fd5b055dcdaa93ad8f9d63ca8db5330537105f new file mode 100644 index 0000000000000000000000000000000000000000..05ab754216dda8a7378997be54992e844cbacaf8 GIT binary patch literal 236 zcmVAWiT`_Ff%bxC{D~R$Vt`9DrWd?ykU#A!uFr{q)$~oob*f2 n;P&fmR7E8fB@A|jp-ejqul&%^m1A9T=GV3F%#{KFDZn9!hz}*T literal 0 HcmV?d00001 diff --git a/packages/git-diff/spec/fixtures/working-dir/git.git/objects/fb/33b0b43b20b7f9de1bca79e192fa2e30dbeb6b b/packages/git-diff/spec/fixtures/working-dir/git.git/objects/fb/33b0b43b20b7f9de1bca79e192fa2e30dbeb6b new file mode 100644 index 0000000000000000000000000000000000000000..e9ffee6407bbb200388e6ccbecf97457892a94e9 GIT binary patch literal 227 zcmV<90382#0bNkbP6Htnb=|KxOGqZ9OmjwG%cPIItCLU@jpTP(vxu>8wO-@v-dBxlIWm2!4c3W8{g~4?p^1@WLCCf* zb9fb*g@skT^J_EjtlV%oX`@Wvo~b2E(@oNre1Ev#@aX#W=QB?1V*lf8=Djo1`Rv@K zJ6k3{{~OI3dv?|2wf%FGPxWp!W;GXx|LEwseRCJrbRDQ4 zxZ7T-V`(Q_ws=00y!`UF@rEtd3fq6)lRj1XaMCY5gWIpOZT?98e{WFD6cP}xQoE+* zek*tO*~S&ir52h53TziV^il4`13jJIEqnz+0&{`cYc{Yr0EG_^ki8zrHUMTLcOd&W zki84YZUoA00MciF8*Is2%ar~8rBBD#NU2=gzo-1Bx@O6&*vWDE=!E@FAHr_=dGV}zx*WUY&swrE}GOGZ--2d3<%)5qLB zq8!)X+VXReqUHQW3-;PgQ_7#xsa`qvhwrBdjp8MrYuEJKmK4tP4~krUKsvqGW{W|G z+w+ZK|88$R_V~Q$^o_N5GUC+V&71v$L2|Y8{r4;lDiw38&-|DXxP6I+X{e&1uA#2w z*)vKvl{7CNu+hDFP3^2mku4dRI%t?j3>7hZF=H9@;LS!F|Jl+t|dgcU^2%lP2rYY1c&lSniV&=6~?1x;s4V zy`sk2lH0-eBc|O6dTS!(Jncjw$BSDJI87Hmh_=+%mic3QuHcD#Npj2EABq36%DrTk zpVD2)d^I99%Vo=ki7HDgu8Vko{4al`PC}u0m*2i!DGz=w|D^MXb@ytA*_&i4=HyQB z%{#0h(E8o-sE*^RfX!!WZrcB84 zYob91ChM=*X(#nY=<({+Mia|2YoqT@ebj$=mB6=Uo}t##TYf426P-8xVuIs8>B{2r z+zs2MG@bg|O#2U?p7SeuZNtWSxfefquGykruy9YX(Z;Sik?hi^pOSi0=T={^p16lg zvT5(86a%})C3gJ5C3B>Xo#mguwl~bWVh;DY^S+@Po@+HOK4xN&P-5P+nx$fnv5A3! zv0xz6rB(bhpJn>(&8m~xzn`nke|0zOOqQNNe#fE}OBS^pTxT#PGyUOI zd8u7RYqZb(+4XJi&L9Q`m1 z#6Q$-&KK|V55B$5!Rw0BLV2GToXx@@SJ*T|U9tb4OSQAx>rU39TUJ~rm%6&HtW>q) zg1g0v%XQ{UNr7#q)0qUOq^CSv;%Ae8B*S**#ETb2l_I#+x`VvEx<83@eeU)$aZt;6 zrTYB2s`|7Hk(6mql`9e|H*B0WOX2O-Ym?OtUu}vgz8b~Mux_!Q?QerEd25-n-@o+f O_!=pdYy0<<-&6o5ToB9v diff --git a/packages/git-diff/spec/fixtures/working-dir/git.git/packed-refs b/packages/git-diff/spec/fixtures/working-dir/git.git/packed-refs deleted file mode 100644 index 1a97c394d..000000000 --- a/packages/git-diff/spec/fixtures/working-dir/git.git/packed-refs +++ /dev/null @@ -1,2 +0,0 @@ -# pack-refs with: peeled fully-peeled sorted -745ed7547d15a61bc4ee7e182615590f44aca201 refs/heads/master diff --git a/packages/git-diff/spec/fixtures/working-dir/git.git/refs/heads/master b/packages/git-diff/spec/fixtures/working-dir/git.git/refs/heads/master new file mode 100644 index 000000000..83fe7393f --- /dev/null +++ b/packages/git-diff/spec/fixtures/working-dir/git.git/refs/heads/master @@ -0,0 +1 @@ +065a272b55ec2ee84530dffd60b6869f7bf5d99c diff --git a/packages/git-diff/spec/git-diff-spec.js b/packages/git-diff/spec/git-diff-spec.js index 950fec71d..badb15f76 100644 --- a/packages/git-diff/spec/git-diff-spec.js +++ b/packages/git-diff/spec/git-diff-spec.js @@ -156,13 +156,13 @@ describe('GitDiff package', () => { describe('move-to-next-diff/move-to-previous-diff events', () => { it('moves the cursor to first character of the next/previous diff line', () => { editor.insertText('a') - editor.setCursorBufferPosition([9]) + editor.setCursorBufferPosition([5]) editor.deleteLine() advanceClock(editor.getBuffer().stoppedChangingDelay) editor.setCursorBufferPosition([0]) atom.commands.dispatch(editorElement, 'git-diff:move-to-next-diff') - expect(editor.getCursorBufferPosition()).toEqual([8, 4]) + expect(editor.getCursorBufferPosition()).toEqual([4, 4]) atom.commands.dispatch(editorElement, 'git-diff:move-to-previous-diff') expect(editor.getCursorBufferPosition()).toEqual([0, 0]) @@ -170,19 +170,19 @@ describe('GitDiff package', () => { it('wraps around to the first/last diff in the file', () => { editor.insertText('a') - editor.setCursorBufferPosition([9]) + editor.setCursorBufferPosition([5]) editor.deleteLine() advanceClock(editor.getBuffer().stoppedChangingDelay) editor.setCursorBufferPosition([0]) atom.commands.dispatch(editorElement, 'git-diff:move-to-next-diff') - expect(editor.getCursorBufferPosition()).toEqual([8, 4]) + expect(editor.getCursorBufferPosition()).toEqual([4, 4]) atom.commands.dispatch(editorElement, 'git-diff:move-to-next-diff') expect(editor.getCursorBufferPosition()).toEqual([0, 0]) atom.commands.dispatch(editorElement, 'git-diff:move-to-previous-diff') - expect(editor.getCursorBufferPosition()).toEqual([8, 4]) + expect(editor.getCursorBufferPosition()).toEqual([4, 4]) }) describe('when the wrapAroundOnMoveToDiff config option is false', () => { @@ -192,16 +192,16 @@ describe('GitDiff package', () => { it('does not wraps around to the first/last diff in the file', () => { editor.insertText('a') - editor.setCursorBufferPosition([9]) + editor.setCursorBufferPosition([5]) editor.deleteLine() advanceClock(editor.getBuffer().stoppedChangingDelay) editor.setCursorBufferPosition([0]) atom.commands.dispatch(editorElement, 'git-diff:move-to-next-diff') - expect(editor.getCursorBufferPosition()).toEqual([8, 4]) + expect(editor.getCursorBufferPosition()).toEqual([4, 4]) atom.commands.dispatch(editorElement, 'git-diff:move-to-next-diff') - expect(editor.getCursorBufferPosition()).toEqual([8, 4]) + expect(editor.getCursorBufferPosition()).toEqual([4, 4]) atom.commands.dispatch(editorElement, 'git-diff:move-to-previous-diff') expect(editor.getCursorBufferPosition()).toEqual([0, 0]) From 46fa62ac593448e79ab3b0898a0516eb76ac250c Mon Sep 17 00:00:00 2001 From: Jason Rudolph Date: Mon, 25 Feb 2019 13:37:35 -0500 Subject: [PATCH 092/112] Revert "Merge #18815 from atom/electron-3.1.3" This reverts commit e81f71318a0673dffbbe9e93cf7714d2cf885a78, reversing changes made to bded0c102a79b4f961ff666143bef133c69feda5. --- package.json | 2 +- script/lib/check-chromedriver-version.js | 12 ++++++------ script/package.json | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 3ca3b9c61..4627d2d13 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "url": "https://github.com/atom/atom/issues" }, "license": "MIT", - "electronVersion": "3.1.3", + "electronVersion": "3.0.14", "dependencies": { "@atom/nsfw": "1.0.21", "@atom/source-map-support": "^0.3.4", diff --git a/script/lib/check-chromedriver-version.js b/script/lib/check-chromedriver-version.js index f5cada045..1659f093c 100644 --- a/script/lib/check-chromedriver-version.js +++ b/script/lib/check-chromedriver-version.js @@ -5,17 +5,17 @@ const CONFIG = require('../config') const semver = require('semver') module.exports = function () { - // Chromedriver should be specified as ^n.x where n matches the Electron major version + // Chromedriver should be specified as ~x.y where x and y match Electron major/minor const chromedriverVer = buildMetadata.dependencies['electron-chromedriver'] const mksnapshotVer = buildMetadata.dependencies['electron-mksnapshot'] - // Always use caret on electron-chromedriver so that it can pick up the best minor/patch versions - if (!chromedriverVer.startsWith('^')) { - throw new Error(`electron-chromedriver version in script/package.json should start with a caret to match latest patch version.`) + // Always use tilde on electron-chromedriver so that it can pick up the best patch version + if (!chromedriverVer.startsWith('~')) { + throw new Error(`electron-chromedriver version in script/package.json should start with a tilde to match latest patch version.`) } - if (!mksnapshotVer.startsWith('^')) { - throw new Error(`electron-mksnapshot version in script/package.json should start with a caret to match latest patch version.`) + if (!mksnapshotVer.startsWith('~')) { + throw new Error(`electron-mksnapshot version in script/package.json should start with a tilde to match latest patch version.`) } const electronVer = CONFIG.appMetadata.electronVersion diff --git a/script/package.json b/script/package.json index 9d270e589..bc1456452 100644 --- a/script/package.json +++ b/script/package.json @@ -9,9 +9,9 @@ "coffeelint": "1.15.7", "colors": "1.1.2", "donna": "1.0.16", - "electron-chromedriver": "^3.0.0-beta.1", + "electron-chromedriver": "~3.0.0-beta.1", "electron-link": "0.3.3", - "electron-mksnapshot": "^3.0.10", + "electron-mksnapshot": "~3.0.10", "electron-packager": "7.3.0", "electron-winstaller": "2.6.4", "fs-admin": "^0.1.5", From c9e6d04e8c9a8cdc7a97f2b1eaecf7f5c1cbff59 Mon Sep 17 00:00:00 2001 From: Jason Rudolph Date: Mon, 25 Feb 2019 13:37:35 -0500 Subject: [PATCH 093/112] Revert "Merge #18603 from atom/electron-3-0" This reverts commit b92ae2ad04abd968fd1642dd15eb82f8dd86e342, reversing changes made to d4fe5ccfeb0ecd8c6e918da42eb5ec827c49dd76. --- apm/package-lock.json | 3 +- package-lock.json | 196 ++++++++++++------------ package.json | 15 +- script/lib/generate-startup-snapshot.js | 35 ++--- script/package-lock.json | 68 +++----- script/package.json | 6 +- spec/decoration-manager-spec.coffee | 1 - spec/fixtures/babel/invalid.js | 2 +- spec/selection-spec.js | 1 - spec/style-manager-spec.js | 9 ++ spec/text-mate-language-mode-spec.js | 1 - spec/theme-manager-spec.js | 4 +- spec/workspace-spec.js | 2 +- src/compile-cache.js | 2 +- src/file-system-blob-store.js | 2 +- src/native-compile-cache.js | 26 +--- src/task.coffee | 12 +- src/text-editor-component.js | 2 +- static/index.js | 4 + 19 files changed, 168 insertions(+), 223 deletions(-) diff --git a/apm/package-lock.json b/apm/package-lock.json index e9b15786d..614b07fa1 100644 --- a/apm/package-lock.json +++ b/apm/package-lock.json @@ -21,6 +21,7 @@ "node-gyp": "3.4.0", "npm": "6.2.0", "open": "0.0.5", + "plist": "git+https://github.com/nathansobo/node-plist.git#bd3a93387f1d4b2cff819b200870d35465796e77", "q": "~0.9.7", "read": "~1.0.5", "request": "^2.87.0", @@ -3973,7 +3974,7 @@ }, "plist": { "version": "git+https://github.com/nathansobo/node-plist.git#bd3a93387f1d4b2cff819b200870d35465796e77", - "from": "git+https://github.com/nathansobo/node-plist.git#bd3a93387f1d4b2cff819b200870d35465796e77", + "from": "git+https://github.com/nathansobo/node-plist.git", "requires": { "xmlbuilder": "0.4.x", "xmldom": "0.1.x" diff --git a/package-lock.json b/package-lock.json index b1560214b..aabc345ce 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,15 +5,15 @@ "requires": true, "dependencies": { "@atom/nsfw": { - "version": "1.0.21", - "resolved": "https://registry.npmjs.org/@atom/nsfw/-/nsfw-1.0.21.tgz", - "integrity": "sha512-ERz76RZstjDvZPM4FHwgO+9dzGkki0mJsn2r+Mu4yn29MzUuAtSmtyJDPmupVUvmz2PF7KvRbC/W2A8A6BHQhA==", + "version": "1.0.18", + "resolved": "https://registry.npmjs.org/@atom/nsfw/-/nsfw-1.0.18.tgz", + "integrity": "sha512-YceKV9a3X62mh4Q78Nyi8aTRaoVGdpeJBHogL8gxU17iBhEpYvxGgMfTe02j1hH2taFT4barkZ5RdZkGKIsJ/w==", "requires": { - "fs-extra": "^7.0.0", + "fs-extra": "^0.26.5", "lodash.isinteger": "^4.0.4", "lodash.isundefined": "^3.0.1", - "nan": "^2.10.0", - "promisify-node": "^0.5.0" + "nan": "^2.0.0", + "promisify-node": "^0.3.0" } }, "@atom/source-map-support": { @@ -149,7 +149,7 @@ "apparatus": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/apparatus/-/apparatus-0.0.10.tgz", - "integrity": "sha512-KLy/ugo33KZA7nugtQ7O0E1c8kQ52N3IvD/XgIh4w/Nr28ypfkwDfA67F1ev4N1m5D+BOk1+b2dEJDfpj/VvZg==", + "integrity": "sha1-gep1Z3Ktp3hj21TO7oICwQm9yj4=", "requires": { "sylvester": ">= 0.0.8" } @@ -340,7 +340,7 @@ "atom-pathspec": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/atom-pathspec/-/atom-pathspec-0.0.0.tgz", - "integrity": "sha512-7UMEHdTtBV5sJONT0uMeQ6M8JFdfMQy/14rxuP6OuoFfSiDjxyZHuorIbv8gqhRB3FQMMLPzqONoFJE2cpHiCg==" + "integrity": "sha1-Z6q6+VAZsK/Y4xWLLNexjXN2Q/E=" }, "atom-select-list": { "version": "0.7.2", @@ -1164,27 +1164,14 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" }, - "caller-callsite": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", - "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", + "cached-run-in-this-context": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cached-run-in-this-context/-/cached-run-in-this-context-0.5.0.tgz", + "integrity": "sha512-FdtDP0u8WjetQ95nLz9vI06efJTFrmtmk5ZT6FECpyTKi9aakNLMHyMH21WRbGYyWlbmB/QlRoB/g1lcEpyjMw==", "requires": { - "callsites": "^2.0.0" + "nan": "^2.10.0" } }, - "caller-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", - "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", - "requires": { - "caller-callsite": "^2.0.0" - } - }, - "callsites": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", - "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=" - }, "camelcase": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", @@ -1303,6 +1290,11 @@ "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.0.1.tgz", "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=" }, + "circular-json": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.5.7.tgz", + "integrity": "sha512-/pXoV1JA847qRKPrHbBK6YIBGFF8GOP4wzSgUOA7q0ew0vAv0iJswP+2/nZQ9uzA3Azi7eTrg9L2yzXc/7ZMIA==" + }, "classnames": { "version": "2.2.6", "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz", @@ -1630,9 +1622,9 @@ } }, "date-format": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-2.0.0.tgz", - "integrity": "sha512-M6UqVvZVgFYqZL1SfHsRGIQSz3ZL+qgbsV5Lp1Vj61LZVYuEwcMXYay7DRDtYs2HQQBK5hQtQ0fD9aEJ89V0LA==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-1.2.0.tgz", + "integrity": "sha1-YV6CjiM90aubua4JUODOzPpuytg=" }, "debug": { "version": "2.6.9", @@ -2266,11 +2258,6 @@ } } }, - "flatted": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.0.tgz", - "integrity": "sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg==" - }, "flatten": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.2.tgz", @@ -2385,13 +2372,25 @@ "integrity": "sha1-a+Dem+mYzhavivwkSXue6bfM2a0=" }, "fs-extra": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.0.tgz", - "integrity": "sha512-EglNDLRpmaTWiD/qraZn6HREAEAHJcJOmxNEYwq6xeMKnVMAy3GUcFB+wXt2C6k4CNvB/mP1y/U3dzvKKj5OtQ==", + "version": "0.26.7", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.26.7.tgz", + "integrity": "sha1-muH92UiXeY7at20JGM9C0MMYT6k=", "requires": { "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" + "jsonfile": "^2.1.0", + "klaw": "^1.0.0", + "path-is-absolute": "^1.0.0", + "rimraf": "^2.2.8" + }, + "dependencies": { + "jsonfile": { + "version": "2.4.0", + "resolved": "http://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", + "requires": { + "graceful-fs": "^4.1.6" + } + } } }, "fs-minipass": { @@ -2403,9 +2402,9 @@ } }, "fs-plus": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/fs-plus/-/fs-plus-3.1.1.tgz", - "integrity": "sha512-Se2PJdOWXqos1qVTkvqqjb0CSnfBnwwD+pq+z4ksT+e97mEShod/hrNg0TRCCsXPbJzcIq+NuzQhigunMWMJUA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/fs-plus/-/fs-plus-3.0.2.tgz", + "integrity": "sha1-a19Sp3EolMTd6f2PgfqMYN8EHz0=", "requires": { "async": "^1.5.2", "mkdirp": "^0.5.1", @@ -2415,7 +2414,7 @@ "dependencies": { "async": { "version": "1.5.2", - "resolved": "http://registry.npmjs.org/async/-/async-1.5.2.tgz", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" } } @@ -3217,6 +3216,14 @@ "is-buffer": "^1.1.5" } }, + "klaw": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", + "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", + "requires": { + "graceful-fs": "^4.1.9" + } + }, "language-c": { "version": "https://www.atom.io/api/packages/language-c/versions/0.60.14/tarball", "integrity": "sha512-jGFMc9vNutvBflFdoUXWJqxBFdMFG7n13PxS8z+SB8H0taZStq55JixDaQ0i/qu7ay4K5BCJ7y/PHdL13vjouQ==", @@ -3661,21 +3668,21 @@ "integrity": "sha1-JMS/zWsvuji/0FlNsRedjptlZWE=" }, "log4js": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-4.0.0.tgz", - "integrity": "sha512-XlxZfcFAvQjnjCJBIV/EpsPmrVC12n+TxNUKgrmQh6eeA+9X+6UqvaRNV8t6dpMtXszl1LAQimB4pqyp2Gsgfw==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-3.0.5.tgz", + "integrity": "sha512-IX5c3G/7fuTtdr0JjOT2OIR12aTESVhsH6cEsijloYwKgcPRlO6DgOU72v0UFhWcoV1HN6+M3dwT89qVPLXm0w==", "requires": { - "date-format": "^2.0.0", + "circular-json": "^0.5.5", + "date-format": "^1.2.0", "debug": "^3.1.0", - "flatted": "^2.0.0", "rfdc": "^1.1.2", - "streamroller": "^1.0.1" + "streamroller": "0.7.0" }, "dependencies": { "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.5.tgz", + "integrity": "sha512-D61LaDQPQkxJ5AUM2mbSJRbPkNs/TmdmOeLAi1hgDkpDfIfetSrjmWhccwtuResSwMbACjx/xXQofvM9CE/aeg==", "requires": { "ms": "^2.1.1" } @@ -4262,9 +4269,9 @@ "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=" }, "pathwatcher": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/pathwatcher/-/pathwatcher-8.0.2.tgz", - "integrity": "sha512-zuP+fLmB2IB6z89ikcehA+vG/ITx3Cmhaj3DJrBgnbdss6dwPolSq7cDBjgZ78Vl+SXmG7CHGIOM5mqdT9h7BQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/pathwatcher/-/pathwatcher-8.0.1.tgz", + "integrity": "sha1-UaLOKgHbbDLYZ/ZYXvKEvmvQo64=", "requires": { "async": "~0.2.10", "emissary": "^1.3.2", @@ -4272,19 +4279,19 @@ "fs-plus": "^3.0.0", "grim": "^2.0.1", "iconv-lite": "~0.4.4", - "nan": "^2.10.0", + "nan": "2.x", "underscore-plus": "~1.x" }, "dependencies": { "async": { "version": "0.2.10", - "resolved": "http://registry.npmjs.org/async/-/async-0.2.10.tgz", + "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=" }, "grim": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/grim/-/grim-2.0.2.tgz", - "integrity": "sha512-Qj7hTJRfd87E/gUgfvM0YIH/g2UA2SV6niv6BYXk1o6w4mhgv+QyYM1EjOJQljvzgEj4SqSsRWldXIeKHz3e3Q==", + "integrity": "sha1-52CinKe4NDsMH/r2ziDyGkbuiu0=", "requires": { "event-kit": "^2.0.0" } @@ -4422,12 +4429,11 @@ } }, "promisify-node": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/promisify-node/-/promisify-node-0.5.0.tgz", - "integrity": "sha512-GR2E4qgCoKFTprhULqP2OP3bl8kHo16XtnqtkHH6be7tPW1yL6rXd15nl3oV2sLTFv1+j6tqoF69VVpFtJ/j+A==", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/promisify-node/-/promisify-node-0.3.0.tgz", + "integrity": "sha1-tLVaz5D6p9K4uQyjlomQhsAwYM8=", "requires": { - "nodegit-promise": "^4.0.0", - "object-assign": "^4.1.1" + "nodegit-promise": "~4.0.0" } }, "prop-types": { @@ -5161,22 +5167,22 @@ "integrity": "sha1-enzShHDMbToc/m1miG9rxDDTrIc=" }, "spell-check": { - "version": "https://www.atom.io/api/packages/spell-check/versions/0.74.3/tarball", - "integrity": "sha512-QYy0xpSKp8OSZjlvq7fOjrf/NdG4BncHvn9AmO/vcuJvWAoiwEWhqqB+BSA6uSrxOxJeJhbDJSxOrvm4YXs1xQ==", + "version": "https://www.atom.io/api/packages/spell-check/versions/0.74.2/tarball", + "integrity": "sha512-WhwhDF4nznhQuwnRemZbXODI6aqax2HlHudfLEjbhzkRGjEbfssRK82lRRvCK9LmQh3fAqCqbmELU40NEODJ8Q==", "requires": { "atom-pathspec": "^0.0.0", "atom-select-list": "^0.7.0", "multi-integer-range": "^2.0.0", "natural": "^0.4.0", - "spellchecker": "^3.5.1", + "spellchecker": "^3.4.4", "spelling-manager": "^1.1.0", "underscore-plus": "^1" } }, "spellchecker": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/spellchecker/-/spellchecker-3.5.1.tgz", - "integrity": "sha512-R1qUBsDZzio+7MFZN6/AtPUe5NGvnc0wywckuXAlp9akASaYSFqKuI5O8p3rSiA+yKP31qC7Iijjoygmzkh6xw==", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/spellchecker/-/spellchecker-3.5.0.tgz", + "integrity": "sha512-Xa7XnRulYhh5N/XENeL2O8/875XhLBjos7Bemv0rfcgV6ojNYMSrXscUZUGJwniX2t67eY+lNUJeptD1bMauHQ==", "requires": { "any-promise": "^1.3.0", "nan": "^2.10.0" @@ -5185,7 +5191,7 @@ "spelling-manager": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/spelling-manager/-/spelling-manager-1.1.0.tgz", - "integrity": "sha512-PpTP6XUZflCWO9YZO3wBSGAmqrUP6BFwSdmVFS6WBT9rFYg3ysmrIfyD1KnaVcnW6wuIKf+FDwefvU8PsD8Smg==", + "integrity": "sha1-UZmGdZUpHgVjlExuL70ao02X3TQ=", "requires": { "natural": "0.5.0", "xregexp": "^3.2.0" @@ -5275,38 +5281,24 @@ } }, "streamroller": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-1.0.1.tgz", - "integrity": "sha512-FKL2mEB0A+XTIWSOlBHm2DvdsER5cGraqrUufO0lFMfsVY+Gpb3TC29Z+6/l0Urbb7vtm6m9zJOQBVl6fEkZBA==", + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-0.7.0.tgz", + "integrity": "sha1-odG3z4PTmvsNYwSaWsv5NJO99ks=", "requires": { - "async": "^2.6.1", - "date-format": "^2.0.0", + "date-format": "^1.2.0", "debug": "^3.1.0", - "fs-extra": "^7.0.0", - "lodash": "^4.17.10" + "mkdirp": "^0.5.1", + "readable-stream": "^2.3.0" }, "dependencies": { - "async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", - "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", - "requires": { - "lodash": "^4.17.10" - } - }, "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.5.tgz", + "integrity": "sha512-D61LaDQPQkxJ5AUM2mbSJRbPkNs/TmdmOeLAi1hgDkpDfIfetSrjmWhccwtuResSwMbACjx/xXQofvM9CE/aeg==", "requires": { "ms": "^2.1.1" } }, - "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" - }, "ms": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", @@ -5378,9 +5370,9 @@ } }, "superstring": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/superstring/-/superstring-2.3.6.tgz", - "integrity": "sha512-kDTXCXArhHL1lRk2zBW7ByRJByqVwoLK3E3jlf8+LcwQLZgSMs9dwrDHDpBdoOm89kstSBSrGcW8OJqNkxjWrQ==", + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/superstring/-/superstring-2.3.4.tgz", + "integrity": "sha512-DcNkTCdB9F3FMZRdURSALsHi+7DWqFCI0cH+Eg8mwBg+kxQs6GeB3LrGUvCI5bEB6Dtlu2ox8UYN0onPN4JeZQ==", "requires": { "nan": "^2.10.0" } @@ -5500,21 +5492,21 @@ } }, "text-buffer": { - "version": "13.15.3", - "resolved": "https://registry.npmjs.org/text-buffer/-/text-buffer-13.15.3.tgz", - "integrity": "sha512-H2fz/N15g0fBP7R33FUFLnIyND+Lji/xmuvHg9rKgmfCh7NAVxiFIvnZTabuBhL9InqPrtV5t4hkUy+r3dNXMg==", + "version": "13.15.1", + "resolved": "https://registry.npmjs.org/text-buffer/-/text-buffer-13.15.1.tgz", + "integrity": "sha512-LZx7EKhVwjo50Y9ZF6WDP2S4zLUcHAagHZhn6HzHjr0SxyWtm95HG7ApSzgLGvIzCZEoTzMYt62scUdesfzYuw==", "requires": { "delegato": "^1.0.0", "diff": "^2.2.1", "emissary": "^1.0.0", "event-kit": "^2.4.0", - "fs-admin": "^0.1.7", + "fs-admin": "^0.1.4", "fs-plus": "^3.0.0", "grim": "^2.0.2", "mkdirp": "^0.5.1", - "pathwatcher": "8.0.2", + "pathwatcher": "8.0.1", "serializable": "^1.0.3", - "superstring": "2.3.6", + "superstring": "2.3.4", "underscore-plus": "^1.0.0" }, "dependencies": { diff --git a/package.json b/package.json index 4627d2d13..ba795cd3b 100644 --- a/package.json +++ b/package.json @@ -12,9 +12,9 @@ "url": "https://github.com/atom/atom/issues" }, "license": "MIT", - "electronVersion": "3.0.14", + "electronVersion": "2.0.16", "dependencies": { - "@atom/nsfw": "1.0.21", + "@atom/nsfw": "1.0.18", "@atom/source-map-support": "^0.3.4", "@atom/watcher": "1.3.1", "about": "file:packages/about", @@ -39,6 +39,7 @@ "base16-tomorrow-light-theme": "file:packages/base16-tomorrow-light-theme", "bookmarks": "https://www.atom.io/api/packages/bookmarks/versions/0.46.0/tarball", "bracket-matcher": "https://www.atom.io/api/packages/bracket-matcher/versions/0.90.4/tarball", + "cached-run-in-this-context": "0.5.0", "chai": "3.5.0", "chart.js": "^2.3.0", "clear-cut": "^2.0.2", @@ -59,7 +60,7 @@ "first-mate": "7.1.3", "focus-trap": "2.4.5", "fs-admin": "^0.1.7", - "fs-plus": "^3.1.1", + "fs-plus": "^3.0.1", "fstream": "0.1.24", "fuzzaldrin": "^2.1", "fuzzy-finder": "https://www.atom.io/api/packages/fuzzy-finder/versions/1.9.1/tarball", @@ -132,7 +133,7 @@ "one-light-ui": "file:packages/one-light-ui", "open-on-github": "https://www.atom.io/api/packages/open-on-github/versions/1.3.1/tarball", "package-generator": "https://www.atom.io/api/packages/package-generator/versions/1.3.0/tarball", - "pathwatcher": "8.0.2", + "pathwatcher": "8.0.1", "postcss": "5.2.4", "postcss-selector-parser": "2.2.1", "property-accessors": "^1.1.3", @@ -149,13 +150,13 @@ "snippets": "https://www.atom.io/api/packages/snippets/versions/1.4.0/tarball", "solarized-dark-syntax": "file:packages/solarized-dark-syntax", "solarized-light-syntax": "file:packages/solarized-light-syntax", - "spell-check": "https://www.atom.io/api/packages/spell-check/versions/0.74.3/tarball", + "spell-check": "https://www.atom.io/api/packages/spell-check/versions/0.74.2/tarball", "status-bar": "https://www.atom.io/api/packages/status-bar/versions/1.8.17/tarball", "styleguide": "https://www.atom.io/api/packages/styleguide/versions/0.49.12/tarball", "symbols-view": "https://www.atom.io/api/packages/symbols-view/versions/0.118.2/tarball", "tabs": "https://www.atom.io/api/packages/tabs/versions/0.110.0/tarball", "temp": "^0.8.3", - "text-buffer": "13.15.3", + "text-buffer": "13.15.1", "timecop": "https://www.atom.io/api/packages/timecop/versions/0.36.2/tarball", "tree-sitter": "0.13.23", "tree-sitter-css": "^0.13.7", @@ -218,7 +219,7 @@ "package-generator": "1.3.0", "settings-view": "0.259.0", "snippets": "1.4.0", - "spell-check": "0.74.3", + "spell-check": "0.74.2", "status-bar": "1.8.17", "styleguide": "0.49.12", "symbols-view": "0.118.2", diff --git a/script/lib/generate-startup-snapshot.js b/script/lib/generate-startup-snapshot.js index f6921d77a..553df33a4 100644 --- a/script/lib/generate-startup-snapshot.js +++ b/script/lib/generate-startup-snapshot.js @@ -42,6 +42,7 @@ module.exports = function (packagedAppPath) { requiredModuleRelativePath === path.join('..', 'src', 'electron-shims.js') || requiredModuleRelativePath === path.join('..', 'node_modules', 'atom-keymap', 'lib', 'command-event.js') || requiredModuleRelativePath === path.join('..', 'node_modules', 'babel-core', 'index.js') || + requiredModuleRelativePath === path.join('..', 'node_modules', 'cached-run-in-this-context', 'lib', 'main.js') || requiredModuleRelativePath === path.join('..', 'node_modules', 'debug', 'node.js') || requiredModuleRelativePath === path.join('..', 'node_modules', 'git-utils', 'src', 'git.js') || requiredModuleRelativePath === path.join('..', 'node_modules', 'glob', 'glob.js') || @@ -96,36 +97,22 @@ module.exports = function (packagedAppPath) { {env: Object.assign({}, process.env, {ELECTRON_RUN_AS_NODE: 1})} ) - console.log('Generating startup blob with mksnapshot') - childProcess.spawnSync( - process.execPath, [ - path.join(CONFIG.repositoryRootPath, 'script', 'node_modules', 'electron-mksnapshot', 'mksnapshot.js'), - snapshotScriptPath, - '--output_dir', - CONFIG.buildOutputPath - ] + const generatedStartupBlobPath = path.join(CONFIG.buildOutputPath, 'snapshot_blob.bin') + console.log(`Generating startup blob at "${generatedStartupBlobPath}"`) + childProcess.execFileSync( + path.join(CONFIG.repositoryRootPath, 'script', 'node_modules', 'electron-mksnapshot', 'bin', 'mksnapshot'), + ['--no-use_ic', snapshotScriptPath, '--startup_blob', generatedStartupBlobPath] ) let startupBlobDestinationPath if (process.platform === 'darwin') { - startupBlobDestinationPath = `${packagedAppPath}/Contents/Frameworks/Electron Framework.framework/Resources` + startupBlobDestinationPath = `${packagedAppPath}/Contents/Frameworks/Electron Framework.framework/Resources/snapshot_blob.bin` } else { - startupBlobDestinationPath = packagedAppPath + startupBlobDestinationPath = path.join(packagedAppPath, 'snapshot_blob.bin') } - const snapshotBinaries = ['v8_context_snapshot.bin', 'snapshot_blob.bin'] - for (let snapshotBinary of snapshotBinaries) { - const destinationPath = path.join(startupBlobDestinationPath, snapshotBinary) - console.log(`Moving generated startup blob into "${destinationPath}"`) - try { - fs.unlinkSync(destinationPath) - } catch (err) { - // Doesn't matter if the file doesn't exist already - if (!err.code || err.code !== 'ENOENT') { - throw err - } - } - fs.renameSync(path.join(CONFIG.buildOutputPath, snapshotBinary), destinationPath) - } + console.log(`Moving generated startup blob into "${startupBlobDestinationPath}"`) + fs.unlinkSync(startupBlobDestinationPath) + fs.renameSync(generatedStartupBlobPath, startupBlobDestinationPath) }) } diff --git a/script/package-lock.json b/script/package-lock.json index 8e960730c..ca50333eb 100644 --- a/script/package-lock.json +++ b/script/package-lock.json @@ -1692,65 +1692,43 @@ } }, "electron-chromedriver": { - "version": "3.0.0-beta.1", - "resolved": "https://registry.npmjs.org/electron-chromedriver/-/electron-chromedriver-3.0.0-beta.1.tgz", - "integrity": "sha512-S8KuOWqTISSfeVccrh1XjqR5tARdkAbF93azz8TvuNJTKoIw7V54mLKoyhi2Hj5UvKuPLcrHmfa4B9Uh45A5lA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/electron-chromedriver/-/electron-chromedriver-2.0.0.tgz", + "integrity": "sha512-kERk/Wzhc9RzW9jUKXA5kJc4m8BlL6c9p5QH+CrIlst0saeqZL1Up7vzD4ZOnuBDpAVBBYJ4jhkAKIssf8ZlXg==", "requires": { "electron-download": "^4.1.0", "extract-zip": "^1.6.5" } }, "electron-download": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/electron-download/-/electron-download-4.1.1.tgz", - "integrity": "sha512-FjEWG9Jb/ppK/2zToP+U5dds114fM1ZOJqMAR4aXXL5CvyPE9fiqBK/9YcwC9poIFQTEJk/EM/zyRwziziRZrg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/electron-download/-/electron-download-4.1.0.tgz", + "integrity": "sha1-v5MsdG8vh//MCdHdRy8v9rkYeEU=", "requires": { - "debug": "^3.0.0", + "debug": "^2.2.0", "env-paths": "^1.0.0", - "fs-extra": "^4.0.1", + "fs-extra": "^2.0.0", "minimist": "^1.2.0", - "nugget": "^2.0.1", + "nugget": "^2.0.0", "path-exists": "^3.0.0", - "rc": "^1.2.1", - "semver": "^5.4.1", - "sumchecker": "^2.0.2" + "rc": "^1.1.2", + "semver": "^5.3.0", + "sumchecker": "^2.0.1" }, "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } - }, "fs-extra": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", - "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-2.1.2.tgz", + "integrity": "sha1-BGxwFjzvmq1GsOSn+kZ/si1x3jU=", "requires": { "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "requires": { - "graceful-fs": "^4.1.6" + "jsonfile": "^2.1.0" } }, "path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" - }, - "semver": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.1.tgz", - "integrity": "sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw==" } } }, @@ -1811,13 +1789,12 @@ } }, "electron-mksnapshot": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/electron-mksnapshot/-/electron-mksnapshot-3.0.10.tgz", - "integrity": "sha512-Toy6sAC3t9tgvq1kUYsx+4TRNPDj7Bzoo+1gx5FD8Q0YCS+tq+ter62Ot6dBXCKG9SwoaGBz84b++MgO0VobYw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/electron-mksnapshot/-/electron-mksnapshot-2.0.0.tgz", + "integrity": "sha512-OoZwZJNKgHP+DwhCGVTJEuDSeb478hOzAbHeg7dKGCHDbKKmUWmjGc+pEjxGutpqQ3Mn8hCdLzdx2c/lAJcTLA==", "requires": { "electron-download": "^4.1.0", - "extract-zip": "^1.6.5", - "temp": "^0.8.3" + "extract-zip": "^1.6.5" } }, "electron-osx-sign": { @@ -10085,11 +10062,6 @@ "unist-util-is": "^2.1.1" } }, - "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" - }, "unset-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", diff --git a/script/package.json b/script/package.json index bc1456452..0cb86bc51 100644 --- a/script/package.json +++ b/script/package.json @@ -9,9 +9,9 @@ "coffeelint": "1.15.7", "colors": "1.1.2", "donna": "1.0.16", - "electron-chromedriver": "~3.0.0-beta.1", - "electron-link": "0.3.3", - "electron-mksnapshot": "~3.0.10", + "electron-chromedriver": "~2.0", + "electron-link": "0.3.2", + "electron-mksnapshot": "~2.0", "electron-packager": "7.3.0", "electron-winstaller": "2.6.4", "fs-admin": "^0.1.5", diff --git a/spec/decoration-manager-spec.coffee b/spec/decoration-manager-spec.coffee index 02073a3a2..b53458cd3 100644 --- a/spec/decoration-manager-spec.coffee +++ b/spec/decoration-manager-spec.coffee @@ -1,7 +1,6 @@ DecorationManager = require '../src/decoration-manager' TextEditor = require '../src/text-editor' -# Tests crash the renderer process on Electron 3.0, disabling for now. describe "DecorationManager", -> [decorationManager, buffer, editor, markerLayer1, markerLayer2] = [] diff --git a/spec/fixtures/babel/invalid.js b/spec/fixtures/babel/invalid.js index 513264538..585a4365b 100644 --- a/spec/fixtures/babel/invalid.js +++ b/spec/fixtures/babel/invalid.js @@ -1,3 +1,3 @@ 'use 6to6'; -export default 42; +module.exports = async function* hello() {} diff --git a/spec/selection-spec.js b/spec/selection-spec.js index 216c3936c..e9cf1c617 100644 --- a/spec/selection-spec.js +++ b/spec/selection-spec.js @@ -1,6 +1,5 @@ const TextEditor = require('../src/text-editor') -// Tests crash the renderer process on Electron 3.0, disabling for now. describe('Selection', () => { let buffer, editor, selection diff --git a/spec/style-manager-spec.js b/spec/style-manager-spec.js index fba73c808..641c93709 100644 --- a/spec/style-manager-spec.js +++ b/spec/style-manager-spec.js @@ -47,6 +47,7 @@ describe('StyleManager', () => { atom-text-editor::shadow .class-1, atom-text-editor::shadow .class-2 { color: red } atom-text-editor::shadow > .class-3 { color: yellow } atom-text-editor .class-4 { color: blue } + another-element::shadow .class-5 { color: white } atom-text-editor[data-grammar*=\"js\"]::shadow .class-6 { color: green; } atom-text-editor[mini].is-focused::shadow .class-7 { color: green; } `) @@ -54,6 +55,7 @@ describe('StyleManager', () => { 'atom-text-editor.editor .class-1, atom-text-editor.editor .class-2', 'atom-text-editor.editor > .class-3', 'atom-text-editor .class-4', + 'another-element::shadow .class-5', 'atom-text-editor[data-grammar*=\"js\"].editor .class-6', 'atom-text-editor[mini].is-focused.editor .class-7' ]) @@ -100,6 +102,13 @@ describe('StyleManager', () => { ]) }) + it('does not transform CSS rules with invalid syntax', () => { + styleManager.addStyleSheet("atom-text-editor::shadow .class-1 { font-family: inval'id }") + expect(Array.from(styleManager.getStyleElements()[0].sheet.cssRules).map((r) => r.selectorText)).toEqual([ + 'atom-text-editor::shadow .class-1' + ]) + }) + it('does not throw exceptions on rules with no selectors', () => { styleManager.addStyleSheet('@media screen {font-size: 10px}', {context: 'atom-text-editor'}) }) diff --git a/spec/text-mate-language-mode-spec.js b/spec/text-mate-language-mode-spec.js index 226a828e7..47b79af2d 100644 --- a/spec/text-mate-language-mode-spec.js +++ b/spec/text-mate-language-mode-spec.js @@ -6,7 +6,6 @@ const _ = require('underscore-plus') const dedent = require('dedent') const {it, fit, ffit, fffit, beforeEach, afterEach} = require('./async-spec-helpers') -// Tests crash the renderer process on Electron 3.0, disabling for now. describe('TextMateLanguageMode', () => { let languageMode, buffer, config diff --git a/spec/theme-manager-spec.js b/spec/theme-manager-spec.js index 48bc17ebe..9d1d3a3cc 100644 --- a/spec/theme-manager-spec.js +++ b/spec/theme-manager-spec.js @@ -251,9 +251,9 @@ h2 { it('returns a disposable allowing styles applied by the given path to be removed', function () { const cssPath = require.resolve('./fixtures/css.css') - expect(getComputedStyle(document.body).fontWeight).not.toBe('700') + expect(getComputedStyle(document.body).fontWeight).not.toBe('bold') const disposable = atom.themes.requireStylesheet(cssPath) - expect(getComputedStyle(document.body).fontWeight).toBe('700') + expect(getComputedStyle(document.body).fontWeight).toBe('bold') let styleElementRemovedHandler atom.styles.onDidRemoveStyleElement(styleElementRemovedHandler = jasmine.createSpy('styleElementRemovedHandler')) diff --git a/spec/workspace-spec.js b/spec/workspace-spec.js index 7bfbe5408..091588a70 100644 --- a/spec/workspace-spec.js +++ b/spec/workspace-spec.js @@ -2086,7 +2086,7 @@ describe('Workspace', () => { }) runs(() => { - fs.renameSync(path.join(projectPath, 'git.git'), path.join(projectPath, '.git')) + fs.rename(path.join(projectPath, 'git.git'), path.join(projectPath, '.git')) ignoredPath = path.join(projectPath, 'ignored.txt') fs.writeFileSync(ignoredPath, 'this match should not be included') }) diff --git a/src/compile-cache.js b/src/compile-cache.js index f1f596e86..ea387a631 100644 --- a/src/compile-cache.js +++ b/src/compile-cache.js @@ -177,7 +177,7 @@ exports.install = function (resourcesPath, nodeRequire) { var rawData = sourceMappingURL.slice(sourceMappingURL.indexOf(',') + 1) try { - var sourceMap = JSON.parse(Buffer.from(rawData, 'base64')) + var sourceMap = JSON.parse(new Buffer(rawData, 'base64')) } catch (error) { console.warn('Error parsing source map', error.stack) return null diff --git a/src/file-system-blob-store.js b/src/file-system-blob-store.js index 81e4a6f39..67a959735 100644 --- a/src/file-system-blob-store.js +++ b/src/file-system-blob-store.js @@ -20,7 +20,7 @@ class FileSystemBlobStore { reset () { this.inMemoryBlobs = new Map() - this.storedBlob = Buffer.alloc(0) + this.storedBlob = new Buffer(0) this.storedBlobMap = {} this.usedKeys = new Set() } diff --git a/src/native-compile-cache.js b/src/native-compile-cache.js index d8211b9f4..cc947e84b 100644 --- a/src/native-compile-cache.js +++ b/src/native-compile-cache.js @@ -1,7 +1,7 @@ const Module = require('module') const path = require('path') +const cachedVm = require('cached-run-in-this-context') const crypto = require('crypto') -const vm = require('vm') function computeHash (contents) { return crypto.createHash('sha1').update(contents, 'utf8').digest('hex') @@ -34,24 +34,6 @@ class NativeCompileCache { this.previousModuleCompile = Module.prototype._compile } - runInThisContext (code, filename) { - // produceCachedData is deprecated after Node 10.6, will need to update - // this for Electron 4.0 to use script.createCachedData() - const script = new vm.Script(code, {filename, produceCachedData: true}) - return { - result: script.runInThisContext(), - cacheBuffer: script.cachedData - } - } - - runInThisContextCached (code, filename, cachedData) { - const script = new vm.Script(code, {filename, cachedData}) - return { - result: script.runInThisContext(), - wasRejected: script.cachedDataRejected - } - } - overrideModuleCompile () { let self = this // Here we override Node's module.js @@ -82,7 +64,7 @@ class NativeCompileCache { let compiledWrapper = null if (self.cacheStore.has(cacheKey)) { let buffer = self.cacheStore.get(cacheKey) - let compilationResult = self.runInThisContextCached(wrapper, filename, buffer) + let compilationResult = cachedVm.runInThisContextCached(wrapper, filename, buffer) compiledWrapper = compilationResult.result if (compilationResult.wasRejected) { self.cacheStore.delete(cacheKey) @@ -90,12 +72,12 @@ class NativeCompileCache { } else { let compilationResult try { - compilationResult = self.runInThisContext(wrapper, filename) + compilationResult = cachedVm.runInThisContext(wrapper, filename) } catch (err) { console.error(`Error running script ${filename}`) throw err } - if (compilationResult.cacheBuffer !== null) { + if (compilationResult.cacheBuffer) { self.cacheStore.set(cacheKey, compilationResult.cacheBuffer) } compiledWrapper = compilationResult.result diff --git a/src/task.coffee b/src/task.coffee index 05d61f5a7..fa09c69f1 100644 --- a/src/task.coffee +++ b/src/task.coffee @@ -84,17 +84,17 @@ class Task # Routes messages from the child to the appropriate event. handleEvents: -> - @childProcess.removeAllListeners('message') + @childProcess.removeAllListeners() @childProcess.on 'message', ({event, args}) => @emitter.emit(event, args) if @childProcess? # Catch the errors that happened before task-bootstrap. if @childProcess.stdout? - @childProcess.stdout.removeAllListeners('data') + @childProcess.stdout.removeAllListeners() @childProcess.stdout.on 'data', (data) -> console.log data.toString() if @childProcess.stderr? - @childProcess.stderr.removeAllListeners('data') + @childProcess.stderr.removeAllListeners() @childProcess.stderr.on 'data', (data) -> console.error data.toString() # Public: Starts the task. @@ -147,9 +147,9 @@ class Task terminate: -> return false unless @childProcess? - @childProcess.removeAllListeners('message') - @childProcess.stdout?.removeAllListeners('data') - @childProcess.stderr?.removeAllListeners('data') + @childProcess.removeAllListeners() + @childProcess.stdout?.removeAllListeners() + @childProcess.stderr?.removeAllListeners() @childProcess.kill() @childProcess = null diff --git a/src/text-editor-component.js b/src/text-editor-component.js index 9da3db137..2f24c0df5 100644 --- a/src/text-editor-component.js +++ b/src/text-editor-component.js @@ -4446,7 +4446,7 @@ class NodePool { if (element) { element.className = className || '' - element.attributeStyleMap.forEach((value, key) => { + element.styleMap.forEach((value, key) => { if (!style || style[key] == null) element.style[key] = '' }) if (style) Object.assign(element.style, style) diff --git a/static/index.js b/static/index.js index 40840f304..7a7513683 100644 --- a/static/index.js +++ b/static/index.js @@ -1,4 +1,8 @@ (function () { + // Eagerly require cached-run-in-this-context to prevent a circular require + // when using `NativeCompileCache` for the first time. + require('cached-run-in-this-context') + const electron = require('electron') const path = require('path') const Module = require('module') From 9ff5160b452626e1eaf750aefbbaba6a8e41f324 Mon Sep 17 00:00:00 2001 From: Jason Rudolph Date: Mon, 25 Feb 2019 15:14:53 -0500 Subject: [PATCH 094/112] Update package-lock.json and script/package-lock.json --- package-lock.json | 27 ++++++++++++++++++++++++--- script/package-lock.json | 18 +++++++++--------- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/package-lock.json b/package-lock.json index aabc345ce..5c6c31a71 100644 --- a/package-lock.json +++ b/package-lock.json @@ -149,7 +149,7 @@ "apparatus": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/apparatus/-/apparatus-0.0.10.tgz", - "integrity": "sha1-gep1Z3Ktp3hj21TO7oICwQm9yj4=", + "integrity": "sha512-KLy/ugo33KZA7nugtQ7O0E1c8kQ52N3IvD/XgIh4w/Nr28ypfkwDfA67F1ev4N1m5D+BOk1+b2dEJDfpj/VvZg==", "requires": { "sylvester": ">= 0.0.8" } @@ -340,7 +340,7 @@ "atom-pathspec": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/atom-pathspec/-/atom-pathspec-0.0.0.tgz", - "integrity": "sha1-Z6q6+VAZsK/Y4xWLLNexjXN2Q/E=" + "integrity": "sha512-7UMEHdTtBV5sJONT0uMeQ6M8JFdfMQy/14rxuP6OuoFfSiDjxyZHuorIbv8gqhRB3FQMMLPzqONoFJE2cpHiCg==" }, "atom-select-list": { "version": "0.7.2", @@ -1172,6 +1172,27 @@ "nan": "^2.10.0" } }, + "caller-callsite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", + "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", + "requires": { + "callsites": "^2.0.0" + } + }, + "caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", + "requires": { + "caller-callsite": "^2.0.0" + } + }, + "callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=" + }, "camelcase": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", @@ -5191,7 +5212,7 @@ "spelling-manager": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/spelling-manager/-/spelling-manager-1.1.0.tgz", - "integrity": "sha1-UZmGdZUpHgVjlExuL70ao02X3TQ=", + "integrity": "sha512-PpTP6XUZflCWO9YZO3wBSGAmqrUP6BFwSdmVFS6WBT9rFYg3ysmrIfyD1KnaVcnW6wuIKf+FDwefvU8PsD8Smg==", "requires": { "natural": "0.5.0", "xregexp": "^3.2.0" diff --git a/script/package-lock.json b/script/package-lock.json index ca50333eb..6bda42fdf 100644 --- a/script/package-lock.json +++ b/script/package-lock.json @@ -1733,9 +1733,9 @@ } }, "electron-link": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/electron-link/-/electron-link-0.3.3.tgz", - "integrity": "sha512-dxFY3o3E9kBkOyfaY66PWabK1AL5Re8qmy2Abz2/VhVkp2KtvUn6BZODTm9XpC0REgWxlQfRyHlNTlXRBPrWCQ==", + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/electron-link/-/electron-link-0.3.2.tgz", + "integrity": "sha512-V7QmtujzWgvrW5BI2CKmIRF+q+pkrFO5Lecd8TpibbBz+FfW5WQ4kCN0sZjNaUOMtGGroCib721OqIDEynjwgA==", "requires": { "ast-util": "^0.6.0", "encoding-down": "~5.0.0", @@ -1753,9 +1753,9 @@ "integrity": "sha512-UY7+9DPzlJ9VM8eY0b2TUZcZvF+1pO0hzMtAyjBYKhOmnvRlqYNYnWdtsMj0V16CGaMlpL0G1jnLbLo4AyotuQ==" }, "core-js": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.3.tgz", - "integrity": "sha512-l00tmFFZOBHtYhN4Cz7k32VM7vTn3rE2ANjQDxdEN6zmXZ/xq1jQuutnmHvMG1ZJ7xd72+TA5YpUK8wz3rWsfQ==" + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.5.tgz", + "integrity": "sha512-klh/kDpwX8hryYL14M9w/xei6vrv6sE8gTHDG7/T/+SEovB/G4ejwcfE/CBzO6Edsu+OETZMZ3wcX/EjUkrl5A==" }, "esprima": { "version": "4.0.1", @@ -4575,9 +4575,9 @@ "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" }, "node-abi": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.7.0.tgz", - "integrity": "sha512-egTtvNoZLMjwxkL/5iiJKYKZgn2im0zP+G+PncMxICYGiD3aZtXUvEsDmu0pF8gpASvLZyD8v53qi1/ELaRZpg==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.7.1.tgz", + "integrity": "sha512-OV8Bq1OrPh6z+Y4dqwo05HqrRL9YNF7QVMRfq1/pguwKLG+q9UB/Lk0x5qXjO23JjJg+/jqCHSTaG1P3tfKfuw==", "requires": { "semver": "^5.4.1" }, From 3b195122c4d22eb7e2f9cfbffa246804232fac1e Mon Sep 17 00:00:00 2001 From: Jason Rudolph Date: Mon, 25 Feb 2019 11:58:04 -0500 Subject: [PATCH 095/112] Tell VSTS to build electron-* branches --- script/vsts/release-branch-build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/script/vsts/release-branch-build.yml b/script/vsts/release-branch-build.yml index 05bfd2d76..de9d4e72f 100644 --- a/script/vsts/release-branch-build.yml +++ b/script/vsts/release-branch-build.yml @@ -1,6 +1,7 @@ trigger: - master - 1.* # VSTS only supports wildcards at the end +- electron-* resources: containers: From bd6a0fc37c2f98c2a56bab7feb83e416defe5171 Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Wed, 27 Feb 2019 20:28:37 +0100 Subject: [PATCH 096/112] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20fuzzy-finder@1.9.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5c6c31a71..1285a957c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2484,8 +2484,8 @@ "integrity": "sha1-gy9kifvodnaUWVmckUpnDsIpR+4=" }, "fuzzy-finder": { - "version": "https://www.atom.io/api/packages/fuzzy-finder/versions/1.9.1/tarball", - "integrity": "sha512-UHyWdvhaiosjg4Rf3OKIWHew7kAB3T6ZQkaTJKMfBoARAdV3t6TvifRKYFICUjERWCHsx2fB+AZ1QwtMYuDiHA==", + "version": "https://www.atom.io/api/packages/fuzzy-finder/versions/1.9.2/tarball", + "integrity": "sha512-gpr1DXfxCEwMO48uCudocIZomhHlMJk+l1lAXJXwamtprDRsuzSqVMFjlyM49/cn4P5ToMhVHHHFngg0wklpvw==", "requires": { "async": "0.2.6", "atom-select-list": "^0.7.0", diff --git a/package.json b/package.json index ba795cd3b..cb1b77686 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "fs-plus": "^3.0.1", "fstream": "0.1.24", "fuzzaldrin": "^2.1", - "fuzzy-finder": "https://www.atom.io/api/packages/fuzzy-finder/versions/1.9.1/tarball", + "fuzzy-finder": "https://www.atom.io/api/packages/fuzzy-finder/versions/1.9.2/tarball", "git-diff": "file:packages/git-diff", "git-utils": "5.2.1", "github": "https://www.atom.io/api/packages/github/versions/0.26.0/tarball", From e7ce8c316628e9771c0820046ef601ff6ce8d190 Mon Sep 17 00:00:00 2001 From: simurai Date: Thu, 28 Feb 2019 17:27:28 +0900 Subject: [PATCH 097/112] :arrow_up: welcome@v0.36.8 --- package-lock.json | 4 ++-- package.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5c6c31a71..59f0f5cea 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5970,8 +5970,8 @@ "integrity": "sha1-BNoCcKh6d4VAFzzb8KLbSZqNnik=" }, "welcome": { - "version": "https://www.atom.io/api/packages/welcome/versions/0.36.7/tarball", - "integrity": "sha512-z1EOTRYfN23fBL75Shrbe/j2VDelw2c8oKRXC2MqLLBiWUCFDkxsEo1R7OfiCaNZi7q/0ue0fqLCpENHker4FA==", + "version": "https://www.atom.io/api/packages/welcome/versions/0.36.8/tarball", + "integrity": "sha512-U2EFFqgGxqQ5eMFFP3bl5oBSSvb0kx4VZwQVyO8oXqjuveiV2gUSrnDP68C9yCqJxcMR9ZP4ZYTLsf255F7CsA==", "requires": { "etch": "0.9.0" }, diff --git a/package.json b/package.json index ba795cd3b..9bc4dcda4 100644 --- a/package.json +++ b/package.json @@ -164,7 +164,7 @@ "typescript-simple": "1.0.0", "underscore-plus": "^1.6.8", "update-package-dependencies": "https://www.atom.io/api/packages/update-package-dependencies/versions/0.13.1/tarball", - "welcome": "https://www.atom.io/api/packages/welcome/versions/0.36.7/tarball", + "welcome": "https://www.atom.io/api/packages/welcome/versions/0.36.8/tarball", "whitespace": "https://www.atom.io/api/packages/whitespace/versions/0.37.7/tarball", "winreg": "^1.2.1", "wrap-guide": "https://www.atom.io/api/packages/wrap-guide/versions/0.41.0/tarball", @@ -227,7 +227,7 @@ "timecop": "0.36.2", "tree-view": "0.224.5", "update-package-dependencies": "0.13.1", - "welcome": "0.36.7", + "welcome": "0.36.8", "whitespace": "0.37.7", "wrap-guide": "0.41.0", "language-c": "0.60.14", From c643d96fcaf46c6436ed700e4c8cd861c64efb60 Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Thu, 28 Feb 2019 10:49:48 +0100 Subject: [PATCH 098/112] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20snippets@1.4.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5c6c31a71..2517c34b9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5114,8 +5114,8 @@ "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=" }, "snippets": { - "version": "https://www.atom.io/api/packages/snippets/versions/1.4.0/tarball", - "integrity": "sha512-pfw/YOwYeU4xJBEe/qztZx8Lq0ODLtSy7seoaMRu4w1lGlzl0HsqBeqTwLxR6bak3nS5WLj+k3hSJO+yNJWH2w==", + "version": "https://www.atom.io/api/packages/snippets/versions/1.4.1/tarball", + "integrity": "sha512-bLQmuMmyC+Sfjm/jdPbY3j/Vml3E4ApKhMFRb4AJLTde5m7TEhdTmsQBtkf+vFqGfr76tZ144F9NWH12ryS5rw==", "requires": { "async": "~0.2.6", "atom-select-list": "^0.7.0", diff --git a/package.json b/package.json index ba795cd3b..8b3691127 100644 --- a/package.json +++ b/package.json @@ -147,7 +147,7 @@ "service-hub": "^0.7.4", "settings-view": "https://www.atom.io/api/packages/settings-view/versions/0.259.0/tarball", "sinon": "1.17.4", - "snippets": "https://www.atom.io/api/packages/snippets/versions/1.4.0/tarball", + "snippets": "https://www.atom.io/api/packages/snippets/versions/1.4.1/tarball", "solarized-dark-syntax": "file:packages/solarized-dark-syntax", "solarized-light-syntax": "file:packages/solarized-light-syntax", "spell-check": "https://www.atom.io/api/packages/spell-check/versions/0.74.2/tarball", From fa0f103c3c386bb362caae257a21ca69bcbb5e7e Mon Sep 17 00:00:00 2001 From: simurai Date: Thu, 28 Feb 2019 19:55:09 +0900 Subject: [PATCH 099/112] :arrow_up: settings-view@v0.260.0 --- package-lock.json | 4 ++-- package.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5c6c31a71..ca591f924 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5003,8 +5003,8 @@ "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" }, "settings-view": { - "version": "https://www.atom.io/api/packages/settings-view/versions/0.259.0/tarball", - "integrity": "sha512-jNQuTozGf1uQtS4Y4hlUT15STnmnKlAWzzJOIe+ts2S/SdrGHZwxhNykJFzM8gC8j4N3Kjb8CkgmbCDzZ98aEw==", + "version": "https://www.atom.io/api/packages/settings-view/versions/0.260.0/tarball", + "integrity": "sha512-uZspfpknxC+47Zr9FJmkrAzR+a7yprv6hevZU6dUIQ1q2n0ws/Bxm6mgZVjyxpDmnNRwxiMrzCl2UArE05sNOg==", "requires": { "async": "~0.2.9", "dompurify": "^1.0.2", diff --git a/package.json b/package.json index ba795cd3b..d5987674a 100644 --- a/package.json +++ b/package.json @@ -145,7 +145,7 @@ "season": "^6.0.2", "semver": "^4.3.3", "service-hub": "^0.7.4", - "settings-view": "https://www.atom.io/api/packages/settings-view/versions/0.259.0/tarball", + "settings-view": "https://www.atom.io/api/packages/settings-view/versions/0.260.0/tarball", "sinon": "1.17.4", "snippets": "https://www.atom.io/api/packages/snippets/versions/1.4.0/tarball", "solarized-dark-syntax": "file:packages/solarized-dark-syntax", @@ -217,7 +217,7 @@ "notifications": "0.70.6", "open-on-github": "1.3.1", "package-generator": "1.3.0", - "settings-view": "0.259.0", + "settings-view": "0.260.0", "snippets": "1.4.0", "spell-check": "0.74.2", "status-bar": "1.8.17", From 96b29fe3cef3d1f0c9cbfb479d03f630af49d15a Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Thu, 28 Feb 2019 12:13:16 +0100 Subject: [PATCH 100/112] Update versions of fuzzy-finder and snippets I forgot to update the second place on the `package.json` where its version is specified --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 1d6372e6c..880ef8031 100644 --- a/package.json +++ b/package.json @@ -202,7 +202,7 @@ "encoding-selector": "0.23.9", "exception-reporting": "file:./packages/exception-reporting", "find-and-replace": "0.218.9", - "fuzzy-finder": "1.9.1", + "fuzzy-finder": "1.9.2", "github": "0.26.0", "git-diff": "file:./packages/git-diff", "go-to-line": "file:./packages/go-to-line", @@ -218,7 +218,7 @@ "open-on-github": "1.3.1", "package-generator": "1.3.0", "settings-view": "0.259.0", - "snippets": "1.4.0", + "snippets": "1.4.1", "spell-check": "0.74.2", "status-bar": "1.8.17", "styleguide": "0.49.12", From 7876e04e975dd6a087de15829ca7a9423d6e125d Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Tue, 26 Feb 2019 23:39:51 +0100 Subject: [PATCH 101/112] Override global jasmine spec functions Currently, if a spec uses the global `it` function on an async test, that test will always pass (since the jasmine version checked in Atom does not natively support tests that return promises). This can be confusing since the test behaviour is different between the async-test-helpers methods and the global ones. By overriding the global functions, we'll also be able to remove all the imports from async-test-helpers since they won't be needed anymore. More info: https://github.com/atom/atom/pull/18896#discussion_r260396102 --- spec/jasmine-test-runner.coffee | 34 ++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/spec/jasmine-test-runner.coffee b/spec/jasmine-test-runner.coffee index 5a11530b7..8bf1d3ede 100644 --- a/spec/jasmine-test-runner.coffee +++ b/spec/jasmine-test-runner.coffee @@ -10,6 +10,16 @@ module.exports = ({logFile, headless, testPaths, buildAtomEnvironment}) -> window[key] = value for key, value of require '../vendor/jasmine' require 'jasmine-tagged' + # Rewrite global jasmine functions to have support for async tests. + # This way packages can create async specs without having to import these from the + # async-spec-helpers file. + global.it = asyncifyJasmineFn global.it, 1 + global.fit = asyncifyJasmineFn global.fit, 1 + global.ffit = asyncifyJasmineFn global.ffit, 1 + global.fffit = asyncifyJasmineFn global.fffit, 1 + global.beforeEach = asyncifyJasmineFn global.beforeEach, 0 + global.afterEach = asyncifyJasmineFn global.afterEach, 0 + # Allow document.title to be assigned in specs without screwing up spec window title documentTitle = null Object.defineProperty document, 'title', @@ -59,6 +69,28 @@ module.exports = ({logFile, headless, testPaths, buildAtomEnvironment}) -> jasmineEnv.execute() promise +asyncifyJasmineFn = (fn, callbackPosition) -> + (args...) -> + if typeof args[callbackPosition] is 'function' + callback = args[callbackPosition] + + args[callbackPosition] = (args...) -> + result = callback.apply this, args + if result instanceof Promise + waitsForPromise(-> result) + + fn.apply this, args + +waitsForPromise = (fn) -> + promise = fn() + + global.waitsFor('spec promise to resolve', (done) -> + promise.then(done, (error) -> + jasmine.getEnv().currentSpec.fail error + done() + ) + ) + disableFocusMethods = -> ['fdescribe', 'ffdescribe', 'fffdescribe', 'fit', 'ffit', 'fffit'].forEach (methodName) -> focusMethod = window[methodName] @@ -124,4 +156,4 @@ buildTerminalReporter = (logFile, resolveWithExitCode) -> new JasmineListReporter(options) else {TerminalReporter} = require 'jasmine-tagged' - new TerminalReporter(options) + new TerminalReporter(options) \ No newline at end of file From c35ec012b46dc76a5294f5cbf7227ce47e859e1d Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Fri, 22 Feb 2019 08:55:17 +0100 Subject: [PATCH 102/112] Run prettier on spec/ folder --- spec/application-delegate-spec.js | 13 +- spec/async-spec-helpers.js | 5 +- spec/atom-environment-spec.js | 309 +- spec/atom-paths-spec.js | 19 +- spec/auto-update-manager-spec.js | 12 +- spec/command-installer-spec.js | 78 +- spec/command-registry-spec.js | 699 +-- spec/config-file-spec.js | 46 +- spec/config-spec.js | 1107 +++-- spec/dock-spec.js | 163 +- spec/git-repository-provider-spec.js | 27 +- spec/git-repository-spec.js | 122 +- spec/grammar-registry-spec.js | 471 +- spec/gutter-container-spec.js | 32 +- spec/gutter-spec.js | 16 +- spec/helpers/random.js | 2 +- spec/history-manager-spec.js | 103 +- spec/jasmine-list-reporter.js | 2 +- spec/main-process/atom-application.test.js | 613 ++- .../file-recovery-service.test.js | 72 +- spec/main-process/mocha-test-runner.js | 5 +- spec/main-process/parse-command-line.test.js | 19 +- spec/menu-sort-helpers-spec.js | 11 +- spec/native-watcher-registry-spec.js | 103 +- spec/notification-manager-spec.js | 15 +- spec/notification-spec.js | 17 +- spec/package-manager-spec.js | 786 +++- spec/package-transpilation-registry-spec.js | 176 +- spec/pane-container-spec.js | 171 +- spec/pane-spec.js | 448 +- spec/panel-container-element-spec.js | 90 +- spec/panel-container-spec.js | 74 +- spec/panel-spec.js | 22 +- spec/path-watcher-spec.js | 41 +- spec/project-spec.js | 502 ++- spec/reopen-project-menu-manager-spec.js | 156 +- spec/selection-spec.js | 51 +- spec/state-store-spec.js | 54 +- spec/style-manager-spec.js | 100 +- spec/syntax-scope-map-spec.js | 4 +- spec/text-editor-component-spec.js | 3801 ++++++++++++----- spec/text-editor-element-spec.js | 99 +- spec/text-editor-registry-spec.js | 117 +- spec/text-editor-spec.js | 2740 ++++++++---- spec/text-mate-language-mode-spec.js | 700 ++- spec/text-utils-spec.js | 50 +- spec/theme-manager-spec.js | 282 +- spec/title-bar-spec.js | 20 +- spec/tooltip-manager-spec.js | 167 +- spec/tree-sitter-language-mode-spec.js | 1417 +++--- spec/update-process-env-spec.js | 153 +- spec/uri-handler-registry-spec.js | 29 +- spec/view-registry-spec.js | 48 +- spec/window-event-handler-spec.js | 128 +- spec/workspace-center-spec.js | 24 +- spec/workspace-element-spec.js | 433 +- spec/workspace-spec.js | 1273 ++++-- 57 files changed, 12629 insertions(+), 5608 deletions(-) diff --git a/spec/application-delegate-spec.js b/spec/application-delegate-spec.js index 5512c88ea..97326aa24 100644 --- a/spec/application-delegate-spec.js +++ b/spec/application-delegate-spec.js @@ -1,14 +1,21 @@ /** @babel */ -import {it, fit, ffit, fffit, beforeEach, afterEach} from './async-spec-helpers' +import { + it, + fit, + ffit, + fffit, + beforeEach, + afterEach +} from './async-spec-helpers' import ApplicationDelegate from '../src/application-delegate' describe('ApplicationDelegate', function () { describe('set/getTemporaryWindowState', function () { it('can serialize object trees containing redundant child object references', async function () { const applicationDelegate = new ApplicationDelegate() - const childObject = {c: 1} - const sentObject = {a: childObject, b: childObject} + const childObject = { c: 1 } + const sentObject = { a: childObject, b: childObject } await applicationDelegate.setTemporaryWindowState(sentObject) const receivedObject = await applicationDelegate.getTemporaryWindowState() diff --git a/spec/async-spec-helpers.js b/spec/async-spec-helpers.js index 90cb85e23..c6a5920a5 100644 --- a/spec/async-spec-helpers.js +++ b/spec/async-spec-helpers.js @@ -32,7 +32,10 @@ function afterEach (fn) { } }) -async function conditionPromise (condition, description = 'anonymous condition') { +async function conditionPromise ( + condition, + description = 'anonymous condition' +) { const startTime = Date.now() while (true) { diff --git a/spec/atom-environment-spec.js b/spec/atom-environment-spec.js index 5e9617374..8e5dd5dba 100644 --- a/spec/atom-environment-spec.js +++ b/spec/atom-environment-spec.js @@ -1,4 +1,11 @@ -const {it, fit, ffit, beforeEach, afterEach, conditionPromise} = require('./async-spec-helpers') +const { + it, + fit, + ffit, + beforeEach, + afterEach, + conditionPromise +} = require('./async-spec-helpers') const _ = require('underscore-plus') const fs = require('fs') const path = require('path') @@ -15,26 +22,26 @@ describe('AtomEnvironment', () => { describe('window sizing methods', () => { describe('::getPosition and ::setPosition', () => { let originalPosition = null - beforeEach(() => originalPosition = atom.getPosition()) + beforeEach(() => (originalPosition = atom.getPosition())) afterEach(() => atom.setPosition(originalPosition.x, originalPosition.y)) it('sets the position of the window, and can retrieve the position just set', () => { atom.setPosition(22, 45) - expect(atom.getPosition()).toEqual({x: 22, y: 45}) + expect(atom.getPosition()).toEqual({ x: 22, y: 45 }) }) }) describe('::getSize and ::setSize', () => { let originalSize = null - beforeEach(() => originalSize = atom.getSize()) + beforeEach(() => (originalSize = atom.getSize())) afterEach(() => atom.setSize(originalSize.width, originalSize.height)) it('sets the size of the window, and can retrieve the size just set', async () => { const newWidth = originalSize.width - 12 const newHeight = originalSize.height - 23 await atom.setSize(newWidth, newHeight) - expect(atom.getSize()).toEqual({width: newWidth, height: newHeight}) + expect(atom.getSize()).toEqual({ width: newWidth, height: newHeight }) }) }) }) @@ -122,7 +129,7 @@ describe('AtomEnvironment', () => { describe('::onDidThrowError', () => { let didThrowSpy = null - beforeEach(() => didThrowSpy = jasmine.createSpy()) + beforeEach(() => (didThrowSpy = jasmine.createSpy())) it('is called when there is an error', () => { let error = null @@ -165,22 +172,24 @@ describe('AtomEnvironment', () => { describe('if passed a callback function', () => { it("calls the callback with the assertion failure's error object", () => { let error = null - atom.assert(false, 'a == b', e => error = e) + atom.assert(false, 'a == b', e => (error = e)) expect(error).toBe(errors[0]) }) }) describe('if passed metadata', () => { it("assigns the metadata on the assertion failure's error object", () => { - atom.assert(false, 'a == b', {foo: 'bar'}) - expect(errors[0].metadata).toEqual({foo: 'bar'}) + atom.assert(false, 'a == b', { foo: 'bar' }) + expect(errors[0].metadata).toEqual({ foo: 'bar' }) }) }) describe('when Atom has been built from source', () => { it('throws an error', () => { atom.isReleasedVersion.andReturn(false) - expect(() => atom.assert(false, 'testing')).toThrow('Assertion failed: testing') + expect(() => atom.assert(false, 'testing')).toThrow( + 'Assertion failed: testing' + ) }) }) }) @@ -195,9 +204,9 @@ describe('AtomEnvironment', () => { }) describe('saving and loading', () => { - beforeEach(() => atom.enablePersistence = true) + beforeEach(() => (atom.enablePersistence = true)) - afterEach(() => atom.enablePersistence = false) + afterEach(() => (atom.enablePersistence = false)) it('selects the state based on the current project paths', async () => { jasmine.useRealClock() @@ -210,7 +219,7 @@ describe('AtomEnvironment', () => { }) spyOn(atom, 'getLoadSettings').andCallFake(() => loadSettings) - spyOn(atom, 'serialize').andReturn({stuff: 'cool'}) + spyOn(atom, 'serialize').andReturn({ stuff: 'cool' }) atom.project.setPaths([dir1, dir2]) @@ -221,7 +230,7 @@ describe('AtomEnvironment', () => { expect(await atom.loadState()).toBeFalsy() loadSettings.initialPaths = [dir2, dir1] - expect(await atom.loadState()).toEqual({stuff: 'cool'}) + expect(await atom.loadState()).toEqual({ stuff: 'cool' }) }) it('saves state when the CPU is idle after a keydown or mousedown event', () => { @@ -231,7 +240,9 @@ describe('AtomEnvironment', () => { const idleCallbacks = [] atomEnv.initialize({ window: { - requestIdleCallback (callback) { idleCallbacks.push(callback) }, + requestIdleCallback (callback) { + idleCallbacks.push(callback) + }, addEventListener () {}, removeEventListener () {} }, @@ -244,16 +255,16 @@ describe('AtomEnvironment', () => { atomEnv.document.dispatchEvent(keydown) advanceClock(atomEnv.saveStateDebounceInterval) idleCallbacks.shift()() - expect(atomEnv.saveState).toHaveBeenCalledWith({isUnloading: false}) - expect(atomEnv.saveState).not.toHaveBeenCalledWith({isUnloading: true}) + expect(atomEnv.saveState).toHaveBeenCalledWith({ isUnloading: false }) + expect(atomEnv.saveState).not.toHaveBeenCalledWith({ isUnloading: true }) atomEnv.saveState.reset() const mousedown = new MouseEvent('mousedown') atomEnv.document.dispatchEvent(mousedown) advanceClock(atomEnv.saveStateDebounceInterval) idleCallbacks.shift()() - expect(atomEnv.saveState).toHaveBeenCalledWith({isUnloading: false}) - expect(atomEnv.saveState).not.toHaveBeenCalledWith({isUnloading: true}) + expect(atomEnv.saveState).toHaveBeenCalledWith({ isUnloading: false }) + expect(atomEnv.saveState).not.toHaveBeenCalledWith({ isUnloading: true }) atomEnv.destroy() }) @@ -265,7 +276,9 @@ describe('AtomEnvironment', () => { const idleCallbacks = [] atomEnv.initialize({ window: { - requestIdleCallback (callback) { idleCallbacks.push(callback) }, + requestIdleCallback (callback) { + idleCallbacks.push(callback) + }, addEventListener () {}, removeEventListener () {} }, @@ -278,7 +291,7 @@ describe('AtomEnvironment', () => { atomEnv.document.dispatchEvent(mousedown) expect(atomEnv.saveState).not.toHaveBeenCalled() await atomEnv.prepareToUnloadEditorWindow() - expect(atomEnv.saveState).toHaveBeenCalledWith({isUnloading: true}) + expect(atomEnv.saveState).toHaveBeenCalledWith({ isUnloading: true }) advanceClock(atomEnv.saveStateDebounceInterval) idleCallbacks.shift()() @@ -294,11 +307,13 @@ describe('AtomEnvironment', () => { }) it('serializes the project state with all the options supplied in saveState', async () => { - spyOn(atom.project, 'serialize').andReturn({foo: 42}) + spyOn(atom.project, 'serialize').andReturn({ foo: 42 }) - await atom.saveState({anyOption: 'any option'}) + await atom.saveState({ anyOption: 'any option' }) expect(atom.project.serialize.calls.length).toBe(1) - expect(atom.project.serialize.mostRecentCall.args[0]).toEqual({anyOption: 'any option'}) + expect(atom.project.serialize.mostRecentCall.args[0]).toEqual({ + anyOption: 'any option' + }) }) it('serializes the text editor registry', async () => { @@ -309,20 +324,22 @@ describe('AtomEnvironment', () => { const atom2 = new AtomEnvironment({ applicationDelegate: atom.applicationDelegate, window: document.createElement('div'), - document: Object.assign( - document.createElement('div'), - { - body: document.createElement('div'), - head: document.createElement('div') - } - ) + document: Object.assign(document.createElement('div'), { + body: document.createElement('div'), + head: document.createElement('div') + }) }) - atom2.initialize({document, window}) + atom2.initialize({ document, window }) await atom2.deserialize(atom.serialize()) await atom2.packages.activatePackage('language-text') const editor2 = atom2.workspace.getActiveTextEditor() - expect(editor2.getBuffer().getLanguageMode().getLanguageId()).toBe('text.plain') + expect( + editor2 + .getBuffer() + .getLanguageMode() + .getLanguageId() + ).toBe('text.plain') atom2.destroy() }) @@ -335,10 +352,13 @@ describe('AtomEnvironment', () => { }) spyOn(atom.notifications, 'addError') - await atom.deserialize({project: 'should work'}) - expect(atom.notifications.addError).toHaveBeenCalledWith('Unable to open project directory', { - description: 'Project directory `/foo` is no longer on disk.' - }) + await atom.deserialize({ project: 'should work' }) + expect(atom.notifications.addError).toHaveBeenCalledWith( + 'Unable to open project directory', + { + description: 'Project directory `/foo` is no longer on disk.' + } + ) }) it('accumulates and reports two errors with one notification', async () => { @@ -349,10 +369,14 @@ describe('AtomEnvironment', () => { }) spyOn(atom.notifications, 'addError') - await atom.deserialize({project: 'should work'}) - expect(atom.notifications.addError).toHaveBeenCalledWith('Unable to open 2 project directories', { - description: 'Project directories `/foo` and `/wat` are no longer on disk.' - }) + await atom.deserialize({ project: 'should work' }) + expect(atom.notifications.addError).toHaveBeenCalledWith( + 'Unable to open 2 project directories', + { + description: + 'Project directories `/foo` and `/wat` are no longer on disk.' + } + ) }) it('accumulates and reports three+ errors with one notification', async () => { @@ -363,17 +387,23 @@ describe('AtomEnvironment', () => { }) spyOn(atom.notifications, 'addError') - await atom.deserialize({project: 'should work'}) - expect(atom.notifications.addError).toHaveBeenCalledWith('Unable to open 4 project directories', { - description: 'Project directories `/foo`, `/wat`, `/stuff`, and `/things` are no longer on disk.' - }) + await atom.deserialize({ project: 'should work' }) + expect(atom.notifications.addError).toHaveBeenCalledWith( + 'Unable to open 4 project directories', + { + description: + 'Project directories `/foo`, `/wat`, `/stuff`, and `/things` are no longer on disk.' + } + ) }) }) }) describe('openInitialEmptyEditorIfNecessary', () => { describe('when there are no paths set', () => { - beforeEach(() => spyOn(atom, 'getLoadSettings').andReturn({initialPaths: []})) + beforeEach(() => + spyOn(atom, 'getLoadSettings').andReturn({ initialPaths: [] }) + ) it('opens an empty buffer', () => { spyOn(atom.workspace, 'open') @@ -396,7 +426,9 @@ describe('AtomEnvironment', () => { describe('when the project has a path', () => { beforeEach(() => { - spyOn(atom, 'getLoadSettings').andReturn({initialPaths: ['something']}) + spyOn(atom, 'getLoadSettings').andReturn({ + initialPaths: ['something'] + }) spyOn(atom.workspace, 'open') }) @@ -425,7 +457,9 @@ describe('AtomEnvironment', () => { it('adds the selected folder to the project', async () => { const initialPaths = atom.project.setPaths([]) const tempDirectory = temp.mkdirSync('a-new-directory') - spyOn(atom, 'pickFolder').andCallFake(callback => callback([tempDirectory])) + spyOn(atom, 'pickFolder').andCallFake(callback => + callback([tempDirectory]) + ) await atom.addProjectFolder() expect(atom.project.getPaths()).toEqual([tempDirectory]) expect(atom.attemptRestoreProjectStateForPaths).not.toHaveBeenCalled() @@ -437,7 +471,9 @@ describe('AtomEnvironment', () => { beforeEach(() => { spyOn(atom, 'getStateKey').andCallFake(dirs => dirs.join(':')) - spyOn(atom, 'loadState').andCallFake(async (key) => key === __dirname ? state : null) + spyOn(atom, 'loadState').andCallFake(async key => + key === __dirname ? state : null + ) spyOn(atom, 'attemptRestoreProjectStateForPaths') spyOn(atom, 'pickFolder').andCallFake(callback => callback([__dirname])) atom.project.setPaths([]) @@ -446,7 +482,10 @@ describe('AtomEnvironment', () => { describe('when there are no project folders', () => { it('attempts to restore the project state', async () => { await atom.addProjectFolder() - expect(atom.attemptRestoreProjectStateForPaths).toHaveBeenCalledWith(state, [__dirname]) + expect(atom.attemptRestoreProjectStateForPaths).toHaveBeenCalledWith( + state, + [__dirname] + ) expect(atom.project.getPaths()).toEqual([]) }) }) @@ -481,7 +520,9 @@ describe('AtomEnvironment', () => { fs.writeFileSync(filePath2, 'def') fs.writeFileSync(filePath3, 'ghi') - const env1 = new AtomEnvironment({applicationDelegate: atom.applicationDelegate}) + const env1 = new AtomEnvironment({ + applicationDelegate: atom.applicationDelegate + }) env1.project.setPaths([projectPath]) await env1.workspace.open(filePath1) await env1.workspace.open(filePath2) @@ -489,8 +530,14 @@ describe('AtomEnvironment', () => { const env1State = env1.serialize() env1.destroy() - const env2 = new AtomEnvironment({applicationDelegate: atom.applicationDelegate}) - await env2.attemptRestoreProjectStateForPaths(env1State, [projectPath], [filePath2]) + const env2 = new AtomEnvironment({ + applicationDelegate: atom.applicationDelegate + }) + await env2.attemptRestoreProjectStateForPaths( + env1State, + [projectPath], + [filePath2] + ) const restoredURIs = env2.workspace.getPaneItems().map(p => p.getURI()) expect(restoredURIs).toEqual([filePath1, filePath2, filePath3]) env2.destroy() @@ -500,12 +547,18 @@ describe('AtomEnvironment', () => { it("doesn't prompt the user to restore state", () => { const dock = atom.workspace.getLeftDock() dock.getActivePane().addItem({ - getTitle () { return 'title' }, + getTitle () { + return 'title' + }, element: document.createElement('div') }) const state = {} spyOn(atom, 'confirm') - atom.attemptRestoreProjectStateForPaths(state, [__dirname], [__filename]) + atom.attemptRestoreProjectStateForPaths( + state, + [__dirname], + [__filename] + ) expect(atom.confirm).not.toHaveBeenCalled() }) }) @@ -527,7 +580,11 @@ describe('AtomEnvironment', () => { spyOn(atom.project, 'addPath') spyOn(atom.workspace, 'open') const state = Symbol() - atom.attemptRestoreProjectStateForPaths(state, [__dirname], [__filename]) + atom.attemptRestoreProjectStateForPaths( + state, + [__dirname], + [__filename] + ) expect(atom.confirm).toHaveBeenCalled() }) }) @@ -539,7 +596,11 @@ describe('AtomEnvironment', () => { spyOn(atom.workspace, 'open') const state = Symbol() - atom.attemptRestoreProjectStateForPaths(state, [__dirname], [__filename]) + atom.attemptRestoreProjectStateForPaths( + state, + [__dirname], + [__filename] + ) expect(atom.confirm).toHaveBeenCalled() await conditionPromise(() => atom.project.addPath.callCount === 1) @@ -554,7 +615,11 @@ describe('AtomEnvironment', () => { spyOn(atom, 'open') const state = Symbol() - atom.attemptRestoreProjectStateForPaths(state, [__dirname], [__filename]) + atom.attemptRestoreProjectStateForPaths( + state, + [__dirname], + [__filename] + ) expect(atom.confirm).toHaveBeenCalled() await conditionPromise(() => atom.open.callCount === 1) expect(atom.open).toHaveBeenCalledWith({ @@ -571,8 +636,16 @@ describe('AtomEnvironment', () => { it('saves the BlobStore so it can be loaded after reload', () => { const configDirPath = temp.mkdirSync('atom-spec-environment') const fakeBlobStore = jasmine.createSpyObj('blob store', ['save']) - const atomEnvironment = new AtomEnvironment({applicationDelegate: atom.applicationDelegate, enablePersistence: true}) - atomEnvironment.initialize({configDirPath, blobStore: fakeBlobStore, window, document}) + const atomEnvironment = new AtomEnvironment({ + applicationDelegate: atom.applicationDelegate, + enablePersistence: true + }) + atomEnvironment.initialize({ + configDirPath, + blobStore: fakeBlobStore, + window, + document + }) atomEnvironment.unloadEditorWindow() @@ -591,9 +664,13 @@ describe('AtomEnvironment', () => { head: document.createElement('head'), body: document.createElement('body') } - const atomEnvironment = new AtomEnvironment({applicationDelegate: atom.applicationDelegate}) - atomEnvironment.initialize({window, document: fakeDocument}) - spyOn(atomEnvironment.packages, 'loadPackages').andReturn(Promise.resolve()) + const atomEnvironment = new AtomEnvironment({ + applicationDelegate: atom.applicationDelegate + }) + atomEnvironment.initialize({ window, document: fakeDocument }) + spyOn(atomEnvironment.packages, 'loadPackages').andReturn( + Promise.resolve() + ) spyOn(atomEnvironment.packages, 'activate').andReturn(Promise.resolve()) spyOn(atomEnvironment, 'displayWindow').andReturn(Promise.resolve()) await atomEnvironment.startEditorWindow() @@ -607,16 +684,20 @@ describe('AtomEnvironment', () => { beforeEach(() => { let resolve = null - const promise = new Promise((r) => { resolve = r }) + const promise = new Promise(r => { + resolve = r + }) envLoaded = () => { resolve() return promise } atomEnvironment = new AtomEnvironment({ applicationDelegate: atom.applicationDelegate, - updateProcessEnv () { return promise } + updateProcessEnv () { + return promise + } }) - atomEnvironment.initialize({window, document}) + atomEnvironment.initialize({ window, document }) spy = jasmine.createSpy() }) @@ -650,23 +731,30 @@ describe('AtomEnvironment', () => { describe('when the opened path exists', () => { it('opens a file', async () => { const pathToOpen = __filename - await atom.openLocations([{pathToOpen}]) + await atom.openLocations([{ pathToOpen }]) expect(atom.project.getPaths()).toEqual([]) }) it('opens a directory as a project folder', async () => { const pathToOpen = __dirname - await atom.openLocations([{pathToOpen}]) - expect(atom.workspace.getTextEditors().map(e => e.getPath())).toEqual([]) + await atom.openLocations([{ pathToOpen }]) + expect(atom.workspace.getTextEditors().map(e => e.getPath())).toEqual( + [] + ) expect(atom.project.getPaths()).toEqual([pathToOpen]) }) }) describe('when the opened path does not exist', () => { it('opens it as a new file', async () => { - const pathToOpen = path.join(__dirname, 'this-path-does-not-exist.txt') - await atom.openLocations([{pathToOpen}]) - expect(atom.workspace.getTextEditors().map(e => e.getPath())).toEqual([pathToOpen]) + const pathToOpen = path.join( + __dirname, + 'this-path-does-not-exist.txt' + ) + await atom.openLocations([{ pathToOpen }]) + expect(atom.workspace.getTextEditors().map(e => e.getPath())).toEqual( + [pathToOpen] + ) expect(atom.project.getPaths()).toEqual([]) }) @@ -678,9 +766,9 @@ describe('AtomEnvironment', () => { const existingDir = path.join(__dirname, 'fixtures') await atom.openLocations([ - {pathToOpen: nonExistent, mustBeDirectory: true}, - {pathToOpen: existingFile, mustBeDirectory: true}, - {pathToOpen: existingDir, mustBeDirectory: true} + { pathToOpen: nonExistent, mustBeDirectory: true }, + { pathToOpen: existingFile, mustBeDirectory: true }, + { pathToOpen: existingDir, mustBeDirectory: true } ]) expect(atom.workspace.getTextEditors()).toEqual([]) @@ -688,7 +776,9 @@ describe('AtomEnvironment', () => { expect(atom.notifications.addWarning).toHaveBeenCalledWith( 'Unable to open project folders', - {description: `The directories \`${nonExistent}\` and \`${existingFile}\` do not exist.`} + { + description: `The directories \`${nonExistent}\` and \`${existingFile}\` do not exist.` + } ) }) }) @@ -697,15 +787,23 @@ describe('AtomEnvironment', () => { let serviceDisposable beforeEach(() => { - serviceDisposable = atom.packages.serviceHub.provide('atom.directory-provider', '0.1.0', { - directoryForURISync (uri) { - if (uri.startsWith('remote://')) { - return { getPath() { return uri } } - } else { - return null + serviceDisposable = atom.packages.serviceHub.provide( + 'atom.directory-provider', + '0.1.0', + { + directoryForURISync (uri) { + if (uri.startsWith('remote://')) { + return { + getPath () { + return uri + } + } + } else { + return null + } } } - }) + ) waitsFor(() => atom.project.directoryProviders.length > 0) }) @@ -717,7 +815,7 @@ describe('AtomEnvironment', () => { it("adds it to the project's paths as is", async () => { const pathToOpen = 'remote://server:7644/some/dir/path' spyOn(atom.project, 'addPath') - await atom.openLocations([{pathToOpen}]) + await atom.openLocations([{ pathToOpen }]) expect(atom.project.addPath).toHaveBeenCalledWith(pathToOpen) }) }) @@ -729,7 +827,11 @@ describe('AtomEnvironment', () => { beforeEach(() => { spyOn(atom, 'getStateKey').andCallFake(dirs => dirs.join(':')) spyOn(atom, 'loadState').andCallFake(function (key) { - if (key === __dirname) { return Promise.resolve(state) } else { return Promise.resolve(null) } + if (key === __dirname) { + return Promise.resolve(state) + } else { + return Promise.resolve(null) + } }) spyOn(atom, 'attemptRestoreProjectStateForPaths') }) @@ -737,8 +839,12 @@ describe('AtomEnvironment', () => { describe('when there are no project folders', () => { it('attempts to restore the project state', async () => { const pathToOpen = __dirname - await atom.openLocations([{pathToOpen}]) - expect(atom.attemptRestoreProjectStateForPaths).toHaveBeenCalledWith(state, [pathToOpen], []) + await atom.openLocations([{ pathToOpen }]) + expect(atom.attemptRestoreProjectStateForPaths).toHaveBeenCalledWith( + state, + [pathToOpen], + [] + ) expect(atom.project.getPaths()).toEqual([]) }) @@ -755,17 +861,28 @@ describe('AtomEnvironment', () => { }) await atom.openLocations([ - {pathToOpen: existingDir}, - {pathToOpen: missingDir, mustBeDirectory: true} + { pathToOpen: existingDir }, + { pathToOpen: missingDir, mustBeDirectory: true } ]) - expect(atom.attemptRestoreProjectStateForPaths).toHaveBeenCalledWith(state, [existingDir], []) + expect(atom.attemptRestoreProjectStateForPaths).toHaveBeenCalledWith( + state, + [existingDir], + [] + ) expect(atom.project.getPaths(), [existingDir]) }) it('opens the specified files', async () => { - await atom.openLocations([{pathToOpen: __dirname}, {pathToOpen: __filename}]) - expect(atom.attemptRestoreProjectStateForPaths).toHaveBeenCalledWith(state, [__dirname], [__filename]) + await atom.openLocations([ + { pathToOpen: __dirname }, + { pathToOpen: __filename } + ]) + expect(atom.attemptRestoreProjectStateForPaths).toHaveBeenCalledWith( + state, + [__dirname], + [__filename] + ) expect(atom.project.getPaths()).toEqual([]) }) }) @@ -775,7 +892,7 @@ describe('AtomEnvironment', () => { it('does not attempt to restore the project state, instead adding the project paths', async () => { const pathToOpen = path.join(__dirname, 'fixtures') - await atom.openLocations([{pathToOpen, forceAddToWindow: true}]) + await atom.openLocations([{ pathToOpen, forceAddToWindow: true }]) expect(atom.attemptRestoreProjectStateForPaths).not.toHaveBeenCalled() expect(atom.project.getPaths()).toEqual([__dirname, pathToOpen]) }) @@ -783,8 +900,10 @@ describe('AtomEnvironment', () => { it('opens the specified files', async () => { const pathToOpen = path.join(__dirname, 'fixtures') const fileToOpen = path.join(pathToOpen, 'michelle-is-awesome.txt') - await atom.openLocations([{pathToOpen}, {pathToOpen: fileToOpen}]) - expect(atom.attemptRestoreProjectStateForPaths).not.toHaveBeenCalledWith(state, [pathToOpen], [fileToOpen]) + await atom.openLocations([{ pathToOpen }, { pathToOpen: fileToOpen }]) + expect( + atom.attemptRestoreProjectStateForPaths + ).not.toHaveBeenCalledWith(state, [pathToOpen], [fileToOpen]) expect(atom.project.getPaths()).toEqual([__dirname, pathToOpen]) }) }) diff --git a/spec/atom-paths-spec.js b/spec/atom-paths-spec.js index f4bbbf2b7..438154d72 100644 --- a/spec/atom-paths-spec.js +++ b/spec/atom-paths-spec.js @@ -1,14 +1,25 @@ /** @babel */ -import {it, fit, ffit, fffit, beforeEach, afterEach} from './async-spec-helpers' -import {app} from 'remote' +import { + it, + fit, + ffit, + fffit, + beforeEach, + afterEach +} from './async-spec-helpers' +import { app } from 'remote' import atomPaths from '../src/atom-paths' import fs from 'fs-plus' import path from 'path' const temp = require('temp').track() -describe("AtomPaths", () => { - const portableAtomHomePath = path.join(atomPaths.getAppDirectory(), '..', '.atom') +describe('AtomPaths', () => { + const portableAtomHomePath = path.join( + atomPaths.getAppDirectory(), + '..', + '.atom' + ) afterEach(() => { atomPaths.setAtomHome(app.getPath('home')) diff --git a/spec/auto-update-manager-spec.js b/spec/auto-update-manager-spec.js index ab9e0ed70..563085934 100644 --- a/spec/auto-update-manager-spec.js +++ b/spec/auto-update-manager-spec.js @@ -1,5 +1,5 @@ const AutoUpdateManager = require('../src/auto-update-manager') -const {remote} = require('electron') +const { remote } = require('electron') const electronAutoUpdater = remote.require('electron').autoUpdater describe('AutoUpdateManager (renderer)', () => { @@ -8,7 +8,9 @@ describe('AutoUpdateManager (renderer)', () => { let autoUpdateManager beforeEach(() => { - autoUpdateManager = new AutoUpdateManager({applicationDelegate: atom.applicationDelegate}) + autoUpdateManager = new AutoUpdateManager({ + applicationDelegate: atom.applicationDelegate + }) autoUpdateManager.initialize() }) @@ -69,14 +71,16 @@ describe('AutoUpdateManager (renderer)', () => { autoUpdateManager.onUpdateError(spy) electronAutoUpdater.emit('error', {}, 'an error message') waitsFor(() => spy.callCount === 1) - runs(() => expect(autoUpdateManager.getErrorMessage()).toBe('an error message')) + runs(() => + expect(autoUpdateManager.getErrorMessage()).toBe('an error message') + ) }) }) describe('::platformSupportsUpdates', () => { let state, releaseChannel it('returns true on macOS and Windows when in stable', () => { - spyOn(autoUpdateManager, 'getState').andCallFake(() => state) + spyOn(autoUpdateManager, 'getState').andCallFake(() => state) spyOn(atom, 'getReleaseChannel').andCallFake(() => releaseChannel) state = 'idle' diff --git a/spec/command-installer-spec.js b/spec/command-installer-spec.js index b303d4954..2afa715fe 100644 --- a/spec/command-installer-spec.js +++ b/spec/command-installer-spec.js @@ -1,7 +1,14 @@ const path = require('path') const fs = require('fs-plus') const temp = require('temp').track() -const {it, fit, ffit, fffit, beforeEach, afterEach} = require('./async-spec-helpers'); +const { + it, + fit, + ffit, + fffit, + beforeEach, + afterEach +} = require('./async-spec-helpers') const CommandInstaller = require('../src/command-installer') describe('CommandInstaller on #darwin', () => { @@ -12,14 +19,25 @@ describe('CommandInstaller on #darwin', () => { resourcesPath = temp.mkdirSync('atom-app') atomBinPath = path.join(resourcesPath, 'app', 'atom.sh') - apmBinPath = path.join(resourcesPath, 'app', 'apm', 'node_modules', '.bin', 'apm') + apmBinPath = path.join( + resourcesPath, + 'app', + 'apm', + 'node_modules', + '.bin', + 'apm' + ) fs.writeFileSync(atomBinPath, '') fs.writeFileSync(apmBinPath, '') fs.chmodSync(atomBinPath, '755') fs.chmodSync(apmBinPath, '755') - spyOn(CommandInstaller.prototype, 'getResourcesDirectory').andReturn(resourcesPath) - spyOn(CommandInstaller.prototype, 'getInstallDirectory').andReturn(installationPath) + spyOn(CommandInstaller.prototype, 'getResourcesDirectory').andReturn( + resourcesPath + ) + spyOn(CommandInstaller.prototype, 'getInstallDirectory').andReturn( + installationPath + ) }) afterEach(() => { @@ -32,7 +50,9 @@ describe('CommandInstaller on #darwin', () => { const appDelegate = jasmine.createSpyObj('appDelegate', ['confirm']) installer = new CommandInstaller(appDelegate) installer.initialize('2.0.2') - spyOn(installer, 'installAtomCommand').andCallFake((__, callback) => callback(new Error('an error'))) + spyOn(installer, 'installAtomCommand').andCallFake((__, callback) => + callback(new Error('an error')) + ) installer.installShellCommandsInteractively() @@ -43,7 +63,9 @@ describe('CommandInstaller on #darwin', () => { appDelegate.confirm.reset() installer.installAtomCommand.andCallFake((__, callback) => callback()) - spyOn(installer, 'installApmCommand').andCallFake((__, callback) => callback(new Error('another error'))) + spyOn(installer, 'installApmCommand').andCallFake((__, callback) => + callback(new Error('another error')) + ) installer.installShellCommandsInteractively() @@ -57,8 +79,12 @@ describe('CommandInstaller on #darwin', () => { const appDelegate = jasmine.createSpyObj('appDelegate', ['confirm']) installer = new CommandInstaller(appDelegate) installer.initialize('2.0.2') - spyOn(installer, 'installAtomCommand').andCallFake((__, callback) => callback(undefined, 'atom')) - spyOn(installer, 'installApmCommand').andCallFake((__, callback) => callback(undefined, 'apm')) + spyOn(installer, 'installAtomCommand').andCallFake((__, callback) => + callback(undefined, 'atom') + ) + spyOn(installer, 'installApmCommand').andCallFake((__, callback) => + callback(undefined, 'apm') + ) installer.installShellCommandsInteractively() @@ -81,9 +107,13 @@ describe('CommandInstaller on #darwin', () => { waitsFor(done => { installer.installAtomCommand(false, error => { expect(error).toBeNull() - expect(fs.realpathSync(installedAtomPath)).toBe(fs.realpathSync(atomBinPath)) + expect(fs.realpathSync(installedAtomPath)).toBe( + fs.realpathSync(atomBinPath) + ) expect(fs.isExecutableSync(installedAtomPath)).toBe(true) - expect(fs.isFileSync(path.join(installationPath, 'atom-beta'))).toBe(false) + expect(fs.isFileSync(path.join(installationPath, 'atom-beta'))).toBe( + false + ) done() }) }) @@ -96,9 +126,13 @@ describe('CommandInstaller on #darwin', () => { waitsFor(done => { installer.installApmCommand(false, error => { expect(error).toBeNull() - expect(fs.realpathSync(installedApmPath)).toBe(fs.realpathSync(apmBinPath)) + expect(fs.realpathSync(installedApmPath)).toBe( + fs.realpathSync(apmBinPath) + ) expect(fs.isExecutableSync(installedApmPath)).toBeTruthy() - expect(fs.isFileSync(path.join(installationPath, 'apm-beta'))).toBe(false) + expect(fs.isFileSync(path.join(installationPath, 'apm-beta'))).toBe( + false + ) done() }) }) @@ -118,7 +152,9 @@ describe('CommandInstaller on #darwin', () => { waitsFor(done => { installer.installAtomCommand(false, error => { expect(error).toBeNull() - expect(fs.realpathSync(installedAtomPath)).toBe(fs.realpathSync(atomBinPath)) + expect(fs.realpathSync(installedAtomPath)).toBe( + fs.realpathSync(atomBinPath) + ) expect(fs.isExecutableSync(installedAtomPath)).toBe(true) expect(fs.isFileSync(path.join(installationPath, 'atom'))).toBe(false) done() @@ -133,7 +169,9 @@ describe('CommandInstaller on #darwin', () => { waitsFor(done => { installer.installApmCommand(false, error => { expect(error).toBeNull() - expect(fs.realpathSync(installedApmPath)).toBe(fs.realpathSync(apmBinPath)) + expect(fs.realpathSync(installedApmPath)).toBe( + fs.realpathSync(apmBinPath) + ) expect(fs.isExecutableSync(installedApmPath)).toBeTruthy() expect(fs.isFileSync(path.join(installationPath, 'apm'))).toBe(false) done() @@ -155,7 +193,9 @@ describe('CommandInstaller on #darwin', () => { waitsFor(done => { installer.installAtomCommand(false, error => { expect(error).toBeNull() - expect(fs.realpathSync(installedAtomPath)).toBe(fs.realpathSync(atomBinPath)) + expect(fs.realpathSync(installedAtomPath)).toBe( + fs.realpathSync(atomBinPath) + ) expect(fs.isExecutableSync(installedAtomPath)).toBe(true) expect(fs.isFileSync(path.join(installationPath, 'atom'))).toBe(false) done() @@ -170,9 +210,13 @@ describe('CommandInstaller on #darwin', () => { waitsFor(done => { installer.installApmCommand(false, error => { expect(error).toBeNull() - expect(fs.realpathSync(installedApmPath)).toBe(fs.realpathSync(apmBinPath)) + expect(fs.realpathSync(installedApmPath)).toBe( + fs.realpathSync(apmBinPath) + ) expect(fs.isExecutableSync(installedApmPath)).toBeTruthy() - expect(fs.isFileSync(path.join(installationPath, 'nightly'))).toBe(false) + expect(fs.isFileSync(path.join(installationPath, 'nightly'))).toBe( + false + ) done() }) }) diff --git a/spec/command-registry-spec.js b/spec/command-registry-spec.js index 03ef0cc34..285cec055 100644 --- a/spec/command-registry-spec.js +++ b/spec/command-registry-spec.js @@ -1,289 +1,314 @@ -const CommandRegistry = require('../src/command-registry'); -const _ = require('underscore-plus'); -const {it, fit, ffit, fffit, beforeEach, afterEach} = require('./async-spec-helpers'); +const CommandRegistry = require('../src/command-registry') +const _ = require('underscore-plus') +const { + it, + fit, + ffit, + fffit, + beforeEach, + afterEach +} = require('./async-spec-helpers') -describe("CommandRegistry", () => { - let registry, parent, child, grandchild; +describe('CommandRegistry', () => { + let registry, parent, child, grandchild beforeEach(() => { - parent = document.createElement("div"); - child = document.createElement("div"); - grandchild = document.createElement("div"); - parent.classList.add('parent'); - child.classList.add('child'); - grandchild.classList.add('grandchild'); - child.appendChild(grandchild); - parent.appendChild(child); - document.querySelector('#jasmine-content').appendChild(parent); + parent = document.createElement('div') + child = document.createElement('div') + grandchild = document.createElement('div') + parent.classList.add('parent') + child.classList.add('child') + grandchild.classList.add('grandchild') + child.appendChild(grandchild) + parent.appendChild(child) + document.querySelector('#jasmine-content').appendChild(parent) - registry = new CommandRegistry; - registry.attach(parent); - }); + registry = new CommandRegistry() + registry.attach(parent) + }) - afterEach(() => registry.destroy()); + afterEach(() => registry.destroy()) - describe("when a command event is dispatched on an element", () => { - it("invokes callbacks with selectors matching the target", () => { - let called = false; + describe('when a command event is dispatched on an element', () => { + it('invokes callbacks with selectors matching the target', () => { + let called = false registry.add('.grandchild', 'command', function (event) { - expect(this).toBe(grandchild); - expect(event.type).toBe('command'); - expect(event.eventPhase).toBe(Event.BUBBLING_PHASE); - expect(event.target).toBe(grandchild); - expect(event.currentTarget).toBe(grandchild); - called = true; - }); + expect(this).toBe(grandchild) + expect(event.type).toBe('command') + expect(event.eventPhase).toBe(Event.BUBBLING_PHASE) + expect(event.target).toBe(grandchild) + expect(event.currentTarget).toBe(grandchild) + called = true + }) - grandchild.dispatchEvent(new CustomEvent('command', {bubbles: true})); - expect(called).toBe(true); - }); + grandchild.dispatchEvent(new CustomEvent('command', { bubbles: true })) + expect(called).toBe(true) + }) - it("invokes callbacks with selectors matching ancestors of the target", () => { - const calls = []; + it('invokes callbacks with selectors matching ancestors of the target', () => { + const calls = [] registry.add('.child', 'command', function (event) { - expect(this).toBe(child); - expect(event.target).toBe(grandchild); - expect(event.currentTarget).toBe(child); - calls.push('child'); - }); + expect(this).toBe(child) + expect(event.target).toBe(grandchild) + expect(event.currentTarget).toBe(child) + calls.push('child') + }) - registry.add('.parent', 'command', function (event) { - expect(this).toBe(parent); - expect(event.target).toBe(grandchild); - expect(event.currentTarget).toBe(parent); - calls.push('parent'); - }); + registry.add('.parent', 'command', function (event) { + expect(this).toBe(parent) + expect(event.target).toBe(grandchild) + expect(event.currentTarget).toBe(parent) + calls.push('parent') + }) - grandchild.dispatchEvent(new CustomEvent('command', {bubbles: true})); - expect(calls).toEqual(['child', 'parent']); - }); + grandchild.dispatchEvent(new CustomEvent('command', { bubbles: true })) + expect(calls).toEqual(['child', 'parent']) + }) - it("invokes inline listeners prior to listeners applied via selectors", () => { - const calls = []; - registry.add('.grandchild', 'command', () => calls.push('grandchild')); - registry.add(child, 'command', () => calls.push('child-inline')); - registry.add('.child', 'command', () => calls.push('child')); - registry.add('.parent', 'command', () => calls.push('parent')); + it('invokes inline listeners prior to listeners applied via selectors', () => { + const calls = [] + registry.add('.grandchild', 'command', () => calls.push('grandchild')) + registry.add(child, 'command', () => calls.push('child-inline')) + registry.add('.child', 'command', () => calls.push('child')) + registry.add('.parent', 'command', () => calls.push('parent')) - grandchild.dispatchEvent(new CustomEvent('command', {bubbles: true})); - expect(calls).toEqual(['grandchild', 'child-inline', 'child', 'parent']); - }); + grandchild.dispatchEvent(new CustomEvent('command', { bubbles: true })) + expect(calls).toEqual(['grandchild', 'child-inline', 'child', 'parent']) + }) - it("orders multiple matching listeners for an element by selector specificity", () => { - child.classList.add('foo', 'bar'); - const calls = []; + it('orders multiple matching listeners for an element by selector specificity', () => { + child.classList.add('foo', 'bar') + const calls = [] - registry.add('.foo.bar', 'command', () => calls.push('.foo.bar')); - registry.add('.foo', 'command', () => calls.push('.foo')); - registry.add('.bar', 'command', () => calls.push('.bar')); // specificity ties favor commands added later, like CSS + registry.add('.foo.bar', 'command', () => calls.push('.foo.bar')) + registry.add('.foo', 'command', () => calls.push('.foo')) + registry.add('.bar', 'command', () => calls.push('.bar')) // specificity ties favor commands added later, like CSS - grandchild.dispatchEvent(new CustomEvent('command', {bubbles: true})); - expect(calls).toEqual(['.foo.bar', '.bar', '.foo']); - }); + grandchild.dispatchEvent(new CustomEvent('command', { bubbles: true })) + expect(calls).toEqual(['.foo.bar', '.bar', '.foo']) + }) - it("orders inline listeners by reverse registration order", () => { - const calls = []; - registry.add(child, 'command', () => calls.push('child1')); - registry.add(child, 'command', () => calls.push('child2')); - child.dispatchEvent(new CustomEvent('command', {bubbles: true})); - expect(calls).toEqual(['child2', 'child1']); - }); + it('orders inline listeners by reverse registration order', () => { + const calls = [] + registry.add(child, 'command', () => calls.push('child1')) + registry.add(child, 'command', () => calls.push('child2')) + child.dispatchEvent(new CustomEvent('command', { bubbles: true })) + expect(calls).toEqual(['child2', 'child1']) + }) - it("stops bubbling through ancestors when .stopPropagation() is called on the event", () => { - const calls = []; + it('stops bubbling through ancestors when .stopPropagation() is called on the event', () => { + const calls = [] - registry.add('.parent', 'command', () => calls.push('parent')); - registry.add('.child', 'command', () => calls.push('child-2')); - registry.add('.child', 'command', (event) => { - calls.push('child-1'); - event.stopPropagation(); - }); + registry.add('.parent', 'command', () => calls.push('parent')) + registry.add('.child', 'command', () => calls.push('child-2')) + registry.add('.child', 'command', event => { + calls.push('child-1') + event.stopPropagation() + }) - const dispatchedEvent = new CustomEvent('command', {bubbles: true}); - spyOn(dispatchedEvent, 'stopPropagation'); - grandchild.dispatchEvent(dispatchedEvent); - expect(calls).toEqual(['child-1', 'child-2']); - expect(dispatchedEvent.stopPropagation).toHaveBeenCalled(); - }); + const dispatchedEvent = new CustomEvent('command', { bubbles: true }) + spyOn(dispatchedEvent, 'stopPropagation') + grandchild.dispatchEvent(dispatchedEvent) + expect(calls).toEqual(['child-1', 'child-2']) + expect(dispatchedEvent.stopPropagation).toHaveBeenCalled() + }) - it("stops invoking callbacks when .stopImmediatePropagation() is called on the event", () => { - const calls = []; + it('stops invoking callbacks when .stopImmediatePropagation() is called on the event', () => { + const calls = [] - registry.add('.parent', 'command', () => calls.push('parent')); - registry.add('.child', 'command', () => calls.push('child-2')); - registry.add('.child', 'command', (event) => { - calls.push('child-1'); - event.stopImmediatePropagation(); - }); + registry.add('.parent', 'command', () => calls.push('parent')) + registry.add('.child', 'command', () => calls.push('child-2')) + registry.add('.child', 'command', event => { + calls.push('child-1') + event.stopImmediatePropagation() + }) - const dispatchedEvent = new CustomEvent('command', {bubbles: true}); - spyOn(dispatchedEvent, 'stopImmediatePropagation'); - grandchild.dispatchEvent(dispatchedEvent); - expect(calls).toEqual(['child-1']); - expect(dispatchedEvent.stopImmediatePropagation).toHaveBeenCalled(); - }); + const dispatchedEvent = new CustomEvent('command', { bubbles: true }) + spyOn(dispatchedEvent, 'stopImmediatePropagation') + grandchild.dispatchEvent(dispatchedEvent) + expect(calls).toEqual(['child-1']) + expect(dispatchedEvent.stopImmediatePropagation).toHaveBeenCalled() + }) - it("forwards .preventDefault() calls from the synthetic event to the original", () => { - registry.add('.child', 'command', event => event.preventDefault()); + it('forwards .preventDefault() calls from the synthetic event to the original', () => { + registry.add('.child', 'command', event => event.preventDefault()) - const dispatchedEvent = new CustomEvent('command', {bubbles: true}); - spyOn(dispatchedEvent, 'preventDefault'); - grandchild.dispatchEvent(dispatchedEvent); - expect(dispatchedEvent.preventDefault).toHaveBeenCalled(); - }); + const dispatchedEvent = new CustomEvent('command', { bubbles: true }) + spyOn(dispatchedEvent, 'preventDefault') + grandchild.dispatchEvent(dispatchedEvent) + expect(dispatchedEvent.preventDefault).toHaveBeenCalled() + }) - it("forwards .abortKeyBinding() calls from the synthetic event to the original", () => { - registry.add('.child', 'command', event => event.abortKeyBinding()); + it('forwards .abortKeyBinding() calls from the synthetic event to the original', () => { + registry.add('.child', 'command', event => event.abortKeyBinding()) - const dispatchedEvent = new CustomEvent('command', {bubbles: true}); - dispatchedEvent.abortKeyBinding = jasmine.createSpy('abortKeyBinding'); - grandchild.dispatchEvent(dispatchedEvent); - expect(dispatchedEvent.abortKeyBinding).toHaveBeenCalled(); - }); + const dispatchedEvent = new CustomEvent('command', { bubbles: true }) + dispatchedEvent.abortKeyBinding = jasmine.createSpy('abortKeyBinding') + grandchild.dispatchEvent(dispatchedEvent) + expect(dispatchedEvent.abortKeyBinding).toHaveBeenCalled() + }) - it("copies non-standard properties from the original event to the synthetic event", () => { - let syntheticEvent = null; - registry.add('.child', 'command', event => syntheticEvent = event); + it('copies non-standard properties from the original event to the synthetic event', () => { + let syntheticEvent = null + registry.add('.child', 'command', event => (syntheticEvent = event)) - const dispatchedEvent = new CustomEvent('command', {bubbles: true}); - dispatchedEvent.nonStandardProperty = 'testing'; - grandchild.dispatchEvent(dispatchedEvent); - expect(syntheticEvent.nonStandardProperty).toBe('testing'); - }); + const dispatchedEvent = new CustomEvent('command', { bubbles: true }) + dispatchedEvent.nonStandardProperty = 'testing' + grandchild.dispatchEvent(dispatchedEvent) + expect(syntheticEvent.nonStandardProperty).toBe('testing') + }) - it("allows listeners to be removed via a disposable returned by ::add", () => { - let calls = []; + it('allows listeners to be removed via a disposable returned by ::add', () => { + let calls = [] - const disposable1 = registry.add('.parent', 'command', () => calls.push('parent')); - const disposable2 = registry.add('.child', 'command', () => calls.push('child')); + const disposable1 = registry.add('.parent', 'command', () => + calls.push('parent') + ) + const disposable2 = registry.add('.child', 'command', () => + calls.push('child') + ) - disposable1.dispose(); - grandchild.dispatchEvent(new CustomEvent('command', {bubbles: true})); - expect(calls).toEqual(['child']); + disposable1.dispose() + grandchild.dispatchEvent(new CustomEvent('command', { bubbles: true })) + expect(calls).toEqual(['child']) - calls = []; - disposable2.dispose(); - grandchild.dispatchEvent(new CustomEvent('command', {bubbles: true})); - expect(calls).toEqual([]); - }); + calls = [] + disposable2.dispose() + grandchild.dispatchEvent(new CustomEvent('command', { bubbles: true })) + expect(calls).toEqual([]) + }) - it("allows multiple commands to be registered under one selector when called with an object", () => { - let calls = []; + it('allows multiple commands to be registered under one selector when called with an object', () => { + let calls = [] const disposable = registry.add('.child', { - 'command-1'() { - calls.push('command-1'); + 'command-1' () { + calls.push('command-1') }, - 'command-2'() { - calls.push('command-2'); + 'command-2' () { + calls.push('command-2') } - }); + }) - grandchild.dispatchEvent(new CustomEvent('command-1', {bubbles: true})); - grandchild.dispatchEvent(new CustomEvent('command-2', {bubbles: true})); + grandchild.dispatchEvent(new CustomEvent('command-1', { bubbles: true })) + grandchild.dispatchEvent(new CustomEvent('command-2', { bubbles: true })) - expect(calls).toEqual(['command-1', 'command-2']); + expect(calls).toEqual(['command-1', 'command-2']) - calls = []; - disposable.dispose(); - grandchild.dispatchEvent(new CustomEvent('command-1', {bubbles: true})); - grandchild.dispatchEvent(new CustomEvent('command-2', {bubbles: true})); - expect(calls).toEqual([]); - }); + calls = [] + disposable.dispose() + grandchild.dispatchEvent(new CustomEvent('command-1', { bubbles: true })) + grandchild.dispatchEvent(new CustomEvent('command-2', { bubbles: true })) + expect(calls).toEqual([]) + }) - it("invokes callbacks registered with ::onWillDispatch and ::onDidDispatch", () => { - const sequence = []; + it('invokes callbacks registered with ::onWillDispatch and ::onDidDispatch', () => { + const sequence = [] - registry.onDidDispatch(event => sequence.push(['onDidDispatch', event])); + registry.onDidDispatch(event => sequence.push(['onDidDispatch', event])) - registry.add('.grandchild', 'command', event => sequence.push(['listener', event])); + registry.add('.grandchild', 'command', event => + sequence.push(['listener', event]) + ) - registry.onWillDispatch(event => sequence.push(['onWillDispatch', event])); + registry.onWillDispatch(event => sequence.push(['onWillDispatch', event])) - grandchild.dispatchEvent(new CustomEvent('command', {bubbles: true})); + grandchild.dispatchEvent(new CustomEvent('command', { bubbles: true })) - expect(sequence[0][0]).toBe('onWillDispatch'); - expect(sequence[1][0]).toBe('listener'); - expect(sequence[2][0]).toBe('onDidDispatch'); + expect(sequence[0][0]).toBe('onWillDispatch') + expect(sequence[1][0]).toBe('listener') + expect(sequence[2][0]).toBe('onDidDispatch') - expect(sequence[0][1] === sequence[1][1] && sequence[1][1] === sequence[2][1]).toBe(true); - expect(sequence[0][1].constructor).toBe(CustomEvent); - expect(sequence[0][1].target).toBe(grandchild); - }); - }); + expect( + sequence[0][1] === sequence[1][1] && sequence[1][1] === sequence[2][1] + ).toBe(true) + expect(sequence[0][1].constructor).toBe(CustomEvent) + expect(sequence[0][1].target).toBe(grandchild) + }) + }) - describe("::add(selector, commandName, callback)", () => { - it("throws an error when called with an invalid selector", () => { - const badSelector = '<>'; - let addError = null; + describe('::add(selector, commandName, callback)', () => { + it('throws an error when called with an invalid selector', () => { + const badSelector = '<>' + let addError = null try { - registry.add(badSelector, 'foo:bar', () => {}); + registry.add(badSelector, 'foo:bar', () => {}) } catch (error) { - addError = error; + addError = error } - expect(addError.message).toContain(badSelector); - }); + expect(addError.message).toContain(badSelector) + }) - it("throws an error when called with a null callback and selector target", () => { - const badCallback = null; + it('throws an error when called with a null callback and selector target', () => { + const badCallback = null expect(() => { - registry.add('.selector', 'foo:bar', badCallback); - }).toThrow(new Error('Cannot register a command with a null listener.')); - }); + registry.add('.selector', 'foo:bar', badCallback) + }).toThrow(new Error('Cannot register a command with a null listener.')) + }) - it("throws an error when called with a null callback and object target", () => { - const badCallback = null; + it('throws an error when called with a null callback and object target', () => { + const badCallback = null expect(() => { - registry.add(document.body, 'foo:bar', badCallback); - }).toThrow(new Error('Cannot register a command with a null listener.')); - }); + registry.add(document.body, 'foo:bar', badCallback) + }).toThrow(new Error('Cannot register a command with a null listener.')) + }) - it("throws an error when called with an object listener without a didDispatch method", () => { + it('throws an error when called with an object listener without a didDispatch method', () => { const badListener = { title: 'a listener without a didDispatch callback', description: 'this should throw an error' - }; + } expect(() => { - registry.add(document.body, 'foo:bar', badListener); - }).toThrow(new Error('Listener must be a callback function or an object with a didDispatch method.')); - }); - }); + registry.add(document.body, 'foo:bar', badListener) + }).toThrow( + new Error( + 'Listener must be a callback function or an object with a didDispatch method.' + ) + ) + }) + }) - describe("::findCommands({target})", () => { - it("returns command descriptors that can be invoked on the target or its ancestors", () => { - registry.add('.parent', 'namespace:command-1', () => {}); - registry.add('.child', 'namespace:command-2', () => {}); - registry.add('.grandchild', 'namespace:command-3', () => {}); - registry.add('.grandchild.no-match', 'namespace:command-4', () => {}); + describe('::findCommands({target})', () => { + it('returns command descriptors that can be invoked on the target or its ancestors', () => { + registry.add('.parent', 'namespace:command-1', () => {}) + registry.add('.child', 'namespace:command-2', () => {}) + registry.add('.grandchild', 'namespace:command-3', () => {}) + registry.add('.grandchild.no-match', 'namespace:command-4', () => {}) - registry.add(grandchild, 'namespace:inline-command-1', () => {}); - registry.add(child, 'namespace:inline-command-2', () => {}); + registry.add(grandchild, 'namespace:inline-command-1', () => {}) + registry.add(child, 'namespace:inline-command-2', () => {}) - const commands = registry.findCommands({target: grandchild}); - const nonJqueryCommands = _.reject(commands, cmd => cmd.jQuery); + const commands = registry.findCommands({ target: grandchild }) + const nonJqueryCommands = _.reject(commands, cmd => cmd.jQuery) expect(nonJqueryCommands).toEqual([ - {name: 'namespace:inline-command-1', displayName: 'Namespace: Inline Command 1'}, - {name: 'namespace:command-3', displayName: 'Namespace: Command 3'}, - {name: 'namespace:inline-command-2', displayName: 'Namespace: Inline Command 2'}, - {name: 'namespace:command-2', displayName: 'Namespace: Command 2'}, - {name: 'namespace:command-1', displayName: 'Namespace: Command 1'} - ]); - }); + { + name: 'namespace:inline-command-1', + displayName: 'Namespace: Inline Command 1' + }, + { name: 'namespace:command-3', displayName: 'Namespace: Command 3' }, + { + name: 'namespace:inline-command-2', + displayName: 'Namespace: Inline Command 2' + }, + { name: 'namespace:command-2', displayName: 'Namespace: Command 2' }, + { name: 'namespace:command-1', displayName: 'Namespace: Command 1' } + ]) + }) - it("returns command descriptors with arbitrary metadata if set in a listener object", () => { - registry.add('.grandchild', 'namespace:command-1', () => {}); + it('returns command descriptors with arbitrary metadata if set in a listener object', () => { + registry.add('.grandchild', 'namespace:command-1', () => {}) registry.add('.grandchild', 'namespace:command-2', { displayName: 'Custom Command 2', metadata: { some: 'other', object: 'data' }, - didDispatch() {} - }); + didDispatch () {} + }) registry.add('.grandchild', 'namespace:command-3', { name: 'some:other:incorrect:commandname', displayName: 'Custom Command 3', @@ -291,10 +316,10 @@ describe("CommandRegistry", () => { some: 'other', object: 'data' }, - didDispatch() {} - }); + didDispatch () {} + }) - const commands = registry.findCommands({target: grandchild}); + const commands = registry.findCommands({ target: grandchild }) expect(commands).toEqual([ { displayName: 'Namespace: Command 1', @@ -303,143 +328,163 @@ describe("CommandRegistry", () => { { displayName: 'Custom Command 2', metadata: { - some : 'other', - object : 'data' + some: 'other', + object: 'data' }, name: 'namespace:command-2' }, { displayName: 'Custom Command 3', metadata: { - some : 'other', - object : 'data' + some: 'other', + object: 'data' }, name: 'namespace:command-3' } - ]); - }); + ]) + }) - it("returns command descriptors with arbitrary metadata if set on a listener function", () => { + it('returns command descriptors with arbitrary metadata if set on a listener function', () => { function listener () {} listener.displayName = 'Custom Command 2' listener.metadata = { some: 'other', object: 'data' - }; + } - registry.add('.grandchild', 'namespace:command-2', listener); - const commands = registry.findCommands({target: grandchild}); + registry.add('.grandchild', 'namespace:command-2', listener) + const commands = registry.findCommands({ target: grandchild }) expect(commands).toEqual([ { - displayName : 'Custom Command 2', + displayName: 'Custom Command 2', metadata: { some: 'other', object: 'data' }, name: 'namespace:command-2' } - ]); - }); - }); - - describe("::dispatch(target, commandName)", () => { - it("simulates invocation of the given command ", () => { - let called = false; - registry.add('.grandchild', 'command', function (event) { - expect(this).toBe(grandchild); - expect(event.type).toBe('command'); - expect(event.eventPhase).toBe(Event.BUBBLING_PHASE); - expect(event.target).toBe(grandchild); - expect(event.currentTarget).toBe(grandchild); - called = true; - }); - - registry.dispatch(grandchild, 'command'); - expect(called).toBe(true); - }); - - it("returns a promise if any listeners matched the command", () => { - registry.add('.grandchild', 'command', () => {}); - - expect(registry.dispatch(grandchild, 'command').constructor.name).toBe("Promise"); - expect(registry.dispatch(grandchild, 'bogus')).toBe(null); - expect(registry.dispatch(parent, 'command')).toBe(null); - }); - - it("returns a promise that resolves when the listeners resolve", async () => { - jasmine.useRealClock(); - registry.add('.grandchild', 'command', () => 1); - registry.add('.grandchild', 'command', () => Promise.resolve(2)); - registry.add('.grandchild', 'command', () => new Promise((resolve) => { - setTimeout(() => { resolve(3); }, 1); - })); - - const values = await registry.dispatch(grandchild, 'command'); - expect(values).toEqual([3, 2, 1]); - }); - - it("returns a promise that rejects when a listener is rejected", async () => { - jasmine.useRealClock(); - registry.add('.grandchild', 'command', () => 1); - registry.add('.grandchild', 'command', () => Promise.resolve(2)); - registry.add('.grandchild', 'command', () => new Promise((resolve, reject) => { - setTimeout(() => { reject(3); }, 1); - })); - - let value; - try { - value = await registry.dispatch(grandchild, 'command'); - } catch (err) { - value = err; - } - expect(value).toBe(3); - }); - }); - - describe("::getSnapshot and ::restoreSnapshot", () => - it("removes all command handlers except for those in the snapshot", () => { - registry.add('.parent', 'namespace:command-1', () => {}); - registry.add('.child', 'namespace:command-2', () => {}); - const snapshot = registry.getSnapshot(); - registry.add('.grandchild', 'namespace:command-3', () => {}); - - expect(registry.findCommands({target: grandchild}).slice(0, 3)).toEqual([ - {name: 'namespace:command-3', displayName: 'Namespace: Command 3'}, - {name: 'namespace:command-2', displayName: 'Namespace: Command 2'}, - {name: 'namespace:command-1', displayName: 'Namespace: Command 1'} - ]); - - registry.restoreSnapshot(snapshot); - - expect(registry.findCommands({target: grandchild}).slice(0, 2)).toEqual([ - {name: 'namespace:command-2', displayName: 'Namespace: Command 2'}, - {name: 'namespace:command-1', displayName: 'Namespace: Command 1'} - ]); - - registry.add('.grandchild', 'namespace:command-3', () => {}); - registry.restoreSnapshot(snapshot); - - expect(registry.findCommands({target: grandchild}).slice(0, 2)).toEqual([ - {name: 'namespace:command-2', displayName: 'Namespace: Command 2'}, - {name: 'namespace:command-1', displayName: 'Namespace: Command 1'} - ]); - }) -); - - describe("::attach(rootNode)", () => - it("adds event listeners for any previously-added commands", () => { - const registry2 = new CommandRegistry; - - const commandSpy = jasmine.createSpy('command-callback'); - registry2.add('.grandchild', 'command-1', commandSpy); - - grandchild.dispatchEvent(new CustomEvent('command-1', {bubbles: true})); - expect(commandSpy).not.toHaveBeenCalled(); - - registry2.attach(parent); - - grandchild.dispatchEvent(new CustomEvent('command-1', {bubbles: true})); - expect(commandSpy).toHaveBeenCalled(); + ]) }) - ); -}); + }) + + describe('::dispatch(target, commandName)', () => { + it('simulates invocation of the given command ', () => { + let called = false + registry.add('.grandchild', 'command', function (event) { + expect(this).toBe(grandchild) + expect(event.type).toBe('command') + expect(event.eventPhase).toBe(Event.BUBBLING_PHASE) + expect(event.target).toBe(grandchild) + expect(event.currentTarget).toBe(grandchild) + called = true + }) + + registry.dispatch(grandchild, 'command') + expect(called).toBe(true) + }) + + it('returns a promise if any listeners matched the command', () => { + registry.add('.grandchild', 'command', () => {}) + + expect(registry.dispatch(grandchild, 'command').constructor.name).toBe( + 'Promise' + ) + expect(registry.dispatch(grandchild, 'bogus')).toBe(null) + expect(registry.dispatch(parent, 'command')).toBe(null) + }) + + it('returns a promise that resolves when the listeners resolve', async () => { + jasmine.useRealClock() + registry.add('.grandchild', 'command', () => 1) + registry.add('.grandchild', 'command', () => Promise.resolve(2)) + registry.add( + '.grandchild', + 'command', + () => + new Promise(resolve => { + setTimeout(() => { + resolve(3) + }, 1) + }) + ) + + const values = await registry.dispatch(grandchild, 'command') + expect(values).toEqual([3, 2, 1]) + }) + + it('returns a promise that rejects when a listener is rejected', async () => { + jasmine.useRealClock() + registry.add('.grandchild', 'command', () => 1) + registry.add('.grandchild', 'command', () => Promise.resolve(2)) + registry.add( + '.grandchild', + 'command', + () => + new Promise((resolve, reject) => { + setTimeout(() => { + reject(3) + }, 1) + }) + ) + + let value + try { + value = await registry.dispatch(grandchild, 'command') + } catch (err) { + value = err + } + expect(value).toBe(3) + }) + }) + + describe('::getSnapshot and ::restoreSnapshot', () => + it('removes all command handlers except for those in the snapshot', () => { + registry.add('.parent', 'namespace:command-1', () => {}) + registry.add('.child', 'namespace:command-2', () => {}) + const snapshot = registry.getSnapshot() + registry.add('.grandchild', 'namespace:command-3', () => {}) + + expect(registry.findCommands({ target: grandchild }).slice(0, 3)).toEqual( + [ + { name: 'namespace:command-3', displayName: 'Namespace: Command 3' }, + { name: 'namespace:command-2', displayName: 'Namespace: Command 2' }, + { name: 'namespace:command-1', displayName: 'Namespace: Command 1' } + ] + ) + + registry.restoreSnapshot(snapshot) + + expect(registry.findCommands({ target: grandchild }).slice(0, 2)).toEqual( + [ + { name: 'namespace:command-2', displayName: 'Namespace: Command 2' }, + { name: 'namespace:command-1', displayName: 'Namespace: Command 1' } + ] + ) + + registry.add('.grandchild', 'namespace:command-3', () => {}) + registry.restoreSnapshot(snapshot) + + expect(registry.findCommands({ target: grandchild }).slice(0, 2)).toEqual( + [ + { name: 'namespace:command-2', displayName: 'Namespace: Command 2' }, + { name: 'namespace:command-1', displayName: 'Namespace: Command 1' } + ] + ) + })) + + describe('::attach(rootNode)', () => + it('adds event listeners for any previously-added commands', () => { + const registry2 = new CommandRegistry() + + const commandSpy = jasmine.createSpy('command-callback') + registry2.add('.grandchild', 'command-1', commandSpy) + + grandchild.dispatchEvent(new CustomEvent('command-1', { bubbles: true })) + expect(commandSpy).not.toHaveBeenCalled() + + registry2.attach(parent) + + grandchild.dispatchEvent(new CustomEvent('command-1', { bubbles: true })) + expect(commandSpy).toHaveBeenCalled() + })) +}) diff --git a/spec/config-file-spec.js b/spec/config-file-spec.js index ae5e05fe6..a053c9755 100644 --- a/spec/config-file-spec.js +++ b/spec/config-file-spec.js @@ -1,4 +1,11 @@ -const {it, fit, ffit, beforeEach, afterEach, conditionPromise} = require('./async-spec-helpers') +const { + it, + fit, + ffit, + beforeEach, + afterEach, + conditionPromise +} = require('./async-spec-helpers') const fs = require('fs-plus') const path = require('path') const temp = require('temp').track() @@ -42,22 +49,25 @@ describe('ConfigFile', () => { const event = new Promise(resolve => configFile.onDidChange(resolve)) - writeFileSync(filePath, dedent ` + writeFileSync( + filePath, + dedent` '*': foo: 'bar' 'javascript': foo: 'baz' - `) + ` + ) expect(await event).toEqual({ - '*': {foo: 'bar'}, - 'javascript': {foo: 'baz'} + '*': { foo: 'bar' }, + javascript: { foo: 'baz' } }) expect(configFile.get()).toEqual({ - '*': {foo: 'bar'}, - 'javascript': {foo: 'baz'} + '*': { foo: 'bar' }, + javascript: { foo: 'baz' } }) }) }) @@ -69,25 +79,33 @@ describe('ConfigFile', () => { const message = new Promise(resolve => configFile.onDidError(resolve)) - writeFileSync(filePath, dedent ` + writeFileSync( + filePath, + dedent` um what? - `, 2) + `, + 2 + ) expect(await message).toContain('Failed to load `the-config.cson`') const event = new Promise(resolve => configFile.onDidChange(resolve)) - writeFileSync(filePath, dedent ` + writeFileSync( + filePath, + dedent` '*': foo: 'bar' 'javascript': foo: 'baz' - `, 4) + `, + 4 + ) expect(await event).toEqual({ - '*': {foo: 'bar'}, - 'javascript': {foo: 'baz'} + '*': { foo: 'bar' }, + javascript: { foo: 'baz' } }) }) }) @@ -115,7 +133,7 @@ describe('ConfigFile', () => { }) function writeFileSync (filePath, content, seconds = 2) { - const utime = (Date.now() / 1000) + seconds + const utime = Date.now() / 1000 + seconds fs.writeFileSync(filePath, content) fs.utimesSync(filePath, utime, utime) } diff --git a/spec/config-spec.js b/spec/config-spec.js index 53cf9fffc..f942d62a5 100644 --- a/spec/config-spec.js +++ b/spec/config-spec.js @@ -19,121 +19,193 @@ describe('Config', () => { }) it("returns a deep clone of the key path's value", () => { - atom.config.set('value', {array: [1, {b: 2}, 3]}) + atom.config.set('value', { array: [1, { b: 2 }, 3] }) const retrievedValue = atom.config.get('value') retrievedValue.array[0] = 4 retrievedValue.array[1].b = 2.1 - expect(atom.config.get('value')).toEqual({array: [1, {b: 2}, 3]}) + expect(atom.config.get('value')).toEqual({ array: [1, { b: 2 }, 3] }) }) it('merges defaults into the returned value if both the assigned value and the default value are objects', () => { - atom.config.setDefaults('foo.bar', {baz: 1, ok: 2}) - atom.config.set('foo.bar', {baz: 3}) - expect(atom.config.get('foo.bar')).toEqual({baz: 3, ok: 2}) + atom.config.setDefaults('foo.bar', { baz: 1, ok: 2 }) + atom.config.set('foo.bar', { baz: 3 }) + expect(atom.config.get('foo.bar')).toEqual({ baz: 3, ok: 2 }) - atom.config.setDefaults('other', {baz: 1}) + atom.config.setDefaults('other', { baz: 1 }) atom.config.set('other', 7) expect(atom.config.get('other')).toBe(7) - atom.config.set('bar.baz', {a: 3}) - atom.config.setDefaults('bar', {baz: 7}) - expect(atom.config.get('bar.baz')).toEqual({a: 3}) + atom.config.set('bar.baz', { a: 3 }) + atom.config.setDefaults('bar', { baz: 7 }) + expect(atom.config.get('bar.baz')).toEqual({ a: 3 }) }) describe("when a 'sources' option is specified", () => it('only retrieves values from the specified sources', () => { - atom.config.set('x.y', 1, {scopeSelector: '.foo', source: 'a'}) - atom.config.set('x.y', 2, {scopeSelector: '.foo', source: 'b'}) - atom.config.set('x.y', 3, {scopeSelector: '.foo', source: 'c'}) - atom.config.setSchema('x.y', {type: 'integer', default: 4}) + atom.config.set('x.y', 1, { scopeSelector: '.foo', source: 'a' }) + atom.config.set('x.y', 2, { scopeSelector: '.foo', source: 'b' }) + atom.config.set('x.y', 3, { scopeSelector: '.foo', source: 'c' }) + atom.config.setSchema('x.y', { type: 'integer', default: 4 }) - expect(atom.config.get('x.y', {sources: ['a'], scope: ['.foo']})).toBe(1) - expect(atom.config.get('x.y', {sources: ['b'], scope: ['.foo']})).toBe(2) - expect(atom.config.get('x.y', {sources: ['c'], scope: ['.foo']})).toBe(3) + expect( + atom.config.get('x.y', { sources: ['a'], scope: ['.foo'] }) + ).toBe(1) + expect( + atom.config.get('x.y', { sources: ['b'], scope: ['.foo'] }) + ).toBe(2) + expect( + atom.config.get('x.y', { sources: ['c'], scope: ['.foo'] }) + ).toBe(3) // Schema defaults never match a specific source. We could potentially add a special "schema" source. - expect(atom.config.get('x.y', {sources: ['x'], scope: ['.foo']})).toBeUndefined() + expect( + atom.config.get('x.y', { sources: ['x'], scope: ['.foo'] }) + ).toBeUndefined() - expect(atom.config.get(null, {sources: ['a'], scope: ['.foo']}).x.y).toBe(1) - }) - ) + expect( + atom.config.get(null, { sources: ['a'], scope: ['.foo'] }).x.y + ).toBe(1) + })) describe("when an 'excludeSources' option is specified", () => it('only retrieves values from the specified sources', () => { atom.config.set('x.y', 0) - atom.config.set('x.y', 1, {scopeSelector: '.foo', source: 'a'}) - atom.config.set('x.y', 2, {scopeSelector: '.foo', source: 'b'}) - atom.config.set('x.y', 3, {scopeSelector: '.foo', source: 'c'}) - atom.config.setSchema('x.y', {type: 'integer', default: 4}) + atom.config.set('x.y', 1, { scopeSelector: '.foo', source: 'a' }) + atom.config.set('x.y', 2, { scopeSelector: '.foo', source: 'b' }) + atom.config.set('x.y', 3, { scopeSelector: '.foo', source: 'c' }) + atom.config.setSchema('x.y', { type: 'integer', default: 4 }) - expect(atom.config.get('x.y', {excludeSources: ['a'], scope: ['.foo']})).toBe(3) - expect(atom.config.get('x.y', {excludeSources: ['c'], scope: ['.foo']})).toBe(2) - expect(atom.config.get('x.y', {excludeSources: ['b', 'c'], scope: ['.foo']})).toBe(1) - expect(atom.config.get('x.y', {excludeSources: ['b', 'c', 'a'], scope: ['.foo']})).toBe(0) - expect(atom.config.get('x.y', {excludeSources: ['b', 'c', 'a', atom.config.getUserConfigPath()], scope: ['.foo']})).toBe(4) - expect(atom.config.get('x.y', {excludeSources: [atom.config.getUserConfigPath()]})).toBe(4) - }) - ) + expect( + atom.config.get('x.y', { excludeSources: ['a'], scope: ['.foo'] }) + ).toBe(3) + expect( + atom.config.get('x.y', { excludeSources: ['c'], scope: ['.foo'] }) + ).toBe(2) + expect( + atom.config.get('x.y', { + excludeSources: ['b', 'c'], + scope: ['.foo'] + }) + ).toBe(1) + expect( + atom.config.get('x.y', { + excludeSources: ['b', 'c', 'a'], + scope: ['.foo'] + }) + ).toBe(0) + expect( + atom.config.get('x.y', { + excludeSources: ['b', 'c', 'a', atom.config.getUserConfigPath()], + scope: ['.foo'] + }) + ).toBe(4) + expect( + atom.config.get('x.y', { + excludeSources: [atom.config.getUserConfigPath()] + }) + ).toBe(4) + })) describe("when a 'scope' option is given", () => { it('returns the property with the most specific scope selector', () => { - atom.config.set('foo.bar.baz', 42, {scopeSelector: '.source.coffee .string.quoted.double.coffee'}) - atom.config.set('foo.bar.baz', 22, {scopeSelector: '.source .string.quoted.double'}) - atom.config.set('foo.bar.baz', 11, {scopeSelector: '.source'}) + atom.config.set('foo.bar.baz', 42, { + scopeSelector: '.source.coffee .string.quoted.double.coffee' + }) + atom.config.set('foo.bar.baz', 22, { + scopeSelector: '.source .string.quoted.double' + }) + atom.config.set('foo.bar.baz', 11, { scopeSelector: '.source' }) - expect(atom.config.get('foo.bar.baz', {scope: ['.source.coffee', '.string.quoted.double.coffee']})).toBe(42) - expect(atom.config.get('foo.bar.baz', {scope: ['.source.js', '.string.quoted.double.js']})).toBe(22) - expect(atom.config.get('foo.bar.baz', {scope: ['.source.js', '.variable.assignment.js']})).toBe(11) - expect(atom.config.get('foo.bar.baz', {scope: ['.text']})).toBeUndefined() + expect( + atom.config.get('foo.bar.baz', { + scope: ['.source.coffee', '.string.quoted.double.coffee'] + }) + ).toBe(42) + expect( + atom.config.get('foo.bar.baz', { + scope: ['.source.js', '.string.quoted.double.js'] + }) + ).toBe(22) + expect( + atom.config.get('foo.bar.baz', { + scope: ['.source.js', '.variable.assignment.js'] + }) + ).toBe(11) + expect( + atom.config.get('foo.bar.baz', { scope: ['.text'] }) + ).toBeUndefined() }) it('favors the most recently added properties in the event of a specificity tie', () => { - atom.config.set('foo.bar.baz', 42, {scopeSelector: '.source.coffee .string.quoted.single'}) - atom.config.set('foo.bar.baz', 22, {scopeSelector: '.source.coffee .string.quoted.double'}) + atom.config.set('foo.bar.baz', 42, { + scopeSelector: '.source.coffee .string.quoted.single' + }) + atom.config.set('foo.bar.baz', 22, { + scopeSelector: '.source.coffee .string.quoted.double' + }) - expect(atom.config.get('foo.bar.baz', {scope: ['.source.coffee', '.string.quoted.single']})).toBe(42) - expect(atom.config.get('foo.bar.baz', {scope: ['.source.coffee', '.string.quoted.single.double']})).toBe(22) + expect( + atom.config.get('foo.bar.baz', { + scope: ['.source.coffee', '.string.quoted.single'] + }) + ).toBe(42) + expect( + atom.config.get('foo.bar.baz', { + scope: ['.source.coffee', '.string.quoted.single.double'] + }) + ).toBe(22) }) describe('when there are global defaults', () => it('falls back to the global when there is no scoped property specified', () => { - atom.config.setDefaults('foo', {hasDefault: 'ok'}) - expect(atom.config.get('foo.hasDefault', {scope: ['.source.coffee', '.string.quoted.single']})).toBe('ok') - }) - ) + atom.config.setDefaults('foo', { hasDefault: 'ok' }) + expect( + atom.config.get('foo.hasDefault', { + scope: ['.source.coffee', '.string.quoted.single'] + }) + ).toBe('ok') + })) describe('when package settings are added after user settings', () => it("returns the user's setting because the user's setting has higher priority", () => { - atom.config.set('foo.bar.baz', 100, {scopeSelector: '.source.coffee'}) - atom.config.set('foo.bar.baz', 1, {scopeSelector: '.source.coffee', source: 'some-package'}) - expect(atom.config.get('foo.bar.baz', {scope: ['.source.coffee']})).toBe(100) - }) - ) + atom.config.set('foo.bar.baz', 100, { + scopeSelector: '.source.coffee' + }) + atom.config.set('foo.bar.baz', 1, { + scopeSelector: '.source.coffee', + source: 'some-package' + }) + expect( + atom.config.get('foo.bar.baz', { scope: ['.source.coffee'] }) + ).toBe(100) + })) }) }) describe('.getAll(keyPath, {scope, sources, excludeSources})', () => { it('reads all of the values for a given key-path', () => { expect(atom.config.set('foo', 41)).toBe(true) - expect(atom.config.set('foo', 43, {scopeSelector: '.a .b'})).toBe(true) - expect(atom.config.set('foo', 42, {scopeSelector: '.a'})).toBe(true) - expect(atom.config.set('foo', 44, {scopeSelector: '.a .b.c'})).toBe(true) + expect(atom.config.set('foo', 43, { scopeSelector: '.a .b' })).toBe(true) + expect(atom.config.set('foo', 42, { scopeSelector: '.a' })).toBe(true) + expect(atom.config.set('foo', 44, { scopeSelector: '.a .b.c' })).toBe( + true + ) - expect(atom.config.set('foo', -44, {scopeSelector: '.d'})).toBe(true) + expect(atom.config.set('foo', -44, { scopeSelector: '.d' })).toBe(true) - expect(atom.config.getAll('foo', {scope: ['.a', '.b.c']})).toEqual([ - {scopeSelector: '.a .b.c', value: 44}, - {scopeSelector: '.a .b', value: 43}, - {scopeSelector: '.a', value: 42}, - {scopeSelector: '*', value: 41} + expect(atom.config.getAll('foo', { scope: ['.a', '.b.c'] })).toEqual([ + { scopeSelector: '.a .b.c', value: 44 }, + { scopeSelector: '.a .b', value: 43 }, + { scopeSelector: '.a', value: 42 }, + { scopeSelector: '*', value: 41 } ]) }) it("includes the schema's default value", () => { - atom.config.setSchema('foo', {type: 'number', default: 40}) - expect(atom.config.set('foo', 43, {scopeSelector: '.a .b'})).toBe(true) - expect(atom.config.getAll('foo', {scope: ['.a', '.b.c']})).toEqual([ - {scopeSelector: '.a .b', value: 43}, - {scopeSelector: '*', value: 40} + atom.config.setSchema('foo', { type: 'number', default: 40 }) + expect(atom.config.set('foo', 43, { scopeSelector: '.a .b' })).toBe(true) + expect(atom.config.getAll('foo', { scope: ['.a', '.b.c'] })).toEqual([ + { scopeSelector: '.a .b', value: 43 }, + { scopeSelector: '*', value: 40 } ]) }) }) @@ -155,23 +227,33 @@ describe('Config', () => { }) it("does not save when a non-default 'source' is given", () => { - atom.config.set('foo.bar.baz', 42, {source: 'some-other-source', scopeSelector: '.a'}) + atom.config.set('foo.bar.baz', 42, { + source: 'some-other-source', + scopeSelector: '.a' + }) advanceClock(500) expect(savedSettings.length).toBe(0) }) it("does not allow a 'source' option without a 'scopeSelector'", () => { - expect(() => atom.config.set('foo', 1, {source: ['.source.ruby']})).toThrow() + expect(() => + atom.config.set('foo', 1, { source: ['.source.ruby'] }) + ).toThrow() }) describe('when the key-path is null', () => it('sets the root object', () => { - expect(atom.config.set(null, {editor: {tabLength: 6}})).toBe(true) + expect(atom.config.set(null, { editor: { tabLength: 6 } })).toBe(true) expect(atom.config.get('editor.tabLength')).toBe(6) - expect(atom.config.set(null, {editor: {tabLength: 8, scopeSelector: ['.source.js']}})).toBe(true) - expect(atom.config.get('editor.tabLength', {scope: ['.source.js']})).toBe(8) - }) - ) + expect( + atom.config.set(null, { + editor: { tabLength: 8, scopeSelector: ['.source.js'] } + }) + ).toBe(true) + expect( + atom.config.get('editor.tabLength', { scope: ['.source.js'] }) + ).toBe(8) + })) describe('when the value equals the default value', () => it("does not store the value in the user's config", () => { @@ -192,7 +274,7 @@ describe('Config', () => { }, sameObject: { type: 'object', - default: {a: 1, b: 2} + default: { a: 1, b: 2 } }, null: { type: '*', @@ -203,8 +285,7 @@ describe('Config', () => { default: undefined } } - } - ) + }) expect(atom.config.settings.foo).toBeUndefined() atom.config.set('foo.same', 1) @@ -212,32 +293,52 @@ describe('Config', () => { atom.config.set('foo.sameArray', [1, 2, 3]) atom.config.set('foo.null', undefined) atom.config.set('foo.undefined', null) - atom.config.set('foo.sameObject', {b: 2, a: 1}) + atom.config.set('foo.sameObject', { b: 2, a: 1 }) const userConfigPath = atom.config.getUserConfigPath() - expect(atom.config.get('foo.same', {sources: [userConfigPath]})).toBeUndefined() + expect( + atom.config.get('foo.same', { sources: [userConfigPath] }) + ).toBeUndefined() expect(atom.config.get('foo.changes')).toBe(2) - expect(atom.config.get('foo.changes', {sources: [userConfigPath]})).toBe(2) + expect( + atom.config.get('foo.changes', { sources: [userConfigPath] }) + ).toBe(2) atom.config.set('foo.changes', 1) - expect(atom.config.get('foo.changes', {sources: [userConfigPath]})).toBeUndefined() - }) - ) + expect( + atom.config.get('foo.changes', { sources: [userConfigPath] }) + ).toBeUndefined() + })) describe("when a 'scopeSelector' is given", () => it('sets the value and overrides the others', () => { - atom.config.set('foo.bar.baz', 42, {scopeSelector: '.source.coffee .string.quoted.double.coffee'}) - atom.config.set('foo.bar.baz', 22, {scopeSelector: '.source .string.quoted.double'}) - atom.config.set('foo.bar.baz', 11, {scopeSelector: '.source'}) + atom.config.set('foo.bar.baz', 42, { + scopeSelector: '.source.coffee .string.quoted.double.coffee' + }) + atom.config.set('foo.bar.baz', 22, { + scopeSelector: '.source .string.quoted.double' + }) + atom.config.set('foo.bar.baz', 11, { scopeSelector: '.source' }) - expect(atom.config.get('foo.bar.baz', {scope: ['.source.coffee', '.string.quoted.double.coffee']})).toBe(42) + expect( + atom.config.get('foo.bar.baz', { + scope: ['.source.coffee', '.string.quoted.double.coffee'] + }) + ).toBe(42) - expect(atom.config.set('foo.bar.baz', 100, {scopeSelector: '.source.coffee .string.quoted.double.coffee'})).toBe(true) - expect(atom.config.get('foo.bar.baz', {scope: ['.source.coffee', '.string.quoted.double.coffee']})).toBe(100) - }) - ) + expect( + atom.config.set('foo.bar.baz', 100, { + scopeSelector: '.source.coffee .string.quoted.double.coffee' + }) + ).toBe(true) + expect( + atom.config.get('foo.bar.baz', { + scope: ['.source.coffee', '.string.quoted.double.coffee'] + }) + ).toBe(100) + })) }) describe('.unset(keyPath, {source, scopeSelector})', () => { @@ -263,12 +364,11 @@ describe('Config', () => { default: 0 } } - } - ) + }) ) it('sets the value of the key path to its default', () => { - atom.config.setDefaults('a', {b: 3}) + atom.config.setDefaults('a', { b: 3 }) atom.config.set('a.b', 4) expect(atom.config.get('a.b')).toBe(4) atom.config.unset('a.b') @@ -281,7 +381,7 @@ describe('Config', () => { }) it('calls ::save()', () => { - atom.config.setDefaults('a', {b: 3}) + atom.config.setDefaults('a', { b: 3 }) atom.config.set('a.b', 4) savedSettings.length = 0 @@ -293,125 +393,204 @@ describe('Config', () => { describe("when no 'scopeSelector' is given", () => { describe("when a 'source' but no key-path is given", () => it('removes all scoped settings with the given source', () => { - atom.config.set('foo.bar.baz', 1, {scopeSelector: '.a', source: 'source-a'}) - atom.config.set('foo.bar.quux', 2, {scopeSelector: '.b', source: 'source-a'}) - expect(atom.config.get('foo.bar', {scope: ['.a.b']})).toEqual({baz: 1, quux: 2}) + atom.config.set('foo.bar.baz', 1, { + scopeSelector: '.a', + source: 'source-a' + }) + atom.config.set('foo.bar.quux', 2, { + scopeSelector: '.b', + source: 'source-a' + }) + expect(atom.config.get('foo.bar', { scope: ['.a.b'] })).toEqual({ + baz: 1, + quux: 2 + }) - atom.config.unset(null, {source: 'source-a'}) - expect(atom.config.get('foo.bar', {scope: ['.a']})).toEqual({baz: 0, ok: 0}) - }) - ) + atom.config.unset(null, { source: 'source-a' }) + expect(atom.config.get('foo.bar', { scope: ['.a'] })).toEqual({ + baz: 0, + ok: 0 + }) + })) describe("when a 'source' and a key-path is given", () => it('removes all scoped settings with the given source and key-path', () => { atom.config.set('foo.bar.baz', 1) - atom.config.set('foo.bar.baz', 2, {scopeSelector: '.a', source: 'source-a'}) - atom.config.set('foo.bar.baz', 3, {scopeSelector: '.a.b', source: 'source-b'}) - expect(atom.config.get('foo.bar.baz', {scope: ['.a.b']})).toEqual(3) + atom.config.set('foo.bar.baz', 2, { + scopeSelector: '.a', + source: 'source-a' + }) + atom.config.set('foo.bar.baz', 3, { + scopeSelector: '.a.b', + source: 'source-b' + }) + expect(atom.config.get('foo.bar.baz', { scope: ['.a.b'] })).toEqual(3) - atom.config.unset('foo.bar.baz', {source: 'source-b'}) - expect(atom.config.get('foo.bar.baz', {scope: ['.a.b']})).toEqual(2) + atom.config.unset('foo.bar.baz', { source: 'source-b' }) + expect(atom.config.get('foo.bar.baz', { scope: ['.a.b'] })).toEqual(2) expect(atom.config.get('foo.bar.baz')).toEqual(1) - }) - ) + })) describe("when no 'source' is given", () => it('removes all scoped and unscoped properties for that key-path', () => { - atom.config.setDefaults('foo.bar', {baz: 100}) + atom.config.setDefaults('foo.bar', { baz: 100 }) - atom.config.set('foo.bar', {baz: 1, ok: 2}, {scopeSelector: '.a'}) - atom.config.set('foo.bar', {baz: 11, ok: 12}, {scopeSelector: '.b'}) - atom.config.set('foo.bar', {baz: 21, ok: 22}) + atom.config.set('foo.bar', { baz: 1, ok: 2 }, { scopeSelector: '.a' }) + atom.config.set( + 'foo.bar', + { baz: 11, ok: 12 }, + { scopeSelector: '.b' } + ) + atom.config.set('foo.bar', { baz: 21, ok: 22 }) atom.config.unset('foo.bar.baz') - expect(atom.config.get('foo.bar.baz', {scope: ['.a']})).toBe(100) - expect(atom.config.get('foo.bar.baz', {scope: ['.b']})).toBe(100) + expect(atom.config.get('foo.bar.baz', { scope: ['.a'] })).toBe(100) + expect(atom.config.get('foo.bar.baz', { scope: ['.b'] })).toBe(100) expect(atom.config.get('foo.bar.baz')).toBe(100) - expect(atom.config.get('foo.bar.ok', {scope: ['.a']})).toBe(2) - expect(atom.config.get('foo.bar.ok', {scope: ['.b']})).toBe(12) + expect(atom.config.get('foo.bar.ok', { scope: ['.a'] })).toBe(2) + expect(atom.config.get('foo.bar.ok', { scope: ['.b'] })).toBe(12) expect(atom.config.get('foo.bar.ok')).toBe(22) - }) - ) + })) }) describe("when a 'scopeSelector' is given", () => { it('restores the global default when no scoped default set', () => { - atom.config.setDefaults('foo', {bar: {baz: 10}}) - atom.config.set('foo.bar.baz', 55, {scopeSelector: '.source.coffee'}) - expect(atom.config.get('foo.bar.baz', {scope: ['.source.coffee']})).toBe(55) + atom.config.setDefaults('foo', { bar: { baz: 10 } }) + atom.config.set('foo.bar.baz', 55, { scopeSelector: '.source.coffee' }) + expect( + atom.config.get('foo.bar.baz', { scope: ['.source.coffee'] }) + ).toBe(55) - atom.config.unset('foo.bar.baz', {scopeSelector: '.source.coffee'}) - expect(atom.config.get('foo.bar.baz', {scope: ['.source.coffee']})).toBe(10) + atom.config.unset('foo.bar.baz', { scopeSelector: '.source.coffee' }) + expect( + atom.config.get('foo.bar.baz', { scope: ['.source.coffee'] }) + ).toBe(10) }) it('restores the scoped default when a scoped default is set', () => { - atom.config.setDefaults('foo', {bar: {baz: 10}}) - atom.config.set('foo.bar.baz', 42, {scopeSelector: '.source.coffee', source: 'some-source'}) - atom.config.set('foo.bar.baz', 55, {scopeSelector: '.source.coffee'}) - atom.config.set('foo.bar.ok', 100, {scopeSelector: '.source.coffee'}) - expect(atom.config.get('foo.bar.baz', {scope: ['.source.coffee']})).toBe(55) + atom.config.setDefaults('foo', { bar: { baz: 10 } }) + atom.config.set('foo.bar.baz', 42, { + scopeSelector: '.source.coffee', + source: 'some-source' + }) + atom.config.set('foo.bar.baz', 55, { scopeSelector: '.source.coffee' }) + atom.config.set('foo.bar.ok', 100, { scopeSelector: '.source.coffee' }) + expect( + atom.config.get('foo.bar.baz', { scope: ['.source.coffee'] }) + ).toBe(55) - atom.config.unset('foo.bar.baz', {scopeSelector: '.source.coffee'}) - expect(atom.config.get('foo.bar.baz', {scope: ['.source.coffee']})).toBe(42) - expect(atom.config.get('foo.bar.ok', {scope: ['.source.coffee']})).toBe(100) + atom.config.unset('foo.bar.baz', { scopeSelector: '.source.coffee' }) + expect( + atom.config.get('foo.bar.baz', { scope: ['.source.coffee'] }) + ).toBe(42) + expect( + atom.config.get('foo.bar.ok', { scope: ['.source.coffee'] }) + ).toBe(100) }) it('calls ::save()', () => { - atom.config.setDefaults('foo', {bar: {baz: 10}}) - atom.config.set('foo.bar.baz', 55, {scopeSelector: '.source.coffee'}) + atom.config.setDefaults('foo', { bar: { baz: 10 } }) + atom.config.set('foo.bar.baz', 55, { scopeSelector: '.source.coffee' }) savedSettings.length = 0 - atom.config.unset('foo.bar.baz', {scopeSelector: '.source.coffee'}) + atom.config.unset('foo.bar.baz', { scopeSelector: '.source.coffee' }) advanceClock(150) expect(savedSettings.length).toBe(1) }) it('allows removing settings for a specific source and scope selector', () => { - atom.config.set('foo.bar.baz', 55, {scopeSelector: '.source.coffee', source: 'source-a'}) - atom.config.set('foo.bar.baz', 65, {scopeSelector: '.source.coffee', source: 'source-b'}) - expect(atom.config.get('foo.bar.baz', {scope: ['.source.coffee']})).toBe(65) + atom.config.set('foo.bar.baz', 55, { + scopeSelector: '.source.coffee', + source: 'source-a' + }) + atom.config.set('foo.bar.baz', 65, { + scopeSelector: '.source.coffee', + source: 'source-b' + }) + expect( + atom.config.get('foo.bar.baz', { scope: ['.source.coffee'] }) + ).toBe(65) - atom.config.unset('foo.bar.baz', {source: 'source-b', scopeSelector: '.source.coffee'}) - expect(atom.config.get('foo.bar.baz', {scope: ['.source.coffee', '.string']})).toBe(55) + atom.config.unset('foo.bar.baz', { + source: 'source-b', + scopeSelector: '.source.coffee' + }) + expect( + atom.config.get('foo.bar.baz', { + scope: ['.source.coffee', '.string'] + }) + ).toBe(55) }) it('allows removing all settings for a specific source', () => { - atom.config.set('foo.bar.baz', 55, {scopeSelector: '.source.coffee', source: 'source-a'}) - atom.config.set('foo.bar.baz', 65, {scopeSelector: '.source.coffee', source: 'source-b'}) - atom.config.set('foo.bar.ok', 65, {scopeSelector: '.source.coffee', source: 'source-b'}) - expect(atom.config.get('foo.bar.baz', {scope: ['.source.coffee']})).toBe(65) + atom.config.set('foo.bar.baz', 55, { + scopeSelector: '.source.coffee', + source: 'source-a' + }) + atom.config.set('foo.bar.baz', 65, { + scopeSelector: '.source.coffee', + source: 'source-b' + }) + atom.config.set('foo.bar.ok', 65, { + scopeSelector: '.source.coffee', + source: 'source-b' + }) + expect( + atom.config.get('foo.bar.baz', { scope: ['.source.coffee'] }) + ).toBe(65) - atom.config.unset(null, {source: 'source-b', scopeSelector: '.source.coffee'}) - expect(atom.config.get('foo.bar.baz', {scope: ['.source.coffee', '.string']})).toBe(55) - expect(atom.config.get('foo.bar.ok', {scope: ['.source.coffee', '.string']})).toBe(0) + atom.config.unset(null, { + source: 'source-b', + scopeSelector: '.source.coffee' + }) + expect( + atom.config.get('foo.bar.baz', { + scope: ['.source.coffee', '.string'] + }) + ).toBe(55) + expect( + atom.config.get('foo.bar.ok', { + scope: ['.source.coffee', '.string'] + }) + ).toBe(0) }) it('does not call ::save or add a scoped property when no value has been set', () => { // see https://github.com/atom/atom/issues/4175 - atom.config.setDefaults('foo', {bar: {baz: 10}}) - atom.config.unset('foo.bar.baz', {scopeSelector: '.source.coffee'}) - expect(atom.config.get('foo.bar.baz', {scope: ['.source.coffee']})).toBe(10) + atom.config.setDefaults('foo', { bar: { baz: 10 } }) + atom.config.unset('foo.bar.baz', { scopeSelector: '.source.coffee' }) + expect( + atom.config.get('foo.bar.baz', { scope: ['.source.coffee'] }) + ).toBe(10) expect(savedSettings.length).toBe(0) - const scopedProperties = atom.config.scopedSettingsStore.propertiesForSource('user-config') + const scopedProperties = atom.config.scopedSettingsStore.propertiesForSource( + 'user-config' + ) expect(scopedProperties['.coffee.source']).toBeUndefined() }) it('removes the scoped value when it was the only set value on the object', () => { - atom.config.setDefaults('foo', {bar: {baz: 10}}) - atom.config.set('foo.bar.baz', 55, {scopeSelector: '.source.coffee'}) - atom.config.set('foo.bar.ok', 20, {scopeSelector: '.source.coffee'}) - expect(atom.config.get('foo.bar.baz', {scope: ['.source.coffee']})).toBe(55) + atom.config.setDefaults('foo', { bar: { baz: 10 } }) + atom.config.set('foo.bar.baz', 55, { scopeSelector: '.source.coffee' }) + atom.config.set('foo.bar.ok', 20, { scopeSelector: '.source.coffee' }) + expect( + atom.config.get('foo.bar.baz', { scope: ['.source.coffee'] }) + ).toBe(55) advanceClock(150) savedSettings.length = 0 - atom.config.unset('foo.bar.baz', {scopeSelector: '.source.coffee'}) - expect(atom.config.get('foo.bar.baz', {scope: ['.source.coffee']})).toBe(10) - expect(atom.config.get('foo.bar.ok', {scope: ['.source.coffee']})).toBe(20) + atom.config.unset('foo.bar.baz', { scopeSelector: '.source.coffee' }) + expect( + atom.config.get('foo.bar.baz', { scope: ['.source.coffee'] }) + ).toBe(10) + expect( + atom.config.get('foo.bar.ok', { scope: ['.source.coffee'] }) + ).toBe(20) advanceClock(150) expect(savedSettings[0]['.coffee.source']).toEqual({ @@ -422,7 +601,7 @@ describe('Config', () => { } }) - atom.config.unset('foo.bar.ok', {scopeSelector: '.source.coffee'}) + atom.config.unset('foo.bar.ok', { scopeSelector: '.source.coffee' }) advanceClock(150) expect(savedSettings.length).toBe(2) @@ -430,15 +609,17 @@ describe('Config', () => { }) it('does not call ::save when the value is already at the default', () => { - atom.config.setDefaults('foo', {bar: {baz: 10}}) + atom.config.setDefaults('foo', { bar: { baz: 10 } }) atom.config.set('foo.bar.baz', 55) advanceClock(150) savedSettings.length = 0 - atom.config.unset('foo.bar.ok', {scopeSelector: '.source.coffee'}) + atom.config.unset('foo.bar.ok', { scopeSelector: '.source.coffee' }) advanceClock(150) expect(savedSettings.length).toBe(0) - expect(atom.config.get('foo.bar.baz', {scope: ['.source.coffee']})).toBe(55) + expect( + atom.config.get('foo.bar.baz', { scope: ['.source.coffee'] }) + ).toBe(55) }) }) }) @@ -453,15 +634,24 @@ describe('Config', () => { atom.config.onDidChange('foo.bar.baz', observeHandler) }) - it('does not fire the given callback with the current value at the keypath', () => expect(observeHandler).not.toHaveBeenCalled()) + it('does not fire the given callback with the current value at the keypath', () => + expect(observeHandler).not.toHaveBeenCalled()) it('fires the callback every time the observed value changes', () => { atom.config.set('foo.bar.baz', 'value 2') - expect(observeHandler).toHaveBeenCalledWith({newValue: 'value 2', oldValue: 'value 1'}) + expect(observeHandler).toHaveBeenCalledWith({ + newValue: 'value 2', + oldValue: 'value 1' + }) observeHandler.reset() - observeHandler.andCallFake(() => { throw new Error('oops') }) + observeHandler.andCallFake(() => { + throw new Error('oops') + }) expect(() => atom.config.set('foo.bar.baz', 'value 1')).toThrow('oops') - expect(observeHandler).toHaveBeenCalledWith({newValue: 'value 1', oldValue: 'value 2'}) + expect(observeHandler).toHaveBeenCalledWith({ + newValue: 'value 1', + oldValue: 'value 2' + }) observeHandler.reset() // Regression: exception in earlier handler shouldn't put observer @@ -478,59 +668,93 @@ describe('Config', () => { atom.config.onDidChange(observeHandler) }) - it('does not fire the given callback initially', () => expect(observeHandler).not.toHaveBeenCalled()) + it('does not fire the given callback initially', () => + expect(observeHandler).not.toHaveBeenCalled()) it('fires the callback every time any value changes', () => { observeHandler.reset() // clear the initial call atom.config.set('foo.bar.baz', 'value 2') expect(observeHandler).toHaveBeenCalled() - expect(observeHandler.mostRecentCall.args[0].newValue.foo.bar.baz).toBe('value 2') - expect(observeHandler.mostRecentCall.args[0].oldValue.foo.bar.baz).toBe('value 1') + expect(observeHandler.mostRecentCall.args[0].newValue.foo.bar.baz).toBe( + 'value 2' + ) + expect(observeHandler.mostRecentCall.args[0].oldValue.foo.bar.baz).toBe( + 'value 1' + ) observeHandler.reset() atom.config.set('foo.bar.baz', 'value 1') expect(observeHandler).toHaveBeenCalled() - expect(observeHandler.mostRecentCall.args[0].newValue.foo.bar.baz).toBe('value 1') - expect(observeHandler.mostRecentCall.args[0].oldValue.foo.bar.baz).toBe('value 2') + expect(observeHandler.mostRecentCall.args[0].newValue.foo.bar.baz).toBe( + 'value 1' + ) + expect(observeHandler.mostRecentCall.args[0].oldValue.foo.bar.baz).toBe( + 'value 2' + ) observeHandler.reset() atom.config.set('foo.bar.int', 1) expect(observeHandler).toHaveBeenCalled() - expect(observeHandler.mostRecentCall.args[0].newValue.foo.bar.int).toBe(1) - expect(observeHandler.mostRecentCall.args[0].oldValue.foo.bar.int).toBe(undefined) + expect(observeHandler.mostRecentCall.args[0].newValue.foo.bar.int).toBe( + 1 + ) + expect(observeHandler.mostRecentCall.args[0].oldValue.foo.bar.int).toBe( + undefined + ) }) }) describe("when a 'scope' is given", () => it('calls the supplied callback when the value at the descriptor/keypath changes', () => { const changeSpy = jasmine.createSpy('onDidChange callback') - atom.config.onDidChange('foo.bar.baz', {scope: ['.source.coffee', '.string.quoted.double.coffee']}, changeSpy) + atom.config.onDidChange( + 'foo.bar.baz', + { scope: ['.source.coffee', '.string.quoted.double.coffee'] }, + changeSpy + ) atom.config.set('foo.bar.baz', 12) - expect(changeSpy).toHaveBeenCalledWith({oldValue: undefined, newValue: 12}) + expect(changeSpy).toHaveBeenCalledWith({ + oldValue: undefined, + newValue: 12 + }) changeSpy.reset() - atom.config.set('foo.bar.baz', 22, {scopeSelector: '.source .string.quoted.double', source: 'a'}) - expect(changeSpy).toHaveBeenCalledWith({oldValue: 12, newValue: 22}) + atom.config.set('foo.bar.baz', 22, { + scopeSelector: '.source .string.quoted.double', + source: 'a' + }) + expect(changeSpy).toHaveBeenCalledWith({ oldValue: 12, newValue: 22 }) changeSpy.reset() - atom.config.set('foo.bar.baz', 42, {scopeSelector: '.source.coffee .string.quoted.double.coffee', source: 'b'}) - expect(changeSpy).toHaveBeenCalledWith({oldValue: 22, newValue: 42}) + atom.config.set('foo.bar.baz', 42, { + scopeSelector: '.source.coffee .string.quoted.double.coffee', + source: 'b' + }) + expect(changeSpy).toHaveBeenCalledWith({ oldValue: 22, newValue: 42 }) changeSpy.reset() - atom.config.unset(null, {scopeSelector: '.source.coffee .string.quoted.double.coffee', source: 'b'}) - expect(changeSpy).toHaveBeenCalledWith({oldValue: 42, newValue: 22}) + atom.config.unset(null, { + scopeSelector: '.source.coffee .string.quoted.double.coffee', + source: 'b' + }) + expect(changeSpy).toHaveBeenCalledWith({ oldValue: 42, newValue: 22 }) changeSpy.reset() - atom.config.unset(null, {scopeSelector: '.source .string.quoted.double', source: 'a'}) - expect(changeSpy).toHaveBeenCalledWith({oldValue: 22, newValue: 12}) + atom.config.unset(null, { + scopeSelector: '.source .string.quoted.double', + source: 'a' + }) + expect(changeSpy).toHaveBeenCalledWith({ oldValue: 22, newValue: 12 }) changeSpy.reset() atom.config.set('foo.bar.baz', undefined) - expect(changeSpy).toHaveBeenCalledWith({oldValue: 12, newValue: undefined}) + expect(changeSpy).toHaveBeenCalledWith({ + oldValue: 12, + newValue: undefined + }) changeSpy.reset() - }) - ) + })) }) describe('.observe(keyPath, {scope})', () => { @@ -542,7 +766,8 @@ describe('Config', () => { observeSubscription = atom.config.observe('foo.bar.baz', observeHandler) }) - it('fires the given callback with the current value at the keypath', () => expect(observeHandler).toHaveBeenCalledWith('value 1')) + it('fires the given callback with the current value at the keypath', () => + expect(observeHandler).toHaveBeenCalledWith('value 1')) it('fires the callback every time the observed value changes', () => { observeHandler.reset() // clear the initial call @@ -555,7 +780,7 @@ describe('Config', () => { advanceClock(100) // complete pending save that was requested in ::set observeHandler.reset() - atom.config.resetUserSettings({foo: {}}) + atom.config.resetUserSettings({ foo: {} }) expect(observeHandler).toHaveBeenCalledWith(undefined) }) @@ -600,17 +825,29 @@ describe('Config', () => { }) it('allows settings to be observed in a specific scope', () => { - atom.config.observe('foo.bar.baz', {scope: ['.some.scope']}, observeHandler) - atom.config.observe('foo.bar.baz', {scope: ['.another.scope']}, otherHandler) + atom.config.observe( + 'foo.bar.baz', + { scope: ['.some.scope'] }, + observeHandler + ) + atom.config.observe( + 'foo.bar.baz', + { scope: ['.another.scope'] }, + otherHandler + ) - atom.config.set('foo.bar.baz', 'value 2', {scopeSelector: '.some'}) + atom.config.set('foo.bar.baz', 'value 2', { scopeSelector: '.some' }) expect(observeHandler).toHaveBeenCalledWith('value 2') expect(otherHandler).not.toHaveBeenCalledWith('value 2') }) it('calls the callback when properties with more specific selectors are removed', () => { const changeSpy = jasmine.createSpy() - atom.config.observe('foo.bar.baz', {scope: ['.source.coffee', '.string.quoted.double.coffee']}, changeSpy) + atom.config.observe( + 'foo.bar.baz', + { scope: ['.source.coffee', '.string.quoted.double.coffee'] }, + changeSpy + ) expect(changeSpy).toHaveBeenCalledWith('value 1') changeSpy.reset() @@ -618,19 +855,31 @@ describe('Config', () => { expect(changeSpy).toHaveBeenCalledWith(12) changeSpy.reset() - atom.config.set('foo.bar.baz', 22, {scopeSelector: '.source .string.quoted.double', source: 'a'}) + atom.config.set('foo.bar.baz', 22, { + scopeSelector: '.source .string.quoted.double', + source: 'a' + }) expect(changeSpy).toHaveBeenCalledWith(22) changeSpy.reset() - atom.config.set('foo.bar.baz', 42, {scopeSelector: '.source.coffee .string.quoted.double.coffee', source: 'b'}) + atom.config.set('foo.bar.baz', 42, { + scopeSelector: '.source.coffee .string.quoted.double.coffee', + source: 'b' + }) expect(changeSpy).toHaveBeenCalledWith(42) changeSpy.reset() - atom.config.unset(null, {scopeSelector: '.source.coffee .string.quoted.double.coffee', source: 'b'}) + atom.config.unset(null, { + scopeSelector: '.source.coffee .string.quoted.double.coffee', + source: 'b' + }) expect(changeSpy).toHaveBeenCalledWith(22) changeSpy.reset() - atom.config.unset(null, {scopeSelector: '.source .string.quoted.double', source: 'a'}) + atom.config.unset(null, { + scopeSelector: '.source .string.quoted.double', + source: 'a' + }) expect(changeSpy).toHaveBeenCalledWith(12) changeSpy.reset() @@ -657,7 +906,10 @@ describe('Config', () => { }) expect(changeSpy.callCount).toBe(1) - expect(changeSpy.argsForCall[0][0]).toEqual({newValue: 3, oldValue: undefined}) + expect(changeSpy.argsForCall[0][0]).toEqual({ + newValue: 3, + oldValue: undefined + }) }) it('does not emit an event if no changes occur while paused', () => { @@ -683,14 +935,19 @@ describe('Config', () => { return Promise.resolve('a result') }) - waitsForPromise(() => transactionPromise.then(result => { - promiseResult = result - })) + waitsForPromise(() => + transactionPromise.then(result => { + promiseResult = result + }) + ) runs(() => { expect(promiseResult).toBe('a result') expect(changeSpy.callCount).toBe(1) - expect(changeSpy.argsForCall[0][0]).toEqual({newValue: 3, oldValue: undefined}) + expect(changeSpy.argsForCall[0][0]).toEqual({ + newValue: 3, + oldValue: undefined + }) }) }) @@ -703,14 +960,19 @@ describe('Config', () => { return Promise.reject(new Error('an error')) }) - waitsForPromise(() => transactionPromise.catch(error => { - promiseError = error - })) + waitsForPromise(() => + transactionPromise.catch(error => { + promiseError = error + }) + ) runs(() => { expect(promiseError.message).toBe('an error') expect(changeSpy.callCount).toBe(1) - expect(changeSpy.argsForCall[0][0]).toEqual({newValue: 3, oldValue: undefined}) + expect(changeSpy.argsForCall[0][0]).toEqual({ + newValue: 3, + oldValue: undefined + }) }) }) @@ -724,14 +986,19 @@ describe('Config', () => { throw error }) - waitsForPromise(() => transactionPromise.catch(e => { - promiseError = e - })) + waitsForPromise(() => + transactionPromise.catch(e => { + promiseError = e + }) + ) runs(() => { expect(promiseError).toBe(error) expect(changeSpy.callCount).toBe(1) - expect(changeSpy.argsForCall[0][0]).toEqual({newValue: 3, oldValue: undefined}) + expect(changeSpy.argsForCall[0][0]).toEqual({ + newValue: 3, + oldValue: undefined + }) }) }) }) @@ -740,10 +1007,10 @@ describe('Config', () => { it("returns an array of all of the config's source names", () => { expect(atom.config.getSources()).toEqual([]) - atom.config.set('a.b', 1, {scopeSelector: '.x1', source: 'source-1'}) - atom.config.set('a.c', 1, {scopeSelector: '.x1', source: 'source-1'}) - atom.config.set('a.b', 2, {scopeSelector: '.x2', source: 'source-2'}) - atom.config.set('a.b', 1, {scopeSelector: '.x3', source: 'source-3'}) + atom.config.set('a.b', 1, { scopeSelector: '.x1', source: 'source-1' }) + atom.config.set('a.c', 1, { scopeSelector: '.x1', source: 'source-1' }) + atom.config.set('a.b', 2, { scopeSelector: '.x2', source: 'source-2' }) + atom.config.set('a.b', 1, { scopeSelector: '.x3', source: 'source-3' }) expect(atom.config.getSources()).toEqual([ 'source-1', @@ -758,10 +1025,10 @@ describe('Config', () => { atom.config.set('a.b.c', 1) atom.config.set('a.b.d', 2) atom.config.set('x.y.z', 3) - atom.config.setDefaults('a.b', {e: 4, f: 5}) + atom.config.setDefaults('a.b', { e: 4, f: 5 }) atom.config.save() - expect(savedSettings).toEqual([{'*': atom.config.settings}]) + expect(savedSettings).toEqual([{ '*': atom.config.settings }]) }) it('serializes properties in alphabetical order', () => { @@ -774,12 +1041,12 @@ describe('Config', () => { atom.config.save() const writtenConfig = savedSettings[0] - expect(writtenConfig).toEqual({'*': atom.config.settings}) + expect(writtenConfig).toEqual({ '*': atom.config.settings }) let expectedKeys = ['bar', 'baz', 'foo'] let foundKeys = [] for (const key in writtenConfig['*']) { - if ((expectedKeys).includes(key)) { + if (expectedKeys.includes(key)) { foundKeys.push(key) } } @@ -787,7 +1054,7 @@ describe('Config', () => { expectedKeys = ['bar', 'foo'] foundKeys = [] for (const key in writtenConfig['*']['baz']) { - if ((expectedKeys).includes(key)) { + if (expectedKeys.includes(key)) { foundKeys.push(key) } } @@ -796,17 +1063,18 @@ describe('Config', () => { describe('when scoped settings are defined', () => { it('serializes any explicitly set config settings', () => { - atom.config.set('foo.bar', 'ruby', {scopeSelector: '.source.ruby'}) - atom.config.set('foo.omg', 'wow', {scopeSelector: '.source.ruby'}) - atom.config.set('foo.bar', 'coffee', {scopeSelector: '.source.coffee'}) + atom.config.set('foo.bar', 'ruby', { scopeSelector: '.source.ruby' }) + atom.config.set('foo.omg', 'wow', { scopeSelector: '.source.ruby' }) + atom.config.set('foo.bar', 'coffee', { + scopeSelector: '.source.coffee' + }) savedSettings.length = 0 atom.config.save() const writtenConfig = savedSettings[0] expect(writtenConfig).toEqualJson({ - '*': - atom.config.settings, + '*': atom.config.settings, '.ruby.source': { foo: { bar: 'ruby', @@ -856,7 +1124,9 @@ describe('Config', () => { } }) expect(atom.config.get('foo.bar')).toBe('baz') - expect(atom.config.get('foo.bar', {scope: ['.source.ruby']})).toBe('more-specific') + expect(atom.config.get('foo.bar', { scope: ['.source.ruby'] })).toBe( + 'more-specific' + ) }) }) @@ -878,20 +1148,22 @@ describe('Config', () => { }) expect(atom.config.get('foo.int')).toBe(12) expect(atom.config.get('foo.bar')).toBe('omg') - expect(atom.config.get('foo.int', {scope: ['.source.ruby']})).toBe(12) - expect(atom.config.get('foo.bar', {scope: ['.source.ruby']})).toBe('scoped') + expect(atom.config.get('foo.int', { scope: ['.source.ruby'] })).toBe(12) + expect(atom.config.get('foo.bar', { scope: ['.source.ruby'] })).toBe( + 'scoped' + ) }) }) it('updates the config data based on the file contents', () => { - atom.config.resetUserSettings({foo: {bar: 'baz'}}) + atom.config.resetUserSettings({ foo: { bar: 'baz' } }) expect(atom.config.get('foo.bar')).toBe('baz') }) it('notifies observers for updated keypaths on load', () => { const observeHandler = jasmine.createSpy('observeHandler') atom.config.observe('foo.bar', observeHandler) - atom.config.resetUserSettings({foo: {bar: 'baz'}}) + atom.config.resetUserSettings({ foo: { bar: 'baz' } }) expect(observeHandler).toHaveBeenCalledWith('baz') }) @@ -912,14 +1184,14 @@ describe('Config', () => { it('does not fire a change event for paths that did not change', () => { atom.config.resetUserSettings({ - foo: {bar: 'baz', int: 3} + foo: { bar: 'baz', int: 3 } }) const noChangeSpy = jasmine.createSpy('unchanged') - atom.config.onDidChange('foo.bar', (noChangeSpy)) + atom.config.onDidChange('foo.bar', noChangeSpy) atom.config.resetUserSettings({ - foo: {bar: 'baz', int: 4} + foo: { bar: 'baz', int: 4 } }) expect(noChangeSpy).not.toHaveBeenCalled() @@ -936,14 +1208,14 @@ describe('Config', () => { }) atom.config.resetUserSettings({ - foo: {bar: ['baz', 'quux'], int: 2} + foo: { bar: ['baz', 'quux'], int: 2 } }) const noChangeSpy = jasmine.createSpy('unchanged') - atom.config.onDidChange('foo.bar', (noChangeSpy)) + atom.config.onDidChange('foo.bar', noChangeSpy) atom.config.resetUserSettings({ - foo: {bar: ['baz', 'quux'], int: 2} + foo: { bar: ['baz', 'quux'], int: 2 } }) expect(noChangeSpy).not.toHaveBeenCalled() @@ -953,18 +1225,18 @@ describe('Config', () => { describe('when a setting with a default is removed', () => { it('resets the setting back to the default', () => { atom.config.resetUserSettings({ - foo: {bar: ['baz', 'quux'], int: 2} + foo: { bar: ['baz', 'quux'], int: 2 } }) const events = [] atom.config.onDidChange('foo.int', event => events.push(event)) atom.config.resetUserSettings({ - foo: {bar: ['baz', 'quux']} + foo: { bar: ['baz', 'quux'] } }) expect(events.length).toBe(1) - expect(events[0]).toEqual({oldValue: 2, newValue: 12}) + expect(events[0]).toEqual({ oldValue: 2, newValue: 12 }) }) }) }) @@ -978,7 +1250,9 @@ describe('Config', () => { expect(atom.config.pushAtKeyPath('foo.bar.baz', 'b')).toBe(2) expect(atom.config.get('foo.bar.baz')).toEqual(['a', 'b']) - expect(observeHandler).toHaveBeenCalledWith(atom.config.get('foo.bar.baz')) + expect(observeHandler).toHaveBeenCalledWith( + atom.config.get('foo.bar.baz') + ) }) }) @@ -991,7 +1265,9 @@ describe('Config', () => { expect(atom.config.unshiftAtKeyPath('foo.bar.baz', 'a')).toBe(2) expect(atom.config.get('foo.bar.baz')).toEqual(['a', 'b']) - expect(observeHandler).toHaveBeenCalledWith(atom.config.get('foo.bar.baz')) + expect(observeHandler).toHaveBeenCalledWith( + atom.config.get('foo.bar.baz') + ) }) }) @@ -1002,21 +1278,26 @@ describe('Config', () => { atom.config.observe('foo.bar.baz', observeHandler) observeHandler.reset() - expect(atom.config.removeAtKeyPath('foo.bar.baz', 'b')).toEqual(['a', 'c']) + expect(atom.config.removeAtKeyPath('foo.bar.baz', 'b')).toEqual([ + 'a', + 'c' + ]) expect(atom.config.get('foo.bar.baz')).toEqual(['a', 'c']) - expect(observeHandler).toHaveBeenCalledWith(atom.config.get('foo.bar.baz')) + expect(observeHandler).toHaveBeenCalledWith( + atom.config.get('foo.bar.baz') + ) }) }) describe('.setDefaults(keyPath, defaults)', () => { it('assigns any previously-unassigned keys to the object at the key path', () => { - atom.config.set('foo.bar.baz', {a: 1}) - atom.config.setDefaults('foo.bar.baz', {a: 2, b: 3, c: 4}) + atom.config.set('foo.bar.baz', { a: 1 }) + atom.config.setDefaults('foo.bar.baz', { a: 2, b: 3, c: 4 }) expect(atom.config.get('foo.bar.baz.a')).toBe(1) expect(atom.config.get('foo.bar.baz.b')).toBe(3) expect(atom.config.get('foo.bar.baz.c')).toBe(4) - atom.config.setDefaults('foo.quux', {x: 0, y: 1}) + atom.config.setDefaults('foo.quux', { x: 0, y: 1 }) expect(atom.config.get('foo.quux.x')).toBe(0) expect(atom.config.get('foo.quux.y')).toBe(1) }) @@ -1025,7 +1306,7 @@ describe('Config', () => { const updatedCallback = jasmine.createSpy('updated') atom.config.onDidChange('foo.bar.baz.a', updatedCallback) expect(updatedCallback.callCount).toBe(0) - atom.config.setDefaults('foo.bar.baz', {a: 2}) + atom.config.setDefaults('foo.bar.baz', { a: 2 }) expect(updatedCallback.callCount).toBe(1) }) }) @@ -1165,7 +1446,7 @@ describe('Config', () => { default: 12 }) - expect(atom.config.getSchema('foo.baz')).toEqual({type: 'any'}) + expect(atom.config.getSchema('foo.baz')).toEqual({ type: 'any' }) expect(atom.config.getSchema('foo.bar.anInt.baz')).toBe(null) }) @@ -1182,8 +1463,12 @@ describe('Config', () => { atom.config.setSchema('foo.bar.str', schema) expect(atom.config.get('foo.bar.str')).toBe('ok') - expect(atom.config.get('foo.bar.str', {scope: ['.source.js']})).toBe('omg') - expect(atom.config.get('foo.bar.str', {scope: ['.source.coffee']})).toBe('ok') + expect(atom.config.get('foo.bar.str', { scope: ['.source.js'] })).toBe( + 'omg' + ) + expect( + atom.config.get('foo.bar.str', { scope: ['.source.coffee'] }) + ).toBe('ok') }) describe('when a schema is added after config values have been set', () => { @@ -1206,47 +1491,93 @@ describe('Config', () => { it('respects the new schema when values are set', () => { expect(atom.config.set('foo.bar.str', 'global')).toBe(true) - expect(atom.config.set('foo.bar.str', 'scoped', {scopeSelector: '.source.js'})).toBe(true) + expect( + atom.config.set('foo.bar.str', 'scoped', { + scopeSelector: '.source.js' + }) + ).toBe(true) expect(atom.config.get('foo.bar.str')).toBe('global') - expect(atom.config.get('foo.bar.str', {scope: ['.source.js']})).toBe('scoped') + expect(atom.config.get('foo.bar.str', { scope: ['.source.js'] })).toBe( + 'scoped' + ) expect(atom.config.set('foo.bar.noschema', 'nsGlobal')).toBe(true) - expect(atom.config.set('foo.bar.noschema', 'nsScoped', {scopeSelector: '.source.js'})).toBe(true) + expect( + atom.config.set('foo.bar.noschema', 'nsScoped', { + scopeSelector: '.source.js' + }) + ).toBe(true) expect(atom.config.get('foo.bar.noschema')).toBe('nsGlobal') - expect(atom.config.get('foo.bar.noschema', {scope: ['.source.js']})).toBe('nsScoped') + expect( + atom.config.get('foo.bar.noschema', { scope: ['.source.js'] }) + ).toBe('nsScoped') expect(atom.config.set('foo.bar.int', 'nope')).toBe(true) - expect(atom.config.set('foo.bar.int', 'notanint', {scopeSelector: '.source.js'})).toBe(true) - expect(atom.config.set('foo.bar.int', 23, {scopeSelector: '.source.coffee'})).toBe(true) + expect( + atom.config.set('foo.bar.int', 'notanint', { + scopeSelector: '.source.js' + }) + ).toBe(true) + expect( + atom.config.set('foo.bar.int', 23, { + scopeSelector: '.source.coffee' + }) + ).toBe(true) expect(atom.config.get('foo.bar.int')).toBe('nope') - expect(atom.config.get('foo.bar.int', {scope: ['.source.js']})).toBe('notanint') - expect(atom.config.get('foo.bar.int', {scope: ['.source.coffee']})).toBe(23) + expect(atom.config.get('foo.bar.int', { scope: ['.source.js'] })).toBe( + 'notanint' + ) + expect( + atom.config.get('foo.bar.int', { scope: ['.source.coffee'] }) + ).toBe(23) atom.config.setSchema('foo.bar', schema) expect(atom.config.get('foo.bar.str')).toBe('global') - expect(atom.config.get('foo.bar.str', {scope: ['.source.js']})).toBe('scoped') + expect(atom.config.get('foo.bar.str', { scope: ['.source.js'] })).toBe( + 'scoped' + ) expect(atom.config.get('foo.bar.noschema')).toBe('nsGlobal') - expect(atom.config.get('foo.bar.noschema', {scope: ['.source.js']})).toBe('nsScoped') + expect( + atom.config.get('foo.bar.noschema', { scope: ['.source.js'] }) + ).toBe('nsScoped') expect(atom.config.get('foo.bar.int')).toBe(2) - expect(atom.config.get('foo.bar.int', {scope: ['.source.js']})).toBe(2) - expect(atom.config.get('foo.bar.int', {scope: ['.source.coffee']})).toBe(23) + expect(atom.config.get('foo.bar.int', { scope: ['.source.js'] })).toBe( + 2 + ) + expect( + atom.config.get('foo.bar.int', { scope: ['.source.coffee'] }) + ).toBe(23) }) it('sets all values that adhere to the schema', () => { expect(atom.config.set('foo.bar.int', 10)).toBe(true) - expect(atom.config.set('foo.bar.int', 15, {scopeSelector: '.source.js'})).toBe(true) - expect(atom.config.set('foo.bar.int', 23, {scopeSelector: '.source.coffee'})).toBe(true) + expect( + atom.config.set('foo.bar.int', 15, { scopeSelector: '.source.js' }) + ).toBe(true) + expect( + atom.config.set('foo.bar.int', 23, { + scopeSelector: '.source.coffee' + }) + ).toBe(true) expect(atom.config.get('foo.bar.int')).toBe(10) - expect(atom.config.get('foo.bar.int', {scope: ['.source.js']})).toBe(15) - expect(atom.config.get('foo.bar.int', {scope: ['.source.coffee']})).toBe(23) + expect(atom.config.get('foo.bar.int', { scope: ['.source.js'] })).toBe( + 15 + ) + expect( + atom.config.get('foo.bar.int', { scope: ['.source.coffee'] }) + ).toBe(23) atom.config.setSchema('foo.bar', schema) expect(atom.config.get('foo.bar.int')).toBe(10) - expect(atom.config.get('foo.bar.int', {scope: ['.source.js']})).toBe(15) - expect(atom.config.get('foo.bar.int', {scope: ['.source.coffee']})).toBe(23) + expect(atom.config.get('foo.bar.int', { scope: ['.source.js'] })).toBe( + 15 + ) + expect( + atom.config.get('foo.bar.int', { scope: ['.source.coffee'] }) + ).toBe(23) }) }) @@ -1449,7 +1780,7 @@ describe('Config', () => { expect(atom.config.set('foo.bar.aString', [])).toBe(false) expect(atom.config.get('foo.bar.aString')).toBe('ok') - expect(atom.config.set('foo.bar.aString', {nope: 'nope'})).toBe(false) + expect(atom.config.set('foo.bar.aString', { nope: 'nope' })).toBe(false) expect(atom.config.get('foo.bar.aString')).toBe('ok') }) @@ -1468,8 +1799,7 @@ describe('Config', () => { atom.config.setSchema('foo.bar.aString', schema) atom.config.set('foo.bar.aString', 'abcdefg') expect(atom.config.get('foo.bar.aString')).toBe('abc') - }) - ) + })) }) describe('when the value has an "object" type', () => { @@ -1501,8 +1831,7 @@ describe('Config', () => { nestedObject: { nestedBool: 'true' } - } - ) + }) expect(atom.config.get('foo.bar')).toEqual({ anInt: 23, nestedObject: { @@ -1512,13 +1841,14 @@ describe('Config', () => { }) it('will set only the values that adhere to the schema', () => { - expect(atom.config.set('foo.bar', { - anInt: 'nope', - nestedObject: { - nestedBool: true - } - } - )).toBe(true) + expect( + atom.config.set('foo.bar', { + anInt: 'nope', + nestedObject: { + nestedBool: true + } + }) + ).toBe(true) expect(atom.config.get('foo.bar.anInt')).toEqual(12) expect(atom.config.get('foo.bar.nestedObject.nestedBool')).toEqual(true) }) @@ -1534,17 +1864,19 @@ describe('Config', () => { } }, additionalProperties: false - } - ) + }) - expect(atom.config.set('foo.bar', {anInt: 5, somethingElse: 'ok'})).toBe(true) + expect( + atom.config.set('foo.bar', { anInt: 5, somethingElse: 'ok' }) + ).toBe(true) expect(atom.config.get('foo.bar.anInt')).toBe(5) expect(atom.config.get('foo.bar.somethingElse')).toBeUndefined() - expect(atom.config.set('foo.bar.somethingElse', {anInt: 5})).toBe(false) + expect(atom.config.set('foo.bar.somethingElse', { anInt: 5 })).toBe( + false + ) expect(atom.config.get('foo.bar.somethingElse')).toBeUndefined() - }) - ) + })) describe('when the value has an additionalProperties schema', () => it('validates properties of the object against that schema', () => { @@ -1559,21 +1891,23 @@ describe('Config', () => { additionalProperties: { type: 'string' } - } - ) + }) - expect(atom.config.set('foo.bar', {anInt: 5, somethingElse: 'ok'})).toBe(true) + expect( + atom.config.set('foo.bar', { anInt: 5, somethingElse: 'ok' }) + ).toBe(true) expect(atom.config.get('foo.bar.anInt')).toBe(5) expect(atom.config.get('foo.bar.somethingElse')).toBe('ok') expect(atom.config.set('foo.bar.somethingElse', 7)).toBe(false) expect(atom.config.get('foo.bar.somethingElse')).toBe('ok') - expect(atom.config.set('foo.bar', {anInt: 6, somethingElse: 7})).toBe(true) + expect( + atom.config.set('foo.bar', { anInt: 6, somethingElse: 7 }) + ).toBe(true) expect(atom.config.get('foo.bar.anInt')).toBe(6) expect(atom.config.get('foo.bar.somethingElse')).toBe(undefined) - }) - ) + })) }) describe('when the value has an "array" type', () => { @@ -1647,46 +1981,131 @@ describe('Config', () => { it('coerces various types to a color object', () => { atom.config.set('foo.bar.aColor', 'red') - expect(atom.config.get('foo.bar.aColor')).toEqual({red: 255, green: 0, blue: 0, alpha: 1}) + expect(atom.config.get('foo.bar.aColor')).toEqual({ + red: 255, + green: 0, + blue: 0, + alpha: 1 + }) atom.config.set('foo.bar.aColor', '#020') - expect(atom.config.get('foo.bar.aColor')).toEqual({red: 0, green: 34, blue: 0, alpha: 1}) + expect(atom.config.get('foo.bar.aColor')).toEqual({ + red: 0, + green: 34, + blue: 0, + alpha: 1 + }) atom.config.set('foo.bar.aColor', '#abcdef') - expect(atom.config.get('foo.bar.aColor')).toEqual({red: 171, green: 205, blue: 239, alpha: 1}) + expect(atom.config.get('foo.bar.aColor')).toEqual({ + red: 171, + green: 205, + blue: 239, + alpha: 1 + }) atom.config.set('foo.bar.aColor', 'rgb(1,2,3)') - expect(atom.config.get('foo.bar.aColor')).toEqual({red: 1, green: 2, blue: 3, alpha: 1}) + expect(atom.config.get('foo.bar.aColor')).toEqual({ + red: 1, + green: 2, + blue: 3, + alpha: 1 + }) atom.config.set('foo.bar.aColor', 'rgba(4,5,6,.7)') - expect(atom.config.get('foo.bar.aColor')).toEqual({red: 4, green: 5, blue: 6, alpha: 0.7}) + expect(atom.config.get('foo.bar.aColor')).toEqual({ + red: 4, + green: 5, + blue: 6, + alpha: 0.7 + }) atom.config.set('foo.bar.aColor', 'hsl(120,100%,50%)') - expect(atom.config.get('foo.bar.aColor')).toEqual({red: 0, green: 255, blue: 0, alpha: 1}) + expect(atom.config.get('foo.bar.aColor')).toEqual({ + red: 0, + green: 255, + blue: 0, + alpha: 1 + }) atom.config.set('foo.bar.aColor', 'hsla(120,100%,50%,0.3)') - expect(atom.config.get('foo.bar.aColor')).toEqual({red: 0, green: 255, blue: 0, alpha: 0.3}) - atom.config.set('foo.bar.aColor', {red: 100, green: 255, blue: 2, alpha: 0.5}) - expect(atom.config.get('foo.bar.aColor')).toEqual({red: 100, green: 255, blue: 2, alpha: 0.5}) - atom.config.set('foo.bar.aColor', {red: 255}) - expect(atom.config.get('foo.bar.aColor')).toEqual({red: 255, green: 0, blue: 0, alpha: 1}) - atom.config.set('foo.bar.aColor', {red: 1000}) - expect(atom.config.get('foo.bar.aColor')).toEqual({red: 255, green: 0, blue: 0, alpha: 1}) - atom.config.set('foo.bar.aColor', {red: 'dark'}) - expect(atom.config.get('foo.bar.aColor')).toEqual({red: 0, green: 0, blue: 0, alpha: 1}) + expect(atom.config.get('foo.bar.aColor')).toEqual({ + red: 0, + green: 255, + blue: 0, + alpha: 0.3 + }) + atom.config.set('foo.bar.aColor', { + red: 100, + green: 255, + blue: 2, + alpha: 0.5 + }) + expect(atom.config.get('foo.bar.aColor')).toEqual({ + red: 100, + green: 255, + blue: 2, + alpha: 0.5 + }) + atom.config.set('foo.bar.aColor', { red: 255 }) + expect(atom.config.get('foo.bar.aColor')).toEqual({ + red: 255, + green: 0, + blue: 0, + alpha: 1 + }) + atom.config.set('foo.bar.aColor', { red: 1000 }) + expect(atom.config.get('foo.bar.aColor')).toEqual({ + red: 255, + green: 0, + blue: 0, + alpha: 1 + }) + atom.config.set('foo.bar.aColor', { red: 'dark' }) + expect(atom.config.get('foo.bar.aColor')).toEqual({ + red: 0, + green: 0, + blue: 0, + alpha: 1 + }) }) it('reverts back to the default value when undefined is passed to set', () => { atom.config.set('foo.bar.aColor', undefined) - expect(atom.config.get('foo.bar.aColor')).toEqual({red: 255, green: 255, blue: 255, alpha: 1}) + expect(atom.config.get('foo.bar.aColor')).toEqual({ + red: 255, + green: 255, + blue: 255, + alpha: 1 + }) }) it('will not set non-colors', () => { atom.config.set('foo.bar.aColor', null) - expect(atom.config.get('foo.bar.aColor')).toEqual({red: 255, green: 255, blue: 255, alpha: 1}) + expect(atom.config.get('foo.bar.aColor')).toEqual({ + red: 255, + green: 255, + blue: 255, + alpha: 1 + }) atom.config.set('foo.bar.aColor', 'nope') - expect(atom.config.get('foo.bar.aColor')).toEqual({red: 255, green: 255, blue: 255, alpha: 1}) + expect(atom.config.get('foo.bar.aColor')).toEqual({ + red: 255, + green: 255, + blue: 255, + alpha: 1 + }) atom.config.set('foo.bar.aColor', 30) - expect(atom.config.get('foo.bar.aColor')).toEqual({red: 255, green: 255, blue: 255, alpha: 1}) + expect(atom.config.get('foo.bar.aColor')).toEqual({ + red: 255, + green: 255, + blue: 255, + alpha: 1 + }) atom.config.set('foo.bar.aColor', false) - expect(atom.config.get('foo.bar.aColor')).toEqual({red: 255, green: 255, blue: 255, alpha: 1}) + expect(atom.config.get('foo.bar.aColor')).toEqual({ + red: 255, + green: 255, + blue: 255, + alpha: 1 + }) }) it('returns a clone of the Color when returned in a parent object', () => { @@ -1726,9 +2145,9 @@ describe('Config', () => { type: 'string', default: 'one', enum: [ - {value: 'one', description: 'One'}, + { value: 'one', description: 'One' }, 'two', - {value: 'three', description: 'Three'} + { value: 'three', description: 'Three' } ] } } @@ -1821,54 +2240,78 @@ describe('Config', () => { const dummyPath = '/Users/dummy/path.json' describe('project settings', () => { it('returns a deep clone of the property value', () => { - atom.config.resetProjectSettings({'*': {'value': {array: [1, {b: 2}, 3]}}}, dummyPath) + atom.config.resetProjectSettings( + { '*': { value: { array: [1, { b: 2 }, 3] } } }, + dummyPath + ) const retrievedValue = atom.config.get('value') retrievedValue.array[0] = 4 retrievedValue.array[1].b = 2.1 - expect(atom.config.get('value')).toEqual({array: [1, {b: 2}, 3]}) + expect(atom.config.get('value')).toEqual({ array: [1, { b: 2 }, 3] }) }) it('properly gets project settings', () => { - atom.config.resetProjectSettings({'*': {'foo': 'wei'}}, dummyPath) + atom.config.resetProjectSettings({ '*': { foo: 'wei' } }, dummyPath) expect(atom.config.get('foo')).toBe('wei') - atom.config.resetProjectSettings({'*': {'foo': {'bar': 'baz'}}}, dummyPath) + atom.config.resetProjectSettings( + { '*': { foo: { bar: 'baz' } } }, + dummyPath + ) expect(atom.config.get('foo.bar')).toBe('baz') }) it('gets project settings with higher priority than regular settings', () => { atom.config.set('foo', 'bar') - atom.config.resetProjectSettings({'*': {'foo': 'baz'}}, dummyPath) + atom.config.resetProjectSettings({ '*': { foo: 'baz' } }, dummyPath) expect(atom.config.get('foo')).toBe('baz') }) it('correctly gets nested and scoped properties for project settings', () => { expect(atom.config.set('foo.bar.str', 'global')).toBe(true) - expect(atom.config.set('foo.bar.str', 'scoped', {scopeSelector: '.source.js'})).toBe(true) + expect( + atom.config.set('foo.bar.str', 'scoped', { + scopeSelector: '.source.js' + }) + ).toBe(true) expect(atom.config.get('foo.bar.str')).toBe('global') - expect(atom.config.get('foo.bar.str', {scope: ['.source.js']})).toBe('scoped') + expect( + atom.config.get('foo.bar.str', { scope: ['.source.js'] }) + ).toBe('scoped') }) it('returns a deep clone of the property value', () => { - atom.config.set('value', {array: [1, {b: 2}, 3]}) + atom.config.set('value', { array: [1, { b: 2 }, 3] }) const retrievedValue = atom.config.get('value') retrievedValue.array[0] = 4 retrievedValue.array[1].b = 2.1 - expect(atom.config.get('value')).toEqual({array: [1, {b: 2}, 3]}) + expect(atom.config.get('value')).toEqual({ array: [1, { b: 2 }, 3] }) }) it('gets scoped values correctly', () => { - atom.config.set('foo', 'bam', {scope: ['second']}) - expect(atom.config.get('foo', {'scopeSelector': 'second'})).toBe('bam') - atom.config.resetProjectSettings({'*': {'foo': 'baz'}, 'second': {'foo': 'bar'}}, dummyPath) - expect(atom.config.get('foo', {'scopeSelector': 'second'})).toBe('baz') + atom.config.set('foo', 'bam', { scope: ['second'] }) + expect(atom.config.get('foo', { scopeSelector: 'second' })).toBe( + 'bam' + ) + atom.config.resetProjectSettings( + { '*': { foo: 'baz' }, second: { foo: 'bar' } }, + dummyPath + ) + expect(atom.config.get('foo', { scopeSelector: 'second' })).toBe( + 'baz' + ) atom.config.clearProjectSettings() - expect(atom.config.get('foo', {'scopeSelector': 'second'})).toBe('bam') + expect(atom.config.get('foo', { scopeSelector: 'second' })).toBe( + 'bam' + ) }) it('clears project settings correctly', () => { atom.config.set('foo', 'bar') expect(atom.config.get('foo')).toBe('bar') - atom.config.resetProjectSettings({'*': {'foo': 'baz'}, 'second': {'foo': 'bar'}}, dummyPath) + atom.config.resetProjectSettings( + { '*': { foo: 'baz' }, second: { foo: 'bar' } }, + dummyPath + ) expect(atom.config.get('foo')).toBe('baz') expect(atom.config.getSources().length).toBe(1) atom.config.clearProjectSettings() @@ -1881,12 +2324,14 @@ describe('Config', () => { describe('config.getAll', () => { const dummyPath = '/Users/dummy/path.json' it('gets settings in the same way .get would return them', () => { - atom.config.resetProjectSettings({'*': {'a': 'b'}}, dummyPath) + atom.config.resetProjectSettings({ '*': { a: 'b' } }, dummyPath) atom.config.set('a', 'f') - expect(atom.config.getAll('a')).toEqual([{ - scopeSelector: '*', - value: 'b' - }]) + expect(atom.config.getAll('a')).toEqual([ + { + scopeSelector: '*', + value: 'b' + } + ]) }) }) }) diff --git a/spec/dock-spec.js b/spec/dock-spec.js index 4713347a8..6b97b6aa8 100644 --- a/spec/dock-spec.js +++ b/spec/dock-spec.js @@ -2,7 +2,14 @@ const Grim = require('grim') -import {it, fit, ffit, fffit, beforeEach, afterEach} from './async-spec-helpers' +import { + it, + fit, + ffit, + fffit, + beforeEach, + afterEach +} from './async-spec-helpers' import etch from 'etch' const getNextUpdatePromise = () => etch.getScheduler().nextUpdatePromise @@ -16,7 +23,12 @@ describe('Dock', () => { dock.onDidChangeVisible(didChangeVisibleSpy) expect(dock.isVisible()).toBe(false) - expect(document.activeElement).toBe(atom.workspace.getCenter().getActivePane().getElement()) + expect(document.activeElement).toBe( + atom.workspace + .getCenter() + .getActivePane() + .getElement() + ) dock.activate() expect(dock.isVisible()).toBe(true) expect(document.activeElement).toBe(dock.getActivePane().getElement()) @@ -36,7 +48,12 @@ describe('Dock', () => { expect(didChangeVisibleSpy.mostRecentCall.args[0]).toBe(true) dock.hide() - expect(document.activeElement).toBe(atom.workspace.getCenter().getActivePane().getElement()) + expect(document.activeElement).toBe( + atom.workspace + .getCenter() + .getActivePane() + .getElement() + ) expect(didChangeVisibleSpy.mostRecentCall.args[0]).toBe(false) dock.activate() @@ -44,13 +61,18 @@ describe('Dock', () => { expect(didChangeVisibleSpy.mostRecentCall.args[0]).toBe(true) dock.toggle() - expect(document.activeElement).toBe(atom.workspace.getCenter().getActivePane().getElement()) + expect(document.activeElement).toBe( + atom.workspace + .getCenter() + .getActivePane() + .getElement() + ) expect(didChangeVisibleSpy.mostRecentCall.args[0]).toBe(false) // Don't change focus if the dock was not focused in the first place const modalElement = document.createElement('div') modalElement.setAttribute('tabindex', -1) - atom.workspace.addModalPanel({item: modalElement}) + atom.workspace.addModalPanel({ item: modalElement }) modalElement.focus() expect(document.activeElement).toBe(modalElement) @@ -68,13 +90,18 @@ describe('Dock', () => { it('opens the dock', async () => { const item = { element: document.createElement('div'), - getDefaultLocation() { return 'left' } + getDefaultLocation () { + return 'left' + } } - await atom.workspace.open(item, {activatePane: false}) + await atom.workspace.open(item, { activatePane: false }) expect(atom.workspace.getLeftDock().isVisible()).toBe(false) - atom.workspace.getLeftDock().getPanes()[0].activate() + atom.workspace + .getLeftDock() + .getPanes()[0] + .activate() expect(atom.workspace.getLeftDock().isVisible()).toBe(true) }) }) @@ -145,47 +172,63 @@ describe('Dock', () => { describe('when the dock resize handle is double-clicked', () => { describe('when the dock is open', () => { - it('resizes a vertically-oriented dock to the current item\'s preferred width', async () => { + it("resizes a vertically-oriented dock to the current item's preferred width", async () => { jasmine.attachToDOM(atom.workspace.getElement()) const item = { element: document.createElement('div'), - getDefaultLocation() { return 'left' }, - getPreferredWidth() { return 142 }, - getPreferredHeight() { return 122 } + getDefaultLocation () { + return 'left' + }, + getPreferredWidth () { + return 142 + }, + getPreferredHeight () { + return 122 + } } await atom.workspace.open(item) const dock = atom.workspace.getLeftDock() const dockElement = dock.getElement() - dock.setState({size: 300}) + dock.setState({ size: 300 }) await getNextUpdatePromise() expect(dockElement.offsetWidth).toBe(300) - dockElement.querySelector('.atom-dock-resize-handle').dispatchEvent(new MouseEvent('mousedown', {detail: 2})) + dockElement + .querySelector('.atom-dock-resize-handle') + .dispatchEvent(new MouseEvent('mousedown', { detail: 2 })) await getNextUpdatePromise() expect(dockElement.offsetWidth).toBe(item.getPreferredWidth()) }) - it('resizes a horizontally-oriented dock to the current item\'s preferred width', async () => { + it("resizes a horizontally-oriented dock to the current item's preferred width", async () => { jasmine.attachToDOM(atom.workspace.getElement()) const item = { element: document.createElement('div'), - getDefaultLocation() { return 'bottom' }, - getPreferredWidth() { return 122 }, - getPreferredHeight() { return 142 } + getDefaultLocation () { + return 'bottom' + }, + getPreferredWidth () { + return 122 + }, + getPreferredHeight () { + return 142 + } } await atom.workspace.open(item) const dock = atom.workspace.getBottomDock() const dockElement = dock.getElement() - dock.setState({size: 300}) + dock.setState({ size: 300 }) await getNextUpdatePromise() expect(dockElement.offsetHeight).toBe(300) - dockElement.querySelector('.atom-dock-resize-handle').dispatchEvent(new MouseEvent('mousedown', {detail: 2})) + dockElement + .querySelector('.atom-dock-resize-handle') + .dispatchEvent(new MouseEvent('mousedown', { detail: 2 })) await getNextUpdatePromise() expect(dockElement.offsetHeight).toBe(item.getPreferredHeight()) @@ -198,19 +241,31 @@ describe('Dock', () => { const item = { element: document.createElement('div'), - getDefaultLocation() { return 'bottom' }, - getPreferredWidth() { return 122 }, - getPreferredHeight() { return 142 } + getDefaultLocation () { + return 'bottom' + }, + getPreferredWidth () { + return 122 + }, + getPreferredHeight () { + return 142 + } } - await atom.workspace.open(item, {activatePane: false}) + await atom.workspace.open(item, { activatePane: false }) const dockElement = atom.workspace.getBottomDock().getElement() - dockElement.querySelector('.atom-dock-resize-handle').dispatchEvent(new MouseEvent('mousedown', {detail: 2})) + dockElement + .querySelector('.atom-dock-resize-handle') + .dispatchEvent(new MouseEvent('mousedown', { detail: 2 })) expect(dockElement.offsetHeight).toBe(0) - expect(dockElement.querySelector('.atom-dock-inner').offsetHeight).toBe(0) + expect(dockElement.querySelector('.atom-dock-inner').offsetHeight).toBe( + 0 + ) // The content should be masked away. - expect(dockElement.querySelector('.atom-dock-mask').offsetHeight).toBe(0) + expect(dockElement.querySelector('.atom-dock-mask').offsetHeight).toBe( + 0 + ) }) }) }) @@ -222,8 +277,12 @@ describe('Dock', () => { const createItem = preferredWidth => ({ element: document.createElement('div'), - getDefaultLocation() { return 'left' }, - getPreferredWidth() { return preferredWidth } + getDefaultLocation () { + return 'left' + }, + getPreferredWidth () { + return preferredWidth + } }) const dock = atom.workspace.getLeftDock() @@ -257,7 +316,9 @@ describe('Dock', () => { const item = { element: document.createElement('div'), - getDefaultLocation() { return 'left' } + getDefaultLocation () { + return 'left' + } } const dock = atom.workspace.getLeftDock() expect(dock.getPaneItems()).toHaveLength(0) @@ -275,9 +336,13 @@ describe('Dock', () => { const item = { element: document.createElement('div'), - getDefaultLocation() { return 'left' }, - getPreferredWidth() { return 122 }, - serialize: () => ({deserializer: 'DockTestItem'}) + getDefaultLocation () { + return 'left' + }, + getPreferredWidth () { + return 122 + }, + serialize: () => ({ deserializer: 'DockTestItem' }) } const itemDeserializer = atom.deserializers.add({ name: 'DockTestItem', @@ -287,10 +352,10 @@ describe('Dock', () => { const dockElement = dock.getElement() await atom.workspace.open(item) - dock.setState({size: 150}) + dock.setState({ size: 150 }) expect(dockElement.offsetWidth).toBe(150) const serialized = dock.serialize() - dock.setState({size: 122}) + dock.setState({ size: 122 }) expect(dockElement.offsetWidth).toBe(122) dock.destroyActivePane() dock.deserialize(serialized, atom.deserializers) @@ -302,8 +367,12 @@ describe('Dock', () => { const item = { element: document.createElement('div'), - getDefaultLocation() { return 'left' }, - getPreferredWidth() { return 122 } + getDefaultLocation () { + return 'left' + }, + getPreferredWidth () { + return 122 + } } const dock = atom.workspace.getLeftDock() @@ -324,16 +393,22 @@ describe('Dock', () => { element.setAttribute('is', 'tabs-tab') element.item = { element, - getDefaultLocation() { return 'left' }, - getPreferredWidth() { return 144 } + getDefaultLocation () { + return 'left' + }, + getPreferredWidth () { + return 144 + } } const dragEvent = new DragEvent('dragstart') - Object.defineProperty(dragEvent, 'target', {value: element}) + Object.defineProperty(dragEvent, 'target', { value: element }) atom.workspace.getElement().handleDragStart(dragEvent) await getNextUpdatePromise() - expect(atom.workspace.getLeftDock().refs.wrapperElement.offsetWidth).toBe(144) + expect(atom.workspace.getLeftDock().refs.wrapperElement.offsetWidth).toBe( + 144 + ) }) it('does nothing when text nodes are dragged', () => { @@ -342,9 +417,11 @@ describe('Dock', () => { const textNode = document.createTextNode('hello') const dragEvent = new DragEvent('dragstart') - Object.defineProperty(dragEvent, 'target', {value: textNode}) + Object.defineProperty(dragEvent, 'target', { value: textNode }) - expect(() => atom.workspace.getElement().handleDragStart(dragEvent)).not.toThrow() + expect(() => + atom.workspace.getElement().handleDragStart(dragEvent) + ).not.toThrow() }) }) diff --git a/spec/git-repository-provider-spec.js b/spec/git-repository-provider-spec.js index 2e679e755..d70d7db3f 100644 --- a/spec/git-repository-provider-spec.js +++ b/spec/git-repository-provider-spec.js @@ -1,16 +1,20 @@ const path = require('path') const fs = require('fs-plus') const temp = require('temp').track() -const {Directory} = require('pathwatcher') +const { Directory } = require('pathwatcher') const GitRepository = require('../src/git-repository') const GitRepositoryProvider = require('../src/git-repository-provider') -const {it, fit, ffit, fffit, beforeEach} = require('./async-spec-helpers') +const { it, fit, ffit, fffit, beforeEach } = require('./async-spec-helpers') describe('GitRepositoryProvider', () => { let provider beforeEach(() => { - provider = new GitRepositoryProvider(atom.project, atom.config, atom.confirm) + provider = new GitRepositoryProvider( + atom.project, + atom.config, + atom.confirm + ) }) afterEach(() => { @@ -24,7 +28,9 @@ describe('GitRepositoryProvider', () => { describe('.repositoryForDirectory(directory)', () => { describe('when specified a Directory with a Git repository', () => { it('resolves with a GitRepository', async () => { - const directory = new Directory(path.join(__dirname, 'fixtures', 'git', 'master.git')) + const directory = new Directory( + path.join(__dirname, 'fixtures', 'git', 'master.git') + ) const result = await provider.repositoryForDirectory(directory) expect(result).toBeInstanceOf(GitRepository) expect(provider.pathToRepository[result.getPath()]).toBeTruthy() @@ -39,7 +45,9 @@ describe('GitRepositoryProvider', () => { new Directory(path.join(__dirname, 'fixtures', 'git', 'master.git')) ) const secondRepo = await provider.repositoryForDirectory( - new Directory(path.join(__dirname, 'fixtures', 'git', 'master.git', 'objects')) + new Directory( + path.join(__dirname, 'fixtures', 'git', 'master.git', 'objects') + ) ) expect(firstRepo).toBeInstanceOf(GitRepository) @@ -72,7 +80,10 @@ describe('GitRepositoryProvider', () => { it('returns a Promise that resolves to a GitRepository', async () => { const gitDirPath = path.join(__dirname, 'fixtures', 'git', 'master.git') const workDirPath = temp.mkdirSync('git-workdir') - fs.writeFileSync(path.join(workDirPath, '.git'), `gitdir: ${gitDirPath}\n`) + fs.writeFileSync( + path.join(workDirPath, '.git'), + `gitdir: ${gitDirPath}\n` + ) const directory = new Directory(workDirPath) const result = await provider.repositoryForDirectory(directory) @@ -90,7 +101,9 @@ describe('GitRepositoryProvider', () => { const subdirectory = {} directory = { getSubdirectory () {}, - isRoot () { return true } + isRoot () { + return true + } } spyOn(directory, 'getSubdirectory').andReturn(subdirectory) }) diff --git a/spec/git-repository-spec.js b/spec/git-repository-spec.js index 65548fb3b..60a0846ac 100644 --- a/spec/git-repository-spec.js +++ b/spec/git-repository-spec.js @@ -1,4 +1,11 @@ -const {it, fit, ffit, fffit, beforeEach, afterEach} = require('./async-spec-helpers') +const { + it, + fit, + ffit, + fffit, + beforeEach, + afterEach +} = require('./async-spec-helpers') const path = require('path') const fs = require('fs-plus') const temp = require('temp').track() @@ -25,30 +32,44 @@ describe('GitRepository', () => { describe('new GitRepository(path)', () => { it('throws an exception when no repository is found', () => { - expect(() => new GitRepository(path.join(temp.dir, 'nogit.txt'))).toThrow() + expect( + () => new GitRepository(path.join(temp.dir, 'nogit.txt')) + ).toThrow() }) }) describe('.getPath()', () => { it('returns the repository path for a .git directory path with a directory', () => { - repo = new GitRepository(path.join(__dirname, 'fixtures', 'git', 'master.git', 'objects')) - expect(repo.getPath()).toBe(path.join(__dirname, 'fixtures', 'git', 'master.git')) + repo = new GitRepository( + path.join(__dirname, 'fixtures', 'git', 'master.git', 'objects') + ) + expect(repo.getPath()).toBe( + path.join(__dirname, 'fixtures', 'git', 'master.git') + ) }) it('returns the repository path for a repository path', () => { - repo = new GitRepository(path.join(__dirname, 'fixtures', 'git', 'master.git')) - expect(repo.getPath()).toBe(path.join(__dirname, 'fixtures', 'git', 'master.git')) + repo = new GitRepository( + path.join(__dirname, 'fixtures', 'git', 'master.git') + ) + expect(repo.getPath()).toBe( + path.join(__dirname, 'fixtures', 'git', 'master.git') + ) }) }) describe('.isPathIgnored(path)', () => { it('returns true for an ignored path', () => { - repo = new GitRepository(path.join(__dirname, 'fixtures', 'git', 'ignore.git')) + repo = new GitRepository( + path.join(__dirname, 'fixtures', 'git', 'ignore.git') + ) expect(repo.isPathIgnored('a.txt')).toBeTruthy() }) it('returns false for a non-ignored path', () => { - repo = new GitRepository(path.join(__dirname, 'fixtures', 'git', 'ignore.git')) + repo = new GitRepository( + path.join(__dirname, 'fixtures', 'git', 'ignore.git') + ) expect(repo.isPathIgnored('b.txt')).toBeFalsy() }) }) @@ -136,7 +157,10 @@ describe('GitRepository', () => { repo.onDidChangeStatus(statusHandler) repo.checkoutHead(filePath) expect(statusHandler.callCount).toBe(1) - expect(statusHandler.argsForCall[0][0]).toEqual({path: filePath, pathStatus: 0}) + expect(statusHandler.argsForCall[0][0]).toEqual({ + path: filePath, + pathStatus: 0 + }) repo.checkoutHead(filePath) expect(statusHandler.callCount).toBe(1) @@ -150,7 +174,11 @@ describe('GitRepository', () => { spyOn(atom, 'confirm') const workingDirPath = copyRepository() - repo = new GitRepository(workingDirPath, {project: atom.project, config: atom.config, confirm: atom.confirm}) + repo = new GitRepository(workingDirPath, { + project: atom.project, + config: atom.config, + confirm: atom.confirm + }) filePath = path.join(workingDirPath, 'a.txt') fs.writeFileSync(filePath, 'ch ch changes') @@ -161,7 +189,7 @@ describe('GitRepository', () => { // Permissions issues with this test on Windows if (process.platform === 'win32') return - atom.confirm.andCallFake(({buttons}) => buttons.OK()) + atom.confirm.andCallFake(({ buttons }) => buttons.OK()) atom.config.set('editor.confirmCheckoutHeadRevision', true) repo.checkoutHeadForEditor(editor) @@ -183,7 +211,9 @@ describe('GitRepository', () => { describe('.destroy()', () => { it('throws an exception when any method is called after it is called', () => { - repo = new GitRepository(path.join(__dirname, 'fixtures', 'git', 'master.git')) + repo = new GitRepository( + path.join(__dirname, 'fixtures', 'git', 'master.git') + ) repo.destroy() expect(() => repo.getShortHead()).toThrow() }) @@ -204,7 +234,10 @@ describe('GitRepository', () => { fs.writeFileSync(filePath, '') let status = repo.getPathStatus(filePath) expect(statusHandler.callCount).toBe(1) - expect(statusHandler.argsForCall[0][0]).toEqual({path: filePath, pathStatus: status}) + expect(statusHandler.argsForCall[0][0]).toEqual({ + path: filePath, + pathStatus: status + }) fs.writeFileSync(filePath, 'abc') status = repo.getPathStatus(filePath) @@ -223,10 +256,14 @@ describe('GitRepository', () => { }) it('gets the status based on the files inside the directory', () => { - expect(repo.isStatusModified(repo.getDirectoryStatus(directoryPath))).toBe(false) + expect( + repo.isStatusModified(repo.getDirectoryStatus(directoryPath)) + ).toBe(false) fs.writeFileSync(filePath, 'abc') repo.getPathStatus(filePath) - expect(repo.isStatusModified(repo.getDirectoryStatus(directoryPath))).toBe(true) + expect( + repo.isStatusModified(repo.getDirectoryStatus(directoryPath)) + ).toBe(true) }) }) @@ -235,7 +272,10 @@ describe('GitRepository', () => { beforeEach(() => { workingDirectory = copyRepository() - repo = new GitRepository(workingDirectory, {project: atom.project, config: atom.config}) + repo = new GitRepository(workingDirectory, { + project: atom.project, + config: atom.config + }) modifiedPath = path.join(workingDirectory, 'file.txt') newPath = path.join(workingDirectory, 'untracked.txt') cleanPath = path.join(workingDirectory, 'other.txt') @@ -252,8 +292,10 @@ describe('GitRepository', () => { await repo.refreshStatus() expect(statusHandler.callCount).toBe(1) expect(repo.getCachedPathStatus(cleanPath)).toBeUndefined() - expect(repo.isStatusNew(repo.getCachedPathStatus(newPath) )).toBeTruthy() - expect(repo.isStatusModified(repo.getCachedPathStatus(modifiedPath))).toBeTruthy() + expect(repo.isStatusNew(repo.getCachedPathStatus(newPath))).toBeTruthy() + expect( + repo.isStatusModified(repo.getCachedPathStatus(modifiedPath)) + ).toBeTruthy() }) it('caches the proper statuses when a subdir is open', async () => { @@ -278,7 +320,9 @@ describe('GitRepository', () => { await repo.refreshStatus() expect(repo.getCachedPathStatus(cleanPath)).toBeUndefined() expect(repo.isStatusNew(repo.getCachedPathStatus(newPath))).toBeTruthy() - expect(repo.isStatusModified(repo.getCachedPathStatus(modifiedPath))).toBeTruthy() + expect( + repo.isStatusModified(repo.getCachedPathStatus(modifiedPath)) + ).toBeTruthy() }) it('caches statuses that were looked up synchronously', async () => { @@ -288,7 +332,9 @@ describe('GitRepository', () => { fs.writeFileSync(modifiedPath, originalContent) await repo.refreshStatus() - expect(repo.isStatusModified(repo.getCachedPathStatus(modifiedPath))).toBeFalsy() + expect( + repo.isStatusModified(repo.getCachedPathStatus(modifiedPath)) + ).toBeFalsy() }) }) @@ -297,7 +343,9 @@ describe('GitRepository', () => { beforeEach(async () => { atom.project.setPaths([copyRepository()]) - const refreshPromise = new Promise(resolve => atom.project.getRepositories()[0].onDidChangeStatuses(resolve)) + const refreshPromise = new Promise(resolve => + atom.project.getRepositories()[0].onDidChangeStatuses(resolve) + ) editor = await atom.workspace.open('other.txt') await refreshPromise }) @@ -310,7 +358,10 @@ describe('GitRepository', () => { await editor.save() expect(statusHandler.callCount).toBe(1) - expect(statusHandler).toHaveBeenCalledWith({path: editor.getPath(), pathStatus: 256}) + expect(statusHandler).toHaveBeenCalledWith({ + path: editor.getPath(), + pathStatus: 256 + }) }) it('emits a status-changed event when a buffer is reloaded', async () => { @@ -321,7 +372,10 @@ describe('GitRepository', () => { await editor.getBuffer().reload() expect(statusHandler.callCount).toBe(1) - expect(statusHandler).toHaveBeenCalledWith({path: editor.getPath(), pathStatus: 256}) + expect(statusHandler).toHaveBeenCalledWith({ + path: editor.getPath(), + pathStatus: 256 + }) await editor.getBuffer().reload() expect(statusHandler.callCount).toBe(1) @@ -334,7 +388,10 @@ describe('GitRepository', () => { atom.project.getRepositories()[0].onDidChangeStatus(statusHandler) editor.getBuffer().emitter.emit('did-change-path') expect(statusHandler.callCount).toBe(1) - expect(statusHandler).toHaveBeenCalledWith({path: editor.getPath(), pathStatus: 256}) + expect(statusHandler).toHaveBeenCalledWith({ + path: editor.getPath(), + pathStatus: 256 + }) editor.getBuffer().emitter.emit('did-change-path') expect(statusHandler.callCount).toBe(1) }) @@ -364,7 +421,7 @@ describe('GitRepository', () => { grammarRegistry: atom.grammars, applicationDelegate: atom.applicationDelegate }) - await project2.deserialize(atom.project.serialize({isUnloading: false})) + await project2.deserialize(atom.project.serialize({ isUnloading: false })) buffer = project2.getBuffers()[0] @@ -376,14 +433,23 @@ describe('GitRepository', () => { await buffer.save() expect(statusHandler.callCount).toBe(1) - expect(statusHandler).toHaveBeenCalledWith({path: buffer.getPath(), pathStatus: 256}) + expect(statusHandler).toHaveBeenCalledWith({ + path: buffer.getPath(), + pathStatus: 256 + }) }) }) }) function copyRepository () { const workingDirPath = temp.mkdirSync('atom-spec-git') - fs.copySync(path.join(__dirname, 'fixtures', 'git', 'working-dir'), workingDirPath) - fs.renameSync(path.join(workingDirPath, 'git.git'), path.join(workingDirPath, '.git')) + fs.copySync( + path.join(__dirname, 'fixtures', 'git', 'working-dir'), + workingDirPath + ) + fs.renameSync( + path.join(workingDirPath, 'git.git'), + path.join(workingDirPath, '.git') + ) return workingDirPath } diff --git a/spec/grammar-registry-spec.js b/spec/grammar-registry-spec.js index b6b314ac3..2f7d82299 100644 --- a/spec/grammar-registry-spec.js +++ b/spec/grammar-registry-spec.js @@ -1,4 +1,11 @@ -const {it, fit, ffit, fffit, beforeEach, afterEach} = require('./async-spec-helpers') +const { + it, + fit, + ffit, + fffit, + beforeEach, + afterEach +} = require('./async-spec-helpers') const dedent = require('dedent') const path = require('path') @@ -13,14 +20,18 @@ describe('GrammarRegistry', () => { let grammarRegistry beforeEach(() => { - grammarRegistry = new GrammarRegistry({config: atom.config}) + grammarRegistry = new GrammarRegistry({ config: atom.config }) expect(subscriptionCount(grammarRegistry)).toBe(1) }) describe('.assignLanguageMode(buffer, languageId)', () => { it('assigns to the buffer a language mode with the given language id', async () => { - grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/javascript.cson')) - grammarRegistry.loadGrammarSync(require.resolve('language-css/grammars/css.cson')) + grammarRegistry.loadGrammarSync( + require.resolve('language-javascript/grammars/javascript.cson') + ) + grammarRegistry.loadGrammarSync( + require.resolve('language-css/grammars/css.cson') + ) const buffer = new TextBuffer() expect(grammarRegistry.assignLanguageMode(buffer, 'source.js')).toBe(true) @@ -31,7 +42,9 @@ describe('GrammarRegistry', () => { expect(grammarRegistry.assignLanguageMode(buffer, 'source.js')).toBe(true) // Language names are not case-sensitive - expect(grammarRegistry.assignLanguageMode(buffer, 'source.css')).toBe(true) + expect(grammarRegistry.assignLanguageMode(buffer, 'source.css')).toBe( + true + ) expect(buffer.getLanguageMode().getLanguageId()).toBe('source.css') // Returns false if no language is found @@ -41,14 +54,20 @@ describe('GrammarRegistry', () => { describe('when no languageId is passed', () => { it('makes the buffer use the null grammar', () => { - grammarRegistry.loadGrammarSync(require.resolve('language-css/grammars/css.cson')) + grammarRegistry.loadGrammarSync( + require.resolve('language-css/grammars/css.cson') + ) const buffer = new TextBuffer() - expect(grammarRegistry.assignLanguageMode(buffer, 'source.css')).toBe(true) + expect(grammarRegistry.assignLanguageMode(buffer, 'source.css')).toBe( + true + ) expect(buffer.getLanguageMode().getLanguageId()).toBe('source.css') expect(grammarRegistry.assignLanguageMode(buffer, null)).toBe(true) - expect(buffer.getLanguageMode().getLanguageId()).toBe('text.plain.null-grammar') + expect(buffer.getLanguageMode().getLanguageId()).toBe( + 'text.plain.null-grammar' + ) expect(grammarRegistry.getAssignedLanguageId(buffer)).toBe(null) }) }) @@ -56,10 +75,18 @@ describe('GrammarRegistry', () => { describe('.grammarForId(languageId)', () => { it('returns a text-mate grammar when `core.useTreeSitterParsers` is false', () => { - atom.config.set('core.useTreeSitterParsers', false, {scopeSelector: '.source.js'}) + atom.config.set('core.useTreeSitterParsers', false, { + scopeSelector: '.source.js' + }) - grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/javascript.cson')) - grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/tree-sitter-javascript.cson')) + grammarRegistry.loadGrammarSync( + require.resolve('language-javascript/grammars/javascript.cson') + ) + grammarRegistry.loadGrammarSync( + require.resolve( + 'language-javascript/grammars/tree-sitter-javascript.cson' + ) + ) const grammar = grammarRegistry.grammarForId('source.js') expect(grammar instanceof FirstMate.Grammar).toBe(true) @@ -72,26 +99,40 @@ describe('GrammarRegistry', () => { it('returns a tree-sitter grammar when `core.useTreeSitterParsers` is true', () => { atom.config.set('core.useTreeSitterParsers', true) - grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/javascript.cson')) - grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/tree-sitter-javascript.cson')) + grammarRegistry.loadGrammarSync( + require.resolve('language-javascript/grammars/javascript.cson') + ) + grammarRegistry.loadGrammarSync( + require.resolve( + 'language-javascript/grammars/tree-sitter-javascript.cson' + ) + ) const grammar = grammarRegistry.grammarForId('source.js') expect(grammar instanceof TreeSitterGrammar).toBe(true) expect(grammar.scopeName).toBe('source.js') grammarRegistry.removeGrammar(grammar) - expect(grammarRegistry.grammarForId('source.js') instanceof FirstMate.Grammar).toBe(true) + expect( + grammarRegistry.grammarForId('source.js') instanceof FirstMate.Grammar + ).toBe(true) }) }) describe('.autoAssignLanguageMode(buffer)', () => { it('assigns to the buffer a language mode based on the best available grammar', () => { - grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/javascript.cson')) - grammarRegistry.loadGrammarSync(require.resolve('language-css/grammars/css.cson')) + grammarRegistry.loadGrammarSync( + require.resolve('language-javascript/grammars/javascript.cson') + ) + grammarRegistry.loadGrammarSync( + require.resolve('language-css/grammars/css.cson') + ) const buffer = new TextBuffer() buffer.setPath('foo.js') - expect(grammarRegistry.assignLanguageMode(buffer, 'source.css')).toBe(true) + expect(grammarRegistry.assignLanguageMode(buffer, 'source.css')).toBe( + true + ) expect(buffer.getLanguageMode().getLanguageId()).toBe('source.css') grammarRegistry.autoAssignLanguageMode(buffer) @@ -103,8 +144,12 @@ describe('GrammarRegistry', () => { it('assigns a grammar to the buffer based on its path', async () => { const buffer = new TextBuffer() - grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/javascript.cson')) - grammarRegistry.loadGrammarSync(require.resolve('language-c/grammars/c.cson')) + grammarRegistry.loadGrammarSync( + require.resolve('language-javascript/grammars/javascript.cson') + ) + grammarRegistry.loadGrammarSync( + require.resolve('language-c/grammars/c.cson') + ) buffer.setPath('test.js') grammarRegistry.maintainLanguageMode(buffer) @@ -114,7 +159,7 @@ describe('GrammarRegistry', () => { expect(buffer.getLanguageMode().getLanguageId()).toBe('source.c') }) - it('updates the buffer\'s grammar when a more appropriate text-mate grammar is added for its path', async () => { + it("updates the buffer's grammar when a more appropriate text-mate grammar is added for its path", async () => { atom.config.set('core.useTreeSitterParsers', false) const buffer = new TextBuffer() @@ -123,14 +168,20 @@ describe('GrammarRegistry', () => { buffer.setPath('test.js') grammarRegistry.maintainLanguageMode(buffer) - const textMateGrammar = grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/javascript.cson')) + const textMateGrammar = grammarRegistry.loadGrammarSync( + require.resolve('language-javascript/grammars/javascript.cson') + ) expect(buffer.getLanguageMode().grammar).toBe(textMateGrammar) - grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/tree-sitter-javascript.cson')) + grammarRegistry.loadGrammarSync( + require.resolve( + 'language-javascript/grammars/tree-sitter-javascript.cson' + ) + ) expect(buffer.getLanguageMode().grammar).toBe(textMateGrammar) }) - it('updates the buffer\'s grammar when a more appropriate tree-sitter grammar is added for its path', async () => { + it("updates the buffer's grammar when a more appropriate tree-sitter grammar is added for its path", async () => { atom.config.set('core.useTreeSitterParsers', true) const buffer = new TextBuffer() @@ -139,10 +190,16 @@ describe('GrammarRegistry', () => { buffer.setPath('test.js') grammarRegistry.maintainLanguageMode(buffer) - const treeSitterGrammar = grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/tree-sitter-javascript.cson')) + const treeSitterGrammar = grammarRegistry.loadGrammarSync( + require.resolve( + 'language-javascript/grammars/tree-sitter-javascript.cson' + ) + ) expect(buffer.getLanguageMode().grammar).toBe(treeSitterGrammar) - grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/javascript.cson')) + grammarRegistry.loadGrammarSync( + require.resolve('language-javascript/grammars/javascript.cson') + ) expect(buffer.getLanguageMode().grammar).toBe(treeSitterGrammar) }) @@ -152,41 +209,59 @@ describe('GrammarRegistry', () => { buffer.setPath('test.js') grammarRegistry.maintainLanguageMode(buffer) - grammarRegistry.loadGrammarSync(require.resolve('language-css/grammars/css.cson')) - expect(grammarRegistry.assignLanguageMode(buffer, 'source.css')).toBe(true) + grammarRegistry.loadGrammarSync( + require.resolve('language-css/grammars/css.cson') + ) + expect(grammarRegistry.assignLanguageMode(buffer, 'source.css')).toBe( + true + ) expect(buffer.getLanguageMode().getLanguageId()).toBe('source.css') - grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/javascript.cson')) + grammarRegistry.loadGrammarSync( + require.resolve('language-javascript/grammars/javascript.cson') + ) expect(buffer.getLanguageMode().getLanguageId()).toBe('source.css') }) it('returns a disposable that can be used to stop the registry from updating the buffer', async () => { const buffer = new TextBuffer() - grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/javascript.cson')) + grammarRegistry.loadGrammarSync( + require.resolve('language-javascript/grammars/javascript.cson') + ) const previousSubscriptionCount = buffer.emitter.getTotalListenerCount() const disposable = grammarRegistry.maintainLanguageMode(buffer) - expect(buffer.emitter.getTotalListenerCount()).toBeGreaterThan(previousSubscriptionCount) + expect(buffer.emitter.getTotalListenerCount()).toBeGreaterThan( + previousSubscriptionCount + ) expect(retainedBufferCount(grammarRegistry)).toBe(1) buffer.setPath('test.js') expect(buffer.getLanguageMode().getLanguageId()).toBe('source.js') buffer.setPath('test.txt') - expect(buffer.getLanguageMode().getLanguageId()).toBe('text.plain.null-grammar') + expect(buffer.getLanguageMode().getLanguageId()).toBe( + 'text.plain.null-grammar' + ) disposable.dispose() - expect(buffer.emitter.getTotalListenerCount()).toBe(previousSubscriptionCount) + expect(buffer.emitter.getTotalListenerCount()).toBe( + previousSubscriptionCount + ) expect(retainedBufferCount(grammarRegistry)).toBe(0) buffer.setPath('test.js') - expect(buffer.getLanguageMode().getLanguageId()).toBe('text.plain.null-grammar') + expect(buffer.getLanguageMode().getLanguageId()).toBe( + 'text.plain.null-grammar' + ) expect(retainedBufferCount(grammarRegistry)).toBe(0) }) - it('doesn\'t do anything when called a second time with the same buffer', async () => { + it("doesn't do anything when called a second time with the same buffer", async () => { const buffer = new TextBuffer() - grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/javascript.cson')) + grammarRegistry.loadGrammarSync( + require.resolve('language-javascript/grammars/javascript.cson') + ) const disposable1 = grammarRegistry.maintainLanguageMode(buffer) const disposable2 = grammarRegistry.maintainLanguageMode(buffer) @@ -195,16 +270,22 @@ describe('GrammarRegistry', () => { disposable2.dispose() buffer.setPath('test.txt') - expect(buffer.getLanguageMode().getLanguageId()).toBe('text.plain.null-grammar') + expect(buffer.getLanguageMode().getLanguageId()).toBe( + 'text.plain.null-grammar' + ) disposable1.dispose() buffer.setPath('test.js') - expect(buffer.getLanguageMode().getLanguageId()).toBe('text.plain.null-grammar') + expect(buffer.getLanguageMode().getLanguageId()).toBe( + 'text.plain.null-grammar' + ) }) it('does not retain the buffer after the buffer is destroyed', () => { const buffer = new TextBuffer() - grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/javascript.cson')) + grammarRegistry.loadGrammarSync( + require.resolve('language-javascript/grammars/javascript.cson') + ) const disposable = grammarRegistry.maintainLanguageMode(buffer) expect(retainedBufferCount(grammarRegistry)).toBe(1) @@ -222,7 +303,9 @@ describe('GrammarRegistry', () => { it('does not retain the buffer when the grammar registry is destroyed', () => { const buffer = new TextBuffer() - grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/javascript.cson')) + grammarRegistry.loadGrammarSync( + require.resolve('language-javascript/grammars/javascript.cson') + ) const disposable = grammarRegistry.maintainLanguageMode(buffer) expect(retainedBufferCount(grammarRegistry)).toBe(1) @@ -238,19 +321,25 @@ describe('GrammarRegistry', () => { describe('.selectGrammar(filePath)', () => { it('always returns a grammar', () => { - const registry = new GrammarRegistry({config: atom.config}) + const registry = new GrammarRegistry({ config: atom.config }) expect(registry.selectGrammar().scopeName).toBe('text.plain.null-grammar') }) it('selects the text.plain grammar over the null grammar', async () => { await atom.packages.activatePackage('language-text') - expect(atom.grammars.selectGrammar('test.txt').scopeName).toBe('text.plain') + expect(atom.grammars.selectGrammar('test.txt').scopeName).toBe( + 'text.plain' + ) }) it('selects a grammar based on the file path case insensitively', async () => { await atom.packages.activatePackage('language-coffee-script') - expect(atom.grammars.selectGrammar('/tmp/source.coffee').scopeName).toBe('source.coffee') - expect(atom.grammars.selectGrammar('/tmp/source.COFFEE').scopeName).toBe('source.coffee') + expect(atom.grammars.selectGrammar('/tmp/source.coffee').scopeName).toBe( + 'source.coffee' + ) + expect(atom.grammars.selectGrammar('/tmp/source.COFFEE').scopeName).toBe( + 'source.coffee' + ) }) describe('on Windows', () => { @@ -258,16 +347,18 @@ describe('GrammarRegistry', () => { beforeEach(() => { originalPlatform = process.platform - Object.defineProperty(process, 'platform', {value: 'win32'}) + Object.defineProperty(process, 'platform', { value: 'win32' }) }) afterEach(() => { - Object.defineProperty(process, 'platform', {value: originalPlatform}) + Object.defineProperty(process, 'platform', { value: originalPlatform }) }) it('normalizes back slashes to forward slashes when matching the fileTypes', async () => { await atom.packages.activatePackage('language-git') - expect(atom.grammars.selectGrammar('something\\.git\\config').scopeName).toBe('source.git-config') + expect( + atom.grammars.selectGrammar('something\\.git\\config').scopeName + ).toBe('source.git-config') }) }) @@ -277,10 +368,14 @@ describe('GrammarRegistry', () => { await atom.packages.activatePackage('language-ruby') expect(atom.grammars.selectGrammar('file.js').name).toBe('JavaScript') // based on extension (.js) - expect(atom.grammars.selectGrammar(path.join(temp.dir, '.git', 'config')).name).toBe('Git Config') // based on end of the path (.git/config) + expect( + atom.grammars.selectGrammar(path.join(temp.dir, '.git', 'config')).name + ).toBe('Git Config') // based on end of the path (.git/config) expect(atom.grammars.selectGrammar('Rakefile').name).toBe('Ruby') // based on the file's basename (Rakefile) expect(atom.grammars.selectGrammar('curb').name).toBe('Null Grammar') - expect(atom.grammars.selectGrammar('/hu.git/config').name).toBe('Null Grammar') + expect(atom.grammars.selectGrammar('/hu.git/config').name).toBe( + 'Null Grammar' + ) }) it("uses the filePath's shebang line if the grammar cannot be determined by the extension or basename", async () => { @@ -296,13 +391,20 @@ describe('GrammarRegistry', () => { await atom.packages.activatePackage('language-coffee-script') let fileContent = 'first-line\n' - expect(atom.grammars.selectGrammar('dummy.coffee', fileContent).name).toBe('CoffeeScript') + expect( + atom.grammars.selectGrammar('dummy.coffee', fileContent).name + ).toBe('CoffeeScript') fileContent = '' - expect(atom.grammars.selectGrammar('grammar.tmLanguage', fileContent).name).toBe('Null Grammar') + expect( + atom.grammars.selectGrammar('grammar.tmLanguage', fileContent).name + ).toBe('Null Grammar') - fileContent += '\n' - expect(atom.grammars.selectGrammar('grammar.tmLanguage', fileContent).name).toBe('Property List (XML)') + fileContent += + '\n' + expect( + atom.grammars.selectGrammar('grammar.tmLanguage', fileContent).name + ).toBe('Property List (XML)') }) it("doesn't read the file when the file contents are specified", async () => { @@ -311,28 +413,36 @@ describe('GrammarRegistry', () => { const filePath = require.resolve('./fixtures/shebang') const filePathContents = fs.readFileSync(filePath, 'utf8') spyOn(fs, 'read').andCallThrough() - expect(atom.grammars.selectGrammar(filePath, filePathContents).name).toBe('Ruby') + expect(atom.grammars.selectGrammar(filePath, filePathContents).name).toBe( + 'Ruby' + ) expect(fs.read).not.toHaveBeenCalled() }) describe('when multiple grammars have matching fileTypes', () => { it('selects the grammar with the longest fileType match', () => { - const grammarPath1 = temp.path({suffix: '.json'}) - fs.writeFileSync(grammarPath1, JSON.stringify({ - name: 'test1', - scopeName: 'source1', - fileTypes: ['test'] - })) + const grammarPath1 = temp.path({ suffix: '.json' }) + fs.writeFileSync( + grammarPath1, + JSON.stringify({ + name: 'test1', + scopeName: 'source1', + fileTypes: ['test'] + }) + ) const grammar1 = atom.grammars.loadGrammarSync(grammarPath1) expect(atom.grammars.selectGrammar('more.test', '')).toBe(grammar1) fs.removeSync(grammarPath1) - const grammarPath2 = temp.path({suffix: '.json'}) - fs.writeFileSync(grammarPath2, JSON.stringify({ - name: 'test2', - scopeName: 'source2', - fileTypes: ['test', 'more.test'] - })) + const grammarPath2 = temp.path({ suffix: '.json' }) + fs.writeFileSync( + grammarPath2, + JSON.stringify({ + name: 'test2', + scopeName: 'source2', + fileTypes: ['test', 'more.test'] + }) + ) const grammar2 = atom.grammars.loadGrammarSync(grammarPath2) expect(atom.grammars.selectGrammar('more.test', '')).toBe(grammar2) return fs.removeSync(grammarPath2) @@ -341,19 +451,28 @@ describe('GrammarRegistry', () => { it('favors non-bundled packages when breaking scoring ties', async () => { await atom.packages.activatePackage('language-ruby') - await atom.packages.activatePackage(path.join(__dirname, 'fixtures', 'packages', 'package-with-rb-filetype')) + await atom.packages.activatePackage( + path.join(__dirname, 'fixtures', 'packages', 'package-with-rb-filetype') + ) atom.grammars.grammarForScopeName('source.ruby').bundledPackage = true atom.grammars.grammarForScopeName('test.rb').bundledPackage = false - expect(atom.grammars.selectGrammar('test.rb', '#!/usr/bin/env ruby').scopeName).toBe('source.ruby') - expect(atom.grammars.selectGrammar('test.rb', '#!/usr/bin/env testruby').scopeName).toBe('test.rb') + expect( + atom.grammars.selectGrammar('test.rb', '#!/usr/bin/env ruby').scopeName + ).toBe('source.ruby') + expect( + atom.grammars.selectGrammar('test.rb', '#!/usr/bin/env testruby') + .scopeName + ).toBe('test.rb') expect(atom.grammars.selectGrammar('test.rb').scopeName).toBe('test.rb') }) describe('when there is no file path', () => { it('does not throw an exception (regression)', () => { - expect(() => atom.grammars.selectGrammar(null, '#!/usr/bin/ruby')).not.toThrow() + expect(() => + atom.grammars.selectGrammar(null, '#!/usr/bin/ruby') + ).not.toThrow() expect(() => atom.grammars.selectGrammar(null, '')).not.toThrow() expect(() => atom.grammars.selectGrammar(null, null)).not.toThrow() }) @@ -362,8 +481,11 @@ describe('GrammarRegistry', () => { describe('when the user has custom grammar file types', () => { it('considers the custom file types as well as those defined in the grammar', async () => { await atom.packages.activatePackage('language-ruby') - atom.config.set('core.customFileTypes', {'source.ruby': ['Cheffile']}) - expect(atom.grammars.selectGrammar('build/Cheffile', 'cookbook "postgres"').scopeName).toBe('source.ruby') + atom.config.set('core.customFileTypes', { 'source.ruby': ['Cheffile'] }) + expect( + atom.grammars.selectGrammar('build/Cheffile', 'cookbook "postgres"') + .scopeName + ).toBe('source.ruby') }) it('favors user-defined file types over built-in ones of equal length', async () => { @@ -374,31 +496,50 @@ describe('GrammarRegistry', () => { 'source.coffee': ['Rakefile'], 'source.ruby': ['Cakefile'] }) - expect(atom.grammars.selectGrammar('Rakefile', '').scopeName).toBe('source.coffee') - expect(atom.grammars.selectGrammar('Cakefile', '').scopeName).toBe('source.ruby') + expect(atom.grammars.selectGrammar('Rakefile', '').scopeName).toBe( + 'source.coffee' + ) + expect(atom.grammars.selectGrammar('Cakefile', '').scopeName).toBe( + 'source.ruby' + ) }) it('favors user-defined file types over grammars with matching first-line-regexps', async () => { await atom.packages.activatePackage('language-ruby') await atom.packages.activatePackage('language-javascript') - atom.config.set('core.customFileTypes', {'source.ruby': ['bootstrap']}) - expect(atom.grammars.selectGrammar('bootstrap', '#!/usr/bin/env node').scopeName).toBe('source.ruby') + atom.config.set('core.customFileTypes', { + 'source.ruby': ['bootstrap'] + }) + expect( + atom.grammars.selectGrammar('bootstrap', '#!/usr/bin/env node') + .scopeName + ).toBe('source.ruby') }) }) it('favors a grammar with a matching file type over one with m matching first line pattern', async () => { await atom.packages.activatePackage('language-ruby') await atom.packages.activatePackage('language-javascript') - expect(atom.grammars.selectGrammar('foo.rb', '#!/usr/bin/env node').scopeName).toBe('source.ruby') + expect( + atom.grammars.selectGrammar('foo.rb', '#!/usr/bin/env node').scopeName + ).toBe('source.ruby') }) describe('tree-sitter vs text-mate', () => { it('favors a text-mate grammar over a tree-sitter grammar when `core.useTreeSitterParsers` is false', () => { - atom.config.set('core.useTreeSitterParsers', false, {scopeSelector: '.source.js'}) + atom.config.set('core.useTreeSitterParsers', false, { + scopeSelector: '.source.js' + }) - grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/javascript.cson')) - grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/tree-sitter-javascript.cson')) + grammarRegistry.loadGrammarSync( + require.resolve('language-javascript/grammars/javascript.cson') + ) + grammarRegistry.loadGrammarSync( + require.resolve( + 'language-javascript/grammars/tree-sitter-javascript.cson' + ) + ) const grammar = grammarRegistry.selectGrammar('test.js') expect(grammar.scopeName).toBe('source.js') @@ -408,8 +549,14 @@ describe('GrammarRegistry', () => { it('favors a tree-sitter grammar over a text-mate grammar when `core.useTreeSitterParsers` is true', () => { atom.config.set('core.useTreeSitterParsers', true) - grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/javascript.cson')) - grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/tree-sitter-javascript.cson')) + grammarRegistry.loadGrammarSync( + require.resolve('language-javascript/grammars/javascript.cson') + ) + grammarRegistry.loadGrammarSync( + require.resolve( + 'language-javascript/grammars/tree-sitter-javascript.cson' + ) + ) const grammar = grammarRegistry.selectGrammar('test.js') expect(grammar instanceof TreeSitterGrammar).toBe(true) @@ -417,7 +564,11 @@ describe('GrammarRegistry', () => { it('only favors a tree-sitter grammar if it actually matches in some way (regression)', () => { atom.config.set('core.useTreeSitterParsers', true) - grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/tree-sitter-javascript.cson')) + grammarRegistry.loadGrammarSync( + require.resolve( + 'language-javascript/grammars/tree-sitter-javascript.cson' + ) + ) const grammar = grammarRegistry.selectGrammar('test', '') expect(grammar.name).toBe('Null Grammar') @@ -427,110 +578,164 @@ describe('GrammarRegistry', () => { describe('tree-sitter grammars with content regexes', () => { it('recognizes C++ header files', () => { atom.config.set('core.useTreeSitterParsers', true) - grammarRegistry.loadGrammarSync(require.resolve('language-c/grammars/tree-sitter-c.cson')) - grammarRegistry.loadGrammarSync(require.resolve('language-c/grammars/tree-sitter-cpp.cson')) - grammarRegistry.loadGrammarSync(require.resolve('language-coffee-script/grammars/coffeescript.cson')) + grammarRegistry.loadGrammarSync( + require.resolve('language-c/grammars/tree-sitter-c.cson') + ) + grammarRegistry.loadGrammarSync( + require.resolve('language-c/grammars/tree-sitter-cpp.cson') + ) + grammarRegistry.loadGrammarSync( + require.resolve('language-coffee-script/grammars/coffeescript.cson') + ) - let grammar = grammarRegistry.selectGrammar('test.h', dedent ` + let grammar = grammarRegistry.selectGrammar( + 'test.h', + dedent` #include typedef struct { void verb(); } Noun; - `) + ` + ) expect(grammar.name).toBe('C') - grammar = grammarRegistry.selectGrammar('test.h', dedent ` + grammar = grammarRegistry.selectGrammar( + 'test.h', + dedent` #include class Noun { public: void verb(); }; - `) + ` + ) expect(grammar.name).toBe('C++') // The word `class` only indicates C++ in `.h` files, not in all files. - grammar = grammarRegistry.selectGrammar('test.coffee', dedent ` + grammar = grammarRegistry.selectGrammar( + 'test.coffee', + dedent` module.exports = class Noun verb: -> true - `) + ` + ) expect(grammar.name).toBe('CoffeeScript') }) it('recognizes C++ files that do not match the content regex (regression)', () => { atom.config.set('core.useTreeSitterParsers', true) - grammarRegistry.loadGrammarSync(require.resolve('language-c/grammars/tree-sitter-c.cson')) - grammarRegistry.loadGrammarSync(require.resolve('language-c/grammars/c++.cson')) - grammarRegistry.loadGrammarSync(require.resolve('language-c/grammars/tree-sitter-cpp.cson')) + grammarRegistry.loadGrammarSync( + require.resolve('language-c/grammars/tree-sitter-c.cson') + ) + grammarRegistry.loadGrammarSync( + require.resolve('language-c/grammars/c++.cson') + ) + grammarRegistry.loadGrammarSync( + require.resolve('language-c/grammars/tree-sitter-cpp.cson') + ) - let grammar = grammarRegistry.selectGrammar('test.cc', dedent ` + let grammar = grammarRegistry.selectGrammar( + 'test.cc', + dedent` int a(); - `) + ` + ) expect(grammar.name).toBe('C++') }) it('does not apply content regexes from grammars without filetype or first line matches', () => { atom.config.set('core.useTreeSitterParsers', true) - grammarRegistry.loadGrammarSync(require.resolve('language-c/grammars/tree-sitter-cpp.cson')) + grammarRegistry.loadGrammarSync( + require.resolve('language-c/grammars/tree-sitter-cpp.cson') + ) - let grammar = grammarRegistry.selectGrammar('', dedent ` + let grammar = grammarRegistry.selectGrammar( + '', + dedent` class Foo # this is ruby, not C++ end - `) + ` + ) expect(grammar.name).toBe('Null Grammar') }) it('recognizes shell scripts with shebang lines', () => { atom.config.set('core.useTreeSitterParsers', true) - grammarRegistry.loadGrammarSync(require.resolve('language-shellscript/grammars/shell-unix-bash.cson')) - grammarRegistry.loadGrammarSync(require.resolve('language-shellscript/grammars/tree-sitter-bash.cson')) + grammarRegistry.loadGrammarSync( + require.resolve('language-shellscript/grammars/shell-unix-bash.cson') + ) + grammarRegistry.loadGrammarSync( + require.resolve('language-shellscript/grammars/tree-sitter-bash.cson') + ) - let grammar = grammarRegistry.selectGrammar('test.h', dedent ` + let grammar = grammarRegistry.selectGrammar( + 'test.h', + dedent` #!/bin/bash echo "hi" - `) + ` + ) expect(grammar.name).toBe('Shell Script') expect(grammar instanceof TreeSitterGrammar).toBeTruthy() - grammar = grammarRegistry.selectGrammar('test.h', dedent ` + grammar = grammarRegistry.selectGrammar( + 'test.h', + dedent` # vim: set ft=bash echo "hi" - `) + ` + ) expect(grammar.name).toBe('Shell Script') expect(grammar instanceof TreeSitterGrammar).toBeTruthy() atom.config.set('core.useTreeSitterParsers', false) - grammar = grammarRegistry.selectGrammar('test.h', dedent ` + grammar = grammarRegistry.selectGrammar( + 'test.h', + dedent` #!/bin/bash echo "hi" - `) + ` + ) expect(grammar.name).toBe('Shell Script') expect(grammar instanceof TreeSitterGrammar).toBeFalsy() }) it('recognizes JavaScript files that use Flow', () => { atom.config.set('core.useTreeSitterParsers', true) - grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/tree-sitter-javascript.cson')) - grammarRegistry.loadGrammarSync(require.resolve('language-typescript/grammars/tree-sitter-flow.cson')) + grammarRegistry.loadGrammarSync( + require.resolve( + 'language-javascript/grammars/tree-sitter-javascript.cson' + ) + ) + grammarRegistry.loadGrammarSync( + require.resolve('language-typescript/grammars/tree-sitter-flow.cson') + ) - let grammar = grammarRegistry.selectGrammar('test.js', dedent` + let grammar = grammarRegistry.selectGrammar( + 'test.js', + dedent` // Copyright something // @flow module.exports = function () { return 1 + 1 } - `) + ` + ) expect(grammar.name).toBe('Flow JavaScript') - grammar = grammarRegistry.selectGrammar('test.js', dedent` + grammar = grammarRegistry.selectGrammar( + 'test.js', + dedent` module.exports = function () { return 1 + 1 } - `) + ` + ) expect(grammar.name).toBe('JavaScript') }) }) @@ -548,8 +753,12 @@ describe('GrammarRegistry', () => { describe('.addInjectionPoint(languageId, {type, language, content})', () => { const injectionPoint = { type: 'some_node_type', - language() { return 'some_language_name' }, - content(node) { return node } + language () { + return 'some_language_name' + }, + content (node) { + return node + } } beforeEach(() => { @@ -574,13 +783,19 @@ describe('GrammarRegistry', () => { }) describe('serialization', () => { - it('persists editors\' grammar overrides', async () => { + it("persists editors' grammar overrides", async () => { const buffer1 = new TextBuffer() const buffer2 = new TextBuffer() - grammarRegistry.loadGrammarSync(require.resolve('language-c/grammars/c.cson')) - grammarRegistry.loadGrammarSync(require.resolve('language-html/grammars/html.cson')) - grammarRegistry.loadGrammarSync(require.resolve('language-javascript/grammars/javascript.cson')) + grammarRegistry.loadGrammarSync( + require.resolve('language-c/grammars/c.cson') + ) + grammarRegistry.loadGrammarSync( + require.resolve('language-html/grammars/html.cson') + ) + grammarRegistry.loadGrammarSync( + require.resolve('language-javascript/grammars/javascript.cson') + ) grammarRegistry.maintainLanguageMode(buffer1) grammarRegistry.maintainLanguageMode(buffer2) @@ -590,11 +805,17 @@ describe('GrammarRegistry', () => { const buffer1Copy = await TextBuffer.deserialize(buffer1.serialize()) const buffer2Copy = await TextBuffer.deserialize(buffer2.serialize()) - const grammarRegistryCopy = new GrammarRegistry({config: atom.config}) - grammarRegistryCopy.deserialize(JSON.parse(JSON.stringify(grammarRegistry.serialize()))) + const grammarRegistryCopy = new GrammarRegistry({ config: atom.config }) + grammarRegistryCopy.deserialize( + JSON.parse(JSON.stringify(grammarRegistry.serialize())) + ) - grammarRegistryCopy.loadGrammarSync(require.resolve('language-c/grammars/c.cson')) - grammarRegistryCopy.loadGrammarSync(require.resolve('language-html/grammars/html.cson')) + grammarRegistryCopy.loadGrammarSync( + require.resolve('language-c/grammars/c.cson') + ) + grammarRegistryCopy.loadGrammarSync( + require.resolve('language-html/grammars/html.cson') + ) expect(buffer1Copy.getLanguageMode().getLanguageId()).toBe(null) expect(buffer2Copy.getLanguageMode().getLanguageId()).toBe(null) @@ -604,7 +825,9 @@ describe('GrammarRegistry', () => { expect(buffer1Copy.getLanguageMode().getLanguageId()).toBe('source.c') expect(buffer2Copy.getLanguageMode().getLanguageId()).toBe(null) - grammarRegistryCopy.loadGrammarSync(require.resolve('language-javascript/grammars/javascript.cson')) + grammarRegistryCopy.loadGrammarSync( + require.resolve('language-javascript/grammars/javascript.cson') + ) expect(buffer1Copy.getLanguageMode().getLanguageId()).toBe('source.c') expect(buffer2Copy.getLanguageMode().getLanguageId()).toBe('source.js') }) diff --git a/spec/gutter-container-spec.js b/spec/gutter-container-spec.js index f41f1d220..50451ecfb 100644 --- a/spec/gutter-container-spec.js +++ b/spec/gutter-container-spec.js @@ -14,26 +14,28 @@ describe('GutterContainer', () => { describe('when initialized', () => it('it has no gutters', () => { expect(gutterContainer.getGutters().length).toBe(0) - }) - ) + })) describe('::addGutter', () => { it('creates a new gutter', () => { - const newGutter = gutterContainer.addGutter({'test-gutter': 'test-gutter', priority: 1}) + const newGutter = gutterContainer.addGutter({ + 'test-gutter': 'test-gutter', + priority: 1 + }) expect(gutterContainer.getGutters()).toEqual([newGutter]) expect(newGutter.priority).toBe(1) }) it('throws an error if the provided gutter name is already in use', () => { const name = 'test-gutter' - gutterContainer.addGutter({name}) - expect(gutterContainer.addGutter.bind(null, {name})).toThrow() + gutterContainer.addGutter({ name }) + expect(gutterContainer.addGutter.bind(null, { name })).toThrow() }) it('keeps added gutters sorted by ascending priority', () => { - const gutter1 = gutterContainer.addGutter({name: 'first', priority: 1}) - const gutter3 = gutterContainer.addGutter({name: 'third', priority: 3}) - const gutter2 = gutterContainer.addGutter({name: 'second', priority: 2}) + const gutter1 = gutterContainer.addGutter({ name: 'first', priority: 1 }) + const gutter3 = gutterContainer.addGutter({ name: 'third', priority: 3 }) + const gutter2 = gutterContainer.addGutter({ name: 'second', priority: 2 }) expect(gutterContainer.getGutters()).toEqual([gutter1, gutter2, gutter3]) }) }) @@ -44,11 +46,13 @@ describe('GutterContainer', () => { beforeEach(function () { gutterContainer = new GutterContainer(fakeTextEditor) removedGutters = [] - gutterContainer.onDidRemoveGutter(gutterName => removedGutters.push(gutterName)) + gutterContainer.onDidRemoveGutter(gutterName => + removedGutters.push(gutterName) + ) }) it('removes the gutter if it is contained by this GutterContainer', () => { - const gutter = gutterContainer.addGutter({'test-gutter': 'test-gutter'}) + const gutter = gutterContainer.addGutter({ 'test-gutter': 'test-gutter' }) expect(gutterContainer.getGutters()).toEqual([gutter]) gutterContainer.removeGutter(gutter) expect(gutterContainer.getGutters().length).toBe(0) @@ -65,13 +69,15 @@ describe('GutterContainer', () => { describe('::destroy', () => it('clears its array of gutters and destroys custom gutters', () => { - const newGutter = gutterContainer.addGutter({'test-gutter': 'test-gutter', priority: 1}) + const newGutter = gutterContainer.addGutter({ + 'test-gutter': 'test-gutter', + priority: 1 + }) const newGutterSpy = jasmine.createSpy() newGutter.onDidDestroy(newGutterSpy) gutterContainer.destroy() expect(newGutterSpy).toHaveBeenCalled() expect(gutterContainer.getGutters()).toEqual([]) - }) -) + })) }) diff --git a/spec/gutter-spec.js b/spec/gutter-spec.js index 4ae23db3e..c5051ea22 100644 --- a/spec/gutter-spec.js +++ b/spec/gutter-spec.js @@ -24,8 +24,7 @@ describe('Gutter', () => { expect(gutter.isVisible()).toBe(false) // An event should only be emitted when the visibility changes. expect(events.length).toBe(1) - }) - ) + })) describe('::show', () => it('shows the gutter if it is hidden.', () => { @@ -45,8 +44,7 @@ describe('Gutter', () => { expect(gutter.isVisible()).toBe(true) // An event should only be emitted when the visibility changes. expect(events.length).toBe(1) - }) - ) + })) describe('::destroy', () => { let mockGutterContainer, mockGutterContainerRemovedGutters @@ -61,21 +59,23 @@ describe('Gutter', () => { }) it('removes the gutter from its container.', () => { - const gutter = new Gutter(mockGutterContainer, {name}) + const gutter = new Gutter(mockGutterContainer, { name }) gutter.destroy() expect(mockGutterContainerRemovedGutters).toEqual([gutter]) }) it('calls all callbacks registered on ::onDidDestroy.', () => { - const gutter = new Gutter(mockGutterContainer, {name}) + const gutter = new Gutter(mockGutterContainer, { name }) let didDestroy = false - gutter.onDidDestroy(() => { didDestroy = true }) + gutter.onDidDestroy(() => { + didDestroy = true + }) gutter.destroy() expect(didDestroy).toBe(true) }) it('does not allow destroying the line-number gutter', () => { - const gutter = new Gutter(mockGutterContainer, {name: 'line-number'}) + const gutter = new Gutter(mockGutterContainer, { name: 'line-number' }) expect(gutter.destroy).toThrow() }) }) diff --git a/spec/helpers/random.js b/spec/helpers/random.js index 62f0e1920..3a2ff9159 100644 --- a/spec/helpers/random.js +++ b/spec/helpers/random.js @@ -1,5 +1,5 @@ const WORDS = require('./words') -const {Point, Range} = require('text-buffer') +const { Point, Range } = require('text-buffer') exports.getRandomBufferRange = function getRandomBufferRange (random, buffer) { const endRow = random(buffer.getLineCount()) diff --git a/spec/history-manager-spec.js b/spec/history-manager-spec.js index cc2a20058..2d1a09cdc 100644 --- a/spec/history-manager-spec.js +++ b/spec/history-manager-spec.js @@ -1,10 +1,17 @@ -const {it, fit, ffit, fffit, beforeEach, afterEach} = require('./async-spec-helpers') -const {Emitter, Disposable, CompositeDisposable} = require('event-kit') +const { + it, + fit, + ffit, + fffit, + beforeEach, + afterEach +} = require('./async-spec-helpers') +const { Emitter, Disposable, CompositeDisposable } = require('event-kit') -const {HistoryManager, HistoryProject} = require('../src/history-manager') +const { HistoryManager, HistoryProject } = require('../src/history-manager') const StateStore = require('../src/state-store') -describe("HistoryManager", () => { +describe('HistoryManager', () => { let historyManager, commandRegistry, project, stateStore let commandDisposable, projectDisposable @@ -16,19 +23,26 @@ describe("HistoryManager", () => { stateStore = new StateStore('history-manager-test', 1) await stateStore.save('history-manager', { projects: [ - {paths: ['/1', 'c:\\2'], lastOpened: new Date(2016, 9, 17, 17, 16, 23)}, - {paths: ['/test'], lastOpened: new Date(2016, 9, 17, 11, 12, 13)} + { + paths: ['/1', 'c:\\2'], + lastOpened: new Date(2016, 9, 17, 17, 16, 23) + }, + { paths: ['/test'], lastOpened: new Date(2016, 9, 17, 11, 12, 13) } ] }) projectDisposable = jasmine.createSpyObj('Disposable', ['dispose']) project = jasmine.createSpyObj('Project', ['onDidChangePaths']) - project.onDidChangePaths.andCallFake((f) => { + project.onDidChangePaths.andCallFake(f => { project.didChangePathsListener = f return projectDisposable }) - historyManager = new HistoryManager({stateStore, project, commands: commandRegistry}) + historyManager = new HistoryManager({ + stateStore, + project, + commands: commandRegistry + }) await historyManager.loadState() }) @@ -36,24 +50,29 @@ describe("HistoryManager", () => { await stateStore.clear() }) - describe("constructor", () => { + describe('constructor', () => { it("registers the 'clear-project-history' command function", () => { expect(commandRegistry.add).toHaveBeenCalled() const cmdCall = commandRegistry.add.calls[0] expect(cmdCall.args.length).toBe(3) expect(cmdCall.args[0]).toBe('atom-workspace') - expect(typeof cmdCall.args[1]['application:clear-project-history']).toBe('function') + expect(typeof cmdCall.args[1]['application:clear-project-history']).toBe( + 'function' + ) }) - describe("getProjects", () => { - it("returns an array of HistoryProjects", () => { + describe('getProjects', () => { + it('returns an array of HistoryProjects', () => { expect(historyManager.getProjects()).toEqual([ - new HistoryProject(['/1', 'c:\\2'], new Date(2016, 9, 17, 17, 16, 23)), + new HistoryProject( + ['/1', 'c:\\2'], + new Date(2016, 9, 17, 17, 16, 23) + ), new HistoryProject(['/test'], new Date(2016, 9, 17, 11, 12, 13)) ]) }) - it("returns an array of HistoryProjects that is not mutable state", () => { + it('returns an array of HistoryProjects that is not mutable state', () => { const firstProjects = historyManager.getProjects() firstProjects.pop() firstProjects[0].path = 'modified' @@ -64,21 +83,25 @@ describe("HistoryManager", () => { }) }) - describe("clearProjects", () => { - it("clears the list of projects", async () => { + describe('clearProjects', () => { + it('clears the list of projects', async () => { expect(historyManager.getProjects().length).not.toBe(0) await historyManager.clearProjects() expect(historyManager.getProjects().length).toBe(0) }) - it("saves the state", async () => { + it('saves the state', async () => { await historyManager.clearProjects() - const historyManager2 = new HistoryManager({stateStore, project, commands: commandRegistry}) + const historyManager2 = new HistoryManager({ + stateStore, + project, + commands: commandRegistry + }) await historyManager2.loadState() expect(historyManager.getProjects().length).toBe(0) }) - it("fires the onDidChangeProjects event", async () => { + it('fires the onDidChangeProjects event', async () => { const didChangeSpy = jasmine.createSpy() historyManager.onDidChangeProjects(didChangeSpy) await historyManager.clearProjects() @@ -87,7 +110,7 @@ describe("HistoryManager", () => { }) }) - it("listens to project.onDidChangePaths adding a new project", () => { + it('listens to project.onDidChangePaths adding a new project', () => { const start = new Date() project.didChangePathsListener(['/a/new', '/path/or/two']) const projects = historyManager.getProjects() @@ -96,7 +119,7 @@ describe("HistoryManager", () => { expect(projects[0].lastOpened).not.toBeLessThan(start) }) - it("listens to project.onDidChangePaths updating an existing project", () => { + it('listens to project.onDidChangePaths updating an existing project', () => { const start = new Date() project.didChangePathsListener(['/test']) const projects = historyManager.getProjects() @@ -106,22 +129,22 @@ describe("HistoryManager", () => { }) }) - describe("loadState", () => { - it("defaults to an empty array if no state", async () => { + describe('loadState', () => { + it('defaults to an empty array if no state', async () => { await stateStore.clear() await historyManager.loadState() expect(historyManager.getProjects()).toEqual([]) }) - it("defaults to an empty array if no projects", async () => { + it('defaults to an empty array if no projects', async () => { await stateStore.save('history-manager', {}) await historyManager.loadState() expect(historyManager.getProjects()).toEqual([]) }) }) - describe("addProject", () => { - it("adds a new project to the end", async () => { + describe('addProject', () => { + it('adds a new project to the end', async () => { const date = new Date(2010, 10, 9, 8, 7, 6) await historyManager.addProject(['/a/b'], date) const projects = historyManager.getProjects() @@ -130,7 +153,7 @@ describe("HistoryManager", () => { expect(projects[2].lastOpened).toBe(date) }) - it("adds a new project to the start", async () => { + it('adds a new project to the start', async () => { const date = new Date() await historyManager.addProject(['/so/new'], date) const projects = historyManager.getProjects() @@ -139,7 +162,7 @@ describe("HistoryManager", () => { expect(projects[0].lastOpened).toBe(date) }) - it("updates an existing project and moves it to the start", async () => { + it('updates an existing project and moves it to the start', async () => { const date = new Date() await historyManager.addProject(['/test'], date) const projects = historyManager.getProjects() @@ -148,7 +171,7 @@ describe("HistoryManager", () => { expect(projects[0].lastOpened).toBe(date) }) - it("fires the onDidChangeProjects event when adding a project", async () => { + it('fires the onDidChangeProjects event when adding a project', async () => { const didChangeSpy = jasmine.createSpy() const beforeCount = historyManager.getProjects().length historyManager.onDidChangeProjects(didChangeSpy) @@ -157,7 +180,7 @@ describe("HistoryManager", () => { expect(historyManager.getProjects().length).toBe(beforeCount + 1) }) - it("fires the onDidChangeProjects event when updating a project", async () => { + it('fires the onDidChangeProjects event when updating a project', async () => { const didChangeSpy = jasmine.createSpy() const beforeCount = historyManager.getProjects().length historyManager.onDidChangeProjects(didChangeSpy) @@ -167,8 +190,8 @@ describe("HistoryManager", () => { }) }) - describe("getProject", () => { - it("returns a project that matches the paths", () => { + describe('getProject', () => { + it('returns a project that matches the paths', () => { const project = historyManager.getProject(['/1', 'c:\\2']) expect(project).not.toBeNull() expect(project.paths).toEqual(['/1', 'c:\\2']) @@ -180,7 +203,7 @@ describe("HistoryManager", () => { }) }) - describe("saveState", () => { + describe('saveState', () => { let savedHistory beforeEach(() => { // historyManager.saveState is spied on globally to prevent specs from @@ -195,11 +218,17 @@ describe("HistoryManager", () => { }) }) - it("saves the state", async () => { - await historyManager.addProject(["/save/state"]) + it('saves the state', async () => { + await historyManager.addProject(['/save/state']) await historyManager.saveState() - const historyManager2 = new HistoryManager({stateStore, project, commands: commandRegistry}) - spyOn(historyManager2.stateStore, 'load').andCallFake(name => Promise.resolve(savedHistory)) + const historyManager2 = new HistoryManager({ + stateStore, + project, + commands: commandRegistry + }) + spyOn(historyManager2.stateStore, 'load').andCallFake(name => + Promise.resolve(savedHistory) + ) await historyManager2.loadState() expect(historyManager2.getProjects()[0].paths).toEqual(['/save/state']) }) diff --git a/spec/jasmine-list-reporter.js b/spec/jasmine-list-reporter.js index b6976b6ca..ffe8b0858 100644 --- a/spec/jasmine-list-reporter.js +++ b/spec/jasmine-list-reporter.js @@ -1,4 +1,4 @@ -const {TerminalReporter} = require('jasmine-tagged') +const { TerminalReporter } = require('jasmine-tagged') class JasmineListReporter extends TerminalReporter { fullDescription (spec) { diff --git a/spec/main-process/atom-application.test.js b/spec/main-process/atom-application.test.js index 296ffcad9..83feac157 100644 --- a/spec/main-process/atom-application.test.js +++ b/spec/main-process/atom-application.test.js @@ -9,14 +9,21 @@ const path = require('path') const sinon = require('sinon') const AtomApplication = require('../../src/main-process/atom-application') const parseCommandLine = require('../../src/main-process/parse-command-line') -const {timeoutPromise, conditionPromise, emitterEventPromise} = require('../async-spec-helpers') +const { + timeoutPromise, + conditionPromise, + emitterEventPromise +} = require('../async-spec-helpers') const ATOM_RESOURCE_PATH = path.resolve(__dirname, '..', '..') describe('AtomApplication', function () { this.timeout(60 * 1000) - let originalAppQuit, originalShowMessageBox, originalAtomHome, atomApplicationsToDestroy + let originalAppQuit, + originalShowMessageBox, + originalAtomHome, + atomApplicationsToDestroy beforeEach(() => { originalAppQuit = electron.app.quit @@ -25,11 +32,15 @@ describe('AtomApplication', function () { originalAtomHome = process.env.ATOM_HOME process.env.ATOM_HOME = makeTempDir('atom-home') // Symlinking the compile cache into the temporary home dir makes the windows load much faster - fs.symlinkSync(path.join(originalAtomHome, 'compile-cache'), path.join(process.env.ATOM_HOME, 'compile-cache'), 'junction') + fs.symlinkSync( + path.join(originalAtomHome, 'compile-cache'), + path.join(process.env.ATOM_HOME, 'compile-cache'), + 'junction' + ) season.writeFileSync(path.join(process.env.ATOM_HOME, 'config.cson'), { '*': { - welcome: {showOnStartup: false}, - core: {telemetryConsent: 'no'} + welcome: { showOnStartup: false }, + core: { telemetryConsent: 'no' } } }) atomApplicationsToDestroy = [] @@ -54,10 +65,14 @@ describe('AtomApplication', function () { const tempDirPath2 = makeTempDir() const atomApplication1 = buildAtomApplication() - const [app1Window1] = await atomApplication1.launch(parseCommandLine([tempDirPath1])) + const [app1Window1] = await atomApplication1.launch( + parseCommandLine([tempDirPath1]) + ) await emitterEventPromise(app1Window1, 'window:locations-opened') - const [app1Window2] = await atomApplication1.launch(parseCommandLine([tempDirPath2])) + const [app1Window2] = await atomApplication1.launch( + parseCommandLine([tempDirPath2]) + ) await emitterEventPromise(app1Window2, 'window:locations-opened') await Promise.all([ @@ -66,30 +81,46 @@ describe('AtomApplication', function () { ]) const atomApplication2 = buildAtomApplication() - const [app2Window1, app2Window2] = await atomApplication2.launch(parseCommandLine([])) + const [app2Window1, app2Window2] = await atomApplication2.launch( + parseCommandLine([]) + ) await Promise.all([ emitterEventPromise(app2Window1, 'window:locations-opened'), emitterEventPromise(app2Window2, 'window:locations-opened') ]) - assert.deepEqual(await getTreeViewRootDirectories(app2Window1), [tempDirPath1]) - assert.deepEqual(await getTreeViewRootDirectories(app2Window2), [tempDirPath2]) + assert.deepEqual(await getTreeViewRootDirectories(app2Window1), [ + tempDirPath1 + ]) + assert.deepEqual(await getTreeViewRootDirectories(app2Window2), [ + tempDirPath2 + ]) }) it('when windows already exist, opens a new window with a single untitled buffer', async () => { const atomApplication = buildAtomApplication() const [window1] = await atomApplication.launch(parseCommandLine([])) await focusWindow(window1) - const window1EditorTitle = await evalInWebContents(window1.browserWindow.webContents, sendBackToMainProcess => { - sendBackToMainProcess(atom.workspace.getActiveTextEditor().getTitle()) - }) + const window1EditorTitle = await evalInWebContents( + window1.browserWindow.webContents, + sendBackToMainProcess => { + sendBackToMainProcess( + atom.workspace.getActiveTextEditor().getTitle() + ) + } + ) assert.equal(window1EditorTitle, 'untitled') const window2 = atomApplication.openWithOptions(parseCommandLine([])) await window2.loadedPromise - const window2EditorTitle = await evalInWebContents(window1.browserWindow.webContents, sendBackToMainProcess => { - sendBackToMainProcess(atom.workspace.getActiveTextEditor().getTitle()) - }) + const window2EditorTitle = await evalInWebContents( + window1.browserWindow.webContents, + sendBackToMainProcess => { + sendBackToMainProcess( + atom.workspace.getActiveTextEditor().getTitle() + ) + } + ) assert.equal(window2EditorTitle, 'untitled') assert.deepEqual(atomApplication.getAllWindows(), [window2, window1]) @@ -101,10 +132,14 @@ describe('AtomApplication', function () { const tempDirPath2 = makeTempDir() const atomApplication1 = buildAtomApplication() - const [app1Window1] = await atomApplication1.launch(parseCommandLine([tempDirPath1])) + const [app1Window1] = await atomApplication1.launch( + parseCommandLine([tempDirPath1]) + ) await emitterEventPromise(app1Window1, 'window:locations-opened') - const [app1Window2] = await atomApplication1.launch(parseCommandLine([tempDirPath2])) + const [app1Window2] = await atomApplication1.launch( + parseCommandLine([tempDirPath2]) + ) await emitterEventPromise(app1Window2, 'window:locations-opened') await Promise.all([ @@ -114,13 +149,20 @@ describe('AtomApplication', function () { // Launch with --new-window const atomApplication2 = buildAtomApplication() - const appWindows2 = await atomApplication2.launch(parseCommandLine(['--new-window'])) + const appWindows2 = await atomApplication2.launch( + parseCommandLine(['--new-window']) + ) assert.lengthOf(appWindows2, 1) const [appWindow2] = appWindows2 await appWindow2.loadedPromise - const window2EditorTitle = await evalInWebContents(appWindow2.browserWindow.webContents, sendBackToMainProcess => { - sendBackToMainProcess(atom.workspace.getActiveTextEditor().getTitle()) - }) + const window2EditorTitle = await evalInWebContents( + appWindow2.browserWindow.webContents, + sendBackToMainProcess => { + sendBackToMainProcess( + atom.workspace.getActiveTextEditor().getTitle() + ) + } + ) assert.equal(window2EditorTitle, 'untitled') }) @@ -135,12 +177,17 @@ describe('AtomApplication', function () { const [window1] = await atomApplication.launch(parseCommandLine([])) await focusWindow(window1) - // wait a bit just to make sure we don't pass due to querying the render process before it loads + // wait a bit just to make sure we don't pass due to querying the render process before it loads await timeoutPromise(1000) - const itemCount = await evalInWebContents(window1.browserWindow.webContents, sendBackToMainProcess => { - sendBackToMainProcess(atom.workspace.getActivePane().getItems().length) - }) + const itemCount = await evalInWebContents( + window1.browserWindow.webContents, + sendBackToMainProcess => { + sendBackToMainProcess( + atom.workspace.getActivePane().getItems().length + ) + } + ) assert.equal(itemCount, 0) }) }) @@ -153,11 +200,18 @@ describe('AtomApplication', function () { fs.mkdirSync(dirBSubdirPath) const atomApplication = buildAtomApplication() - const [window1] = await atomApplication.launch(parseCommandLine([dirAPath, dirBPath])) + const [window1] = await atomApplication.launch( + parseCommandLine([dirAPath, dirBPath]) + ) await focusWindow(window1) - await conditionPromise(async () => (await getTreeViewRootDirectories(window1)).length === 2) - assert.deepEqual(await getTreeViewRootDirectories(window1), [dirAPath, dirBPath]) + await conditionPromise( + async () => (await getTreeViewRootDirectories(window1)).length === 2 + ) + assert.deepEqual(await getTreeViewRootDirectories(window1), [ + dirAPath, + dirBPath + ]) }) it('can open to a specific line number of a file', async () => { @@ -165,14 +219,19 @@ describe('AtomApplication', function () { fs.writeFileSync(filePath, '1\n2\n3\n4\n') const atomApplication = buildAtomApplication() - const [window] = await atomApplication.launch(parseCommandLine([filePath + ':3'])) + const [window] = await atomApplication.launch( + parseCommandLine([filePath + ':3']) + ) await focusWindow(window) - const cursorRow = await evalInWebContents(window.browserWindow.webContents, sendBackToMainProcess => { - atom.workspace.observeTextEditors(textEditor => { - sendBackToMainProcess(textEditor.getCursorBufferPosition().row) - }) - }) + const cursorRow = await evalInWebContents( + window.browserWindow.webContents, + sendBackToMainProcess => { + atom.workspace.observeTextEditors(textEditor => { + sendBackToMainProcess(textEditor.getCursorBufferPosition().row) + }) + } + ) assert.equal(cursorRow, 2) }) @@ -182,16 +241,21 @@ describe('AtomApplication', function () { fs.writeFileSync(filePath, '1\n2\n3\n4\n') const atomApplication = buildAtomApplication() - const [window] = await atomApplication.launch(parseCommandLine([filePath + ':2:2'])) + const [window] = await atomApplication.launch( + parseCommandLine([filePath + ':2:2']) + ) await focusWindow(window) - const cursorPosition = await evalInWebContents(window.browserWindow.webContents, sendBackToMainProcess => { - atom.workspace.observeTextEditors(textEditor => { - sendBackToMainProcess(textEditor.getCursorBufferPosition()) - }) - }) + const cursorPosition = await evalInWebContents( + window.browserWindow.webContents, + sendBackToMainProcess => { + atom.workspace.observeTextEditors(textEditor => { + sendBackToMainProcess(textEditor.getCursorBufferPosition()) + }) + } + ) - assert.deepEqual(cursorPosition, {row: 1, column: 1}) + assert.deepEqual(cursorPosition, { row: 1, column: 1 }) }) it('removes all trailing whitespace and colons from the specified path', async () => { @@ -199,31 +263,44 @@ describe('AtomApplication', function () { fs.writeFileSync(filePath, '1\n2\n3\n4\n') const atomApplication = buildAtomApplication() - const [window] = await atomApplication.launch(parseCommandLine([filePath + ':: '])) + const [window] = await atomApplication.launch( + parseCommandLine([filePath + ':: ']) + ) await focusWindow(window) - const openedPath = await evalInWebContents(window.browserWindow.webContents, sendBackToMainProcess => { - atom.workspace.observeTextEditors(textEditor => { - sendBackToMainProcess(textEditor.getPath()) - }) - }) + const openedPath = await evalInWebContents( + window.browserWindow.webContents, + sendBackToMainProcess => { + atom.workspace.observeTextEditors(textEditor => { + sendBackToMainProcess(textEditor.getPath()) + }) + } + ) assert.equal(openedPath, filePath) }) it('opens an empty text editor when launched with a new file path', async () => { // Choosing "Don't save" - mockElectronShowMessageBox({response: 2}) + mockElectronShowMessageBox({ response: 2 }) const atomApplication = buildAtomApplication() const newFilePath = path.join(makeTempDir(), 'new-file') - const [window] = await atomApplication.launch(parseCommandLine([newFilePath])) + const [window] = await atomApplication.launch( + parseCommandLine([newFilePath]) + ) await focusWindow(window) - const {editorTitle, editorText} = await evalInWebContents(window.browserWindow.webContents, sendBackToMainProcess => { - atom.workspace.observeTextEditors(editor => { - sendBackToMainProcess({editorTitle: editor.getTitle(), editorText: editor.getText()}) - }) - }) + const { editorTitle, editorText } = await evalInWebContents( + window.browserWindow.webContents, + sendBackToMainProcess => { + atom.workspace.observeTextEditors(editor => { + sendBackToMainProcess({ + editorTitle: editor.getTitle(), + editorText: editor.getText() + }) + }) + } + ) assert.equal(editorTitle, path.basename(newFilePath)) assert.equal(editorText, '') assert.deepEqual(await getTreeViewRootDirectories(window), []) @@ -239,32 +316,51 @@ describe('AtomApplication', function () { fs.writeFileSync(existingDirCFilePath, 'this is an existing file') const atomApplication = buildAtomApplication() - const [window1] = await atomApplication.launch(parseCommandLine([dirAPath])) + const [window1] = await atomApplication.launch( + parseCommandLine([dirAPath]) + ) await focusWindow(window1) - await conditionPromise(async () => (await getTreeViewRootDirectories(window1)).length === 1) + await conditionPromise( + async () => (await getTreeViewRootDirectories(window1)).length === 1 + ) assert.deepEqual(await getTreeViewRootDirectories(window1), [dirAPath]) // When opening *files* with --add, reuses an existing window - let [reusedWindow] = await atomApplication.launch(parseCommandLine([existingDirCFilePath, '--add'])) + let [reusedWindow] = await atomApplication.launch( + parseCommandLine([existingDirCFilePath, '--add']) + ) assert.equal(reusedWindow, window1) assert.deepEqual(atomApplication.getAllWindows(), [window1]) - let activeEditorPath = await evalInWebContents(window1.browserWindow.webContents, sendBackToMainProcess => { - const subscription = atom.workspace.onDidChangeActivePaneItem(textEditor => { - sendBackToMainProcess(textEditor.getPath()) - subscription.dispose() - }) - }) + let activeEditorPath = await evalInWebContents( + window1.browserWindow.webContents, + sendBackToMainProcess => { + const subscription = atom.workspace.onDidChangeActivePaneItem( + textEditor => { + sendBackToMainProcess(textEditor.getPath()) + subscription.dispose() + } + ) + } + ) assert.equal(activeEditorPath, existingDirCFilePath) assert.deepEqual(await getTreeViewRootDirectories(window1), [dirAPath]) // When opening *directories* with --add, reuses an existing window and adds the directory to the project - reusedWindow = (await atomApplication.launch(parseCommandLine([dirBPath, '-a'])))[0] + reusedWindow = (await atomApplication.launch( + parseCommandLine([dirBPath, '-a']) + ))[0] assert.equal(reusedWindow, window1) assert.deepEqual(atomApplication.getAllWindows(), [window1]) - await conditionPromise(async () => (await getTreeViewRootDirectories(reusedWindow)).length === 2) - assert.deepEqual(await getTreeViewRootDirectories(window1), [dirAPath, dirBPath]) + await conditionPromise( + async () => + (await getTreeViewRootDirectories(reusedWindow)).length === 2 + ) + assert.deepEqual(await getTreeViewRootDirectories(window1), [ + dirAPath, + dirBPath + ]) }) }) @@ -272,11 +368,15 @@ describe('AtomApplication', function () { it('positions new windows at an offset distance from the previous window', async () => { const atomApplication = buildAtomApplication() - const [window1] = await atomApplication.launch(parseCommandLine([makeTempDir()])) + const [window1] = await atomApplication.launch( + parseCommandLine([makeTempDir()]) + ) await focusWindow(window1) - window1.browserWindow.setBounds({width: 400, height: 400, x: 0, y: 0}) + window1.browserWindow.setBounds({ width: 400, height: 400, x: 0, y: 0 }) - const [window2] = await atomApplication.launch(parseCommandLine([makeTempDir()])) + const [window2] = await atomApplication.launch( + parseCommandLine([makeTempDir()]) + ) await focusWindow(window2) assert.notEqual(window1, window2) @@ -289,70 +389,109 @@ describe('AtomApplication', function () { it('persists window state based on the project directories', async () => { // Choosing "Don't save" - mockElectronShowMessageBox({response: 2}) + mockElectronShowMessageBox({ response: 2 }) const tempDirPath = makeTempDir() const atomApplication = buildAtomApplication() const nonExistentFilePath = path.join(tempDirPath, 'new-file') - const [window1] = await atomApplication.launch(parseCommandLine([tempDirPath, nonExistentFilePath])) - await evalInWebContents(window1.browserWindow.webContents, sendBackToMainProcess => { - atom.workspace.observeTextEditors(textEditor => { - textEditor.insertText('Hello World!') - sendBackToMainProcess(null) - }) - }) + const [window1] = await atomApplication.launch( + parseCommandLine([tempDirPath, nonExistentFilePath]) + ) + await evalInWebContents( + window1.browserWindow.webContents, + sendBackToMainProcess => { + atom.workspace.observeTextEditors(textEditor => { + textEditor.insertText('Hello World!') + sendBackToMainProcess(null) + }) + } + ) await window1.prepareToUnload() window1.close() await window1.closedPromise // Restore unsaved state when opening the same project directory - const [window2] = await atomApplication.launch(parseCommandLine([tempDirPath])) + const [window2] = await atomApplication.launch( + parseCommandLine([tempDirPath]) + ) await window2.loadedPromise - const window2Text = await evalInWebContents(window2.browserWindow.webContents, sendBackToMainProcess => { - const textEditor = atom.workspace.getActiveTextEditor() - textEditor.moveToBottom() - textEditor.insertText(' How are you?') - sendBackToMainProcess(textEditor.getText()) - }) + const window2Text = await evalInWebContents( + window2.browserWindow.webContents, + sendBackToMainProcess => { + const textEditor = atom.workspace.getActiveTextEditor() + textEditor.moveToBottom() + textEditor.insertText(' How are you?') + sendBackToMainProcess(textEditor.getText()) + } + ) assert.equal(window2Text, 'Hello World! How are you?') }) it('adds a remote directory to the project when launched with a remote directory', async () => { - const packagePath = path.join(__dirname, '..', 'fixtures', 'packages', 'package-with-directory-provider') + const packagePath = path.join( + __dirname, + '..', + 'fixtures', + 'packages', + 'package-with-directory-provider' + ) const packagesDirPath = path.join(process.env.ATOM_HOME, 'packages') fs.mkdirSync(packagesDirPath) - fs.symlinkSync(packagePath, path.join(packagesDirPath, 'package-with-directory-provider'), 'junction') + fs.symlinkSync( + packagePath, + path.join(packagesDirPath, 'package-with-directory-provider'), + 'junction' + ) const atomApplication = buildAtomApplication() atomApplication.config.set('core.disabledPackages', ['fuzzy-finder']) const remotePath = 'remote://server:3437/some/directory/path' - let [window] = await atomApplication.launch(parseCommandLine([remotePath])) + let [window] = await atomApplication.launch( + parseCommandLine([remotePath]) + ) await focusWindow(window) - await conditionPromise(async () => (await getProjectDirectories()).length > 0) + await conditionPromise( + async () => (await getProjectDirectories()).length > 0 + ) let directories = await getProjectDirectories() - assert.deepEqual(directories, [{type: 'FakeRemoteDirectory', path: remotePath}]) + assert.deepEqual(directories, [ + { type: 'FakeRemoteDirectory', path: remotePath } + ]) await window.reload() await focusWindow(window) directories = await getProjectDirectories() - assert.deepEqual(directories, [{type: 'FakeRemoteDirectory', path: remotePath}]) + assert.deepEqual(directories, [ + { type: 'FakeRemoteDirectory', path: remotePath } + ]) function getProjectDirectories () { - return evalInWebContents(window.browserWindow.webContents, sendBackToMainProcess => { - sendBackToMainProcess(atom.project.getDirectories().map(d => ({ type: d.constructor.name, path: d.getPath() }))) - }) + return evalInWebContents( + window.browserWindow.webContents, + sendBackToMainProcess => { + sendBackToMainProcess( + atom.project + .getDirectories() + .map(d => ({ type: d.constructor.name, path: d.getPath() })) + ) + } + ) } }) it('does not reopen any previously opened windows when launched with no path and `core.restorePreviousWindowsOnStart` is no', async () => { const atomApplication1 = buildAtomApplication() - const [app1Window1] = await atomApplication1.launch(parseCommandLine([makeTempDir()])) + const [app1Window1] = await atomApplication1.launch( + parseCommandLine([makeTempDir()]) + ) await focusWindow(app1Window1) - const [app1Window2] = await atomApplication1.launch(parseCommandLine([makeTempDir()])) + const [app1Window2] = await atomApplication1.launch( + parseCommandLine([makeTempDir()]) + ) await focusWindow(app1Window2) const configPath = path.join(process.env.ATOM_HOME, 'config.cson') @@ -382,19 +521,27 @@ describe('AtomApplication', function () { }) it('kills the specified pid after a newly-opened window is closed', async () => { - const [window1] = await atomApplication.launch(parseCommandLine(['--wait', '--pid', '101'])) + const [window1] = await atomApplication.launch( + parseCommandLine(['--wait', '--pid', '101']) + ) await focusWindow(window1) - const [window2] = await atomApplication.launch(parseCommandLine(['--new-window', '--wait', '--pid', '102'])) + const [window2] = await atomApplication.launch( + parseCommandLine(['--new-window', '--wait', '--pid', '102']) + ) await focusWindow(window2) assert.deepEqual(killedPids, []) - let processKillPromise = new Promise(resolve => { onDidKillProcess = resolve }) + let processKillPromise = new Promise(resolve => { + onDidKillProcess = resolve + }) window1.close() await processKillPromise assert.deepEqual(killedPids, [101]) - processKillPromise = new Promise(resolve => { onDidKillProcess = resolve }) + processKillPromise = new Promise(resolve => { + onDidKillProcess = resolve + }) window2.close() await processKillPromise assert.deepEqual(killedPids, [101, 102]) @@ -407,18 +554,34 @@ describe('AtomApplication', function () { fs.writeFileSync(filePath1, 'File 1') fs.writeFileSync(filePath2, 'File 2') - const [window] = await atomApplication.launch(parseCommandLine(['--wait', '--pid', '101', projectDir])) + const [window] = await atomApplication.launch( + parseCommandLine(['--wait', '--pid', '101', projectDir]) + ) await focusWindow(window) - const [reusedWindow] = await atomApplication.launch(parseCommandLine(['--add', '--wait', '--pid', '102', filePath1, filePath2])) + const [reusedWindow] = await atomApplication.launch( + parseCommandLine([ + '--add', + '--wait', + '--pid', + '102', + filePath1, + filePath2 + ]) + ) assert.equal(reusedWindow, window) - const activeEditorPath = await evalInWebContents(window.browserWindow.webContents, send => { - const subscription = atom.workspace.onDidChangeActivePaneItem(editor => { - send(editor.getPath()) - subscription.dispose() - }) - }) + const activeEditorPath = await evalInWebContents( + window.browserWindow.webContents, + send => { + const subscription = atom.workspace.onDidChangeActivePaneItem( + editor => { + send(editor.getPath()) + subscription.dispose() + } + ) + } + ) assert([filePath1, filePath2].includes(activeEditorPath)) assert.deepEqual(killedPids, []) @@ -430,7 +593,9 @@ describe('AtomApplication', function () { await timeoutPromise(100) assert.deepEqual(killedPids, []) - let processKillPromise = new Promise(resolve => { onDidKillProcess = resolve }) + let processKillPromise = new Promise(resolve => { + onDidKillProcess = resolve + }) await evalInWebContents(window.browserWindow.webContents, send => { atom.workspace.getActivePaneItem().destroy() send() @@ -438,7 +603,9 @@ describe('AtomApplication', function () { await processKillPromise assert.deepEqual(killedPids, [102]) - processKillPromise = new Promise(resolve => { onDidKillProcess = resolve }) + processKillPromise = new Promise(resolve => { + onDidKillProcess = resolve + }) window.close() await processKillPromise assert.deepEqual(killedPids, [102, 101]) @@ -449,25 +616,40 @@ describe('AtomApplication', function () { await focusWindow(window) const dirPath1 = makeTempDir() - const [reusedWindow] = await atomApplication.launch(parseCommandLine(['--add', '--wait', '--pid', '101', dirPath1])) + const [reusedWindow] = await atomApplication.launch( + parseCommandLine(['--add', '--wait', '--pid', '101', dirPath1]) + ) assert.equal(reusedWindow, window) - await conditionPromise(async () => (await getTreeViewRootDirectories(window)).length === 1) + await conditionPromise( + async () => (await getTreeViewRootDirectories(window)).length === 1 + ) assert.deepEqual(await getTreeViewRootDirectories(window), [dirPath1]) assert.deepEqual(killedPids, []) const dirPath2 = makeTempDir() - await evalInWebContents(window.browserWindow.webContents, (send, dirPath1, dirPath2) => { - atom.project.setPaths([dirPath1, dirPath2]) - send() - }, dirPath1, dirPath2) + await evalInWebContents( + window.browserWindow.webContents, + (send, dirPath1, dirPath2) => { + atom.project.setPaths([dirPath1, dirPath2]) + send() + }, + dirPath1, + dirPath2 + ) await timeoutPromise(100) assert.deepEqual(killedPids, []) - let processKillPromise = new Promise(resolve => { onDidKillProcess = resolve }) - await evalInWebContents(window.browserWindow.webContents, (send, dirPath2) => { - atom.project.setPaths([dirPath2]) - send() - }, dirPath2) + let processKillPromise = new Promise(resolve => { + onDidKillProcess = resolve + }) + await evalInWebContents( + window.browserWindow.webContents, + (send, dirPath2) => { + atom.project.setPaths([dirPath2]) + send() + }, + dirPath2 + ) await processKillPromise assert.deepEqual(killedPids, [101]) }) @@ -477,7 +659,9 @@ describe('AtomApplication', function () { if (process.platform === 'linux' || process.platform === 'win32') { it('quits the application', async () => { const atomApplication = buildAtomApplication() - const [window] = await atomApplication.launch(parseCommandLine([path.join(makeTempDir('a'), 'file-a')])) + const [window] = await atomApplication.launch( + parseCommandLine([path.join(makeTempDir('a'), 'file-a')]) + ) await focusWindow(window) window.close() await window.closedPromise @@ -487,7 +671,9 @@ describe('AtomApplication', function () { } else if (process.platform === 'darwin') { it('leaves the application open', async () => { const atomApplication = buildAtomApplication() - const [window] = await atomApplication.launch(parseCommandLine([path.join(makeTempDir('a'), 'file-a')])) + const [window] = await atomApplication.launch( + parseCommandLine([path.join(makeTempDir('a'), 'file-a')]) + ) await focusWindow(window) window.close() await window.closedPromise @@ -503,16 +689,29 @@ describe('AtomApplication', function () { const dirB = makeTempDir() const atomApplication = buildAtomApplication() - const [window0] = await atomApplication.launch(parseCommandLine([dirA, dirB])) + const [window0] = await atomApplication.launch( + parseCommandLine([dirA, dirB]) + ) await focusWindow(window0) - await conditionPromise(async () => (await getTreeViewRootDirectories(window0)).length === 2) - assert.deepEqual(await getTreeViewRootDirectories(window0), [dirA, dirB]) + await conditionPromise( + async () => (await getTreeViewRootDirectories(window0)).length === 2 + ) + assert.deepEqual(await getTreeViewRootDirectories(window0), [ + dirA, + dirB + ]) - const saveStatePromise = emitterEventPromise(atomApplication, 'application:did-save-state') - await evalInWebContents(window0.browserWindow.webContents, (sendBackToMainProcess) => { - atom.project.removePath(atom.project.getPaths()[0]) - sendBackToMainProcess(null) - }) + const saveStatePromise = emitterEventPromise( + atomApplication, + 'application:did-save-state' + ) + await evalInWebContents( + window0.browserWindow.webContents, + sendBackToMainProcess => { + atom.project.removePath(atom.project.getPaths()[0]) + sendBackToMainProcess(null) + } + ) assert.deepEqual(await getTreeViewRootDirectories(window0), [dirB]) await saveStatePromise @@ -520,17 +719,29 @@ describe('AtomApplication', function () { const atomApplication2 = buildAtomApplication() const [window2] = await atomApplication2.launch(parseCommandLine([])) await focusWindow(window2) - await conditionPromise(async () => (await getTreeViewRootDirectories(window2)).length === 1) + await conditionPromise( + async () => (await getTreeViewRootDirectories(window2)).length === 1 + ) assert.deepEqual(await getTreeViewRootDirectories(window2), [dirB]) }) }) describe('when opening atom:// URLs', () => { it('loads the urlMain file in a new window', async () => { - const packagePath = path.join(__dirname, '..', 'fixtures', 'packages', 'package-with-url-main') + const packagePath = path.join( + __dirname, + '..', + 'fixtures', + 'packages', + 'package-with-url-main' + ) const packagesDirPath = path.join(process.env.ATOM_HOME, 'packages') fs.mkdirSync(packagesDirPath) - fs.symlinkSync(packagePath, path.join(packagesDirPath, 'package-with-url-main'), 'junction') + fs.symlinkSync( + packagePath, + path.join(packagesDirPath, 'package-with-url-main'), + 'junction' + ) const atomApplication = buildAtomApplication() const launchOptions = parseCommandLine([]) @@ -538,9 +749,12 @@ describe('AtomApplication', function () { let [windows] = await atomApplication.launch(launchOptions) await windows[0].loadedPromise - let reached = await evalInWebContents(windows[0].browserWindow.webContents, sendBackToMainProcess => { - sendBackToMainProcess(global.reachedUrlMain) - }) + let reached = await evalInWebContents( + windows[0].browserWindow.webContents, + sendBackToMainProcess => { + sendBackToMainProcess(global.reachedUrlMain) + } + ) assert.isTrue(reached) windows[0].close() }) @@ -550,9 +764,13 @@ describe('AtomApplication', function () { const dirBPath = makeTempDir('b') const atomApplication = buildAtomApplication() - const [window1] = await atomApplication.launch(parseCommandLine([path.join(dirAPath)])) + const [window1] = await atomApplication.launch( + parseCommandLine([path.join(dirAPath)]) + ) await focusWindow(window1) - const [window2] = await atomApplication.launch(parseCommandLine([path.join(dirBPath)])) + const [window2] = await atomApplication.launch( + parseCommandLine([path.join(dirBPath)]) + ) await focusWindow(window2) const fileA = path.join(dirAPath, 'file-a') @@ -564,10 +782,16 @@ describe('AtomApplication', function () { sinon.spy(window2, 'sendURIMessage') atomApplication.launch(parseCommandLine(['--uri-handler', uriA])) - await conditionPromise(() => window1.sendURIMessage.calledWith(uriA), `window1 to be focused from ${fileA}`) + await conditionPromise( + () => window1.sendURIMessage.calledWith(uriA), + `window1 to be focused from ${fileA}` + ) atomApplication.launch(parseCommandLine(['--uri-handler', uriB])) - await conditionPromise(() => window2.sendURIMessage.calledWith(uriB), `window2 to be focused from ${fileB}`) + await conditionPromise( + () => window2.sendURIMessage.calledWith(uriB), + `window2 to be focused from ${fileB}` + ) }) }) }) @@ -584,7 +808,10 @@ describe('AtomApplication', function () { await new Promise(process.nextTick) assert(!electron.app.didQuit()) - await Promise.all([window1.lastPrepareToUnloadPromise, window2.lastPrepareToUnloadPromise]) + await Promise.all([ + window1.lastPrepareToUnloadPromise, + window2.lastPrepareToUnloadPromise + ]) assert(!electron.app.didQuit()) await atomApplication.lastBeforeQuitPromise await new Promise(process.nextTick) @@ -596,20 +823,23 @@ describe('AtomApplication', function () { const [window1] = await atomApplication.launch(parseCommandLine([])) const [window2] = await atomApplication.launch(parseCommandLine([])) await Promise.all([window1.loadedPromise, window2.loadedPromise]) - await evalInWebContents(window1.browserWindow.webContents, sendBackToMainProcess => { - atom.workspace.getActiveTextEditor().insertText('unsaved text') - sendBackToMainProcess() - }) + await evalInWebContents( + window1.browserWindow.webContents, + sendBackToMainProcess => { + atom.workspace.getActiveTextEditor().insertText('unsaved text') + sendBackToMainProcess() + } + ) // Choosing "Cancel" - mockElectronShowMessageBox({response: 1}) + mockElectronShowMessageBox({ response: 1 }) electron.app.quit() await atomApplication.lastBeforeQuitPromise assert(!electron.app.didQuit()) assert.equal(electron.app.quit.callCount, 1) // Ensure choosing "Cancel" doesn't try to quit the electron app more than once (regression) // Choosing "Don't save" - mockElectronShowMessageBox({response: 2}) + mockElectronShowMessageBox({ response: 2 }) electron.app.quit() await atomApplication.lastBeforeQuitPromise assert(electron.app.didQuit()) @@ -620,19 +850,22 @@ describe('AtomApplication', function () { const [window1] = await atomApplication.launch(parseCommandLine([])) const [window2] = await atomApplication.launch(parseCommandLine([])) await Promise.all([window1.loadedPromise, window2.loadedPromise]) - await evalInWebContents(window1.browserWindow.webContents, sendBackToMainProcess => { - atom.workspace.getActiveTextEditor().insertText('unsaved text') - sendBackToMainProcess() - }) + await evalInWebContents( + window1.browserWindow.webContents, + sendBackToMainProcess => { + atom.workspace.getActiveTextEditor().insertText('unsaved text') + sendBackToMainProcess() + } + ) // Choosing "Cancel" - mockElectronShowMessageBox({response: 1}) + mockElectronShowMessageBox({ response: 1 }) electron.app.quit() await atomApplication.lastBeforeQuitPromise assert(atomApplication.getAllWindows().length === 1) // Choosing "Don't save" - mockElectronShowMessageBox({response: 2}) + mockElectronShowMessageBox({ response: 2 }) electron.app.quit() await atomApplication.lastBeforeQuitPromise assert(atomApplication.getAllWindows().length === 0) @@ -650,24 +883,35 @@ describe('AtomApplication', function () { await window.closedPromise atomApplication.emit('application:open') - await conditionPromise(() => atomApplication.promptForPathToOpen.calledWith('all')) + await conditionPromise(() => + atomApplication.promptForPathToOpen.calledWith('all') + ) atomApplication.promptForPathToOpen.reset() atomApplication.emit('application:open-file') - await conditionPromise(() => atomApplication.promptForPathToOpen.calledWith('file')) + await conditionPromise(() => + atomApplication.promptForPathToOpen.calledWith('file') + ) atomApplication.promptForPathToOpen.reset() atomApplication.emit('application:open-folder') - await conditionPromise(() => atomApplication.promptForPathToOpen.calledWith('folder')) + await conditionPromise(() => + atomApplication.promptForPathToOpen.calledWith('folder') + ) atomApplication.promptForPathToOpen.reset() }) } function buildAtomApplication (params = {}) { - const atomApplication = new AtomApplication(Object.assign({ - resourcePath: ATOM_RESOURCE_PATH, - atomHomeDirPath: process.env.ATOM_HOME - }, params)) + const atomApplication = new AtomApplication( + Object.assign( + { + resourcePath: ATOM_RESOURCE_PATH, + atomHomeDirPath: process.env.ATOM_HOME + }, + params + ) + ) atomApplicationsToDestroy.push(atomApplication) return atomApplication } @@ -675,7 +919,9 @@ describe('AtomApplication', function () { async function focusWindow (window) { window.focus() await window.loadedPromise - await conditionPromise(() => window.atomApplication.getLastFocusedWindow() === window) + await conditionPromise( + () => window.atomApplication.getLastFocusedWindow() === window + ) } function mockElectronAppQuit () { @@ -684,7 +930,11 @@ describe('AtomApplication', function () { electron.app.quit = function () { this.quit.callCount++ let defaultPrevented = false - this.emit('before-quit', {preventDefault () { defaultPrevented = true }}) + this.emit('before-quit', { + preventDefault () { + defaultPrevented = true + } + }) if (!defaultPrevented) didQuit = true } @@ -693,7 +943,7 @@ describe('AtomApplication', function () { electron.app.didQuit = () => didQuit } - function mockElectronShowMessageBox ({response}) { + function mockElectronShowMessageBox ({ response }) { electron.dialog.showMessageBox = (window, options, callback) => { callback(response) } @@ -718,7 +968,9 @@ describe('AtomApplication', function () { function sendBackToMainProcess (result) { require('electron').ipcRenderer.send('${channelId}', result) } - (${source})(sendBackToMainProcess, ${args.map(JSON.stringify).join(', ')}) + (${source})(sendBackToMainProcess, ${args + .map(JSON.stringify) + .join(', ')}) ` // console.log(`about to execute:\n${js}`) @@ -727,19 +979,24 @@ describe('AtomApplication', function () { } function getTreeViewRootDirectories (atomWindow) { - return evalInWebContents(atomWindow.browserWindow.webContents, sendBackToMainProcess => { - atom.workspace.getLeftDock().observeActivePaneItem((treeView) => { - if (treeView) { - sendBackToMainProcess( - Array - .from(treeView.element.querySelectorAll('.project-root > .header .name')) - .map(element => element.dataset.path) - ) - } else { - sendBackToMainProcess([]) - } - }) - }) + return evalInWebContents( + atomWindow.browserWindow.webContents, + sendBackToMainProcess => { + atom.workspace.getLeftDock().observeActivePaneItem(treeView => { + if (treeView) { + sendBackToMainProcess( + Array.from( + treeView.element.querySelectorAll( + '.project-root > .header .name' + ) + ).map(element => element.dataset.path) + ) + } else { + sendBackToMainProcess([]) + } + }) + } + ) } function clearElectronSession () { diff --git a/spec/main-process/file-recovery-service.test.js b/spec/main-process/file-recovery-service.test.js index 45c10c25b..25484f6c2 100644 --- a/spec/main-process/file-recovery-service.test.js +++ b/spec/main-process/file-recovery-service.test.js @@ -1,13 +1,13 @@ -const {dialog} = require('electron') +const { dialog } = require('electron') const FileRecoveryService = require('../../src/main-process/file-recovery-service') const fs = require('fs-plus') const fsreal = require('fs') const EventEmitter = require('events').EventEmitter const sinon = require('sinon') -const {escapeRegExp} = require('underscore-plus') +const { escapeRegExp } = require('underscore-plus') const temp = require('temp').track() -describe("FileRecoveryService", () => { +describe('FileRecoveryService', () => { let recoveryService, recoveryDirectory, spies beforeEach(() => { @@ -25,90 +25,90 @@ describe("FileRecoveryService", () => { } }) - describe("when no crash happens during a save", () => { - it("creates a recovery file and deletes it after saving", async () => { + describe('when no crash happens during a save', () => { + it('creates a recovery file and deletes it after saving', async () => { const mockWindow = {} const filePath = temp.path() - fs.writeFileSync(filePath, "some content") + fs.writeFileSync(filePath, 'some content') await recoveryService.willSavePath(mockWindow, filePath) assert.equal(fs.listTreeSync(recoveryDirectory).length, 1) - fs.writeFileSync(filePath, "changed") + fs.writeFileSync(filePath, 'changed') await recoveryService.didSavePath(mockWindow, filePath) assert.equal(fs.listTreeSync(recoveryDirectory).length, 0) - assert.equal(fs.readFileSync(filePath, 'utf8'), "changed") + assert.equal(fs.readFileSync(filePath, 'utf8'), 'changed') fs.removeSync(filePath) }) - it("creates only one recovery file when many windows attempt to save the same file, deleting it when the last one finishes saving it", async () => { + it('creates only one recovery file when many windows attempt to save the same file, deleting it when the last one finishes saving it', async () => { const mockWindow = {} const anotherMockWindow = {} const filePath = temp.path() - fs.writeFileSync(filePath, "some content") + fs.writeFileSync(filePath, 'some content') await recoveryService.willSavePath(mockWindow, filePath) await recoveryService.willSavePath(anotherMockWindow, filePath) assert.equal(fs.listTreeSync(recoveryDirectory).length, 1) - fs.writeFileSync(filePath, "changed") + fs.writeFileSync(filePath, 'changed') await recoveryService.didSavePath(mockWindow, filePath) assert.equal(fs.listTreeSync(recoveryDirectory).length, 1) - assert.equal(fs.readFileSync(filePath, 'utf8'), "changed") + assert.equal(fs.readFileSync(filePath, 'utf8'), 'changed') await recoveryService.didSavePath(anotherMockWindow, filePath) assert.equal(fs.listTreeSync(recoveryDirectory).length, 0) - assert.equal(fs.readFileSync(filePath, 'utf8'), "changed") + assert.equal(fs.readFileSync(filePath, 'utf8'), 'changed') fs.removeSync(filePath) }) }) - describe("when a crash happens during a save", () => { - it("restores the created recovery file and deletes it", async () => { + describe('when a crash happens during a save', () => { + it('restores the created recovery file and deletes it', async () => { const mockWindow = {} const filePath = temp.path() - fs.writeFileSync(filePath, "some content") + fs.writeFileSync(filePath, 'some content') await recoveryService.willSavePath(mockWindow, filePath) assert.equal(fs.listTreeSync(recoveryDirectory).length, 1) - fs.writeFileSync(filePath, "changed") + fs.writeFileSync(filePath, 'changed') await recoveryService.didCrashWindow(mockWindow) assert.equal(fs.listTreeSync(recoveryDirectory).length, 0) - assert.equal(fs.readFileSync(filePath, 'utf8'), "some content") + assert.equal(fs.readFileSync(filePath, 'utf8'), 'some content') fs.removeSync(filePath) }) - it("restores the created recovery file when many windows attempt to save the same file and one of them crashes", async () => { + it('restores the created recovery file when many windows attempt to save the same file and one of them crashes', async () => { const mockWindow = {} const anotherMockWindow = {} const filePath = temp.path() - fs.writeFileSync(filePath, "A") + fs.writeFileSync(filePath, 'A') await recoveryService.willSavePath(mockWindow, filePath) - fs.writeFileSync(filePath, "B") + fs.writeFileSync(filePath, 'B') await recoveryService.willSavePath(anotherMockWindow, filePath) assert.equal(fs.listTreeSync(recoveryDirectory).length, 1) - fs.writeFileSync(filePath, "C") + fs.writeFileSync(filePath, 'C') await recoveryService.didCrashWindow(mockWindow) - assert.equal(fs.readFileSync(filePath, 'utf8'), "A") + assert.equal(fs.readFileSync(filePath, 'utf8'), 'A') assert.equal(fs.listTreeSync(recoveryDirectory).length, 0) - fs.writeFileSync(filePath, "D") + fs.writeFileSync(filePath, 'D') await recoveryService.willSavePath(mockWindow, filePath) - fs.writeFileSync(filePath, "E") + fs.writeFileSync(filePath, 'E') await recoveryService.willSavePath(anotherMockWindow, filePath) assert.equal(fs.listTreeSync(recoveryDirectory).length, 1) - fs.writeFileSync(filePath, "F") + fs.writeFileSync(filePath, 'F') await recoveryService.didCrashWindow(anotherMockWindow) - assert.equal(fs.readFileSync(filePath, 'utf8'), "D") + assert.equal(fs.readFileSync(filePath, 'utf8'), 'D') assert.equal(fs.listTreeSync(recoveryDirectory).length, 0) fs.removeSync(filePath) @@ -117,10 +117,10 @@ describe("FileRecoveryService", () => { it("emits a warning when a file can't be recovered", async () => { const mockWindow = {} const filePath = temp.path() - fs.writeFileSync(filePath, "content") + fs.writeFileSync(filePath, 'content') let logs = [] - spies.stub(console, 'log', (message) => logs.push(message)) + spies.stub(console, 'log', message => logs.push(message)) spies.stub(dialog, 'showMessageBox') // Copy files to be recovered before mocking fs.createWriteStream @@ -130,9 +130,15 @@ describe("FileRecoveryService", () => { // attempting to copy the recovered file to its original location var fakeEmitter = new EventEmitter() var onStub = spies.stub(fakeEmitter, 'on') - onStub.withArgs('error').yields(new Error('Nope')).returns(fakeEmitter) + onStub + .withArgs('error') + .yields(new Error('Nope')) + .returns(fakeEmitter) onStub.withArgs('open').returns(fakeEmitter) - spies.stub(fsreal, 'createWriteStream').withArgs(filePath).returns(fakeEmitter) + spies + .stub(fsreal, 'createWriteStream') + .withArgs(filePath) + .returns(fakeEmitter) await recoveryService.didCrashWindow(mockWindow) let recoveryFiles = fs.listTreeSync(recoveryDirectory) @@ -148,10 +154,10 @@ describe("FileRecoveryService", () => { it("doesn't create a recovery file when the file that's being saved doesn't exist yet", async () => { const mockWindow = {} - await recoveryService.willSavePath(mockWindow, "a-file-that-doesnt-exist") + await recoveryService.willSavePath(mockWindow, 'a-file-that-doesnt-exist') assert.equal(fs.listTreeSync(recoveryDirectory).length, 0) - await recoveryService.didSavePath(mockWindow, "a-file-that-doesnt-exist") + await recoveryService.didSavePath(mockWindow, 'a-file-that-doesnt-exist') assert.equal(fs.listTreeSync(recoveryDirectory).length, 0) }) }) diff --git a/spec/main-process/mocha-test-runner.js b/spec/main-process/mocha-test-runner.js index 61d533417..ef8ef69ef 100644 --- a/spec/main-process/mocha-test-runner.js +++ b/spec/main-process/mocha-test-runner.js @@ -1,9 +1,8 @@ const Mocha = require('mocha') const fs = require('fs-plus') -const {assert} = require('chai') +const { assert } = require('chai') -module.exports = -function (testPaths) { +module.exports = function (testPaths) { global.assert = assert let reporterOptions = { diff --git a/spec/main-process/parse-command-line.test.js b/spec/main-process/parse-command-line.test.js index bb5d625a9..2fcece469 100644 --- a/spec/main-process/parse-command-line.test.js +++ b/spec/main-process/parse-command-line.test.js @@ -3,7 +3,14 @@ const parseCommandLine = require('../../src/main-process/parse-command-line') describe('parseCommandLine', () => { describe('when --uri-handler is not passed', () => { it('parses arguments as normal', () => { - const args = parseCommandLine(['-d', '--safe', '--test', '/some/path', 'atom://test/url', 'atom://other/url']) + const args = parseCommandLine([ + '-d', + '--safe', + '--test', + '/some/path', + 'atom://test/url', + 'atom://other/url' + ]) assert.isTrue(args.devMode) assert.isTrue(args.safeMode) assert.isTrue(args.test) @@ -14,7 +21,15 @@ describe('parseCommandLine', () => { describe('when --uri-handler is passed', () => { it('ignores other arguments and limits to one URL', () => { - const args = parseCommandLine(['-d', '--uri-handler', '--safe', '--test', '/some/path', 'atom://test/url', 'atom://other/url']) + const args = parseCommandLine([ + '-d', + '--uri-handler', + '--safe', + '--test', + '/some/path', + 'atom://test/url', + 'atom://other/url' + ]) assert.isUndefined(args.devMode) assert.isUndefined(args.safeMode) assert.isUndefined(args.test) diff --git a/spec/menu-sort-helpers-spec.js b/spec/menu-sort-helpers-spec.js index 86f00b37e..0e63824ff 100644 --- a/spec/menu-sort-helpers-spec.js +++ b/spec/menu-sort-helpers-spec.js @@ -1,4 +1,4 @@ -const {sortMenuItems} = require('../src/menu-sort-helpers') +const { sortMenuItems } = require('../src/menu-sort-helpers') describe('contextMenu', () => { describe('dedupes separators', () => { @@ -18,7 +18,8 @@ describe('contextMenu', () => { it('preserves separators at the begining of set two', () => { const items = [ { command: 'core:one' }, - { type: 'separator' }, { command: 'core:two' } + { type: 'separator' }, + { command: 'core:two' } ] const expected = [ { command: 'core:one' }, @@ -36,8 +37,10 @@ describe('contextMenu', () => { it('removes duplicate separators across sets', () => { const items = [ - { command: 'core:one' }, { type: 'separator' }, - { type: 'separator' }, { command: 'core:two' } + { command: 'core:one' }, + { type: 'separator' }, + { type: 'separator' }, + { command: 'core:two' } ] const expected = [ { command: 'core:one' }, diff --git a/spec/native-watcher-registry-spec.js b/spec/native-watcher-registry-spec.js index bc657f496..c83028c73 100644 --- a/spec/native-watcher-registry-spec.js +++ b/spec/native-watcher-registry-spec.js @@ -1,11 +1,11 @@ /** @babel */ -import {it, beforeEach} from './async-spec-helpers' +import { it, beforeEach } from './async-spec-helpers' import path from 'path' -import {Emitter} from 'event-kit' +import { Emitter } from 'event-kit' -import {NativeWatcherRegistry} from '../src/native-watcher-registry' +import { NativeWatcherRegistry } from '../src/native-watcher-registry' function findRootDirectory () { let current = process.cwd() @@ -42,7 +42,9 @@ class MockWatcher { attachToNative (native, nativePath) { if (this.normalizedPath.startsWith(nativePath)) { if (this.native) { - this.native.attached = this.native.attached.filter(each => each !== this) + this.native.attached = this.native.attached.filter( + each => each !== this + ) } this.native = native this.native.attached.push(this) @@ -84,7 +86,9 @@ describe('NativeWatcherRegistry', function () { let createNative, registry beforeEach(function () { - registry = new NativeWatcherRegistry(normalizedPath => createNative(normalizedPath)) + registry = new NativeWatcherRegistry(normalizedPath => + createNative(normalizedPath) + ) }) it('attaches a Watcher to a newly created NativeWatcher for a new directory', async function () { @@ -201,9 +205,20 @@ describe('NativeWatcherRegistry', function () { const RUNNING = new MockNative('running') const stoppedPath = absolute('watcher', 'that', 'will', 'be', 'stopped') - const stoppedPathParts = stoppedPath.split(path.sep).filter(part => part.length > 0) - const runningPath = absolute('watcher', 'that', 'will', 'continue', 'to', 'exist') - const runningPathParts = runningPath.split(path.sep).filter(part => part.length > 0) + const stoppedPathParts = stoppedPath + .split(path.sep) + .filter(part => part.length > 0) + const runningPath = absolute( + 'watcher', + 'that', + 'will', + 'continue', + 'to', + 'exist' + ) + const runningPathParts = runningPath + .split(path.sep) + .filter(part => part.length > 0) createNative = dir => { if (dir === stoppedPath) { @@ -281,23 +296,29 @@ describe('NativeWatcherRegistry', function () { expect(childWatcher0.native).toBe(CHILD0) expect(childWatcher1.native).toBe(CHILD1) - expect(registry.tree.root.lookup(parts(parentDir)).when({ - parent: () => false, - missing: () => false, - children: () => true - })).toBe(true) + expect( + registry.tree.root.lookup(parts(parentDir)).when({ + parent: () => false, + missing: () => false, + children: () => true + }) + ).toBe(true) - expect(registry.tree.root.lookup(parts(childDir0)).when({ - parent: () => true, - missing: () => false, - children: () => false - })).toBe(true) + expect( + registry.tree.root.lookup(parts(childDir0)).when({ + parent: () => true, + missing: () => false, + children: () => false + }) + ).toBe(true) - expect(registry.tree.root.lookup(parts(childDir1)).when({ - parent: () => true, - missing: () => false, - children: () => false - })).toBe(true) + expect( + registry.tree.root.lookup(parts(childDir1)).when({ + parent: () => true, + missing: () => false, + children: () => false + }) + ).toBe(true) }) it('consolidates children when splitting a parent watcher', async function () { @@ -340,23 +361,29 @@ describe('NativeWatcherRegistry', function () { expect(childWatcher0.native).toBe(CHILD0) expect(childWatcher1.native).toBe(CHILD0) - expect(registry.tree.root.lookup(parts(parentDir)).when({ - parent: () => false, - missing: () => false, - children: () => true - })).toBe(true) + expect( + registry.tree.root.lookup(parts(parentDir)).when({ + parent: () => false, + missing: () => false, + children: () => true + }) + ).toBe(true) - expect(registry.tree.root.lookup(parts(childDir0)).when({ - parent: () => true, - missing: () => false, - children: () => false - })).toBe(true) + expect( + registry.tree.root.lookup(parts(childDir0)).when({ + parent: () => true, + missing: () => false, + children: () => false + }) + ).toBe(true) - expect(registry.tree.root.lookup(parts(childDir1)).when({ - parent: () => true, - missing: () => false, - children: () => false - })).toBe(true) + expect( + registry.tree.root.lookup(parts(childDir1)).when({ + parent: () => true, + missing: () => false, + children: () => false + }) + ).toBe(true) }) }) }) diff --git a/spec/notification-manager-spec.js b/spec/notification-manager-spec.js index 3a8544d4e..3fd91d0ca 100644 --- a/spec/notification-manager-spec.js +++ b/spec/notification-manager-spec.js @@ -10,8 +10,7 @@ describe('NotificationManager', () => { describe('the atom global', () => it('has a notifications instance', () => { expect(atom.notifications instanceof NotificationManager).toBe(true) - }) - ) + })) describe('adding events', () => { let addSpy @@ -22,7 +21,7 @@ describe('NotificationManager', () => { }) it('emits an event when a notification has been added', () => { - manager.add('error', 'Some error!', {icon: 'someIcon'}) + manager.add('error', 'Some error!', { icon: 'someIcon' }) expect(addSpy).toHaveBeenCalled() const notification = addSpy.mostRecentCall.args[0] @@ -32,35 +31,35 @@ describe('NotificationManager', () => { }) it('emits a fatal error when ::addFatalError has been called', () => { - manager.addFatalError('Some error!', {icon: 'someIcon'}) + manager.addFatalError('Some error!', { icon: 'someIcon' }) expect(addSpy).toHaveBeenCalled() const notification = addSpy.mostRecentCall.args[0] expect(notification.getType()).toBe('fatal') }) it('emits an error when ::addError has been called', () => { - manager.addError('Some error!', {icon: 'someIcon'}) + manager.addError('Some error!', { icon: 'someIcon' }) expect(addSpy).toHaveBeenCalled() const notification = addSpy.mostRecentCall.args[0] expect(notification.getType()).toBe('error') }) it('emits a warning notification when ::addWarning has been called', () => { - manager.addWarning('Something!', {icon: 'someIcon'}) + manager.addWarning('Something!', { icon: 'someIcon' }) expect(addSpy).toHaveBeenCalled() const notification = addSpy.mostRecentCall.args[0] expect(notification.getType()).toBe('warning') }) it('emits an info notification when ::addInfo has been called', () => { - manager.addInfo('Something!', {icon: 'someIcon'}) + manager.addInfo('Something!', { icon: 'someIcon' }) expect(addSpy).toHaveBeenCalled() const notification = addSpy.mostRecentCall.args[0] expect(notification.getType()).toBe('info') }) it('emits a success notification when ::addSuccess has been called', () => { - manager.addSuccess('Something!', {icon: 'someIcon'}) + manager.addSuccess('Something!', { icon: 'someIcon' }) expect(addSpy).toHaveBeenCalled() const notification = addSpy.mostRecentCall.args[0] expect(notification.getType()).toBe('success') diff --git a/spec/notification-spec.js b/spec/notification-spec.js index 4702cd13d..179f70950 100644 --- a/spec/notification-spec.js +++ b/spec/notification-spec.js @@ -20,8 +20,7 @@ describe('Notification', () => { it('returns a Date object', () => { const notification = new Notification('error', 'message!') expect(notification.getTimestamp() instanceof Date).toBe(true) - }) - ) + })) describe('::getIcon()', () => { it('returns a default when no icon specified', () => { @@ -30,7 +29,9 @@ describe('Notification', () => { }) it('returns the icon specified', () => { - const notification = new Notification('error', 'message!', {icon: 'my-icon'}) + const notification = new Notification('error', 'message!', { + icon: 'my-icon' + }) expect(notification.getIcon()).toBe('my-icon') }) }) @@ -39,7 +40,9 @@ describe('Notification', () => { describe('when the notfication is dismissable', () => it('calls a callback when the notification is dismissed', () => { const dismissedSpy = jasmine.createSpy() - const notification = new Notification('error', 'message', {dismissable: true}) + const notification = new Notification('error', 'message', { + dismissable: true + }) notification.onDidDismiss(dismissedSpy) expect(notification.isDismissable()).toBe(true) @@ -49,8 +52,7 @@ describe('Notification', () => { expect(dismissedSpy).toHaveBeenCalled() expect(notification.isDismissed()).toBe(true) - }) - ) + })) describe('when the notfication is not dismissable', () => it('does nothing when ::dismiss() is called', () => { @@ -65,7 +67,6 @@ describe('Notification', () => { expect(dismissedSpy).not.toHaveBeenCalled() expect(notification.isDismissed()).toBe(true) - }) - ) + })) }) }) diff --git a/spec/package-manager-spec.js b/spec/package-manager-spec.js index dd87f85fa..9dec5bde6 100644 --- a/spec/package-manager-spec.js +++ b/spec/package-manager-spec.js @@ -4,11 +4,11 @@ const Package = require('../src/package') const PackageManager = require('../src/package-manager') const temp = require('temp').track() const fs = require('fs-plus') -const {Disposable} = require('atom') -const {buildKeydownEvent} = require('../src/keymap-extensions') -const {mockLocalStorage} = require('./spec-helper') +const { Disposable } = require('atom') +const { buildKeydownEvent } = require('../src/keymap-extensions') +const { mockLocalStorage } = require('./spec-helper') const ModuleCache = require('../src/module-cache') -const {it, fit, ffit, beforeEach, afterEach} = require('./async-spec-helpers') +const { it, fit, ffit, beforeEach, afterEach } = require('./async-spec-helpers') describe('PackageManager', () => { function createTestElement (className) { @@ -25,20 +25,28 @@ describe('PackageManager', () => { it('adds regular package path', () => { const packageManger = new PackageManager({}) const configDirPath = path.join('~', 'someConfig') - packageManger.initialize({configDirPath}) + packageManger.initialize({ configDirPath }) expect(packageManger.packageDirPaths.length).toBe(1) - expect(packageManger.packageDirPaths[0]).toBe(path.join(configDirPath, 'packages')) + expect(packageManger.packageDirPaths[0]).toBe( + path.join(configDirPath, 'packages') + ) }) it('adds regular package path, dev package path, and Atom repo package path in dev mode and dev resource path is set', () => { const packageManger = new PackageManager({}) const configDirPath = path.join('~', 'someConfig') const resourcePath = path.join('~', '/atom') - packageManger.initialize({configDirPath, resourcePath, devMode: true}) + packageManger.initialize({ configDirPath, resourcePath, devMode: true }) expect(packageManger.packageDirPaths.length).toBe(3) - expect(packageManger.packageDirPaths).toContain(path.join(configDirPath, 'packages')) - expect(packageManger.packageDirPaths).toContain(path.join(configDirPath, 'dev', 'packages')) - expect(packageManger.packageDirPaths).toContain(path.join(resourcePath, 'packages')) + expect(packageManger.packageDirPaths).toContain( + path.join(configDirPath, 'packages') + ) + expect(packageManger.packageDirPaths).toContain( + path.join(configDirPath, 'dev', 'packages') + ) + expect(packageManger.packageDirPaths).toContain( + path.join(resourcePath, 'packages') + ) }) }) @@ -102,43 +110,62 @@ describe('PackageManager', () => { atom.notifications.onDidAddNotification(addErrorHandler) expect(() => pack.reloadStylesheets()).not.toThrow() expect(addErrorHandler.callCount).toBe(2) - expect(addErrorHandler.argsForCall[1][0].message).toContain('Failed to reload the package-with-invalid-styles package stylesheets') - expect(addErrorHandler.argsForCall[1][0].options.packageName).toEqual('package-with-invalid-styles') + expect(addErrorHandler.argsForCall[1][0].message).toContain( + 'Failed to reload the package-with-invalid-styles package stylesheets' + ) + expect(addErrorHandler.argsForCall[1][0].options.packageName).toEqual( + 'package-with-invalid-styles' + ) }) it('returns null if the package has an invalid package.json', () => { spyOn(atom, 'inSpecMode').andReturn(false) const addErrorHandler = jasmine.createSpy() atom.notifications.onDidAddNotification(addErrorHandler) - expect(atom.packages.loadPackage('package-with-broken-package-json')).toBeNull() + expect( + atom.packages.loadPackage('package-with-broken-package-json') + ).toBeNull() expect(addErrorHandler.callCount).toBe(1) - expect(addErrorHandler.argsForCall[0][0].message).toContain('Failed to load the package-with-broken-package-json package') - expect(addErrorHandler.argsForCall[0][0].options.packageName).toEqual('package-with-broken-package-json') + expect(addErrorHandler.argsForCall[0][0].message).toContain( + 'Failed to load the package-with-broken-package-json package' + ) + expect(addErrorHandler.argsForCall[0][0].options.packageName).toEqual( + 'package-with-broken-package-json' + ) }) it('returns null if the package name or path starts with a dot', () => { - expect(atom.packages.loadPackage('/Users/user/.atom/packages/.git')).toBeNull() + expect( + atom.packages.loadPackage('/Users/user/.atom/packages/.git') + ).toBeNull() }) it('normalizes short repository urls in package.json', () => { - let {metadata} = atom.packages.loadPackage('package-with-short-url-package-json') + let { metadata } = atom.packages.loadPackage( + 'package-with-short-url-package-json' + ) expect(metadata.repository.type).toBe('git') - expect(metadata.repository.url).toBe('https://github.com/example/repo'); - - ({metadata} = atom.packages.loadPackage('package-with-invalid-url-package-json')) + expect(metadata.repository.url).toBe('https://github.com/example/repo') + ;({ metadata } = atom.packages.loadPackage( + 'package-with-invalid-url-package-json' + )) expect(metadata.repository.type).toBe('git') expect(metadata.repository.url).toBe('foo') }) it('trims git+ from the beginning and .git from the end of repository URLs, even if npm already normalized them ', () => { - const {metadata} = atom.packages.loadPackage('package-with-prefixed-and-suffixed-repo-url') + const { metadata } = atom.packages.loadPackage( + 'package-with-prefixed-and-suffixed-repo-url' + ) expect(metadata.repository.type).toBe('git') expect(metadata.repository.url).toBe('https://github.com/example/repo') }) it('returns null if the package is not found in any package directory', () => { spyOn(console, 'warn') - expect(atom.packages.loadPackage('this-package-cannot-be-found')).toBeNull() + expect( + atom.packages.loadPackage('this-package-cannot-be-found') + ).toBeNull() expect(console.warn.callCount).toBe(1) expect(console.warn.argsForCall[0][0]).toContain('Could not resolve') }) @@ -146,11 +173,23 @@ describe('PackageManager', () => { describe('when the package is deprecated', () => { it('returns null', () => { spyOn(console, 'warn') - expect(atom.packages.loadPackage(path.join(__dirname, 'fixtures', 'packages', 'wordcount'))).toBeNull() - expect(atom.packages.isDeprecatedPackage('wordcount', '2.1.9')).toBe(true) - expect(atom.packages.isDeprecatedPackage('wordcount', '2.2.0')).toBe(true) - expect(atom.packages.isDeprecatedPackage('wordcount', '2.2.1')).toBe(false) - expect(atom.packages.getDeprecatedPackageMetadata('wordcount').version).toBe('<=2.2.0') + expect( + atom.packages.loadPackage( + path.join(__dirname, 'fixtures', 'packages', 'wordcount') + ) + ).toBeNull() + expect(atom.packages.isDeprecatedPackage('wordcount', '2.1.9')).toBe( + true + ) + expect(atom.packages.isDeprecatedPackage('wordcount', '2.2.0')).toBe( + true + ) + expect(atom.packages.isDeprecatedPackage('wordcount', '2.2.1')).toBe( + false + ) + expect( + atom.packages.getDeprecatedPackageMetadata('wordcount').version + ).toBe('<=2.2.0') }) }) @@ -169,13 +208,13 @@ describe('PackageManager', () => { it("registers any deserializers specified in the package's package.json", () => { atom.packages.loadPackage('package-with-deserializers') - const state1 = {deserializer: 'Deserializer1', a: 'b'} + const state1 = { deserializer: 'Deserializer1', a: 'b' } expect(atom.deserializers.deserialize(state1)).toEqual({ wasDeserializedBy: 'deserializeMethod1', state: state1 }) - const state2 = {deserializer: 'Deserializer2', c: 'd'} + const state2 = { deserializer: 'Deserializer2', c: 'd' } expect(atom.deserializers.deserialize(state2)).toEqual({ wasDeserializedBy: 'deserializeMethod2', state: state2 @@ -186,15 +225,21 @@ describe('PackageManager', () => { jasmine.useRealClock() const providers = [] - atom.packages.serviceHub.consume('atom.directory-provider', '^0.1.0', provider => providers.push(provider)) + atom.packages.serviceHub.consume( + 'atom.directory-provider', + '^0.1.0', + provider => providers.push(provider) + ) atom.packages.loadPackage('package-with-directory-provider') - expect(providers.map(p => p.name)).toEqual(['directory provider from package-with-directory-provider']) + expect(providers.map(p => p.name)).toEqual([ + 'directory provider from package-with-directory-provider' + ]) }) describe("when there are view providers specified in the package's package.json", () => { - const model1 = {worksWithViewProvider1: true} - const model2 = {worksWithViewProvider2: true} + const model1 = { worksWithViewProvider1: true } + const model2 = { worksWithViewProvider2: true } afterEach(async () => { await atom.packages.deactivatePackage('package-with-view-providers') @@ -254,8 +299,8 @@ describe('PackageManager', () => { expect(atom.config.getSchema('package-with-json-config-schema')).toEqual({ type: 'object', properties: { - a: {type: 'number', default: 5}, - b: {type: 'string', default: 'five'} + a: { type: 'number', default: 5 }, + b: { type: 'string', default: 'five' } } }) @@ -268,8 +313,8 @@ describe('PackageManager', () => { expect(atom.config.getSchema('package-with-json-config-schema')).toEqual({ type: 'object', properties: { - a: {type: 'number', default: 5}, - b: {type: 'string', default: 'five'} + a: { type: 'number', default: 5 }, + b: { type: 'string', default: 'five' } } }) }) @@ -288,12 +333,16 @@ describe('PackageManager', () => { }) it("does not defer loading the package's main module if the package previously used Atom APIs when its main module was required", () => { - const pack1 = atom.packages.loadPackage('package-with-eval-time-api-calls') + const pack1 = atom.packages.loadPackage( + 'package-with-eval-time-api-calls' + ) expect(pack1.mainModule).toBeDefined() atom.packages.unloadPackage('package-with-eval-time-api-calls') - const pack2 = atom.packages.loadPackage('package-with-eval-time-api-calls') + const pack2 = atom.packages.loadPackage( + 'package-with-eval-time-api-calls' + ) expect(pack2.mainModule).not.toBeNull() }) }) @@ -302,35 +351,49 @@ describe('PackageManager', () => { describe('::loadAvailablePackage(availablePackage)', () => { describe('if the package was preloaded', () => { it('adds the package path to the module cache', () => { - const availablePackage = atom.packages.getAvailablePackages().find(p => p.name === 'spell-check') + const availablePackage = atom.packages + .getAvailablePackages() + .find(p => p.name === 'spell-check') availablePackage.isBundled = true - expect(atom.packages.preloadedPackages[availablePackage.name]).toBeUndefined() + expect( + atom.packages.preloadedPackages[availablePackage.name] + ).toBeUndefined() expect(atom.packages.isPackageLoaded(availablePackage.name)).toBe(false) const metadata = atom.packages.loadPackageMetadata(availablePackage) - atom.packages.preloadPackage( - availablePackage.name, - { - rootDirPath: path.relative(atom.packages.resourcePath, availablePackage.path), - metadata - } - ) + atom.packages.preloadPackage(availablePackage.name, { + rootDirPath: path.relative( + atom.packages.resourcePath, + availablePackage.path + ), + metadata + }) atom.packages.loadAvailablePackage(availablePackage) expect(atom.packages.isPackageLoaded(availablePackage.name)).toBe(true) - expect(ModuleCache.add).toHaveBeenCalledWith(availablePackage.path, metadata) + expect(ModuleCache.add).toHaveBeenCalledWith( + availablePackage.path, + metadata + ) }) it('deactivates it if it had been disabled', () => { - const availablePackage = atom.packages.getAvailablePackages().find(p => p.name === 'spell-check') + const availablePackage = atom.packages + .getAvailablePackages() + .find(p => p.name === 'spell-check') availablePackage.isBundled = true - expect(atom.packages.preloadedPackages[availablePackage.name]).toBeUndefined() + expect( + atom.packages.preloadedPackages[availablePackage.name] + ).toBeUndefined() expect(atom.packages.isPackageLoaded(availablePackage.name)).toBe(false) const metadata = atom.packages.loadPackageMetadata(availablePackage) const preloadedPackage = atom.packages.preloadPackage( availablePackage.name, { - rootDirPath: path.relative(atom.packages.resourcePath, availablePackage.path), + rootDirPath: path.relative( + atom.packages.resourcePath, + availablePackage.path + ), metadata } ) @@ -338,7 +401,10 @@ describe('PackageManager', () => { expect(preloadedPackage.settingsActivated).toBe(true) expect(preloadedPackage.menusActivated).toBe(true) - atom.packages.loadAvailablePackage(availablePackage, new Set([availablePackage.name])) + atom.packages.loadAvailablePackage( + availablePackage, + new Set([availablePackage.name]) + ) expect(atom.packages.isPackageLoaded(availablePackage.name)).toBe(false) expect(preloadedPackage.keymapActivated).toBe(false) expect(preloadedPackage.settingsActivated).toBe(false) @@ -346,16 +412,23 @@ describe('PackageManager', () => { }) it('deactivates it and reloads the new one if trying to load the same package outside of the bundle', () => { - const availablePackage = atom.packages.getAvailablePackages().find(p => p.name === 'spell-check') + const availablePackage = atom.packages + .getAvailablePackages() + .find(p => p.name === 'spell-check') availablePackage.isBundled = true - expect(atom.packages.preloadedPackages[availablePackage.name]).toBeUndefined() + expect( + atom.packages.preloadedPackages[availablePackage.name] + ).toBeUndefined() expect(atom.packages.isPackageLoaded(availablePackage.name)).toBe(false) const metadata = atom.packages.loadPackageMetadata(availablePackage) const preloadedPackage = atom.packages.preloadPackage( availablePackage.name, { - rootDirPath: path.relative(atom.packages.resourcePath, availablePackage.path), + rootDirPath: path.relative( + atom.packages.resourcePath, + availablePackage.path + ), metadata } ) @@ -374,21 +447,30 @@ describe('PackageManager', () => { describe('if the package was not preloaded', () => { it('adds the package path to the module cache', () => { - const availablePackage = atom.packages.getAvailablePackages().find(p => p.name === 'spell-check') + const availablePackage = atom.packages + .getAvailablePackages() + .find(p => p.name === 'spell-check') availablePackage.isBundled = true const metadata = atom.packages.loadPackageMetadata(availablePackage) atom.packages.loadAvailablePackage(availablePackage) - expect(ModuleCache.add).toHaveBeenCalledWith(availablePackage.path, metadata) + expect(ModuleCache.add).toHaveBeenCalledWith( + availablePackage.path, + metadata + ) }) }) }) describe('preloading', () => { it('requires the main module, loads the config schema and activates keymaps, menus and settings without reactivating them during package activation', () => { - const availablePackage = atom.packages.getAvailablePackages().find(p => p.name === 'spell-check') + const availablePackage = atom.packages + .getAvailablePackages() + .find(p => p.name === 'spell-check') availablePackage.isBundled = true const metadata = atom.packages.loadPackageMetadata(availablePackage) - expect(atom.packages.preloadedPackages[availablePackage.name]).toBeUndefined() + expect( + atom.packages.preloadedPackages[availablePackage.name] + ).toBeUndefined() expect(atom.packages.isPackageLoaded(availablePackage.name)).toBe(false) atom.packages.packagesCache = {} @@ -399,7 +481,10 @@ describe('PackageManager', () => { const preloadedPackage = atom.packages.preloadPackage( availablePackage.name, { - rootDirPath: path.relative(atom.packages.resourcePath, availablePackage.path), + rootDirPath: path.relative( + atom.packages.resourcePath, + availablePackage.path + ), metadata } ) @@ -415,7 +500,9 @@ describe('PackageManager', () => { spyOn(atom.config, 'setSchema') atom.packages.loadAvailablePackage(availablePackage) - expect(preloadedPackage.getMainModulePath()).toBe(path.join(availablePackage.path, metadata.main)) + expect(preloadedPackage.getMainModulePath()).toBe( + path.join(availablePackage.path, metadata.main) + ) atom.packages.activatePackage(availablePackage.name) expect(atom.keymaps.add).not.toHaveBeenCalled() @@ -430,10 +517,14 @@ describe('PackageManager', () => { }) it('deactivates disabled keymaps during package activation', () => { - const availablePackage = atom.packages.getAvailablePackages().find(p => p.name === 'spell-check') + const availablePackage = atom.packages + .getAvailablePackages() + .find(p => p.name === 'spell-check') availablePackage.isBundled = true const metadata = atom.packages.loadPackageMetadata(availablePackage) - expect(atom.packages.preloadedPackages[availablePackage.name]).toBeUndefined() + expect( + atom.packages.preloadedPackages[availablePackage.name] + ).toBeUndefined() expect(atom.packages.isPackageLoaded(availablePackage.name)).toBe(false) atom.packages.packagesCache = {} @@ -444,7 +535,10 @@ describe('PackageManager', () => { const preloadedPackage = atom.packages.preloadPackage( availablePackage.name, { - rootDirPath: path.relative(atom.packages.resourcePath, availablePackage.path), + rootDirPath: path.relative( + atom.packages.resourcePath, + availablePackage.path + ), metadata } ) @@ -453,7 +547,9 @@ describe('PackageManager', () => { expect(preloadedPackage.menusActivated).toBe(true) atom.packages.loadAvailablePackage(availablePackage) - atom.config.set('core.packagesWithKeymapsDisabled', [availablePackage.name]) + atom.config.set('core.packagesWithKeymapsDisabled', [ + availablePackage.name + ]) atom.packages.activatePackage(availablePackage.name) expect(preloadedPackage.keymapActivated).toBe(false) @@ -539,14 +635,26 @@ describe('PackageManager', () => { }) it('assigns config schema, including defaults when package contains a schema', async () => { - expect(atom.config.get('package-with-config-schema.numbers.one')).toBeUndefined() + expect( + atom.config.get('package-with-config-schema.numbers.one') + ).toBeUndefined() await atom.packages.activatePackage('package-with-config-schema') - expect(atom.config.get('package-with-config-schema.numbers.one')).toBe(1) - expect(atom.config.get('package-with-config-schema.numbers.two')).toBe(2) - expect(atom.config.set('package-with-config-schema.numbers.one', 'nope')).toBe(false) - expect(atom.config.set('package-with-config-schema.numbers.one', '10')).toBe(true) - expect(atom.config.get('package-with-config-schema.numbers.one')).toBe(10) + expect(atom.config.get('package-with-config-schema.numbers.one')).toBe( + 1 + ) + expect(atom.config.get('package-with-config-schema.numbers.two')).toBe( + 2 + ) + expect( + atom.config.set('package-with-config-schema.numbers.one', 'nope') + ).toBe(false) + expect( + atom.config.set('package-with-config-schema.numbers.one', '10') + ).toBe(true) + expect(atom.config.get('package-with-config-schema.numbers.one')).toBe( + 10 + ) }) describe('when the package metadata includes `activationCommands`', () => { @@ -559,10 +667,18 @@ describe('PackageManager', () => { spyOn(mainModule, 'activate').andCallThrough() spyOn(Package.prototype, 'requireMainModule').andCallThrough() - workspaceCommandListener = jasmine.createSpy('workspaceCommandListener') - registration = atom.commands.add('.workspace', 'activation-command', workspaceCommandListener) + workspaceCommandListener = jasmine.createSpy( + 'workspaceCommandListener' + ) + registration = atom.commands.add( + '.workspace', + 'activation-command', + workspaceCommandListener + ) - promise = atom.packages.activatePackage('package-with-activation-commands') + promise = atom.packages.activatePackage( + 'package-with-activation-commands' + ) }) afterEach(() => { @@ -575,7 +691,11 @@ describe('PackageManager', () => { it('defers requiring/activating the main module until an activation event bubbles to the root view', async () => { expect(Package.prototype.requireMainModule.callCount).toBe(0) - atom.workspace.getElement().dispatchEvent(new CustomEvent('activation-command', {bubbles: true})) + atom.workspace + .getElement() + .dispatchEvent( + new CustomEvent('activation-command', { bubbles: true }) + ) await promise expect(Package.prototype.requireMainModule.callCount).toBe(1) @@ -584,9 +704,17 @@ describe('PackageManager', () => { it('triggers the activation event on all handlers registered during activation', async () => { await atom.workspace.open() - const editorElement = atom.workspace.getActiveTextEditor().getElement() - const editorCommandListener = jasmine.createSpy('editorCommandListener') - atom.commands.add('atom-text-editor', 'activation-command', editorCommandListener) + const editorElement = atom.workspace + .getActiveTextEditor() + .getElement() + const editorCommandListener = jasmine.createSpy( + 'editorCommandListener' + ) + atom.commands.add( + 'atom-text-editor', + 'activation-command', + editorCommandListener + ) atom.commands.dispatch(editorElement, 'activation-command') expect(mainModule.activate.callCount).toBe(1) @@ -605,7 +733,9 @@ describe('PackageManager', () => { mainModule = require('./fixtures/packages/package-with-empty-activation-commands/index') spyOn(mainModule, 'activate').andCallThrough() - atom.packages.activatePackage('package-with-empty-activation-commands') + atom.packages.activatePackage( + 'package-with-empty-activation-commands' + ) expect(mainModule.activate.callCount).toBe(1) }) @@ -614,54 +744,80 @@ describe('PackageManager', () => { spyOn(atom, 'inSpecMode').andReturn(false) const addErrorHandler = jasmine.createSpy() atom.notifications.onDidAddNotification(addErrorHandler) - expect(() => atom.packages.activatePackage('package-with-invalid-activation-commands')).not.toThrow() + expect(() => + atom.packages.activatePackage( + 'package-with-invalid-activation-commands' + ) + ).not.toThrow() expect(addErrorHandler.callCount).toBe(1) - expect(addErrorHandler.argsForCall[0][0].message).toContain('Failed to activate the package-with-invalid-activation-commands package') - expect(addErrorHandler.argsForCall[0][0].options.packageName).toEqual('package-with-invalid-activation-commands') + expect(addErrorHandler.argsForCall[0][0].message).toContain( + 'Failed to activate the package-with-invalid-activation-commands package' + ) + expect(addErrorHandler.argsForCall[0][0].options.packageName).toEqual( + 'package-with-invalid-activation-commands' + ) }) it('adds a notification when the context menu is invalid', () => { spyOn(atom, 'inSpecMode').andReturn(false) const addErrorHandler = jasmine.createSpy() atom.notifications.onDidAddNotification(addErrorHandler) - expect(() => atom.packages.activatePackage('package-with-invalid-context-menu')).not.toThrow() + expect(() => + atom.packages.activatePackage('package-with-invalid-context-menu') + ).not.toThrow() expect(addErrorHandler.callCount).toBe(1) - expect(addErrorHandler.argsForCall[0][0].message).toContain('Failed to activate the package-with-invalid-context-menu package') - expect(addErrorHandler.argsForCall[0][0].options.packageName).toEqual('package-with-invalid-context-menu') + expect(addErrorHandler.argsForCall[0][0].message).toContain( + 'Failed to activate the package-with-invalid-context-menu package' + ) + expect(addErrorHandler.argsForCall[0][0].options.packageName).toEqual( + 'package-with-invalid-context-menu' + ) }) it('adds a notification when the grammar is invalid', async () => { let notificationEvent await new Promise(resolve => { - const subscription = atom.notifications.onDidAddNotification(event => { - notificationEvent = event - subscription.dispose() - resolve() - }) + const subscription = atom.notifications.onDidAddNotification( + event => { + notificationEvent = event + subscription.dispose() + resolve() + } + ) atom.packages.activatePackage('package-with-invalid-grammar') }) - expect(notificationEvent.message).toContain('Failed to load a package-with-invalid-grammar package grammar') - expect(notificationEvent.options.packageName).toEqual('package-with-invalid-grammar') + expect(notificationEvent.message).toContain( + 'Failed to load a package-with-invalid-grammar package grammar' + ) + expect(notificationEvent.options.packageName).toEqual( + 'package-with-invalid-grammar' + ) }) it('adds a notification when the settings are invalid', async () => { let notificationEvent await new Promise(resolve => { - const subscription = atom.notifications.onDidAddNotification(event => { - notificationEvent = event - subscription.dispose() - resolve() - }) + const subscription = atom.notifications.onDidAddNotification( + event => { + notificationEvent = event + subscription.dispose() + resolve() + } + ) atom.packages.activatePackage('package-with-invalid-settings') }) - expect(notificationEvent.message).toContain('Failed to load the package-with-invalid-settings package settings') - expect(notificationEvent.options.packageName).toEqual('package-with-invalid-settings') + expect(notificationEvent.message).toContain( + 'Failed to load the package-with-invalid-settings package settings' + ) + expect(notificationEvent.options.packageName).toEqual( + 'package-with-invalid-settings' + ) }) }) }) @@ -710,7 +866,9 @@ describe('PackageManager', () => { expect(Package.prototype.requireMainModule.callCount).toBe(0) - await atom.packages.activatePackage('package-with-empty-activation-hooks') + await atom.packages.activatePackage( + 'package-with-empty-activation-hooks' + ) expect(mainModule.activate.callCount).toBe(1) expect(Package.prototype.requireMainModule.callCount).toBe(1) }) @@ -729,7 +887,9 @@ describe('PackageManager', () => { it('does not throw an exception', () => { spyOn(console, 'error') spyOn(console, 'warn').andCallThrough() - expect(() => atom.packages.activatePackage('package-without-module')).not.toThrow() + expect(() => + atom.packages.activatePackage('package-without-module') + ).not.toThrow() expect(console.error).not.toHaveBeenCalled() expect(console.warn).not.toHaveBeenCalled() }) @@ -744,7 +904,9 @@ describe('PackageManager', () => { }) it("passes the activate method the package's previously serialized state if it exists", async () => { - const pack = await atom.packages.activatePackage('package-with-serialization') + const pack = await atom.packages.activatePackage( + 'package-with-serialization' + ) expect(pack.mainModule.someNumber).not.toBe(77) pack.mainModule.someNumber = 77 atom.packages.serializePackage('package-with-serialization') @@ -752,7 +914,7 @@ describe('PackageManager', () => { spyOn(pack.mainModule, 'activate').andCallThrough() await atom.packages.activatePackage('package-with-serialization') - expect(pack.mainModule.activate).toHaveBeenCalledWith({someNumber: 77}) + expect(pack.mainModule.activate).toHaveBeenCalledWith({ someNumber: 77 }) }) it('invokes ::onDidActivatePackage listeners with the activated package', async () => { @@ -771,15 +933,23 @@ describe('PackageManager', () => { atom.config.set('core.disabledPackages', []) const addErrorHandler = jasmine.createSpy() atom.notifications.onDidAddNotification(addErrorHandler) - expect(() => atom.packages.activatePackage('package-that-throws-an-exception')).not.toThrow() + expect(() => + atom.packages.activatePackage('package-that-throws-an-exception') + ).not.toThrow() expect(addErrorHandler.callCount).toBe(1) - expect(addErrorHandler.argsForCall[0][0].message).toContain('Failed to load the package-that-throws-an-exception package') - expect(addErrorHandler.argsForCall[0][0].options.packageName).toEqual('package-that-throws-an-exception') + expect(addErrorHandler.argsForCall[0][0].message).toContain( + 'Failed to load the package-that-throws-an-exception package' + ) + expect(addErrorHandler.argsForCall[0][0].options.packageName).toEqual( + 'package-that-throws-an-exception' + ) }) it('re-throws the exception in test mode', () => { atom.config.set('core.disabledPackages', []) - expect(() => atom.packages.activatePackage('package-that-throws-an-exception')).toThrow('This package throws an exception') + expect(() => + atom.packages.activatePackage('package-that-throws-an-exception') + ).toThrow('This package throws an exception') }) }) @@ -793,7 +963,9 @@ describe('PackageManager', () => { expect('Error to be thrown').toBe('') } catch (error) { expect(console.warn.callCount).toBe(1) - expect(error.message).toContain("Failed to load package 'this-doesnt-exist'") + expect(error.message).toContain( + "Failed to load package 'this-doesnt-exist'" + ) } }) }) @@ -804,14 +976,44 @@ describe('PackageManager', () => { const element1 = createTestElement('test-1') const element2 = createTestElement('test-2') const element3 = createTestElement('test-3') - expect(atom.keymaps.findKeyBindings({keystrokes: 'ctrl-z', target: element1})).toHaveLength(0) - expect(atom.keymaps.findKeyBindings({keystrokes: 'ctrl-z', target: element2})).toHaveLength(0) - expect(atom.keymaps.findKeyBindings({keystrokes: 'ctrl-z', target: element3})).toHaveLength(0) + expect( + atom.keymaps.findKeyBindings({ + keystrokes: 'ctrl-z', + target: element1 + }) + ).toHaveLength(0) + expect( + atom.keymaps.findKeyBindings({ + keystrokes: 'ctrl-z', + target: element2 + }) + ).toHaveLength(0) + expect( + atom.keymaps.findKeyBindings({ + keystrokes: 'ctrl-z', + target: element3 + }) + ).toHaveLength(0) await atom.packages.activatePackage('package-with-keymaps') - expect(atom.keymaps.findKeyBindings({keystrokes: 'ctrl-z', target: element1})[0].command).toBe('test-1') - expect(atom.keymaps.findKeyBindings({keystrokes: 'ctrl-z', target: element2})[0].command).toBe('test-2') - expect(atom.keymaps.findKeyBindings({keystrokes: 'ctrl-z', target: element3})).toHaveLength(0) + expect( + atom.keymaps.findKeyBindings({ + keystrokes: 'ctrl-z', + target: element1 + })[0].command + ).toBe('test-1') + expect( + atom.keymaps.findKeyBindings({ + keystrokes: 'ctrl-z', + target: element2 + })[0].command + ).toBe('test-2') + expect( + atom.keymaps.findKeyBindings({ + keystrokes: 'ctrl-z', + target: element3 + }) + ).toHaveLength(0) }) }) @@ -819,30 +1021,64 @@ describe('PackageManager', () => { it('loads only the keymaps specified by the manifest, in the specified order', async () => { const element1 = createTestElement('test-1') const element3 = createTestElement('test-3') - expect(atom.keymaps.findKeyBindings({keystrokes: 'ctrl-z', target: element1})).toHaveLength(0) + expect( + atom.keymaps.findKeyBindings({ + keystrokes: 'ctrl-z', + target: element1 + }) + ).toHaveLength(0) await atom.packages.activatePackage('package-with-keymaps-manifest') - expect(atom.keymaps.findKeyBindings({keystrokes: 'ctrl-z', target: element1})[0].command).toBe('keymap-1') - expect(atom.keymaps.findKeyBindings({keystrokes: 'ctrl-n', target: element1})[0].command).toBe('keymap-2') - expect(atom.keymaps.findKeyBindings({keystrokes: 'ctrl-y', target: element3})).toHaveLength(0) + expect( + atom.keymaps.findKeyBindings({ + keystrokes: 'ctrl-z', + target: element1 + })[0].command + ).toBe('keymap-1') + expect( + atom.keymaps.findKeyBindings({ + keystrokes: 'ctrl-n', + target: element1 + })[0].command + ).toBe('keymap-2') + expect( + atom.keymaps.findKeyBindings({ + keystrokes: 'ctrl-y', + target: element3 + }) + ).toHaveLength(0) }) }) describe('when the keymap file is empty', () => { it('does not throw an error on activation', async () => { await atom.packages.activatePackage('package-with-empty-keymap') - expect(atom.packages.isPackageActive('package-with-empty-keymap')).toBe(true) + expect( + atom.packages.isPackageActive('package-with-empty-keymap') + ).toBe(true) }) }) describe("when the package's keymaps have been disabled", () => { it('does not add the keymaps', async () => { const element1 = createTestElement('test-1') - expect(atom.keymaps.findKeyBindings({keystrokes: 'ctrl-z', target: element1})).toHaveLength(0) + expect( + atom.keymaps.findKeyBindings({ + keystrokes: 'ctrl-z', + target: element1 + }) + ).toHaveLength(0) - atom.config.set('core.packagesWithKeymapsDisabled', ['package-with-keymaps-manifest']) + atom.config.set('core.packagesWithKeymapsDisabled', [ + 'package-with-keymaps-manifest' + ]) await atom.packages.activatePackage('package-with-keymaps-manifest') - expect(atom.keymaps.findKeyBindings({keystrokes: 'ctrl-z', target: element1})).toHaveLength(0) + expect( + atom.keymaps.findKeyBindings({ + keystrokes: 'ctrl-z', + target: element1 + }) + ).toHaveLength(0) }) }) @@ -850,8 +1086,14 @@ describe('PackageManager', () => { it("ignores package names in the array that aren't loaded", () => { atom.packages.observePackagesWithKeymapsDisabled() - expect(() => atom.config.set('core.packagesWithKeymapsDisabled', ['package-does-not-exist'])).not.toThrow() - expect(() => atom.config.set('core.packagesWithKeymapsDisabled', [])).not.toThrow() + expect(() => + atom.config.set('core.packagesWithKeymapsDisabled', [ + 'package-does-not-exist' + ]) + ).not.toThrow() + expect(() => + atom.config.set('core.packagesWithKeymapsDisabled', []) + ).not.toThrow() }) }) @@ -862,11 +1104,23 @@ describe('PackageManager', () => { await atom.packages.activatePackage('package-with-keymaps-manifest') - atom.config.set('core.packagesWithKeymapsDisabled', ['package-with-keymaps-manifest']) - expect(atom.keymaps.findKeyBindings({keystrokes: 'ctrl-z', target: element1})).toHaveLength(0) + atom.config.set('core.packagesWithKeymapsDisabled', [ + 'package-with-keymaps-manifest' + ]) + expect( + atom.keymaps.findKeyBindings({ + keystrokes: 'ctrl-z', + target: element1 + }) + ).toHaveLength(0) atom.config.set('core.packagesWithKeymapsDisabled', []) - expect(atom.keymaps.findKeyBindings({keystrokes: 'ctrl-z', target: element1})[0].command).toBe('keymap-1') + expect( + atom.keymaps.findKeyBindings({ + keystrokes: 'ctrl-z', + target: element1 + })[0].command + ).toBe('keymap-1') }) }) @@ -896,17 +1150,24 @@ describe('PackageManager', () => { }) it("doesn't override user-defined keymaps", async () => { - fs.writeFileSync(userKeymapPath, `".test-1": {"ctrl-z": "user-command"}`) + fs.writeFileSync( + userKeymapPath, + `".test-1": {"ctrl-z": "user-command"}` + ) atom.keymaps.loadUserKeymap() await atom.packages.activatePackage('package-with-keymaps') - atom.keymaps.handleKeyboardEvent(buildKeydownEvent('z', {ctrl: true, target: element})) + atom.keymaps.handleKeyboardEvent( + buildKeydownEvent('z', { ctrl: true, target: element }) + ) expect(events.length).toBe(1) expect(events[0].type).toBe('user-command') await atom.packages.deactivatePackage('package-with-keymaps') await atom.packages.activatePackage('package-with-keymaps') - atom.keymaps.handleKeyboardEvent(buildKeydownEvent('z', {ctrl: true, target: element})) + atom.keymaps.handleKeyboardEvent( + buildKeydownEvent('z', { ctrl: true, target: element }) + ) expect(events.length).toBe(2) expect(events[1].type).toBe('user-command') }) @@ -928,9 +1189,15 @@ describe('PackageManager', () => { expect(atom.menu.template.length).toBe(2) expect(atom.menu.template[0].label).toBe('Second to Last') expect(atom.menu.template[1].label).toBe('Last') - expect(atom.contextMenu.templateForElement(element)[0].label).toBe('Menu item 1') - expect(atom.contextMenu.templateForElement(element)[1].label).toBe('Menu item 2') - expect(atom.contextMenu.templateForElement(element)[2].label).toBe('Menu item 3') + expect(atom.contextMenu.templateForElement(element)[0].label).toBe( + 'Menu item 1' + ) + expect(atom.contextMenu.templateForElement(element)[1].label).toBe( + 'Menu item 2' + ) + expect(atom.contextMenu.templateForElement(element)[2].label).toBe( + 'Menu item 3' + ) }) }) @@ -942,16 +1209,24 @@ describe('PackageManager', () => { await atom.packages.activatePackage('package-with-menus-manifest') expect(atom.menu.template[0].label).toBe('Second to Last') expect(atom.menu.template[1].label).toBe('Last') - expect(atom.contextMenu.templateForElement(element)[0].label).toBe('Menu item 2') - expect(atom.contextMenu.templateForElement(element)[1].label).toBe('Menu item 1') - expect(atom.contextMenu.templateForElement(element)[2]).toBeUndefined() + expect(atom.contextMenu.templateForElement(element)[0].label).toBe( + 'Menu item 2' + ) + expect(atom.contextMenu.templateForElement(element)[1].label).toBe( + 'Menu item 1' + ) + expect( + atom.contextMenu.templateForElement(element)[2] + ).toBeUndefined() }) }) describe('when the menu file is empty', () => { it('does not throw an error on activation', async () => { await atom.packages.activatePackage('package-with-empty-menu') - expect(atom.packages.isPackageActive('package-with-empty-menu')).toBe(true) + expect(atom.packages.isPackageActive('package-with-empty-menu')).toBe( + true + ) }) }) }) @@ -959,28 +1234,47 @@ describe('PackageManager', () => { describe('stylesheet loading', () => { describe("when the metadata contains a 'styleSheets' manifest", () => { it('loads style sheets from the styles directory as specified by the manifest', async () => { - const one = require.resolve('./fixtures/packages/package-with-style-sheets-manifest/styles/1.css') - const two = require.resolve('./fixtures/packages/package-with-style-sheets-manifest/styles/2.less') - const three = require.resolve('./fixtures/packages/package-with-style-sheets-manifest/styles/3.css') + const one = require.resolve( + './fixtures/packages/package-with-style-sheets-manifest/styles/1.css' + ) + const two = require.resolve( + './fixtures/packages/package-with-style-sheets-manifest/styles/2.less' + ) + const three = require.resolve( + './fixtures/packages/package-with-style-sheets-manifest/styles/3.css' + ) expect(atom.themes.stylesheetElementForId(one)).toBeNull() expect(atom.themes.stylesheetElementForId(two)).toBeNull() expect(atom.themes.stylesheetElementForId(three)).toBeNull() - await atom.packages.activatePackage('package-with-style-sheets-manifest') + await atom.packages.activatePackage( + 'package-with-style-sheets-manifest' + ) expect(atom.themes.stylesheetElementForId(one)).not.toBeNull() expect(atom.themes.stylesheetElementForId(two)).not.toBeNull() expect(atom.themes.stylesheetElementForId(three)).toBeNull() - expect(getComputedStyle(document.querySelector('#jasmine-content')).fontSize).toBe('1px') + expect( + getComputedStyle(document.querySelector('#jasmine-content')) + .fontSize + ).toBe('1px') }) }) describe("when the metadata does not contain a 'styleSheets' manifest", () => { it('loads all style sheets from the styles directory', async () => { - const one = require.resolve('./fixtures/packages/package-with-styles/styles/1.css') - const two = require.resolve('./fixtures/packages/package-with-styles/styles/2.less') - const three = require.resolve('./fixtures/packages/package-with-styles/styles/3.test-context.css') - const four = require.resolve('./fixtures/packages/package-with-styles/styles/4.css') + const one = require.resolve( + './fixtures/packages/package-with-styles/styles/1.css' + ) + const two = require.resolve( + './fixtures/packages/package-with-styles/styles/2.less' + ) + const three = require.resolve( + './fixtures/packages/package-with-styles/styles/3.test-context.css' + ) + const four = require.resolve( + './fixtures/packages/package-with-styles/styles/4.css' + ) expect(atom.themes.stylesheetElementForId(one)).toBeNull() expect(atom.themes.stylesheetElementForId(two)).toBeNull() @@ -992,7 +1286,10 @@ describe('PackageManager', () => { expect(atom.themes.stylesheetElementForId(two)).not.toBeNull() expect(atom.themes.stylesheetElementForId(three)).not.toBeNull() expect(atom.themes.stylesheetElementForId(four)).not.toBeNull() - expect(getComputedStyle(document.querySelector('#jasmine-content')).fontSize).toBe('3px') + expect( + getComputedStyle(document.querySelector('#jasmine-content')) + .fontSize + ).toBe('3px') }) }) @@ -1045,18 +1342,23 @@ describe('PackageManager', () => { describe('scoped-property loading', () => { it('loads the scoped properties', async () => { await atom.packages.activatePackage('package-with-settings') - expect(atom.config.get('editor.increaseIndentPattern', {scope: ['.source.omg']})).toBe('^a') + expect( + atom.config.get('editor.increaseIndentPattern', { + scope: ['.source.omg'] + }) + ).toBe('^a') }) }) - - describe("URI handler registration", () => { + describe('URI handler registration', () => { it("registers the package's specified URI handler", async () => { const uri = 'atom://package-with-uri-handler/some/url?with=args' const mod = require('./fixtures/packages/package-with-uri-handler') spyOn(mod, 'handleURI') spyOn(atom.packages, 'hasLoadedInitialPackages').andReturn(true) - const activationPromise = atom.packages.activatePackage('package-with-uri-handler') + const activationPromise = atom.packages.activatePackage( + 'package-with-uri-handler' + ) atom.dispatchURIMessage(uri) await activationPromise expect(mod.handleURI).toHaveBeenCalledWith(url.parse(uri, true), uri) @@ -1070,16 +1372,34 @@ describe('PackageManager', () => { let firstServiceV3Disposed = false let firstServiceV4Disposed = false let secondServiceDisposed = false - spyOn(consumerModule, 'consumeFirstServiceV3').andReturn(new Disposable(() => { firstServiceV3Disposed = true })) - spyOn(consumerModule, 'consumeFirstServiceV4').andReturn(new Disposable(() => { firstServiceV4Disposed = true })) - spyOn(consumerModule, 'consumeSecondService').andReturn(new Disposable(() => { secondServiceDisposed = true })) + spyOn(consumerModule, 'consumeFirstServiceV3').andReturn( + new Disposable(() => { + firstServiceV3Disposed = true + }) + ) + spyOn(consumerModule, 'consumeFirstServiceV4').andReturn( + new Disposable(() => { + firstServiceV4Disposed = true + }) + ) + spyOn(consumerModule, 'consumeSecondService').andReturn( + new Disposable(() => { + secondServiceDisposed = true + }) + ) await atom.packages.activatePackage('package-with-consumed-services') await atom.packages.activatePackage('package-with-provided-services') expect(consumerModule.consumeFirstServiceV3.callCount).toBe(1) - expect(consumerModule.consumeFirstServiceV3).toHaveBeenCalledWith('first-service-v3') - expect(consumerModule.consumeFirstServiceV4).toHaveBeenCalledWith('first-service-v4') - expect(consumerModule.consumeSecondService).toHaveBeenCalledWith('second-service') + expect(consumerModule.consumeFirstServiceV3).toHaveBeenCalledWith( + 'first-service-v3' + ) + expect(consumerModule.consumeFirstServiceV4).toHaveBeenCalledWith( + 'first-service-v4' + ) + expect(consumerModule.consumeSecondService).toHaveBeenCalledWith( + 'second-service' + ) consumerModule.consumeFirstServiceV3.reset() consumerModule.consumeFirstServiceV4.reset() @@ -1101,10 +1421,22 @@ describe('PackageManager', () => { const addErrorHandler = jasmine.createSpy() atom.notifications.onDidAddNotification(addErrorHandler) - await atom.packages.activatePackage('package-with-missing-consumed-services') - await atom.packages.activatePackage('package-with-missing-provided-services') - expect(atom.packages.isPackageActive('package-with-missing-consumed-services')).toBe(true) - expect(atom.packages.isPackageActive('package-with-missing-provided-services')).toBe(true) + await atom.packages.activatePackage( + 'package-with-missing-consumed-services' + ) + await atom.packages.activatePackage( + 'package-with-missing-provided-services' + ) + expect( + atom.packages.isPackageActive( + 'package-with-missing-consumed-services' + ) + ).toBe(true) + expect( + atom.packages.isPackageActive( + 'package-with-missing-provided-services' + ) + ).toBe(true) expect(addErrorHandler.callCount).toBe(0) }) }) @@ -1115,7 +1447,9 @@ describe('PackageManager', () => { spyOn(atom, 'inSpecMode').andReturn(false) spyOn(console, 'warn') - const badPack = await atom.packages.activatePackage('package-that-throws-on-activate') + const badPack = await atom.packages.activatePackage( + 'package-that-throws-on-activate' + ) spyOn(badPack.mainModule, 'serialize').andCallThrough() atom.packages.serialize() @@ -1128,16 +1462,24 @@ describe('PackageManager', () => { await atom.packages.activatePackage('package-with-serialize-error') await atom.packages.activatePackage('package-with-serialization') atom.packages.serialize() - expect(atom.packages.packageStates['package-with-serialize-error']).toBeUndefined() - expect(atom.packages.packageStates['package-with-serialization']).toEqual({someNumber: 1}) + expect( + atom.packages.packageStates['package-with-serialize-error'] + ).toBeUndefined() + expect(atom.packages.packageStates['package-with-serialization']).toEqual( + { someNumber: 1 } + ) expect(console.error).toHaveBeenCalled() }) }) describe('::deactivatePackages()', () => { it('deactivates all packages but does not serialize them', async () => { - const pack1 = await atom.packages.activatePackage('package-with-deactivate') - const pack2 = await atom.packages.activatePackage('package-with-serialization') + const pack1 = await atom.packages.activatePackage( + 'package-with-deactivate' + ) + const pack2 = await atom.packages.activatePackage( + 'package-with-serialization' + ) spyOn(pack1.mainModule, 'deactivate') spyOn(pack2.mainModule, 'serialize') @@ -1153,8 +1495,12 @@ describe('PackageManager', () => { it("calls `deactivate` on the package's main module if activate was successful", async () => { spyOn(atom, 'inSpecMode').andReturn(false) - const pack = await atom.packages.activatePackage('package-with-deactivate') - expect(atom.packages.isPackageActive('package-with-deactivate')).toBeTruthy() + const pack = await atom.packages.activatePackage( + 'package-with-deactivate' + ) + expect( + atom.packages.isPackageActive('package-with-deactivate') + ).toBeTruthy() spyOn(pack.mainModule, 'deactivate').andCallThrough() await atom.packages.deactivatePackage('package-with-deactivate') @@ -1162,13 +1508,19 @@ describe('PackageManager', () => { expect(atom.packages.isPackageActive('package-with-module')).toBeFalsy() spyOn(console, 'warn') - const badPack = await atom.packages.activatePackage('package-that-throws-on-activate') - expect(atom.packages.isPackageActive('package-that-throws-on-activate')).toBeTruthy() + const badPack = await atom.packages.activatePackage( + 'package-that-throws-on-activate' + ) + expect( + atom.packages.isPackageActive('package-that-throws-on-activate') + ).toBeTruthy() spyOn(badPack.mainModule, 'deactivate').andCallThrough() await atom.packages.deactivatePackage('package-that-throws-on-activate') expect(badPack.mainModule.deactivate).not.toHaveBeenCalled() - expect(atom.packages.isPackageActive('package-that-throws-on-activate')).toBeFalsy() + expect( + atom.packages.isPackageActive('package-that-throws-on-activate') + ).toBeFalsy() }) it("absorbs exceptions that are thrown by the package module's deactivate method", async () => { @@ -1188,17 +1540,33 @@ describe('PackageManager', () => { it("removes the package's keymaps", async () => { await atom.packages.activatePackage('package-with-keymaps') await atom.packages.deactivatePackage('package-with-keymaps') - expect(atom.keymaps.findKeyBindings({keystrokes: 'ctrl-z', target: createTestElement('test-1')})).toHaveLength(0) - expect(atom.keymaps.findKeyBindings({keystrokes: 'ctrl-z', target: createTestElement('test-2')})).toHaveLength(0) + expect( + atom.keymaps.findKeyBindings({ + keystrokes: 'ctrl-z', + target: createTestElement('test-1') + }) + ).toHaveLength(0) + expect( + atom.keymaps.findKeyBindings({ + keystrokes: 'ctrl-z', + target: createTestElement('test-2') + }) + ).toHaveLength(0) }) it("removes the package's stylesheets", async () => { await atom.packages.activatePackage('package-with-styles') await atom.packages.deactivatePackage('package-with-styles') - const one = require.resolve('./fixtures/packages/package-with-style-sheets-manifest/styles/1.css') - const two = require.resolve('./fixtures/packages/package-with-style-sheets-manifest/styles/2.less') - const three = require.resolve('./fixtures/packages/package-with-style-sheets-manifest/styles/3.css') + const one = require.resolve( + './fixtures/packages/package-with-style-sheets-manifest/styles/1.css' + ) + const two = require.resolve( + './fixtures/packages/package-with-style-sheets-manifest/styles/2.less' + ) + const three = require.resolve( + './fixtures/packages/package-with-style-sheets-manifest/styles/3.css' + ) expect(atom.themes.stylesheetElementForId(one)).not.toExist() expect(atom.themes.stylesheetElementForId(two)).not.toExist() expect(atom.themes.stylesheetElementForId(three)).not.toExist() @@ -1206,10 +1574,18 @@ describe('PackageManager', () => { it("removes the package's scoped-properties", async () => { await atom.packages.activatePackage('package-with-settings') - expect(atom.config.get('editor.increaseIndentPattern', {scope: ['.source.omg']})).toBe('^a') + expect( + atom.config.get('editor.increaseIndentPattern', { + scope: ['.source.omg'] + }) + ).toBe('^a') await atom.packages.deactivatePackage('package-with-settings') - expect(atom.config.get('editor.increaseIndentPattern', {scope: ['.source.omg']})).toBeUndefined() + expect( + atom.config.get('editor.increaseIndentPattern', { + scope: ['.source.omg'] + }) + ).toBeUndefined() }) it('invokes ::onDidDeactivatePackage listeners with the deactivated package', async () => { @@ -1261,21 +1637,31 @@ describe('PackageManager', () => { expect(themeActivator).toHaveBeenCalled() const packages = packageActivator.mostRecentCall.args[0] - for (let pack of packages) { expect(['atom', 'textmate']).toContain(pack.getType()) } + for (let pack of packages) { + expect(['atom', 'textmate']).toContain(pack.getType()) + } const themes = themeActivator.mostRecentCall.args[0] - themes.map((theme) => expect(['theme']).toContain(theme.getType())) + themes.map(theme => expect(['theme']).toContain(theme.getType())) }) it('calls callbacks registered with ::onDidActivateInitialPackages', async () => { const package1 = atom.packages.loadPackage('package-with-main') const package2 = atom.packages.loadPackage('package-with-index') - const package3 = atom.packages.loadPackage('package-with-activation-commands') - spyOn(atom.packages, 'getLoadedPackages').andReturn([package1, package2, package3]) + const package3 = atom.packages.loadPackage( + 'package-with-activation-commands' + ) + spyOn(atom.packages, 'getLoadedPackages').andReturn([ + package1, + package2, + package3 + ]) spyOn(atom.themes, 'activatePackages') atom.packages.activate() - await new Promise(resolve => atom.packages.onDidActivateInitialPackages(resolve)) + await new Promise(resolve => + atom.packages.onDidActivateInitialPackages(resolve) + ) jasmine.unspy(atom.packages, 'getLoadedPackages') expect(atom.packages.getActivePackages().includes(package1)).toBe(true) @@ -1293,11 +1679,15 @@ describe('PackageManager', () => { expect(atom.config.get('core.disabledPackages')).toContain(packageName) const pack = atom.packages.enablePackage(packageName) - await new Promise(resolve => atom.packages.onDidActivatePackage(resolve)) + await new Promise(resolve => + atom.packages.onDidActivatePackage(resolve) + ) expect(atom.packages.getLoadedPackages()).toContain(pack) expect(atom.packages.getActivePackages()).toContain(pack) - expect(atom.config.get('core.disabledPackages')).not.toContain(packageName) + expect(atom.config.get('core.disabledPackages')).not.toContain( + packageName + ) }) it('disables an enabled package', async () => { @@ -1305,7 +1695,9 @@ describe('PackageManager', () => { const pack = await atom.packages.activatePackage(packageName) atom.packages.observeDisabledPackages() - expect(atom.config.get('core.disabledPackages')).not.toContain(packageName) + expect(atom.config.get('core.disabledPackages')).not.toContain( + packageName + ) await new Promise(resolve => { atom.packages.onDidDeactivatePackage(resolve) atom.packages.disablePackage(packageName) @@ -1328,7 +1720,9 @@ describe('PackageManager', () => { expect(atom.config.get('core.disabledPackages')).toContain(packageName) atom.packages.disablePackage(packageName) - const packagesDisabled = atom.config.get('core.disabledPackages').filter(pack => pack === packageName) + const packagesDisabled = atom.config + .get('core.disabledPackages') + .filter(pack => pack === packageName) expect(packagesDisabled.length).toEqual(1) }) }) @@ -1340,14 +1734,20 @@ describe('PackageManager', () => { it('enables and disables a theme', async () => { const packageName = 'theme-with-package-file' expect(atom.config.get('core.themes')).not.toContain(packageName) - expect(atom.config.get('core.disabledPackages')).not.toContain(packageName) + expect(atom.config.get('core.disabledPackages')).not.toContain( + packageName + ) // enabling of theme const pack = atom.packages.enablePackage(packageName) - await new Promise(resolve => atom.packages.onDidActivatePackage(resolve)) + await new Promise(resolve => + atom.packages.onDidActivatePackage(resolve) + ) expect(atom.packages.isPackageActive(packageName)).toBe(true) expect(atom.config.get('core.themes')).toContain(packageName) - expect(atom.config.get('core.disabledPackages')).not.toContain(packageName) + expect(atom.config.get('core.disabledPackages')).not.toContain( + packageName + ) await new Promise(resolve => { atom.themes.onDidChangeActiveThemes(resolve) @@ -1357,7 +1757,9 @@ describe('PackageManager', () => { expect(atom.packages.getActivePackages()).not.toContain(pack) expect(atom.config.get('core.themes')).not.toContain(packageName) expect(atom.config.get('core.themes')).not.toContain(packageName) - expect(atom.config.get('core.disabledPackages')).not.toContain(packageName) + expect(atom.config.get('core.disabledPackages')).not.toContain( + packageName + ) }) }) }) diff --git a/spec/package-transpilation-registry-spec.js b/spec/package-transpilation-registry-spec.js index 214f1177e..90a06ea6c 100644 --- a/spec/package-transpilation-registry-spec.js +++ b/spec/package-transpilation-registry-spec.js @@ -2,17 +2,24 @@ import fs from 'fs' import path from 'path' -import {it, fit, ffit, fffit, beforeEach, afterEach} from './async-spec-helpers' +import { + it, + fit, + ffit, + fffit, + beforeEach, + afterEach +} from './async-spec-helpers' import PackageTranspilationRegistry from '../src/package-transpilation-registry' const originalCompiler = { getCachePath: (sourceCode, filePath) => { - return "orig-cache-path" + return 'orig-cache-path' }, compile: (sourceCode, filePath) => { - return sourceCode + "-original-compiler" + return sourceCode + '-original-compiler' }, shouldCompile: (sourceCode, filePath) => { @@ -20,7 +27,7 @@ const originalCompiler = { } } -describe("PackageTranspilationRegistry", () => { +describe('PackageTranspilationRegistry', () => { let registry let wrappedCompiler @@ -47,20 +54,36 @@ describe("PackageTranspilationRegistry", () => { const hitPath = path.join('/path/to/lib/file.js') const hitPathCoffee = path.join('/path/to/file2.coffee') const missPath = path.join('/path/other/file3.js') - const hitPathMissSubdir =path.join('/path/to/file4.js') + const hitPathMissSubdir = path.join('/path/to/file4.js') const hitPathMissExt = path.join('/path/to/file5.ts') const nodeModulesFolder = path.join('/path/to/lib/node_modules/file6.js') const hitNonStandardExt = path.join('/path/to/file7.omgwhatisthis') - const jsSpec = { glob: "lib/**/*.js", transpiler: './transpiler-js', options: { type: 'js' } } - const coffeeSpec = { glob: "*.coffee", transpiler: './transpiler-coffee', options: { type: 'coffee' } } - const omgSpec = { glob: "*.omgwhatisthis", transpiler: './transpiler-omg', options: { type: 'omg' } } + const jsSpec = { + glob: 'lib/**/*.js', + transpiler: './transpiler-js', + options: { type: 'js' } + } + const coffeeSpec = { + glob: '*.coffee', + transpiler: './transpiler-coffee', + options: { type: 'coffee' } + } + const omgSpec = { + glob: '*.omgwhatisthis', + transpiler: './transpiler-omg', + options: { type: 'omg' } + } - const expectedMeta = { name: 'my-package', path: path.join('/path/to'), meta: { some: 'metadata' } } + const expectedMeta = { + name: 'my-package', + path: path.join('/path/to'), + meta: { some: 'metadata' } + } const jsTranspiler = { transpile: (sourceCode, filePath, options) => { - return {code: sourceCode + "-transpiler-js"} + return { code: sourceCode + '-transpiler-js' } }, getCacheKeyData: (sourceCode, filePath, options) => { @@ -70,7 +93,7 @@ describe("PackageTranspilationRegistry", () => { const coffeeTranspiler = { transpile: (sourceCode, filePath, options) => { - return {code: sourceCode + "-transpiler-coffee"} + return { code: sourceCode + '-transpiler-coffee' } }, getCacheKeyData: (sourceCode, filePath, options) => { @@ -80,7 +103,7 @@ describe("PackageTranspilationRegistry", () => { const omgTranspiler = { transpile: (sourceCode, filePath, options) => { - return {code: sourceCode + "-transpiler-omg"} + return { code: sourceCode + '-transpiler-omg' } }, getCacheKeyData: (sourceCode, filePath, options) => { @@ -89,72 +112,135 @@ describe("PackageTranspilationRegistry", () => { } beforeEach(() => { - jsSpec._transpilerSource = "js-transpiler-source" - coffeeSpec._transpilerSource = "coffee-transpiler-source" - omgTranspiler._transpilerSource = "omg-transpiler-source" + jsSpec._transpilerSource = 'js-transpiler-source' + coffeeSpec._transpilerSource = 'coffee-transpiler-source' + omgTranspiler._transpilerSource = 'omg-transpiler-source' - spyOn(registry, "getTranspiler").andCallFake(spec => { + spyOn(registry, 'getTranspiler').andCallFake(spec => { if (spec.transpiler === './transpiler-js') return jsTranspiler if (spec.transpiler === './transpiler-coffee') return coffeeTranspiler if (spec.transpiler === './transpiler-omg') return omgTranspiler throw new Error('bad transpiler path ' + spec.transpiler) }) - registry.addTranspilerConfigForPath(path.join('/path/to'), 'my-package', { some: 'metadata' }, [ - jsSpec, coffeeSpec, omgSpec - ]) + registry.addTranspilerConfigForPath( + path.join('/path/to'), + 'my-package', + { some: 'metadata' }, + [jsSpec, coffeeSpec, omgSpec] + ) }) it('always returns true from shouldCompile for a file in that dir that match a glob', () => { spyOn(originalCompiler, 'shouldCompile').andReturn(false) expect(wrappedCompiler.shouldCompile('source', hitPath)).toBe(true) expect(wrappedCompiler.shouldCompile('source', hitPathCoffee)).toBe(true) - expect(wrappedCompiler.shouldCompile('source', hitNonStandardExt)).toBe(true) - expect(wrappedCompiler.shouldCompile('source', hitPathMissExt)).toBe(false) - expect(wrappedCompiler.shouldCompile('source', hitPathMissSubdir)).toBe(false) + expect(wrappedCompiler.shouldCompile('source', hitNonStandardExt)).toBe( + true + ) + expect(wrappedCompiler.shouldCompile('source', hitPathMissExt)).toBe( + false + ) + expect(wrappedCompiler.shouldCompile('source', hitPathMissSubdir)).toBe( + false + ) expect(wrappedCompiler.shouldCompile('source', missPath)).toBe(false) - expect(wrappedCompiler.shouldCompile('source', nodeModulesFolder)).toBe(false) + expect(wrappedCompiler.shouldCompile('source', nodeModulesFolder)).toBe( + false + ) }) it('calls getCacheKeyData on the transpiler to get additional cache key data', () => { - spyOn(registry, "getTranspilerPath").andReturn("./transpiler-js") + spyOn(registry, 'getTranspilerPath').andReturn('./transpiler-js') spyOn(jsTranspiler, 'getCacheKeyData').andCallThrough() wrappedCompiler.getCachePath('source', missPath, jsSpec) - expect(jsTranspiler.getCacheKeyData).not.toHaveBeenCalledWith('source', missPath, jsSpec.options, expectedMeta) + expect(jsTranspiler.getCacheKeyData).not.toHaveBeenCalledWith( + 'source', + missPath, + jsSpec.options, + expectedMeta + ) wrappedCompiler.getCachePath('source', hitPath, jsSpec) - expect(jsTranspiler.getCacheKeyData).toHaveBeenCalledWith('source', hitPath, jsSpec.options, expectedMeta) + expect(jsTranspiler.getCacheKeyData).toHaveBeenCalledWith( + 'source', + hitPath, + jsSpec.options, + expectedMeta + ) }) it('compiles files matching a glob with the associated transpiler, and the old one otherwise', () => { - spyOn(jsTranspiler, "transpile").andCallThrough() - spyOn(coffeeTranspiler, "transpile").andCallThrough() - spyOn(omgTranspiler, "transpile").andCallThrough() + spyOn(jsTranspiler, 'transpile').andCallThrough() + spyOn(coffeeTranspiler, 'transpile').andCallThrough() + spyOn(omgTranspiler, 'transpile').andCallThrough() - expect(wrappedCompiler.compile('source', hitPath)).toEqual('source-transpiler-js') - expect(jsTranspiler.transpile).toHaveBeenCalledWith('source', hitPath, jsSpec.options, expectedMeta) - expect(wrappedCompiler.compile('source', hitPathCoffee)).toEqual('source-transpiler-coffee') - expect(coffeeTranspiler.transpile).toHaveBeenCalledWith('source', hitPathCoffee, coffeeSpec.options, expectedMeta) - expect(wrappedCompiler.compile('source', hitNonStandardExt)).toEqual('source-transpiler-omg') - expect(omgTranspiler.transpile).toHaveBeenCalledWith('source', hitNonStandardExt, omgSpec.options, expectedMeta) + expect(wrappedCompiler.compile('source', hitPath)).toEqual( + 'source-transpiler-js' + ) + expect(jsTranspiler.transpile).toHaveBeenCalledWith( + 'source', + hitPath, + jsSpec.options, + expectedMeta + ) + expect(wrappedCompiler.compile('source', hitPathCoffee)).toEqual( + 'source-transpiler-coffee' + ) + expect(coffeeTranspiler.transpile).toHaveBeenCalledWith( + 'source', + hitPathCoffee, + coffeeSpec.options, + expectedMeta + ) + expect(wrappedCompiler.compile('source', hitNonStandardExt)).toEqual( + 'source-transpiler-omg' + ) + expect(omgTranspiler.transpile).toHaveBeenCalledWith( + 'source', + hitNonStandardExt, + omgSpec.options, + expectedMeta + ) - expect(wrappedCompiler.compile('source', missPath)).toEqual('source-original-compiler') - expect(wrappedCompiler.compile('source', hitPathMissExt)).toEqual('source-original-compiler') - expect(wrappedCompiler.compile('source', hitPathMissSubdir)).toEqual('source-original-compiler') - expect(wrappedCompiler.compile('source', nodeModulesFolder)).toEqual('source-original-compiler') + expect(wrappedCompiler.compile('source', missPath)).toEqual( + 'source-original-compiler' + ) + expect(wrappedCompiler.compile('source', hitPathMissExt)).toEqual( + 'source-original-compiler' + ) + expect(wrappedCompiler.compile('source', hitPathMissSubdir)).toEqual( + 'source-original-compiler' + ) + expect(wrappedCompiler.compile('source', nodeModulesFolder)).toEqual( + 'source-original-compiler' + ) }) - describe('when the packages root path contains node_modules', () =>{ + describe('when the packages root path contains node_modules', () => { beforeEach(() => { - registry.addTranspilerConfigForPath(path.join('/path/with/node_modules/in/root'), 'my-other-package', { some: 'metadata' }, [ - jsSpec - ]) + registry.addTranspilerConfigForPath( + path.join('/path/with/node_modules/in/root'), + 'my-other-package', + { some: 'metadata' }, + [jsSpec] + ) }) it('returns appropriate values from shouldCompile', () => { spyOn(originalCompiler, 'shouldCompile').andReturn(false) - expect(wrappedCompiler.shouldCompile('source', '/path/with/node_modules/in/root/lib/test.js')).toBe(true) - expect(wrappedCompiler.shouldCompile('source', '/path/with/node_modules/in/root/lib/node_modules/test.js')).toBe(false) + expect( + wrappedCompiler.shouldCompile( + 'source', + '/path/with/node_modules/in/root/lib/test.js' + ) + ).toBe(true) + expect( + wrappedCompiler.shouldCompile( + 'source', + '/path/with/node_modules/in/root/lib/node_modules/test.js' + ) + ).toBe(false) }) }) }) diff --git a/spec/pane-container-spec.js b/spec/pane-container-spec.js index 060808d0b..50a60d2b0 100644 --- a/spec/pane-container-spec.js +++ b/spec/pane-container-spec.js @@ -1,11 +1,20 @@ const PaneContainer = require('../src/pane-container') -const {it, fit, ffit, fffit, beforeEach, afterEach} = require('./async-spec-helpers') +const { + it, + fit, + ffit, + fffit, + beforeEach, + afterEach +} = require('./async-spec-helpers') describe('PaneContainer', () => { let confirm, params beforeEach(() => { - confirm = spyOn(atom.applicationDelegate, 'confirm').andCallFake((options, callback) => callback(0)) + confirm = spyOn(atom.applicationDelegate, 'confirm').andCallFake( + (options, callback) => callback(0) + ) params = { location: 'center', config: atom.config, @@ -21,16 +30,20 @@ describe('PaneContainer', () => { beforeEach(() => { // This is a dummy item to prevent panes from being empty on deserialization class Item { - static deserialize () { return new (this)() } - serialize () { return {deserializer: 'Item'} } + static deserialize () { + return new this() + } + serialize () { + return { deserializer: 'Item' } + } } atom.deserializers.add(Item) containerA = new PaneContainer(params) pane1A = containerA.getActivePane() pane1A.addItem(new Item()) - pane2A = pane1A.splitRight({items: [new Item()]}) - pane3A = pane2A.splitDown({items: [new Item()]}) + pane2A = pane1A.splitRight({ items: [new Item()] }) + pane3A = pane2A.splitDown({ items: [new Item()] }) pane3A.focus() }) @@ -64,7 +77,7 @@ describe('PaneContainer', () => { describe('if there are empty panes after deserialization', () => { beforeEach(() => { - pane3A.getItems()[0].serialize = () => ({deserializer: 'Bogus'}) + pane3A.getItems()[0].serialize = () => ({ deserializer: 'Bogus' }) }) describe("if the 'core.destroyEmptyPanes' config option is false (the default)", () => @@ -78,8 +91,7 @@ describe('PaneContainer', () => { expect(leftPane.getItems().length).toBe(1) expect(topPane.getItems().length).toBe(1) expect(bottomPane.getItems().length).toBe(0) - }) - ) + })) describe("if the 'core.destroyEmptyPanes' config option is true", () => it('removes empty panes on deserialization', () => { @@ -92,8 +104,7 @@ describe('PaneContainer', () => { expect(leftPane.getItems().length).toBe(1) expect(rightPane.getItems().length).toBe(1) - }) - ) + })) }) }) @@ -144,8 +155,8 @@ describe('PaneContainer', () => { beforeEach(() => { container = new PaneContainer(params) container.getRoot().addItems([{}, {}]) - container.getRoot().splitRight({items: [{}, {}]}); - [pane1, pane2] = container.getPanes() + container.getRoot().splitRight({ items: [{}, {}] }) + ;[pane1, pane2] = container.getPanes() observed = [] container.onDidChangeActivePane(pane => observed.push(pane)) @@ -164,8 +175,8 @@ describe('PaneContainer', () => { beforeEach(() => { container = new PaneContainer(params) container.getRoot().addItems([{}, {}]) - container.getRoot().splitRight({items: [{}, {}]}); - [pane1, pane2] = container.getPanes() + container.getRoot().splitRight({ items: [{}, {}] }) + ;[pane1, pane2] = container.getPanes() observed = [] container.onDidChangeActivePaneItem(item => observed.push(item)) @@ -190,8 +201,8 @@ describe('PaneContainer', () => { beforeEach(() => { container = new PaneContainer(params) container.getRoot().addItems([{}, {}]) - container.getRoot().splitRight({items: [{}, {}]}); - [pane1, pane2] = container.getPanes() + container.getRoot().splitRight({ items: [{}, {}] }) + ;[pane1, pane2] = container.getPanes() observed = [] container.onDidStopChangingActivePaneItem(item => observed.push(item)) @@ -251,30 +262,33 @@ describe('PaneContainer', () => { it('invokes observers with all current and future pane items', () => { const container = new PaneContainer(params) container.getRoot().addItems([{}, {}]) - container.getRoot().splitRight({items: [{}]}) + container.getRoot().splitRight({ items: [{}] }) const pane2 = container.getPanes()[1] const observed = [] container.observePaneItems(pane => observed.push(pane)) - const pane3 = pane2.splitDown({items: [{}]}) + const pane3 = pane2.splitDown({ items: [{}] }) pane3.addItems([{}, {}]) expect(observed).toEqual(container.getPaneItems()) - }) - ) + })) describe('::confirmClose()', () => { let container, pane1, pane2 beforeEach(() => { class TestItem { - shouldPromptToSave () { return true } - getURI () { return 'test' } + shouldPromptToSave () { + return true + } + getURI () { + return 'test' + } } container = new PaneContainer(params) - container.getRoot().splitRight(); - [pane1, pane2] = container.getPanes() + container.getRoot().splitRight() + ;[pane1, pane2] = container.getPanes() pane1.addItem(new TestItem()) pane2.addItem(new TestItem()) }) @@ -298,7 +312,7 @@ describe('PaneContainer', () => { it('invokes the given callback when panes are added', () => { const container = new PaneContainer(params) const events = [] - container.onDidAddPane((event) => { + container.onDidAddPane(event => { expect(container.getPanes().includes(event.pane)).toBe(true) events.push(event) }) @@ -307,23 +321,31 @@ describe('PaneContainer', () => { const pane2 = pane1.splitRight() const pane3 = pane2.splitDown() - expect(events).toEqual([{pane: pane2}, {pane: pane3}]) + expect(events).toEqual([{ pane: pane2 }, { pane: pane3 }]) }) }) describe('::onWillDestroyPane(callback)', () => { it('invokes the given callback before panes or their items are destroyed', () => { class TestItem { - constructor () { this._isDestroyed = false } - destroy () { this._isDestroyed = true } - isDestroyed () { return this._isDestroyed } + constructor () { + this._isDestroyed = false + } + destroy () { + this._isDestroyed = true + } + isDestroyed () { + return this._isDestroyed + } } const container = new PaneContainer(params) const events = [] - container.onWillDestroyPane((event) => { - const itemsDestroyed = event.pane.getItems().map((item) => item.isDestroyed()) - events.push([event, {itemsDestroyed}]) + container.onWillDestroyPane(event => { + const itemsDestroyed = event.pane + .getItems() + .map(item => item.isDestroyed()) + events.push([event, { itemsDestroyed }]) }) const pane1 = container.getActivePane() @@ -332,7 +354,7 @@ describe('PaneContainer', () => { pane2.destroy() - expect(events).toEqual([[{pane: pane2}, {itemsDestroyed: [false]}]]) + expect(events).toEqual([[{ pane: pane2 }, { itemsDestroyed: [false] }]]) }) }) @@ -340,7 +362,7 @@ describe('PaneContainer', () => { it('invokes the given callback when panes are destroyed', () => { const container = new PaneContainer(params) const events = [] - container.onDidDestroyPane((event) => { + container.onDidDestroyPane(event => { expect(container.getPanes().includes(event.pane)).toBe(false) events.push(event) }) @@ -352,13 +374,13 @@ describe('PaneContainer', () => { pane2.destroy() pane3.destroy() - expect(events).toEqual([{pane: pane2}, {pane: pane3}]) + expect(events).toEqual([{ pane: pane2 }, { pane: pane3 }]) }) it('invokes the given callback when the container is destroyed', () => { const container = new PaneContainer(params) const events = [] - container.onDidDestroyPane((event) => { + container.onDidDestroyPane(event => { expect(container.getPanes().includes(event.pane)).toBe(false) events.push(event) }) @@ -369,7 +391,11 @@ describe('PaneContainer', () => { container.destroy() - expect(events).toEqual([{pane: pane1}, {pane: pane2}, {pane: pane3}]) + expect(events).toEqual([ + { pane: pane1 }, + { pane: pane2 }, + { pane: pane3 } + ]) }) }) @@ -385,19 +411,19 @@ describe('PaneContainer', () => { const events = [] container.onWillDestroyPaneItem(event => events.push(['will', event])) container.onDidDestroyPaneItem(event => events.push(['did', event])) - const pane2 = pane1.splitRight({items: [item2, item3]}) + const pane2 = pane1.splitRight({ items: [item2, item3] }) await pane1.destroyItem(item1) await pane2.destroyItem(item3) await pane2.destroyItem(item2) expect(events).toEqual([ - ['will', {item: item1, pane: pane1, index: 0}], - ['did', {item: item1, pane: pane1, index: 0}], - ['will', {item: item3, pane: pane2, index: 1}], - ['did', {item: item3, pane: pane2, index: 1}], - ['will', {item: item2, pane: pane2, index: 0}], - ['did', {item: item2, pane: pane2, index: 0}] + ['will', { item: item1, pane: pane1, index: 0 }], + ['did', { item: item1, pane: pane1, index: 0 }], + ['will', { item: item3, pane: pane2, index: 1 }], + ['did', { item: item3, pane: pane2, index: 1 }], + ['will', { item: item2, pane: pane2, index: 0 }], + ['did', { item: item2, pane: pane2, index: 0 }] ]) }) }) @@ -410,21 +436,39 @@ describe('PaneContainer', () => { const item1 = { saved: false, - getURI () { return '' }, - isModified () { return true }, - save () { this.saved = true } + getURI () { + return '' + }, + isModified () { + return true + }, + save () { + this.saved = true + } } const item2 = { saved: false, - getURI () { return '' }, - isModified () { return false }, - save () { this.saved = true } + getURI () { + return '' + }, + isModified () { + return false + }, + save () { + this.saved = true + } } const item3 = { saved: false, - getURI () { return '' }, - isModified () { return true }, - save () { this.saved = true } + getURI () { + return '' + }, + isModified () { + return true + }, + save () { + this.saved = true + } } pane1.addItem(item1) @@ -436,37 +480,38 @@ describe('PaneContainer', () => { expect(item1.saved).toBe(true) expect(item2.saved).toBe(false) expect(item3.saved).toBe(true) - }) - ) + })) describe('::moveActiveItemToPane(destPane) and ::copyActiveItemToPane(destPane)', () => { let container, pane1, pane2, item1 beforeEach(() => { class TestItem { - constructor (id) { this.id = id } - copy () { return new TestItem(this.id) } + constructor (id) { + this.id = id + } + copy () { + return new TestItem(this.id) + } } container = new PaneContainer(params) pane1 = container.getRoot() item1 = new TestItem('1') - pane2 = pane1.splitRight({items: [item1]}) + pane2 = pane1.splitRight({ items: [item1] }) }) describe('::::moveActiveItemToPane(destPane)', () => it('moves active item to given pane and focuses it', () => { container.moveActiveItemToPane(pane1) expect(pane1.getActiveItem()).toBe(item1) - }) - ) + })) describe('::::copyActiveItemToPane(destPane)', () => it('copies active item to given pane and focuses it', () => { container.copyActiveItemToPane(pane1) expect(container.paneForItem(item1)).toBe(pane2) expect(pane1.getActiveItem().id).toBe(item1.id) - }) - ) + })) }) }) diff --git a/spec/pane-spec.js b/spec/pane-spec.js index ddb92b96e..b87e9e8ad 100644 --- a/spec/pane-spec.js +++ b/spec/pane-spec.js @@ -1,15 +1,23 @@ -const {extend} = require('underscore-plus') -const {Emitter} = require('event-kit') +const { extend } = require('underscore-plus') +const { Emitter } = require('event-kit') const Grim = require('grim') const Pane = require('../src/pane') const PaneContainer = require('../src/pane-container') -const {it, fit, ffit, fffit, beforeEach, conditionPromise, timeoutPromise} = require('./async-spec-helpers') +const { + it, + fit, + ffit, + fffit, + beforeEach, + conditionPromise, + timeoutPromise +} = require('./async-spec-helpers') describe('Pane', () => { let confirm, showSaveDialog, deserializerDisposable class Item { - static deserialize ({name, uri}) { + static deserialize ({ name, uri }) { return new Item(name, uri) } @@ -20,14 +28,24 @@ describe('Pane', () => { this.destroyed = false } - getURI () { return this.uri } - getPath () { return this.path } - isEqual (other) { return this.name === (other && other.name) } - isPermanentDockItem () { return false } - isDestroyed () { return this.destroyed } + getURI () { + return this.uri + } + getPath () { + return this.path + } + isEqual (other) { + return this.name === (other && other.name) + } + isPermanentDockItem () { + return false + } + isDestroyed () { + return this.destroyed + } serialize () { - return {deserializer: 'Item', name: this.name, uri: this.uri} + return { deserializer: 'Item', name: this.name, uri: this.uri } } copy () { @@ -63,22 +81,29 @@ describe('Pane', () => { }) function paneParams (params) { - return extend({ - applicationDelegate: atom.applicationDelegate, - config: atom.config, - deserializerManager: atom.deserializers, - notificationManager: atom.notifications - }, params) + return extend( + { + applicationDelegate: atom.applicationDelegate, + config: atom.config, + deserializerManager: atom.deserializers, + notificationManager: atom.notifications + }, + params + ) } describe('construction', () => { it('sets the active item to the first item', () => { - const pane = new Pane(paneParams({items: [new Item('A'), new Item('B')]})) + const pane = new Pane( + paneParams({ items: [new Item('A'), new Item('B')] }) + ) expect(pane.getActiveItem()).toBe(pane.itemAtIndex(0)) }) it('compacts the items array', () => { - const pane = new Pane(paneParams({items: [undefined, new Item('A'), null, new Item('B')]})) + const pane = new Pane( + paneParams({ items: [undefined, new Item('A'), null, new Item('B')] }) + ) expect(pane.getItems().length).toBe(2) expect(pane.getActiveItem()).toBe(pane.itemAtIndex(0)) }) @@ -136,15 +161,19 @@ describe('Pane', () => { describe('::addItem(item, index)', () => { it('adds the item at the given index', () => { - const pane = new Pane(paneParams({items: [new Item('A'), new Item('B')]})) + const pane = new Pane( + paneParams({ items: [new Item('A'), new Item('B')] }) + ) const [item1, item2] = pane.getItems() const item3 = new Item('C') - pane.addItem(item3, {index: 1}) + pane.addItem(item3, { index: 1 }) expect(pane.getItems()).toEqual([item1, item3, item2]) }) it('adds the item after the active item if no index is provided', () => { - const pane = new Pane(paneParams({items: [new Item('A'), new Item('B'), new Item('C')]})) + const pane = new Pane( + paneParams({ items: [new Item('A'), new Item('B'), new Item('C')] }) + ) const [item1, item2, item3] = pane.getItems() pane.activateItem(item2) const item4 = new Item('D') @@ -160,18 +189,23 @@ describe('Pane', () => { }) it('invokes ::onDidAddItem() observers', () => { - const pane = new Pane(paneParams({items: [new Item('A'), new Item('B')]})) + const pane = new Pane( + paneParams({ items: [new Item('A'), new Item('B')] }) + ) const events = [] pane.onDidAddItem(event => events.push(event)) const item = new Item('C') - pane.addItem(item, {index: 1}) - expect(events).toEqual([{item, index: 1, moved: false}]) + pane.addItem(item, { index: 1 }) + expect(events).toEqual([{ item, index: 1, moved: false }]) }) it('throws an exception if the item is already present on a pane', () => { const item = new Item('A') - const container = new PaneContainer({config: atom.config, applicationDelegate: atom.applicationDelegate}) + const container = new PaneContainer({ + config: atom.config, + applicationDelegate: atom.applicationDelegate + }) const pane1 = container.getActivePane() pane1.addItem(item) const pane2 = pane1.splitRight() @@ -179,36 +213,36 @@ describe('Pane', () => { }) it("throws an exception if the item isn't an object", () => { - const pane = new Pane(paneParams({items: []})) + const pane = new Pane(paneParams({ items: [] })) expect(() => pane.addItem(null)).toThrow() expect(() => pane.addItem('foo')).toThrow() expect(() => pane.addItem(1)).toThrow() }) it('destroys any existing pending item', () => { - const pane = new Pane(paneParams({items: []})) + const pane = new Pane(paneParams({ items: [] })) const itemA = new Item('A') const itemB = new Item('B') const itemC = new Item('C') - pane.addItem(itemA, {pending: false}) - pane.addItem(itemB, {pending: true}) - pane.addItem(itemC, {pending: false}) + pane.addItem(itemA, { pending: false }) + pane.addItem(itemB, { pending: true }) + pane.addItem(itemC, { pending: false }) expect(itemB.isDestroyed()).toBe(true) }) it('adds the new item before destroying any existing pending item', () => { const eventOrder = [] - const pane = new Pane(paneParams({items: []})) + const pane = new Pane(paneParams({ items: [] })) const itemA = new Item('A') const itemB = new Item('B') - pane.addItem(itemA, {pending: true}) + pane.addItem(itemA, { pending: true }) - pane.onDidAddItem(function ({item}) { + pane.onDidAddItem(function ({ item }) { if (item === itemB) eventOrder.push('add') }) - pane.onDidRemoveItem(function ({item}) { + pane.onDidRemoveItem(function ({ item }) { if (item === itemA) eventOrder.push('remove') }) @@ -221,9 +255,11 @@ describe('Pane', () => { it('subscribes to be notified when item terminates its pending state', () => { const fakeDisposable = { dispose: () => {} } - const spy = jasmine.createSpy('onDidTerminatePendingState').andReturn((fakeDisposable)) + const spy = jasmine + .createSpy('onDidTerminatePendingState') + .andReturn(fakeDisposable) - const pane = new Pane(paneParams({items: []})) + const pane = new Pane(paneParams({ items: [] })) const item = { getTitle: () => '', onDidTerminatePendingState: spy @@ -235,9 +271,9 @@ describe('Pane', () => { it('subscribes to be notified when item is destroyed', () => { const fakeDisposable = { dispose: () => {} } - const spy = jasmine.createSpy('onDidDestroy').andReturn((fakeDisposable)) + const spy = jasmine.createSpy('onDidDestroy').andReturn(fakeDisposable) - const pane = new Pane(paneParams({items: []})) + const pane = new Pane(paneParams({ items: [] })) const item = { getTitle: () => '', onDidDestroy: spy @@ -251,7 +287,7 @@ describe('Pane', () => { beforeEach(() => spyOn(Grim, 'deprecate')) it('supports the older public API', () => { - const pane = new Pane(paneParams({items: []})) + const pane = new Pane(paneParams({ items: [] })) const itemA = new Item('A') const itemB = new Item('B') const itemC = new Item('C') @@ -262,9 +298,11 @@ describe('Pane', () => { }) it('shows a deprecation warning', () => { - const pane = new Pane(paneParams({items: []})) + const pane = new Pane(paneParams({ items: [] })) pane.addItem(new Item(), 2) - expect(Grim.deprecate).toHaveBeenCalledWith('Pane::addItem(item, 2) is deprecated in favor of Pane::addItem(item, {index: 2})') + expect(Grim.deprecate).toHaveBeenCalledWith( + 'Pane::addItem(item, 2) is deprecated in favor of Pane::addItem(item, {index: 2})' + ) }) }) }) @@ -273,7 +311,7 @@ describe('Pane', () => { let pane = null beforeEach(() => { - pane = new Pane(paneParams({items: [new Item('A'), new Item('B')]})) + pane = new Pane(paneParams({ items: [new Item('A'), new Item('B')] })) }) it('changes the active item to the current item', () => { @@ -306,16 +344,16 @@ describe('Pane', () => { }) it('replaces the active item if it is pending', () => { - pane.activateItem(itemC, {pending: true}) + pane.activateItem(itemC, { pending: true }) expect(pane.getItems().map(item => item.name)).toEqual(['A', 'C', 'B']) - pane.activateItem(itemD, {pending: true}) + pane.activateItem(itemD, { pending: true }) expect(pane.getItems().map(item => item.name)).toEqual(['A', 'D', 'B']) }) it('adds the item after the active item if it is not pending', () => { - pane.activateItem(itemC, {pending: true}) + pane.activateItem(itemC, { pending: true }) pane.activateItemAtIndex(2) - pane.activateItem(itemD, {pending: true}) + pane.activateItem(itemD, { pending: true }) expect(pane.getItems().map(item => item.name)).toEqual(['A', 'B', 'D']) }) }) @@ -369,14 +407,14 @@ describe('Pane', () => { const pendingSpy = jasmine.createSpy('onItemDidTerminatePendingState') const destroySpy = jasmine.createSpy('onWillDestroyItem') - await atom.workspace.open('sample.txt', {pending: true}).then(() => { + await atom.workspace.open('sample.txt', { pending: true }).then(() => { pane = atom.workspace.getActivePane() }) pane.onItemDidTerminatePendingState(pendingSpy) pane.onWillDestroyItem(destroySpy) - await atom.workspace.open('sample.js', {pending: true}) + await atom.workspace.open('sample.js', { pending: true }) expect(destroySpy).toHaveBeenCalled() expect(pendingSpy).not.toHaveBeenCalled() @@ -385,7 +423,17 @@ describe('Pane', () => { describe('::activateNextRecentlyUsedItem() and ::activatePreviousRecentlyUsedItem()', () => { it('sets the active item to the next/previous item in the itemStack, looping around at either end', () => { - const pane = new Pane(paneParams({items: [new Item('A'), new Item('B'), new Item('C'), new Item('D'), new Item('E')]})) + const pane = new Pane( + paneParams({ + items: [ + new Item('A'), + new Item('B'), + new Item('C'), + new Item('D'), + new Item('E') + ] + }) + ) const [item1, item2, item3, item4, item5] = pane.getItems() pane.itemStack = [item3, item1, item2, item5, item4] @@ -416,7 +464,9 @@ describe('Pane', () => { describe('::activateNextItem() and ::activatePreviousItem()', () => { it('sets the active item to the next/previous item, looping around at either end', () => { - const pane = new Pane(paneParams({items: [new Item('A'), new Item('B'), new Item('C')]})) + const pane = new Pane( + paneParams({ items: [new Item('A'), new Item('B'), new Item('C')] }) + ) const [item1, item2, item3] = pane.getItems() expect(pane.getActiveItem()).toBe(item1) @@ -433,8 +483,10 @@ describe('Pane', () => { describe('::activateLastItem()', () => { it('sets the active item to the last item', () => { - const pane = new Pane(paneParams({items: [new Item('A'), new Item('B'), new Item('C')]})) - const [item1,, item3] = pane.getItems() + const pane = new Pane( + paneParams({ items: [new Item('A'), new Item('B'), new Item('C')] }) + ) + const [item1, , item3] = pane.getItems() expect(pane.getActiveItem()).toBe(item1) pane.activateLastItem() @@ -444,7 +496,9 @@ describe('Pane', () => { describe('::moveItemRight() and ::moveItemLeft()', () => { it('moves the active item to the right and left, without looping around at either end', () => { - const pane = new Pane(paneParams({items: [new Item('A'), new Item('B'), new Item('C')]})) + const pane = new Pane( + paneParams({ items: [new Item('A'), new Item('B'), new Item('C')] }) + ) const [item1, item2, item3] = pane.getItems() pane.activateItemAtIndex(0) @@ -464,7 +518,9 @@ describe('Pane', () => { describe('::activateItemAtIndex(index)', () => { it('activates the item at the given index', () => { - const pane = new Pane(paneParams({items: [new Item('A'), new Item('B'), new Item('C')]})) + const pane = new Pane( + paneParams({ items: [new Item('A'), new Item('B'), new Item('C')] }) + ) const [item1, item2, item3] = pane.getItems() pane.activateItemAtIndex(2) expect(pane.getActiveItem()).toBe(item3) @@ -485,7 +541,9 @@ describe('Pane', () => { let pane, item1, item2, item3 beforeEach(() => { - pane = new Pane(paneParams({items: [new Item('A'), new Item('B'), new Item('C')]})) + pane = new Pane( + paneParams({ items: [new Item('A'), new Item('B'), new Item('C')] }) + ) ;[item1, item2, item3] = pane.getItems() }) @@ -521,17 +579,17 @@ describe('Pane', () => { it('invokes ::onWillDestroyItem() and PaneContainer::onWillDestroyPaneItem observers before destroying the item', async () => { jasmine.useRealClock() - pane.container = new PaneContainer({config: atom.config, confirm}) + pane.container = new PaneContainer({ config: atom.config, confirm }) const events = [] - pane.onWillDestroyItem(async (event) => { + pane.onWillDestroyItem(async event => { expect(item2.isDestroyed()).toBe(false) await timeoutPromise(50) expect(item2.isDestroyed()).toBe(false) events.push(['will-destroy-item', event]) }) - pane.container.onWillDestroyPaneItem(async (event) => { + pane.container.onWillDestroyPaneItem(async event => { expect(item2.isDestroyed()).toBe(false) await timeoutPromise(50) expect(item2.isDestroyed()).toBe(false) @@ -541,8 +599,8 @@ describe('Pane', () => { await pane.destroyItem(item2) expect(item2.isDestroyed()).toBe(true) expect(events).toEqual([ - ['will-destroy-item', {item: item2, index: 1}], - ['will-destroy-pane-item', {item: item2, index: 1, pane}] + ['will-destroy-item', { item: item2, index: 1 }], + ['will-destroy-pane-item', { item: item2, index: 1, pane }] ]) }) @@ -550,14 +608,18 @@ describe('Pane', () => { const events = [] pane.onWillRemoveItem(event => events.push(event)) pane.destroyItem(item2) - expect(events).toEqual([{item: item2, index: 1, moved: false, destroyed: true}]) + expect(events).toEqual([ + { item: item2, index: 1, moved: false, destroyed: true } + ]) }) it('invokes ::onDidRemoveItem() observers', () => { const events = [] pane.onDidRemoveItem(event => events.push(event)) pane.destroyItem(item2) - expect(events).toEqual([{item: item2, index: 1, moved: false, destroyed: true}]) + expect(events).toEqual([ + { item: item2, index: 1, moved: false, destroyed: true } + ]) }) describe('when the destroyed item is the active item and is the first item', () => { @@ -608,7 +670,9 @@ describe('Pane', () => { itemURI = null - showSaveDialog.andCallFake((options, callback) => callback('/selected/path')) + showSaveDialog.andCallFake((options, callback) => + callback('/selected/path') + ) confirm.andCallFake((options, callback) => callback(0)) const success = await pane.destroyItem(item1) @@ -631,7 +695,7 @@ describe('Pane', () => { expect(item1.save).not.toHaveBeenCalled() expect(pane.getItems().includes(item1)).toBe(false) expect(item1.isDestroyed()).toBe(true) - expect(success).toBe(true); + expect(success).toBe(true) }) }) @@ -662,7 +726,9 @@ describe('Pane', () => { describe("when the 'core.destroyEmptyPanes' config option is false (the default)", () => { it('does not destroy the pane, but leaves it in place with empty items', () => { expect(atom.config.get('core.destroyEmptyPanes')).toBe(false) - for (let item of pane.getItems()) { pane.destroyItem(item) } + for (let item of pane.getItems()) { + pane.destroyItem(item) + } expect(pane.isDestroyed()).toBe(false) expect(pane.getActiveItem()).toBeUndefined() expect(() => pane.saveActiveItem()).not.toThrow() @@ -687,7 +753,7 @@ describe('Pane', () => { const success = await pane.destroyItem(item1) expect(pane.getItems().includes(item1)).toBe(true) expect(item1.isDestroyed()).toBe(false) - expect(success).toBe(false); + expect(success).toBe(false) }) it('destroy the item if force=true', async () => { @@ -702,7 +768,9 @@ describe('Pane', () => { describe('::destroyActiveItem()', () => { it('destroys the active item', () => { - const pane = new Pane(paneParams({items: [new Item('A'), new Item('B')]})) + const pane = new Pane( + paneParams({ items: [new Item('A'), new Item('B')] }) + ) const activeItem = pane.getActiveItem() pane.destroyActiveItem() expect(activeItem.isDestroyed()).toBe(true) @@ -717,7 +785,9 @@ describe('Pane', () => { describe('::destroyItems()', () => { it('destroys all items', async () => { - const pane = new Pane(paneParams({items: [new Item('A'), new Item('B'), new Item('C')]})) + const pane = new Pane( + paneParams({ items: [new Item('A'), new Item('B'), new Item('C')] }) + ) const [item1, item2, item3] = pane.getItems() await pane.destroyItems() @@ -730,7 +800,7 @@ describe('Pane', () => { describe('::observeItems()', () => { it('invokes the observer with all current and future items', () => { - const pane = new Pane(paneParams({items: [new Item(), new Item()]})) + const pane = new Pane(paneParams({ items: [new Item(), new Item()] })) const [item1, item2] = pane.getItems() const observed = [] @@ -745,8 +815,10 @@ describe('Pane', () => { describe('when an item emits a destroyed event', () => { it('removes it from the list of items', () => { - const pane = new Pane(paneParams({items: [new Item('A'), new Item('B'), new Item('C')]})) - const [item1,, item3] = pane.getItems() + const pane = new Pane( + paneParams({ items: [new Item('A'), new Item('B'), new Item('C')] }) + ) + const [item1, , item3] = pane.getItems() pane.itemAtIndex(1).destroy() expect(pane.getItems()).toEqual([item1, item3]) }) @@ -754,7 +826,9 @@ describe('Pane', () => { describe('::destroyInactiveItems()', () => { it('destroys all items but the active item', () => { - const pane = new Pane(paneParams({items: [new Item('A'), new Item('B'), new Item('C')]})) + const pane = new Pane( + paneParams({ items: [new Item('A'), new Item('B'), new Item('C')] }) + ) const [, item2] = pane.getItems() pane.activateItem(item2) pane.destroyInactiveItems() @@ -766,8 +840,10 @@ describe('Pane', () => { let pane beforeEach(() => { - pane = new Pane(paneParams({items: [new Item('A')]})) - showSaveDialog.andCallFake((options, callback) => callback('/selected/path')) + pane = new Pane(paneParams({ items: [new Item('A')] })) + showSaveDialog.andCallFake((options, callback) => + callback('/selected/path') + ) }) describe('when the active item has a uri', () => { @@ -797,7 +873,9 @@ describe('Pane', () => { pane.getActiveItem().saveAs = jasmine.createSpy('saveAs') await pane.saveActiveItem() expect(showSaveDialog.mostRecentCall.args[0]).toEqual({}) - expect(pane.getActiveItem().saveAs).toHaveBeenCalledWith('/selected/path') + expect(pane.getActiveItem().saveAs).toHaveBeenCalledWith( + '/selected/path' + ) }) }) @@ -826,14 +904,16 @@ describe('Pane', () => { return Promise.reject(error) } - waitsFor((done) => { - const subscription = atom.notifications.onDidAddNotification(function (notification) { - expect(notification.getType()).toBe('warning') - expect(notification.getMessage()).toContain('Permission denied') - expect(notification.getMessage()).toContain('/foo') - subscription.dispose() - done() - }) + waitsFor(done => { + const subscription = atom.notifications.onDidAddNotification( + function (notification) { + expect(notification.getType()).toBe('warning') + expect(notification.getMessage()).toContain('Permission denied') + expect(notification.getMessage()).toContain('/foo') + subscription.dispose() + done() + } + ) pane.saveActiveItem() }) }) @@ -848,14 +928,16 @@ describe('Pane', () => { throw error } - waitsFor((done) => { - const subscription = atom.notifications.onDidAddNotification(function (notification) { - expect(notification.getType()).toBe('warning') - expect(notification.getMessage()).toContain('Permission denied') - expect(notification.getMessage()).toContain('/foo') - subscription.dispose() - done() - }) + waitsFor(done => { + const subscription = atom.notifications.onDidAddNotification( + function (notification) { + expect(notification.getType()).toBe('warning') + expect(notification.getMessage()).toContain('Permission denied') + expect(notification.getMessage()).toContain('/foo') + subscription.dispose() + done() + } + ) pane.saveActiveItem() }) }) @@ -866,8 +948,10 @@ describe('Pane', () => { let pane = null beforeEach(() => { - pane = new Pane(paneParams({items: [new Item('A')]})) - showSaveDialog.andCallFake((options, callback) => callback('/selected/path')) + pane = new Pane(paneParams({ items: [new Item('A')] })) + showSaveDialog.andCallFake((options, callback) => + callback('/selected/path') + ) }) describe('when the current item has a saveAs method', () => { @@ -877,10 +961,16 @@ describe('Pane', () => { pane.getActiveItem().path = __filename pane.getActiveItem().saveAs = jasmine.createSpy('saveAs') pane.saveActiveItemAs() - expect(showSaveDialog.mostRecentCall.args[0]).toEqual({defaultPath: __filename}) + expect(showSaveDialog.mostRecentCall.args[0]).toEqual({ + defaultPath: __filename + }) - await conditionPromise(() => pane.getActiveItem().saveAs.callCount === 1) - expect(pane.getActiveItem().saveAs).toHaveBeenCalledWith('/selected/path') + await conditionPromise( + () => pane.getActiveItem().saveAs.callCount === 1 + ) + expect(pane.getActiveItem().saveAs).toHaveBeenCalledWith( + '/selected/path' + ) }) }) @@ -901,14 +991,16 @@ describe('Pane', () => { return Promise.reject(error) } - waitsFor((done) => { - const subscription = atom.notifications.onDidAddNotification(function (notification) { - expect(notification.getType()).toBe('warning') - expect(notification.getMessage()).toContain('Permission denied') - expect(notification.getMessage()).toContain('/foo') - subscription.dispose() - done() - }) + waitsFor(done => { + const subscription = atom.notifications.onDidAddNotification( + function (notification) { + expect(notification.getType()).toBe('warning') + expect(notification.getMessage()).toContain('Permission denied') + expect(notification.getMessage()).toContain('/foo') + subscription.dispose() + done() + } + ) pane.saveActiveItemAs() }) }) @@ -917,7 +1009,11 @@ describe('Pane', () => { describe('::itemForURI(uri)', () => { it('returns the item for which a call to .getURI() returns the given uri', () => { - const pane = new Pane(paneParams({items: [new Item('A'), new Item('B'), new Item('C'), new Item('D')]})) + const pane = new Pane( + paneParams({ + items: [new Item('A'), new Item('B'), new Item('C'), new Item('D')] + }) + ) const [item1, item2] = pane.getItems() item1.uri = 'a' item2.uri = 'b' @@ -931,7 +1027,11 @@ describe('Pane', () => { let pane, item1, item2, item3, item4 beforeEach(() => { - pane = new Pane(paneParams({items: [new Item('A'), new Item('B'), new Item('C'), new Item('D')]})) + pane = new Pane( + paneParams({ + items: [new Item('A'), new Item('B'), new Item('C'), new Item('D')] + }) + ) ;[item1, item2, item3, item4] = pane.getItems() }) @@ -953,8 +1053,8 @@ describe('Pane', () => { pane.moveItem(item1, 2) pane.moveItem(item2, 3) expect(events).toEqual([ - {item: item1, oldIndex: 0, newIndex: 2}, - {item: item2, oldIndex: 0, newIndex: 3} + { item: item1, oldIndex: 0, newIndex: 2 }, + { item: item2, oldIndex: 0, newIndex: 3 } ]) }) }) @@ -964,12 +1064,12 @@ describe('Pane', () => { let item1, item2, item3, item4, item5 beforeEach(() => { - container = new PaneContainer({config: atom.config, confirm}) + container = new PaneContainer({ config: atom.config, confirm }) pane1 = container.getActivePane() pane1.addItems([new Item('A'), new Item('B'), new Item('C')]) - pane2 = pane1.splitRight({items: [new Item('D'), new Item('E')]}); - [item1, item2, item3] = pane1.getItems(); - [item4, item5] = pane2.getItems() + pane2 = pane1.splitRight({ items: [new Item('D'), new Item('E')] }) + ;[item1, item2, item3] = pane1.getItems() + ;[item4, item5] = pane2.getItems() }) it('moves the item to the given pane at the given index', () => { @@ -983,7 +1083,9 @@ describe('Pane', () => { pane1.onWillRemoveItem(event => events.push(event)) pane1.moveItemToPane(item2, pane2, 1) - expect(events).toEqual([{item: item2, index: 1, moved: true, destroyed: false}]) + expect(events).toEqual([ + { item: item2, index: 1, moved: true, destroyed: false } + ]) }) it('invokes ::onDidRemoveItem() observers', () => { @@ -991,7 +1093,9 @@ describe('Pane', () => { pane1.onDidRemoveItem(event => events.push(event)) pane1.moveItemToPane(item2, pane2, 1) - expect(events).toEqual([{item: item2, index: 1, moved: true, destroyed: false}]) + expect(events).toEqual([ + { item: item2, index: 1, moved: true, destroyed: false } + ]) }) it('does not invoke ::onDidAddPaneItem observers on the container', () => { @@ -1025,7 +1129,7 @@ describe('Pane', () => { describe('when the item being moved is pending', () => { it('is made permanent in the new pane', () => { const item6 = new Item('F') - pane1.addItem(item6, {pending: true}) + pane1.addItem(item6, { pending: true }) expect(pane1.getPendingItem()).toEqual(item6) pane1.moveItemToPane(item6, pane2, 0) expect(pane2.getPendingItem()).not.toEqual(item6) @@ -1035,7 +1139,7 @@ describe('Pane', () => { describe('when the target pane has a pending item', () => { it('does not destroy the pending item', () => { const item6 = new Item('F') - pane1.addItem(item6, {pending: true}) + pane1.addItem(item6, { pending: true }) expect(pane1.getPendingItem()).toEqual(item6) pane2.moveItemToPane(item5, pane1, 0) expect(pane1.getPendingItem()).toEqual(item6) @@ -1047,7 +1151,11 @@ describe('Pane', () => { let pane1, item1, container beforeEach(() => { - container = new PaneContainer({config: atom.config, confirm, deserializerManager: atom.deserializers}) + container = new PaneContainer({ + config: atom.config, + confirm, + deserializerManager: atom.deserializers + }) pane1 = container.getActivePane() item1 = new Item('A') pane1.addItem(item1) @@ -1056,8 +1164,8 @@ describe('Pane', () => { describe('::splitLeft(params)', () => { describe('when the parent is the container root', () => { it('replaces itself with a row and inserts a new pane to the left of itself', () => { - const pane2 = pane1.splitLeft({items: [new Item('B')]}) - const pane3 = pane1.splitLeft({items: [new Item('C')]}) + const pane2 = pane1.splitLeft({ items: [new Item('B')] }) + const pane3 = pane1.splitLeft({ items: [new Item('C')] }) expect(container.root.orientation).toBe('horizontal') expect(container.root.children).toEqual([pane2, pane3, pane1]) }) @@ -1065,20 +1173,20 @@ describe('Pane', () => { describe('when `moveActiveItem: true` is passed in the params', () => { it('moves the active item', () => { - const pane2 = pane1.splitLeft({moveActiveItem: true}) + const pane2 = pane1.splitLeft({ moveActiveItem: true }) expect(pane2.getActiveItem()).toBe(item1) }) }) describe('when `copyActiveItem: true` is passed in the params', () => { it('duplicates the active item', () => { - const pane2 = pane1.splitLeft({copyActiveItem: true}) + const pane2 = pane1.splitLeft({ copyActiveItem: true }) expect(pane2.getActiveItem()).toEqual(pane1.getActiveItem()) }) it("does nothing if the active item doesn't implement .copy()", () => { item1.copy = null - const pane2 = pane1.splitLeft({copyActiveItem: true}) + const pane2 = pane1.splitLeft({ copyActiveItem: true }) expect(pane2.getActiveItem()).toBeUndefined() }) }) @@ -1086,8 +1194,8 @@ describe('Pane', () => { describe('when the parent is a column', () => { it('replaces itself with a row and inserts a new pane to the left of itself', () => { pane1.splitDown() - const pane2 = pane1.splitLeft({items: [new Item('B')]}) - const pane3 = pane1.splitLeft({items: [new Item('C')]}) + const pane2 = pane1.splitLeft({ items: [new Item('B')] }) + const pane3 = pane1.splitLeft({ items: [new Item('C')] }) const row = container.root.children[0] expect(row.orientation).toBe('horizontal') expect(row.children).toEqual([pane2, pane3, pane1]) @@ -1098,8 +1206,8 @@ describe('Pane', () => { describe('::splitRight(params)', () => { describe('when the parent is the container root', () => { it('replaces itself with a row and inserts a new pane to the right of itself', () => { - const pane2 = pane1.splitRight({items: [new Item('B')]}) - const pane3 = pane1.splitRight({items: [new Item('C')]}) + const pane2 = pane1.splitRight({ items: [new Item('B')] }) + const pane3 = pane1.splitRight({ items: [new Item('C')] }) expect(container.root.orientation).toBe('horizontal') expect(container.root.children).toEqual([pane1, pane3, pane2]) }) @@ -1107,14 +1215,14 @@ describe('Pane', () => { describe('when `moveActiveItem: true` is passed in the params', () => { it('moves the active item', () => { - const pane2 = pane1.splitRight({moveActiveItem: true}) + const pane2 = pane1.splitRight({ moveActiveItem: true }) expect(pane2.getActiveItem()).toBe(item1) }) }) describe('when `copyActiveItem: true` is passed in the params', () => { it('duplicates the active item', () => { - const pane2 = pane1.splitRight({copyActiveItem: true}) + const pane2 = pane1.splitRight({ copyActiveItem: true }) expect(pane2.getActiveItem()).toEqual(pane1.getActiveItem()) }) }) @@ -1122,8 +1230,8 @@ describe('Pane', () => { describe('when the parent is a column', () => { it('replaces itself with a row and inserts a new pane to the right of itself', () => { pane1.splitDown() - const pane2 = pane1.splitRight({items: [new Item('B')]}) - const pane3 = pane1.splitRight({items: [new Item('C')]}) + const pane2 = pane1.splitRight({ items: [new Item('B')] }) + const pane3 = pane1.splitRight({ items: [new Item('C')] }) const row = container.root.children[0] expect(row.orientation).toBe('horizontal') expect(row.children).toEqual([pane1, pane3, pane2]) @@ -1134,8 +1242,8 @@ describe('Pane', () => { describe('::splitUp(params)', () => { describe('when the parent is the container root', () => { it('replaces itself with a column and inserts a new pane above itself', () => { - const pane2 = pane1.splitUp({items: [new Item('B')]}) - const pane3 = pane1.splitUp({items: [new Item('C')]}) + const pane2 = pane1.splitUp({ items: [new Item('B')] }) + const pane3 = pane1.splitUp({ items: [new Item('C')] }) expect(container.root.orientation).toBe('vertical') expect(container.root.children).toEqual([pane2, pane3, pane1]) }) @@ -1143,14 +1251,14 @@ describe('Pane', () => { describe('when `moveActiveItem: true` is passed in the params', () => { it('moves the active item', () => { - const pane2 = pane1.splitUp({moveActiveItem: true}) + const pane2 = pane1.splitUp({ moveActiveItem: true }) expect(pane2.getActiveItem()).toBe(item1) }) }) describe('when `copyActiveItem: true` is passed in the params', () => { it('duplicates the active item', () => { - const pane2 = pane1.splitUp({copyActiveItem: true}) + const pane2 = pane1.splitUp({ copyActiveItem: true }) expect(pane2.getActiveItem()).toEqual(pane1.getActiveItem()) }) }) @@ -1158,8 +1266,8 @@ describe('Pane', () => { describe('when the parent is a row', () => { it('replaces itself with a column and inserts a new pane above itself', () => { pane1.splitRight() - const pane2 = pane1.splitUp({items: [new Item('B')]}) - const pane3 = pane1.splitUp({items: [new Item('C')]}) + const pane2 = pane1.splitUp({ items: [new Item('B')] }) + const pane3 = pane1.splitUp({ items: [new Item('C')] }) const column = container.root.children[0] expect(column.orientation).toBe('vertical') expect(column.children).toEqual([pane2, pane3, pane1]) @@ -1170,8 +1278,8 @@ describe('Pane', () => { describe('::splitDown(params)', () => { describe('when the parent is the container root', () => { it('replaces itself with a column and inserts a new pane below itself', () => { - const pane2 = pane1.splitDown({items: [new Item('B')]}) - const pane3 = pane1.splitDown({items: [new Item('C')]}) + const pane2 = pane1.splitDown({ items: [new Item('B')] }) + const pane3 = pane1.splitDown({ items: [new Item('C')] }) expect(container.root.orientation).toBe('vertical') expect(container.root.children).toEqual([pane1, pane3, pane2]) }) @@ -1179,14 +1287,14 @@ describe('Pane', () => { describe('when `moveActiveItem: true` is passed in the params', () => { it('moves the active item', () => { - const pane2 = pane1.splitDown({moveActiveItem: true}) + const pane2 = pane1.splitDown({ moveActiveItem: true }) expect(pane2.getActiveItem()).toBe(item1) }) }) describe('when `copyActiveItem: true` is passed in the params', () => { it('duplicates the active item', () => { - const pane2 = pane1.splitDown({copyActiveItem: true}) + const pane2 = pane1.splitDown({ copyActiveItem: true }) expect(pane2.getActiveItem()).toEqual(pane1.getActiveItem()) }) }) @@ -1194,8 +1302,8 @@ describe('Pane', () => { describe('when the parent is a row', () => { it('replaces itself with a column and inserts a new pane below itself', () => { pane1.splitRight() - const pane2 = pane1.splitDown({items: [new Item('B')]}) - const pane3 = pane1.splitDown({items: [new Item('C')]}) + const pane2 = pane1.splitDown({ items: [new Item('B')] }) + const pane3 = pane1.splitDown({ items: [new Item('C')] }) const column = container.root.children[0] expect(column.orientation).toBe('vertical') expect(column.children).toEqual([pane1, pane3, pane2]) @@ -1209,7 +1317,9 @@ describe('Pane', () => { pane1.destroyItem(item1) expect(pane1.getActiveItem()).toBe(undefined) - const pane2 = pane1.split('horizontal', 'before', {moveActiveItem: true}) + const pane2 = pane1.split('horizontal', 'before', { + moveActiveItem: true + }) expect(container.root.children).toEqual([pane2, pane1]) expect(pane2.getActiveItem()).toBe(undefined) @@ -1221,7 +1331,9 @@ describe('Pane', () => { pane1.destroyItem(item1) expect(pane1.getActiveItem()).toBe(undefined) - const pane2 = pane1.split('horizontal', 'before', {copyActiveItem: true}) + const pane2 = pane1.split('horizontal', 'before', { + copyActiveItem: true + }) expect(container.root.children).toEqual([pane2, pane1]) expect(pane2.getActiveItem()).toBe(undefined) @@ -1239,7 +1351,9 @@ describe('Pane', () => { describe('::close()', () => { it('prompts to save unsaved items before destroying the pane', async () => { - const pane = new Pane(paneParams({items: [new Item('A'), new Item('B')]})) + const pane = new Pane( + paneParams({ items: [new Item('A'), new Item('B')] }) + ) const [item1] = pane.getItems() item1.shouldPromptToSave = () => true @@ -1254,7 +1368,9 @@ describe('Pane', () => { }) it('does not destroy the pane if the user clicks cancel', async () => { - const pane = new Pane(paneParams({items: [new Item('A'), new Item('B')]})) + const pane = new Pane( + paneParams({ items: [new Item('A'), new Item('B')] }) + ) const [item1] = pane.getItems() item1.shouldPromptToSave = () => true @@ -1270,7 +1386,9 @@ describe('Pane', () => { }) it('does not destroy the pane if the user starts to save but then does not choose a path', async () => { - const pane = new Pane(paneParams({items: [new Item('A'), new Item('B')]})) + const pane = new Pane( + paneParams({ items: [new Item('A'), new Item('B')] }) + ) const [item1] = pane.getItems() item1.shouldPromptToSave = () => true @@ -1290,8 +1408,12 @@ describe('Pane', () => { let pane, item1 beforeEach(() => { - pane = new Pane({items: [new Item('A'), new Item('B')], applicationDelegate: atom.applicationDelegate, config: atom.config}); - [item1] = pane.getItems() + pane = new Pane({ + items: [new Item('A'), new Item('B')], + applicationDelegate: atom.applicationDelegate, + config: atom.config + }) + ;[item1] = pane.getItems() item1.shouldPromptToSave = () => true item1.getURI = () => '/test/path' @@ -1336,7 +1458,9 @@ describe('Pane', () => { await pane.close() expect(atom.applicationDelegate.confirm).toHaveBeenCalled() expect(confirmations).toBe(2) - expect(atom.applicationDelegate.showSaveDialog.mostRecentCall.args[0]).toEqual({}) + expect( + atom.applicationDelegate.showSaveDialog.mostRecentCall.args[0] + ).toEqual({}) expect(item1.save).toHaveBeenCalled() expect(item1.saveAs).toHaveBeenCalled() expect(pane.isDestroyed()).toBe(true) @@ -1365,7 +1489,9 @@ describe('Pane', () => { await pane.close() expect(atom.applicationDelegate.confirm).toHaveBeenCalled() expect(confirmations).toBe(3) - expect(atom.applicationDelegate.showSaveDialog.mostRecentCall.args[0]).toEqual({}) + expect( + atom.applicationDelegate.showSaveDialog.mostRecentCall.args[0] + ).toEqual({}) expect(item1.save).toHaveBeenCalled() expect(item1.saveAs).toHaveBeenCalled() expect(pane.isDestroyed()).toBe(true) @@ -1377,7 +1503,7 @@ describe('Pane', () => { let container, pane1, pane2 beforeEach(() => { - container = new PaneContainer({config: atom.config, confirm}) + container = new PaneContainer({ config: atom.config, confirm }) pane1 = container.root pane1.addItems([new Item('A'), new Item('B')]) pane2 = pane1.splitRight() @@ -1386,7 +1512,7 @@ describe('Pane', () => { it('invokes ::onWillDestroy observers before destroying items', () => { let itemsDestroyed = null pane1.onWillDestroy(() => { - itemsDestroyed = (pane1.getItems().map((item) => item.isDestroyed())) + itemsDestroyed = pane1.getItems().map(item => item.isDestroyed()) }) pane1.destroy() expect(itemsDestroyed).toEqual([false, false]) @@ -1435,7 +1561,7 @@ describe('Pane', () => { let editor1, pane, eventCount beforeEach(async () => { - editor1 = await atom.workspace.open('sample.txt', {pending: true}) + editor1 = await atom.workspace.open('sample.txt', { pending: true }) pane = atom.workspace.getActivePane() eventCount = 0 editor1.onDidTerminatePendingState(() => eventCount++) @@ -1458,7 +1584,7 @@ describe('Pane', () => { }) it('terminates pending state when buffer is changed', () => { - editor1.insertText('I\'ll be back!') + editor1.insertText("I'll be back!") advanceClock(editor1.getBuffer().stoppedChangingDelay) expect(pane.getPendingItem()).toBeNull() @@ -1498,10 +1624,12 @@ describe('Pane', () => { let pane = null beforeEach(() => { - pane = new Pane(paneParams({ - items: [new Item('A', 'a'), new Item('B', 'b'), new Item('C', 'c')], - flexScale: 2 - })) + pane = new Pane( + paneParams({ + items: [new Item('A', 'a'), new Item('B', 'b'), new Item('C', 'c')], + flexScale: 2 + }) + ) }) it('can serialize and deserialize the pane and all its items', () => { @@ -1524,7 +1652,7 @@ describe('Pane', () => { it("restores the correct item when it doesn't implement getURI() and some items weren't deserialized", () => { const unserializable = {} - pane.addItem(unserializable, {index: 0}) + pane.addItem(unserializable, { index: 0 }) pane.items[2].getURI = null pane.activateItemAtIndex(2) const newPane = Pane.deserialize(pane.serialize(), atom) diff --git a/spec/panel-container-element-spec.js b/spec/panel-container-element-spec.js index 5634883df..039061ae8 100644 --- a/spec/panel-container-element-spec.js +++ b/spec/panel-container-element-spec.js @@ -6,8 +6,7 @@ const PanelContainer = require('../src/panel-container') describe('PanelContainerElement', () => { let jasmineContent, element, container - class TestPanelContainerItem { - } + class TestPanelContainerItem {} class TestPanelContainerItemElement_ extends HTMLElement { createdCallback () { @@ -17,23 +16,25 @@ describe('PanelContainerElement', () => { this.model = model return this } - focus() {} + focus () {} } const TestPanelContainerItemElement = document.registerElement( 'atom-test-container-item-element', - {prototype: TestPanelContainerItemElement_.prototype} + { prototype: TestPanelContainerItemElement_.prototype } ) beforeEach(() => { jasmineContent = document.body.querySelector('#jasmine-content') - atom.views.addViewProvider( - TestPanelContainerItem, - model => new TestPanelContainerItemElement().initialize(model) + atom.views.addViewProvider(TestPanelContainerItem, model => + new TestPanelContainerItemElement().initialize(model) ) - container = new PanelContainer({viewRegistry: atom.views, location: 'left'}) + container = new PanelContainer({ + viewRegistry: atom.views, + location: 'left' + }) element = container.getElement() jasmineContent.appendChild(element) }) @@ -50,9 +51,18 @@ describe('PanelContainerElement', () => { describe('adding and removing panels', () => { it('allows panels to be inserted at any position', () => { - const panel1 = new Panel({item: new TestPanelContainerItem(), priority: 10}, atom.views) - const panel2 = new Panel({item: new TestPanelContainerItem(), priority: 5}, atom.views) - const panel3 = new Panel({item: new TestPanelContainerItem(), priority: 8}, atom.views) + const panel1 = new Panel( + { item: new TestPanelContainerItem(), priority: 10 }, + atom.views + ) + const panel2 = new Panel( + { item: new TestPanelContainerItem(), priority: 5 }, + atom.views + ) + const panel3 = new Panel( + { item: new TestPanelContainerItem(), priority: 8 }, + atom.views + ) container.addPanel(panel1) container.addPanel(panel2) @@ -67,7 +77,10 @@ describe('PanelContainerElement', () => { it('adds atom-panel elements when a new panel is added to the container; removes them when the panels are destroyed', () => { expect(element.childNodes.length).toBe(0) - const panel1 = new Panel({item: new TestPanelContainerItem()}, atom.views) + const panel1 = new Panel( + { item: new TestPanelContainerItem() }, + atom.views + ) container.addPanel(panel1) expect(element.childNodes.length).toBe(1) expect(element.childNodes[0]).toHaveClass('left') @@ -76,7 +89,10 @@ describe('PanelContainerElement', () => { expect(element.childNodes[0].tagName).toBe('ATOM-PANEL') - const panel2 = new Panel({item: new TestPanelContainerItem()}, atom.views) + const panel2 = new Panel( + { item: new TestPanelContainerItem() }, + atom.views + ) container.addPanel(panel2) expect(element.childNodes.length).toBe(2) @@ -88,12 +104,14 @@ describe('PanelContainerElement', () => { panel2.destroy() expect(element.childNodes.length).toBe(0) - }) - ) + })) describe('when the container is at the bottom location', () => { beforeEach(() => { - container = new PanelContainer({viewRegistry: atom.views, location: 'bottom'}) + container = new PanelContainer({ + viewRegistry: atom.views, + location: 'bottom' + }) element = container.getElement() jasmineContent.appendChild(element) }) @@ -101,7 +119,10 @@ describe('PanelContainerElement', () => { it('adds atom-panel elements when a new panel is added to the container; removes them when the panels are destroyed', () => { expect(element.childNodes.length).toBe(0) - const panel1 = new Panel({item: new TestPanelContainerItem(), className: 'one'}, atom.views) + const panel1 = new Panel( + { item: new TestPanelContainerItem(), className: 'one' }, + atom.views + ) container.addPanel(panel1) expect(element.childNodes.length).toBe(1) expect(element.childNodes[0]).toHaveClass('bottom') @@ -110,7 +131,10 @@ describe('PanelContainerElement', () => { expect(element.childNodes[0].tagName).toBe('ATOM-PANEL') expect(panel1.getElement()).toHaveClass('one') - const panel2 = new Panel({item: new TestPanelContainerItem(), className: 'two'}, atom.views) + const panel2 = new Panel( + { item: new TestPanelContainerItem(), className: 'two' }, + atom.views + ) container.addPanel(panel2) expect(element.childNodes.length).toBe(2) expect(panel2.getElement()).toHaveClass('two') @@ -126,18 +150,27 @@ describe('PanelContainerElement', () => { describe('when the container is modal', () => { beforeEach(() => { - container = new PanelContainer({viewRegistry: atom.views, location: 'modal'}) + container = new PanelContainer({ + viewRegistry: atom.views, + location: 'modal' + }) element = container.getElement() jasmineContent.appendChild(element) }) it('allows only one panel to be visible at a time', () => { - const panel1 = new Panel({item: new TestPanelContainerItem()}, atom.views) + const panel1 = new Panel( + { item: new TestPanelContainerItem() }, + atom.views + ) container.addPanel(panel1) expect(panel1.getElement().style.display).not.toBe('none') - const panel2 = new Panel({item: new TestPanelContainerItem()}, atom.views) + const panel2 = new Panel( + { item: new TestPanelContainerItem() }, + atom.views + ) container.addPanel(panel2) expect(panel1.getElement().style.display).toBe('none') @@ -150,7 +183,10 @@ describe('PanelContainerElement', () => { }) it("adds the 'modal' class to panels", () => { - const panel1 = new Panel({item: new TestPanelContainerItem()}, atom.views) + const panel1 = new Panel( + { item: new TestPanelContainerItem() }, + atom.views + ) container.addPanel(panel1) expect(panel1.getElement()).toHaveClass('modal') @@ -161,8 +197,8 @@ describe('PanelContainerElement', () => { expect(panel1.getElement()).toHaveClass('from-top') }) - describe("autoFocus", () => { - function createPanel() { + describe('autoFocus', () => { + function createPanel () { const panel = new Panel( { item: new TestPanelContainerItem(), @@ -176,7 +212,7 @@ describe('PanelContainerElement', () => { return panel } - it("focuses the first tabbable item if available", () => { + it('focuses the first tabbable item if available', () => { const panel = createPanel() const panelEl = panel.getElement() const inputEl = document.createElement('input') @@ -188,7 +224,7 @@ describe('PanelContainerElement', () => { expect(document.activeElement).toBe(inputEl) }) - it("focuses the entire panel item when no tabbable item is available and the panel is focusable", () => { + it('focuses the entire panel item when no tabbable item is available and the panel is focusable', () => { const panel = createPanel() const panelEl = panel.getElement() @@ -197,7 +233,7 @@ describe('PanelContainerElement', () => { expect(panelEl.focus).toHaveBeenCalled() }) - it("returns focus to the original activeElement", () => { + it('returns focus to the original activeElement', () => { const panel = createPanel() const previousActiveElement = document.activeElement const panelEl = panel.getElement() diff --git a/spec/panel-container-spec.js b/spec/panel-container-spec.js index f5537f0b8..35286cd36 100644 --- a/spec/panel-container-spec.js +++ b/spec/panel-container-spec.js @@ -6,11 +6,10 @@ const PanelContainer = require('../src/panel-container') describe('PanelContainer', () => { let container - class TestPanelItem { - } + class TestPanelItem {} beforeEach(() => { - container = new PanelContainer({viewRegistry: atom.views}) + container = new PanelContainer({ viewRegistry: atom.views }) }) describe('::addPanel(panel)', () => { @@ -18,13 +17,13 @@ describe('PanelContainer', () => { const addPanelSpy = jasmine.createSpy() container.onDidAddPanel(addPanelSpy) - const panel1 = new Panel({item: new TestPanelItem()}, atom.views) + const panel1 = new Panel({ item: new TestPanelItem() }, atom.views) container.addPanel(panel1) - expect(addPanelSpy).toHaveBeenCalledWith({panel: panel1, index: 0}) + expect(addPanelSpy).toHaveBeenCalledWith({ panel: panel1, index: 0 }) - const panel2 = new Panel({item: new TestPanelItem()}, atom.views) + const panel2 = new Panel({ item: new TestPanelItem() }, atom.views) container.addPanel(panel2) - expect(addPanelSpy).toHaveBeenCalledWith({panel: panel2, index: 1}) + expect(addPanelSpy).toHaveBeenCalledWith({ panel: panel2, index: 1 }) }) }) @@ -33,18 +32,18 @@ describe('PanelContainer', () => { const removePanelSpy = jasmine.createSpy() container.onDidRemovePanel(removePanelSpy) - const panel1 = new Panel({item: new TestPanelItem()}, atom.views) + const panel1 = new Panel({ item: new TestPanelItem() }, atom.views) container.addPanel(panel1) - const panel2 = new Panel({item: new TestPanelItem()}, atom.views) + const panel2 = new Panel({ item: new TestPanelItem() }, atom.views) container.addPanel(panel2) expect(removePanelSpy).not.toHaveBeenCalled() panel2.destroy() - expect(removePanelSpy).toHaveBeenCalledWith({panel: panel2, index: 1}) + expect(removePanelSpy).toHaveBeenCalledWith({ panel: panel2, index: 1 }) panel1.destroy() - expect(removePanelSpy).toHaveBeenCalledWith({panel: panel1, index: 0}) + expect(removePanelSpy).toHaveBeenCalledWith({ panel: panel1, index: 0 }) }) }) @@ -52,12 +51,16 @@ describe('PanelContainer', () => { it('destroys the container and all of its panels', () => { const destroyedPanels = [] - const panel1 = new Panel({item: new TestPanelItem()}, atom.views) - panel1.onDidDestroy(() => { destroyedPanels.push(panel1) }) + const panel1 = new Panel({ item: new TestPanelItem() }, atom.views) + panel1.onDidDestroy(() => { + destroyedPanels.push(panel1) + }) container.addPanel(panel1) - const panel2 = new Panel({item: new TestPanelItem()}, atom.views) - panel2.onDidDestroy(() => { destroyedPanels.push(panel2) }) + const panel2 = new Panel({ item: new TestPanelItem() }, atom.views) + panel2.onDidDestroy(() => { + destroyedPanels.push(panel2) + }) container.addPanel(panel2) container.destroy() @@ -72,8 +75,8 @@ describe('PanelContainer', () => { let initialPanel beforeEach(() => { // 'left' logic is the same as 'top' - container = new PanelContainer({location: 'left'}) - initialPanel = new Panel({item: new TestPanelItem()}, atom.views) + container = new PanelContainer({ location: 'left' }) + initialPanel = new Panel({ item: new TestPanelItem() }, atom.views) container.addPanel(initialPanel) }) @@ -81,10 +84,13 @@ describe('PanelContainer', () => { it('is inserted at the beginning of the list', () => { const addPanelSpy = jasmine.createSpy() container.onDidAddPanel(addPanelSpy) - const panel = new Panel({item: new TestPanelItem(), priority: 0}, atom.views) + const panel = new Panel( + { item: new TestPanelItem(), priority: 0 }, + atom.views + ) container.addPanel(panel) - expect(addPanelSpy).toHaveBeenCalledWith({panel, index: 0}) + expect(addPanelSpy).toHaveBeenCalledWith({ panel, index: 0 }) expect(container.getPanels()[0]).toBe(panel) }) }) @@ -92,14 +98,20 @@ describe('PanelContainer', () => { describe('when a panel with priority between two other panels is added', () => { it('is inserted at the between the two panels', () => { const addPanelSpy = jasmine.createSpy() - let panel = new Panel({item: new TestPanelItem(), priority: 1000}, atom.views) + let panel = new Panel( + { item: new TestPanelItem(), priority: 1000 }, + atom.views + ) container.addPanel(panel) container.onDidAddPanel(addPanelSpy) - panel = new Panel({item: new TestPanelItem(), priority: 101}, atom.views) + panel = new Panel( + { item: new TestPanelItem(), priority: 101 }, + atom.views + ) container.addPanel(panel) - expect(addPanelSpy).toHaveBeenCalledWith({panel, index: 1}) + expect(addPanelSpy).toHaveBeenCalledWith({ panel, index: 1 }) expect(container.getPanels()[1]).toBe(panel) }) }) @@ -109,8 +121,8 @@ describe('PanelContainer', () => { let initialPanel beforeEach(() => { // 'bottom' logic is the same as 'right' - container = new PanelContainer({location: 'right'}) - initialPanel = new Panel({item: new TestPanelItem()}, atom.views) + container = new PanelContainer({ location: 'right' }) + initialPanel = new Panel({ item: new TestPanelItem() }, atom.views) container.addPanel(initialPanel) }) @@ -118,10 +130,13 @@ describe('PanelContainer', () => { it('is inserted at the beginning of the list', () => { const addPanelSpy = jasmine.createSpy() container.onDidAddPanel(addPanelSpy) - const panel = new Panel({item: new TestPanelItem(), priority: 1000}, atom.views) + const panel = new Panel( + { item: new TestPanelItem(), priority: 1000 }, + atom.views + ) container.addPanel(panel) - expect(addPanelSpy).toHaveBeenCalledWith({panel, index: 0}) + expect(addPanelSpy).toHaveBeenCalledWith({ panel, index: 0 }) expect(container.getPanels()[0]).toBe(panel) }) }) @@ -130,10 +145,13 @@ describe('PanelContainer', () => { it('is inserted at the end of the list', () => { const addPanelSpy = jasmine.createSpy() container.onDidAddPanel(addPanelSpy) - const panel = new Panel({item: new TestPanelItem(), priority: 0}, atom.views) + const panel = new Panel( + { item: new TestPanelItem(), priority: 0 }, + atom.views + ) container.addPanel(panel) - expect(addPanelSpy).toHaveBeenCalledWith({panel, index: 1}) + expect(addPanelSpy).toHaveBeenCalledWith({ panel, index: 1 }) expect(container.getPanels()[1]).toBe(panel) }) }) diff --git a/spec/panel-spec.js b/spec/panel-spec.js index 8df51a2fb..7e1365a67 100644 --- a/spec/panel-spec.js +++ b/spec/panel-spec.js @@ -12,8 +12,8 @@ describe('Panel', () => { } } - it('adds the item\'s element as a child of the panel', () => { - const panel = new Panel({item: new TestPanelItem()}, atom.views) + it("adds the item's element as a child of the panel", () => { + const panel = new Panel({ item: new TestPanelItem() }, atom.views) const element = panel.getElement() expect(element.tagName.toLowerCase()).toBe('atom-panel') expect(element.firstChild).toBe(panel.getItem().getElement()) @@ -21,7 +21,7 @@ describe('Panel', () => { describe('destroying the panel', () => { it('removes the element when the panel is destroyed', () => { - const panel = new Panel({item: new TestPanelItem()}, atom.views) + const panel = new Panel({ item: new TestPanelItem() }, atom.views) const element = panel.getElement() const jasmineContent = document.getElementById('jasmine-content') jasmineContent.appendChild(element) @@ -33,7 +33,7 @@ describe('Panel', () => { it('does not try to remove the element twice', () => { const item = new TestPanelItem() - const panel = new Panel({item}, atom.views) + const panel = new Panel({ item }, atom.views) const element = panel.getElement() const jasmineContent = document.getElementById('jasmine-content') jasmineContent.appendChild(element) @@ -52,7 +52,7 @@ describe('Panel', () => { describe('changing panel visibility', () => { it('notifies observers added with onDidChangeVisible', () => { - const panel = new Panel({item: new TestPanelItem()}, atom.views) + const panel = new Panel({ item: new TestPanelItem() }, atom.views) const spy = jasmine.createSpy() panel.onDidChangeVisible(spy) @@ -72,13 +72,16 @@ describe('Panel', () => { }) it('initially renders panel created with visible: false', () => { - const panel = new Panel({visible: false, item: new TestPanelItem()}, atom.views) + const panel = new Panel( + { visible: false, item: new TestPanelItem() }, + atom.views + ) const element = panel.getElement() expect(element.style.display).toBe('none') }) it('hides and shows the panel element when Panel::hide() and Panel::show() are called', () => { - const panel = new Panel({item: new TestPanelItem()}, atom.views) + const panel = new Panel({ item: new TestPanelItem() }, atom.views) const element = panel.getElement() expect(element.style.display).not.toBe('none') @@ -92,7 +95,10 @@ describe('Panel', () => { describe('when a class name is specified', () => { it('initially renders panel created with visible: false', () => { - const panel = new Panel({className: 'some classes', item: new TestPanelItem()}, atom.views) + const panel = new Panel( + { className: 'some classes', item: new TestPanelItem() }, + atom.views + ) const element = panel.getElement() expect(element).toHaveClass('some') diff --git a/spec/path-watcher-spec.js b/spec/path-watcher-spec.js index ae5cd7d75..050f9df45 100644 --- a/spec/path-watcher-spec.js +++ b/spec/path-watcher-spec.js @@ -1,16 +1,22 @@ /** @babel */ -import {it, beforeEach, afterEach, promisifySome} from './async-spec-helpers' +import { it, beforeEach, afterEach, promisifySome } from './async-spec-helpers' import tempCb from 'temp' import fsCb from 'fs-plus' import path from 'path' -import {CompositeDisposable} from 'event-kit' -import {watchPath, stopAllWatchers} from '../src/path-watcher' +import { CompositeDisposable } from 'event-kit' +import { watchPath, stopAllWatchers } from '../src/path-watcher' tempCb.track() -const fs = promisifySome(fsCb, ['writeFile', 'mkdir', 'symlink', 'appendFile', 'realpath']) +const fs = promisifySome(fsCb, [ + 'writeFile', + 'mkdir', + 'symlink', + 'appendFile', + 'realpath' +]) const temp = promisifySome(tempCb, ['mkdir']) describe('watchPath', function () { @@ -105,16 +111,18 @@ describe('watchPath', function () { waitForChanges(rootWatcher, subFile), waitForChanges(childWatcher, subFile) ]) - await fs.writeFile(subFile, 'subfile\n', {encoding: 'utf8'}) + await fs.writeFile(subFile, 'subfile\n', { encoding: 'utf8' }) await firstChanges const nextRootEvent = waitForChanges(rootWatcher, rootFile) - await fs.writeFile(rootFile, 'rootfile\n', {encoding: 'utf8'}) + await fs.writeFile(rootFile, 'rootfile\n', { encoding: 'utf8' }) await nextRootEvent }) it('adopts existing child watchers and filters events appropriately to them', async function () { - const parentDir = await temp.mkdir('atom-fsmanager-test-').then(fs.realpath) + const parentDir = await temp + .mkdir('atom-fsmanager-test-') + .then(fs.realpath) // Create the directory tree const rootFile = path.join(parentDir, 'rootfile.txt') @@ -126,9 +134,9 @@ describe('watchPath', function () { await fs.mkdir(subDir0) await fs.mkdir(subDir1) await Promise.all([ - fs.writeFile(rootFile, 'rootfile\n', {encoding: 'utf8'}), - fs.writeFile(subFile0, 'subfile 0\n', {encoding: 'utf8'}), - fs.writeFile(subFile1, 'subfile 1\n', {encoding: 'utf8'}) + fs.writeFile(rootFile, 'rootfile\n', { encoding: 'utf8' }), + fs.writeFile(subFile0, 'subfile 0\n', { encoding: 'utf8' }), + fs.writeFile(subFile1, 'subfile 1\n', { encoding: 'utf8' }) ]) // Begin the child watchers and keep them alive @@ -142,16 +150,21 @@ describe('watchPath', function () { // Create the parent watcher const parentWatcher = await watchPath(parentDir, {}, () => {}) - const parentWatcherChanges = waitForChanges(parentWatcher, rootFile, subFile0, subFile1) + const parentWatcherChanges = waitForChanges( + parentWatcher, + rootFile, + subFile0, + subFile1 + ) expect(subWatcher0.native).toBe(parentWatcher.native) expect(subWatcher1.native).toBe(parentWatcher.native) // Ensure events are filtered correctly await Promise.all([ - fs.appendFile(rootFile, 'change\n', {encoding: 'utf8'}), - fs.appendFile(subFile0, 'change\n', {encoding: 'utf8'}), - fs.appendFile(subFile1, 'change\n', {encoding: 'utf8'}) + fs.appendFile(rootFile, 'change\n', { encoding: 'utf8' }), + fs.appendFile(subFile0, 'change\n', { encoding: 'utf8' }), + fs.appendFile(subFile1, 'change\n', { encoding: 'utf8' }) ]) await Promise.all([ diff --git a/spec/project-spec.js b/spec/project-spec.js index 861a0f53a..2025cae71 100644 --- a/spec/project-spec.js +++ b/spec/project-spec.js @@ -3,8 +3,8 @@ const TextBuffer = require('text-buffer') const Project = require('../src/project') const fs = require('fs-plus') const path = require('path') -const {Directory} = require('pathwatcher') -const {stopAllWatchers} = require('../src/path-watcher') +const { Directory } = require('pathwatcher') +const { stopAllWatchers } = require('../src/path-watcher') const GitRepository = require('../src/git-repository') describe('Project', () => { @@ -46,13 +46,16 @@ describe('Project', () => { let err = null waitsForPromise(() => - deserializedProject.deserialize(state, atom.deserializers) - .catch(e => { err = e }) + deserializedProject.deserialize(state, atom.deserializers).catch(e => { + err = e + }) ) runs(() => { expect(deserializedProject.getPaths()).toEqual(atom.project.getPaths()) - expect(err.missingProjectPaths).toEqual(['/directory/that/does/not/exist']) + expect(err.missingProjectPaths).toEqual([ + '/directory/that/does/not/exist' + ]) }) }) @@ -74,8 +77,9 @@ describe('Project', () => { let err = null waitsForPromise(() => - deserializedProject.deserialize(state, atom.deserializers) - .catch(e => { err = e }) + deserializedProject.deserialize(state, atom.deserializers).catch(e => { + err = e + }) ) runs(() => { @@ -98,7 +102,11 @@ describe('Project', () => { }) }) - waitsForPromise(() => deserializedProject.deserialize(atom.project.serialize({isUnloading: false}))) + waitsForPromise(() => + deserializedProject.deserialize( + atom.project.serialize({ isUnloading: false }) + ) + ) runs(() => expect(deserializedProject.getBuffers().length).toBe(0)) }) @@ -116,7 +124,11 @@ describe('Project', () => { }) }) - waitsForPromise(() => deserializedProject.deserialize(atom.project.serialize({isUnloading: false}))) + waitsForPromise(() => + deserializedProject.deserialize( + atom.project.serialize({ isUnloading: false }) + ) + ) runs(() => { expect(deserializedProject.getBuffers().length).toBe(1) @@ -126,7 +138,10 @@ describe('Project', () => { }) it('does not deserialize buffers when their path is now a directory', () => { - const pathToOpen = path.join(temp.mkdirSync('atom-spec-project'), 'file.txt') + const pathToOpen = path.join( + temp.mkdirSync('atom-spec-project'), + 'file.txt' + ) waitsForPromise(() => atom.workspace.open(pathToOpen)) @@ -141,14 +156,23 @@ describe('Project', () => { }) }) - waitsForPromise(() => deserializedProject.deserialize(atom.project.serialize({isUnloading: false}))) + waitsForPromise(() => + deserializedProject.deserialize( + atom.project.serialize({ isUnloading: false }) + ) + ) runs(() => expect(deserializedProject.getBuffers().length).toBe(0)) }) it('does not deserialize buffers when their path is inaccessible', () => { - if (process.platform === 'win32') { return } // chmod not supported on win32 - const pathToOpen = path.join(temp.mkdirSync('atom-spec-project'), 'file.txt') + if (process.platform === 'win32') { + return + } // chmod not supported on win32 + const pathToOpen = path.join( + temp.mkdirSync('atom-spec-project'), + 'file.txt' + ) fs.writeFileSync(pathToOpen, '') waitsForPromise(() => atom.workspace.open(pathToOpen)) @@ -164,13 +188,20 @@ describe('Project', () => { }) }) - waitsForPromise(() => deserializedProject.deserialize(atom.project.serialize({isUnloading: false}))) + waitsForPromise(() => + deserializedProject.deserialize( + atom.project.serialize({ isUnloading: false }) + ) + ) runs(() => expect(deserializedProject.getBuffers().length).toBe(0)) }) it('does not deserialize buffers with their path is no longer present', () => { - const pathToOpen = path.join(temp.mkdirSync('atom-spec-project'), 'file.txt') + const pathToOpen = path.join( + temp.mkdirSync('atom-spec-project'), + 'file.txt' + ) fs.writeFileSync(pathToOpen, '') waitsForPromise(() => atom.workspace.open(pathToOpen)) @@ -186,13 +217,20 @@ describe('Project', () => { }) }) - waitsForPromise(() => deserializedProject.deserialize(atom.project.serialize({isUnloading: false}))) + waitsForPromise(() => + deserializedProject.deserialize( + atom.project.serialize({ isUnloading: false }) + ) + ) runs(() => expect(deserializedProject.getBuffers().length).toBe(0)) }) it('deserializes buffers that have never been saved before', () => { - const pathToOpen = path.join(temp.mkdirSync('atom-spec-project'), 'file.txt') + const pathToOpen = path.join( + temp.mkdirSync('atom-spec-project'), + 'file.txt' + ) waitsForPromise(() => atom.workspace.open(pathToOpen)) @@ -208,7 +246,11 @@ describe('Project', () => { }) }) - waitsForPromise(() => deserializedProject.deserialize(atom.project.serialize({isUnloading: false}))) + waitsForPromise(() => + deserializedProject.deserialize( + atom.project.serialize({ isUnloading: false }) + ) + ) runs(() => { expect(deserializedProject.getBuffers().length).toBe(1) @@ -226,7 +268,7 @@ describe('Project', () => { runs(() => { bufferA = atom.project.getBuffers()[0] - layerA = bufferA.addMarkerLayer({persistent: true}) + layerA = bufferA.addMarkerLayer({ persistent: true }) markerA = layerA.markPosition([0, 3]) bufferA.append('!') notQuittingProject = new Project({ @@ -237,10 +279,17 @@ describe('Project', () => { }) }) - waitsForPromise(() => notQuittingProject.deserialize(atom.project.serialize({isUnloading: false}))) + waitsForPromise(() => + notQuittingProject.deserialize( + atom.project.serialize({ isUnloading: false }) + ) + ) runs(() => { - expect(notQuittingProject.getBuffers()[0].getMarkerLayer(layerA.id), x => x.getMarker(markerA.id)).toBeUndefined() + expect( + notQuittingProject.getBuffers()[0].getMarkerLayer(layerA.id), + x => x.getMarker(markerA.id) + ).toBeUndefined() expect(notQuittingProject.getBuffers()[0].undo()).toBe(false) quittingProject = new Project({ notificationManager: atom.notifications, @@ -250,10 +299,16 @@ describe('Project', () => { }) }) - waitsForPromise(() => quittingProject.deserialize(atom.project.serialize({isUnloading: true}))) + waitsForPromise(() => + quittingProject.deserialize( + atom.project.serialize({ isUnloading: true }) + ) + ) runs(() => { - expect(quittingProject.getBuffers()[0].getMarkerLayer(layerA.id), x => x.getMarker(markerA.id)).not.toBeUndefined() + expect(quittingProject.getBuffers()[0].getMarkerLayer(layerA.id), x => + x.getMarker(markerA.id) + ).not.toBeUndefined() expect(quittingProject.getBuffers()[0].undo()).toBe(true) }) }) @@ -266,11 +321,17 @@ describe('Project', () => { expect(atom.project.getPaths()[0]).toBeUndefined() let editor = null - waitsForPromise(() => atom.workspace.open().then(o => { editor = o })) + waitsForPromise(() => + atom.workspace.open().then(o => { + editor = o + }) + ) waitsForPromise(() => editor.saveAs(tempFile)) - runs(() => expect(atom.project.getPaths()[0]).toBe(path.dirname(tempFile))) + runs(() => + expect(atom.project.getPaths()[0]).toBe(path.dirname(tempFile)) + ) }) }) @@ -284,7 +345,7 @@ describe('Project', () => { paths: [projectPath1, projectPath2], originPath: 'originPath', config: { - 'baz': 'buzz' + baz: 'buzz' } } }) @@ -323,10 +384,12 @@ describe('Project', () => { let buffer beforeEach(() => waitsForPromise(() => - atom.project.bufferForPath(path.join(__dirname, 'fixtures', 'sample.js')).then((o) => { - buffer = o - buffer.retain() - }) + atom.project + .bufferForPath(path.join(__dirname, 'fixtures', 'sample.js')) + .then(o => { + buffer = o + buffer.retain() + }) ) ) @@ -339,10 +402,18 @@ describe('Project', () => { waitsForPromise(() => buffer.save()) runs(() => { - expect(atom.project.applicationDelegate.emitDidSavePath.calls.length).toBe(1) - expect(atom.project.applicationDelegate.emitDidSavePath).toHaveBeenCalledWith(buffer.getPath()) - expect(atom.project.applicationDelegate.emitWillSavePath.calls.length).toBe(1) - expect(atom.project.applicationDelegate.emitWillSavePath).toHaveBeenCalledWith(buffer.getPath()) + expect( + atom.project.applicationDelegate.emitDidSavePath.calls.length + ).toBe(1) + expect( + atom.project.applicationDelegate.emitDidSavePath + ).toHaveBeenCalledWith(buffer.getPath()) + expect( + atom.project.applicationDelegate.emitWillSavePath.calls.length + ).toBe(1) + expect( + atom.project.applicationDelegate.emitWillSavePath + ).toHaveBeenCalledWith(buffer.getPath()) }) }) }) @@ -350,20 +421,23 @@ describe('Project', () => { describe('when a watch error is thrown from the TextBuffer', () => { let editor = null beforeEach(() => - waitsForPromise(() => atom.workspace.open(require.resolve('./fixtures/dir/a')).then(o => { editor = o })) + waitsForPromise(() => + atom.workspace.open(require.resolve('./fixtures/dir/a')).then(o => { + editor = o + }) + ) ) it('creates a warning notification', () => { let noteSpy - atom.notifications.onDidAddNotification(noteSpy = jasmine.createSpy()) + atom.notifications.onDidAddNotification((noteSpy = jasmine.createSpy())) const error = new Error('SomeError') error.eventType = 'resurrect' editor.buffer.emitter.emit('will-throw-watch-error', { handle: jasmine.createSpy(), error - } - ) + }) expect(noteSpy).toHaveBeenCalled() @@ -371,7 +445,9 @@ describe('Project', () => { expect(notification.getType()).toBe('warning') expect(notification.getDetail()).toBe('SomeError') expect(notification.getMessage()).toContain('`resurrect`') - expect(notification.getMessage()).toContain(path.join('fixtures', 'dir', 'a')) + expect(notification.getMessage()).toContain( + path.join('fixtures', 'dir', 'a') + ) }) }) @@ -379,10 +455,18 @@ describe('Project', () => { let fakeRepositoryProvider, fakeRepository beforeEach(() => { - fakeRepository = {destroy () { return null }} + fakeRepository = { + destroy () { + return null + } + } fakeRepositoryProvider = { - repositoryForDirectory (directory) { return Promise.resolve(fakeRepository) }, - repositoryForDirectorySync (directory) { return fakeRepository } + repositoryForDirectory (directory) { + return Promise.resolve(fakeRepository) + }, + repositoryForDirectorySync (directory) { + return fakeRepository + } } }) @@ -391,7 +475,11 @@ describe('Project', () => { atom.project.setPaths([projectPath]) expect(atom.project.getRepositories()).toEqual([null]) - atom.packages.serviceHub.provide('atom.repository-provider', '0.1.0', fakeRepositoryProvider) + atom.packages.serviceHub.provide( + 'atom.repository-provider', + '0.1.0', + fakeRepositoryProvider + ) waitsFor(() => atom.project.repositoryProviders.length > 1) runs(() => atom.project.getRepositories()[0] === fakeRepository) }) @@ -401,7 +489,11 @@ describe('Project', () => { expect(repositories.length).toEqual(1) expect(repositories[0]).toBeTruthy() - atom.packages.serviceHub.provide('atom.repository-provider', '0.1.0', fakeRepositoryProvider) + atom.packages.serviceHub.provide( + 'atom.repository-provider', + '0.1.0', + fakeRepositoryProvider + ) waitsFor(() => atom.project.repositoryProviders.length > 1) runs(() => expect(atom.project.getRepositories()).toBe(repositories)) }) @@ -409,7 +501,11 @@ describe('Project', () => { it('stops using it to create repositories when the service is removed', () => { atom.project.setPaths([]) - const disposable = atom.packages.serviceHub.provide('atom.repository-provider', '0.1.0', fakeRepositoryProvider) + const disposable = atom.packages.serviceHub.provide( + 'atom.repository-provider', + '0.1.0', + fakeRepositoryProvider + ) waitsFor(() => atom.project.repositoryProviders.length > 1) runs(() => { disposable.dispose() @@ -424,15 +520,35 @@ describe('Project', () => { constructor (aPath) { this.path = aPath } - getPath () { return this.path } - getFile () { return {existsSync () { return false }} } - getSubdirectory () { return {existsSync () { return false }} } - isRoot () { return true } - existsSync () { return this.path.endsWith('does-exist') } - contains (filePath) { return filePath.startsWith(this.path) } + getPath () { + return this.path + } + getFile () { + return { + existsSync () { + return false + } + } + } + getSubdirectory () { + return { + existsSync () { + return false + } + } + } + isRoot () { + return true + } + existsSync () { + return this.path.endsWith('does-exist') + } + contains (filePath) { + return filePath.startsWith(this.path) + } onDidChangeFiles (callback) { onDidChangeFilesCallback = callback - return {dispose: () => {}} + return { dispose: () => {} } } } @@ -440,15 +556,19 @@ describe('Project', () => { let onDidChangeFilesCallback = null beforeEach(() => { - serviceDisposable = atom.packages.serviceHub.provide('atom.directory-provider', '0.1.0', { - directoryForURISync (uri) { - if (uri.startsWith('ssh://')) { - return new DummyDirectory(uri) - } else { - return null + serviceDisposable = atom.packages.serviceHub.provide( + 'atom.directory-provider', + '0.1.0', + { + directoryForURISync (uri) { + if (uri.startsWith('ssh://')) { + return new DummyDirectory(uri) + } else { + return null + } } } - }) + ) onDidChangeFilesCallback = null waitsFor(() => atom.project.directoryProviders.length > 0) @@ -467,7 +587,8 @@ describe('Project', () => { expect(directories[1] instanceof DummyDirectory).toBe(true) // It does not add new remote paths that do not exist - const nonExistentRemotePath = 'ssh://another-directory:8080/does-not-exist' + const nonExistentRemotePath = + 'ssh://another-directory:8080/does-not-exist' atom.project.addPath(nonExistentRemotePath) expect(atom.project.getDirectories().length).toBe(2) @@ -499,7 +620,7 @@ describe('Project', () => { const changeSpy = jasmine.createSpy('atom.project.onDidChangeFiles') const disposable = atom.project.onDidChangeFiles(changeSpy) - const events = [{action: 'created', path: remotePath + '/test.txt'}] + const events = [{ action: 'created', path: remotePath + '/test.txt' }] onDidChangeFilesCallback(events) expect(changeSpy).toHaveBeenCalledWith(events) @@ -520,7 +641,11 @@ describe('Project', () => { describe("when given an absolute path that isn't currently open", () => { it("returns a new edit session for the given path and emits 'buffer-created'", () => { let editor = null - waitsForPromise(() => atom.workspace.open(absolutePath).then(o => { editor = o })) + waitsForPromise(() => + atom.workspace.open(absolutePath).then(o => { + editor = o + }) + ) runs(() => { expect(editor.buffer.getPath()).toBe(absolutePath) @@ -532,7 +657,11 @@ describe('Project', () => { describe("when given a relative path that isn't currently opened", () => { it("returns a new edit session for the given path (relative to the project root) and emits 'buffer-created'", () => { let editor = null - waitsForPromise(() => atom.workspace.open(absolutePath).then(o => { editor = o })) + waitsForPromise(() => + atom.workspace.open(absolutePath).then(o => { + editor = o + }) + ) runs(() => { expect(editor.buffer.getPath()).toBe(absolutePath) @@ -545,16 +674,22 @@ describe('Project', () => { it('returns a new edit session containing currently opened buffer', () => { let editor = null - waitsForPromise(() => atom.workspace.open(absolutePath).then(o => { editor = o })) + waitsForPromise(() => + atom.workspace.open(absolutePath).then(o => { + editor = o + }) + ) runs(() => newBufferHandler.reset()) waitsForPromise(() => - atom.workspace.open(absolutePath).then(({buffer}) => expect(buffer).toBe(editor.buffer)) + atom.workspace + .open(absolutePath) + .then(({ buffer }) => expect(buffer).toBe(editor.buffer)) ) waitsForPromise(() => - atom.workspace.open('a').then(({buffer}) => { + atom.workspace.open('a').then(({ buffer }) => { expect(buffer).toBe(editor.buffer) expect(newBufferHandler).not.toHaveBeenCalled() }) @@ -565,7 +700,11 @@ describe('Project', () => { describe('when not passed a path', () => { it("returns a new edit session and emits 'buffer-created'", () => { let editor = null - waitsForPromise(() => atom.workspace.open().then(o => { editor = o })) + waitsForPromise(() => + atom.workspace.open().then(o => { + editor = o + }) + ) runs(() => { expect(editor.buffer.getPath()).toBeUndefined() @@ -580,7 +719,7 @@ describe('Project', () => { beforeEach(() => waitsForPromise(() => - atom.project.bufferForPath('a').then((o) => { + atom.project.bufferForPath('a').then(o => { buffer = o buffer.retain() }) @@ -592,11 +731,15 @@ describe('Project', () => { describe('when opening a previously opened path', () => { it('does not create a new buffer', () => { waitsForPromise(() => - atom.project.bufferForPath('a').then(anotherBuffer => expect(anotherBuffer).toBe(buffer)) + atom.project + .bufferForPath('a') + .then(anotherBuffer => expect(anotherBuffer).toBe(buffer)) ) waitsForPromise(() => - atom.project.bufferForPath('b').then(anotherBuffer => expect(anotherBuffer).not.toBe(buffer)) + atom.project + .bufferForPath('b') + .then(anotherBuffer => expect(anotherBuffer).not.toBe(buffer)) ) waitsForPromise(() => @@ -610,12 +753,14 @@ describe('Project', () => { }) it('retries loading the buffer if it previously failed', () => { - waitsForPromise({shouldReject: true}, () => { - spyOn(TextBuffer, 'load').andCallFake(() => Promise.reject(new Error('Could not open file'))) + waitsForPromise({ shouldReject: true }, () => { + spyOn(TextBuffer, 'load').andCallFake(() => + Promise.reject(new Error('Could not open file')) + ) return atom.project.bufferForPath('b') }) - waitsForPromise({shouldReject: false}, () => { + waitsForPromise({ shouldReject: false }, () => { TextBuffer.load.andCallThrough() return atom.project.bufferForPath('b') }) @@ -625,7 +770,9 @@ describe('Project', () => { buffer.release() waitsForPromise(() => - atom.project.bufferForPath('b').then(anotherBuffer => expect(anotherBuffer).not.toBe(buffer)) + atom.project + .bufferForPath('b') + .then(anotherBuffer => expect(anotherBuffer).not.toBe(buffer)) ) }) }) @@ -635,7 +782,7 @@ describe('Project', () => { it('resolves to null when the directory does not have a repository', () => { waitsForPromise(() => { const directory = new Directory('/tmp') - return atom.project.repositoryForDirectory(directory).then((result) => { + return atom.project.repositoryForDirectory(directory).then(result => { expect(result).toBeNull() expect(atom.project.repositoryProviders.length).toBeGreaterThan(0) expect(atom.project.repositoryPromisesByPath.size).toBe(0) @@ -647,7 +794,7 @@ describe('Project', () => { waitsForPromise(() => { const directory = new Directory(path.join(__dirname, '..')) const promise = atom.project.repositoryForDirectory(directory) - return promise.then((result) => { + return promise.then(result => { expect(result).toBeInstanceOf(GitRepository) const dirPath = directory.getRealPathSync() expect(result.getPath()).toBe(path.join(dirPath, '.git')) @@ -662,7 +809,11 @@ describe('Project', () => { let repository = null const directory = new Directory(path.join(__dirname, '..')) - waitsForPromise(() => atom.project.repositoryForDirectory(directory).then(repo => { repository = repo })) + waitsForPromise(() => + atom.project.repositoryForDirectory(directory).then(repo => { + repository = repo + }) + ) runs(() => { expect(repository.isDestroyed()).toBe(false) @@ -670,7 +821,11 @@ describe('Project', () => { expect(repository.isDestroyed()).toBe(true) }) - waitsForPromise(() => atom.project.repositoryForDirectory(directory).then(repo => { repository = repo })) + waitsForPromise(() => + atom.project.repositoryForDirectory(directory).then(repo => { + repository = repo + }) + ) runs(() => expect(repository.isDestroyed()).toBe(false)) }) @@ -682,7 +837,9 @@ describe('Project', () => { const filePath = require.resolve('./fixtures/dir/a') atom.project.setPaths([filePath]) expect(atom.project.getPaths()[0]).toEqual(path.dirname(filePath)) - expect(atom.project.getDirectories()[0].path).toEqual(path.dirname(filePath)) + expect(atom.project.getDirectories()[0].path).toEqual( + path.dirname(filePath) + ) }) }) @@ -692,7 +849,9 @@ describe('Project', () => { const directory2 = temp.mkdirSync('git-repo1') const directory3 = temp.mkdirSync('git-repo2') - const gitDirPath = fs.absolute(path.join(__dirname, 'fixtures', 'git', 'master.git')) + const gitDirPath = fs.absolute( + path.join(__dirname, 'fixtures', 'git', 'master.git') + ) fs.copySync(gitDirPath, path.join(directory2, '.git')) fs.copySync(gitDirPath, path.join(directory3, '.git')) @@ -701,16 +860,20 @@ describe('Project', () => { const [repo1, repo2, repo3] = atom.project.getRepositories() expect(repo1).toBeNull() expect(repo2.getShortHead()).toBe('master') - expect(repo2.getPath()).toBe(fs.realpathSync(path.join(directory2, '.git'))) + expect(repo2.getPath()).toBe( + fs.realpathSync(path.join(directory2, '.git')) + ) expect(repo3.getShortHead()).toBe('master') - expect(repo3.getPath()).toBe(fs.realpathSync(path.join(directory3, '.git'))) + expect(repo3.getPath()).toBe( + fs.realpathSync(path.join(directory3, '.git')) + ) }) it('calls callbacks registered with ::onDidChangePaths', () => { const onDidChangePathsSpy = jasmine.createSpy('onDidChangePaths spy') atom.project.onDidChangePaths(onDidChangePathsSpy) - const paths = [ temp.mkdirSync('dir1'), temp.mkdirSync('dir2') ] + const paths = [temp.mkdirSync('dir1'), temp.mkdirSync('dir2')] atom.project.setPaths(paths) expect(onDidChangePathsSpy.callCount).toBe(1) @@ -718,10 +881,15 @@ describe('Project', () => { }) it('optionally throws an error with any paths that did not exist', () => { - const paths = [temp.mkdirSync('exists0'), '/doesnt-exists/0', temp.mkdirSync('exists1'), '/doesnt-exists/1'] + const paths = [ + temp.mkdirSync('exists0'), + '/doesnt-exists/0', + temp.mkdirSync('exists1'), + '/doesnt-exists/1' + ] try { - atom.project.setPaths(paths, {mustExist: true}) + atom.project.setPaths(paths, { mustExist: true }) expect('no exception thrown').toBeUndefined() } catch (e) { expect(e.missingProjectPaths).toEqual([paths[1], paths[3]]) @@ -740,9 +908,17 @@ describe('Project', () => { }) it('normalizes the path to remove consecutive slashes, ., and .. segments', () => { - atom.project.setPaths([`${require.resolve('./fixtures/dir/a')}${path.sep}b${path.sep}${path.sep}..`]) - expect(atom.project.getPaths()[0]).toEqual(path.dirname(require.resolve('./fixtures/dir/a'))) - expect(atom.project.getDirectories()[0].path).toEqual(path.dirname(require.resolve('./fixtures/dir/a'))) + atom.project.setPaths([ + `${require.resolve('./fixtures/dir/a')}${path.sep}b${path.sep}${ + path.sep + }..` + ]) + expect(atom.project.getPaths()[0]).toEqual( + path.dirname(require.resolve('./fixtures/dir/a')) + ) + expect(atom.project.getDirectories()[0].path).toEqual( + path.dirname(require.resolve('./fixtures/dir/a')) + ) }) }) @@ -757,7 +933,10 @@ describe('Project', () => { atom.project.addPath(newPath) expect(onDidChangePathsSpy.callCount).toBe(1) - expect(onDidChangePathsSpy.mostRecentCall.args[0]).toEqual([oldPath, newPath]) + expect(onDidChangePathsSpy.mostRecentCall.args[0]).toEqual([ + oldPath, + newPath + ]) }) it("doesn't add redundant paths", () => { @@ -789,7 +968,11 @@ describe('Project', () => { }) it('optionally throws on non-existent directories', () => { - expect(() => atom.project.addPath('/this-definitely/does-not-exist', {mustExist: true})).toThrow() + expect(() => + atom.project.addPath('/this-definitely/does-not-exist', { + mustExist: true + }) + ).toThrow() }) }) @@ -821,7 +1004,9 @@ describe('Project', () => { it("doesn't destroy the repository if it is shared by another root directory", () => { atom.project.setPaths([__dirname, path.join(__dirname, '..', 'src')]) atom.project.removePath(__dirname) - expect(atom.project.getPaths()).toEqual([path.join(__dirname, '..', 'src')]) + expect(atom.project.getPaths()).toEqual([ + path.join(__dirname, '..', 'src') + ]) expect(atom.project.getRepositories()[0].isSubmodule('src')).toBe(false) }) @@ -829,10 +1014,18 @@ describe('Project', () => { atom.packages.serviceHub.provide('atom.directory-provider', '0.1.0', { directoryForURISync (uri) { return { - getPath () { return uri }, - getSubdirectory () { return {} }, - isRoot () { return true }, - existsSync () { return true }, + getPath () { + return uri + }, + getSubdirectory () { + return {} + }, + isRoot () { + return true + }, + existsSync () { + return true + }, off () {} } } @@ -854,7 +1047,7 @@ describe('Project', () => { let checkCallback = () => {} beforeEach(() => { - sub = atom.project.onDidChangeFiles((incoming) => { + sub = atom.project.onDidChangeFiles(incoming => { events.push(...incoming) checkCallback() }) @@ -862,18 +1055,24 @@ describe('Project', () => { afterEach(() => sub.dispose()) - const waitForEvents = (paths) => { - const remaining = new Set(paths.map((p) => fs.realpathSync(p))) + const waitForEvents = paths => { + const remaining = new Set(paths.map(p => fs.realpathSync(p))) return new Promise((resolve, reject) => { checkCallback = () => { - for (let event of events) { remaining.delete(event.path) } - if (remaining.size === 0) { resolve() } + for (let event of events) { + remaining.delete(event.path) + } + if (remaining.size === 0) { + resolve() + } } const expire = () => { checkCallback = () => {} console.error('Paths not seen:', remaining) - reject(new Error('Expired before all expected events were delivered.')) + reject( + new Error('Expired before all expected events were delivered.') + ) } checkCallback() @@ -904,7 +1103,9 @@ describe('Project', () => { waitsForPromise(() => waitForEvents([fileOne, fileTwo])) - runs(() => expect(events.some(event => event.path === fileThree)).toBeFalsy()) + runs(() => + expect(events.some(event => event.path === fileThree)).toBeFalsy() + ) }) }) @@ -914,7 +1115,8 @@ describe('Project', () => { const added = [] waitsForPromise(() => - atom.project.buildBuffer(require.resolve('./fixtures/dir/a')) + atom.project + .buildBuffer(require.resolve('./fixtures/dir/a')) .then(o => buffers.push(o)) ) @@ -924,7 +1126,8 @@ describe('Project', () => { }) waitsForPromise(() => - atom.project.buildBuffer(require.resolve('./fixtures/dir/b')) + atom.project + .buildBuffer(require.resolve('./fixtures/dir/b')) .then(o => buffers.push(o)) ) @@ -941,12 +1144,14 @@ describe('Project', () => { const observed = [] waitsForPromise(() => - atom.project.buildBuffer(require.resolve('./fixtures/dir/a')) + atom.project + .buildBuffer(require.resolve('./fixtures/dir/a')) .then(o => buffers.push(o)) ) waitsForPromise(() => - atom.project.buildBuffer(require.resolve('./fixtures/dir/b')) + atom.project + .buildBuffer(require.resolve('./fixtures/dir/b')) .then(o => buffers.push(o)) ) @@ -957,7 +1162,8 @@ describe('Project', () => { }) waitsForPromise(() => - atom.project.buildBuffer(require.resolve('./fixtures/dir/b')) + atom.project + .buildBuffer(require.resolve('./fixtures/dir/b')) .then(o => buffers.push(o)) ) @@ -974,22 +1180,38 @@ describe('Project', () => { const observed = [] const directory1 = temp.mkdirSync('git-repo1') - const gitDirPath1 = fs.absolute(path.join(__dirname, 'fixtures', 'git', 'master.git')) + const gitDirPath1 = fs.absolute( + path.join(__dirname, 'fixtures', 'git', 'master.git') + ) fs.copySync(gitDirPath1, path.join(directory1, '.git')) const directory2 = temp.mkdirSync('git-repo2') - const gitDirPath2 = fs.absolute(path.join(__dirname, 'fixtures', 'git', 'repo-with-submodules', 'git.git')) + const gitDirPath2 = fs.absolute( + path.join( + __dirname, + 'fixtures', + 'git', + 'repo-with-submodules', + 'git.git' + ) + ) fs.copySync(gitDirPath2, path.join(directory2, '.git')) atom.project.setPaths([directory1]) - const disposable = atom.project.observeRepositories((repo) => observed.push(repo)) + const disposable = atom.project.observeRepositories(repo => + observed.push(repo) + ) expect(observed.length).toBe(1) - expect(observed[0].getReferenceTarget('refs/heads/master')).toBe('ef046e9eecaa5255ea5e9817132d4001724d6ae1') + expect(observed[0].getReferenceTarget('refs/heads/master')).toBe( + 'ef046e9eecaa5255ea5e9817132d4001724d6ae1' + ) atom.project.addPath(directory2) expect(observed.length).toBe(2) - expect(observed[1].getReferenceTarget('refs/heads/master')).toBe('d2b0ad9cbc6f6c4372e8956e5cc5af771b2342e5') + expect(observed[1].getReferenceTarget('refs/heads/master')).toBe( + 'd2b0ad9cbc6f6c4372e8956e5cc5af771b2342e5' + ) disposable.dispose() }) @@ -998,25 +1220,35 @@ describe('Project', () => { describe('.onDidAddRepository()', () => { it('invokes callback when a path is added and the path is the root of a repository', () => { const observed = [] - const disposable = atom.project.onDidAddRepository((repo) => observed.push(repo)) + const disposable = atom.project.onDidAddRepository(repo => + observed.push(repo) + ) const projectRootPath = temp.mkdirSync() - const fixtureRepoPath = fs.absolute(path.join(__dirname, 'fixtures', 'git', 'master.git')) + const fixtureRepoPath = fs.absolute( + path.join(__dirname, 'fixtures', 'git', 'master.git') + ) fs.copySync(fixtureRepoPath, path.join(projectRootPath, '.git')) atom.project.addPath(projectRootPath) expect(observed.length).toBe(1) - expect(observed[0].getOriginURL()).toEqual('https://github.com/example-user/example-repo.git') + expect(observed[0].getOriginURL()).toEqual( + 'https://github.com/example-user/example-repo.git' + ) disposable.dispose() }) it('invokes callback when a path is added and the path is subdirectory of a repository', () => { const observed = [] - const disposable = atom.project.onDidAddRepository((repo) => observed.push(repo)) + const disposable = atom.project.onDidAddRepository(repo => + observed.push(repo) + ) const projectRootPath = temp.mkdirSync() - const fixtureRepoPath = fs.absolute(path.join(__dirname, 'fixtures', 'git', 'master.git')) + const fixtureRepoPath = fs.absolute( + path.join(__dirname, 'fixtures', 'git', 'master.git') + ) fs.copySync(fixtureRepoPath, path.join(projectRootPath, '.git')) const projectSubDirPath = path.join(projectRootPath, 'sub-dir') @@ -1024,14 +1256,18 @@ describe('Project', () => { atom.project.addPath(projectSubDirPath) expect(observed.length).toBe(1) - expect(observed[0].getOriginURL()).toEqual('https://github.com/example-user/example-repo.git') + expect(observed[0].getOriginURL()).toEqual( + 'https://github.com/example-user/example-repo.git' + ) disposable.dispose() }) it('does not invoke callback when a path is added and the path is not part of a repository', () => { const observed = [] - const disposable = atom.project.onDidAddRepository((repo) => observed.push(repo)) + const disposable = atom.project.onDidAddRepository(repo => + observed.push(repo) + ) atom.project.addPath(temp.mkdirSync('not-a-repository')) expect(observed.length).toBe(0) @@ -1046,11 +1282,15 @@ describe('Project', () => { let rootPath = atom.project.getPaths()[0] let childPath = path.join(rootPath, 'some', 'child', 'directory') - expect(atom.project.relativize(childPath)).toBe(path.join('some', 'child', 'directory')) + expect(atom.project.relativize(childPath)).toBe( + path.join('some', 'child', 'directory') + ) rootPath = atom.project.getPaths()[1] childPath = path.join(rootPath, 'some', 'child', 'directory') - expect(atom.project.relativize(childPath)).toBe(path.join('some', 'child', 'directory')) + expect(atom.project.relativize(childPath)).toBe( + path.join('some', 'child', 'directory') + ) }) it('returns the given path if it is not in any of the root directories', () => { @@ -1065,17 +1305,26 @@ describe('Project', () => { let rootPath = atom.project.getPaths()[0] let childPath = path.join(rootPath, 'some', 'child', 'directory') - expect(atom.project.relativizePath(childPath)).toEqual([rootPath, path.join('some', 'child', 'directory')]) + expect(atom.project.relativizePath(childPath)).toEqual([ + rootPath, + path.join('some', 'child', 'directory') + ]) rootPath = atom.project.getPaths()[1] childPath = path.join(rootPath, 'some', 'child', 'directory') - expect(atom.project.relativizePath(childPath)).toEqual([rootPath, path.join('some', 'child', 'directory')]) + expect(atom.project.relativizePath(childPath)).toEqual([ + rootPath, + path.join('some', 'child', 'directory') + ]) }) describe("when the given path isn't inside of any of the project's path", () => { it('returns null for the root path, and the given path unchanged', () => { const randomPath = path.join('some', 'random', 'path') - expect(atom.project.relativizePath(randomPath)).toEqual([null, randomPath]) + expect(atom.project.relativizePath(randomPath)).toEqual([ + null, + randomPath + ]) }) }) @@ -1090,7 +1339,10 @@ describe('Project', () => { it('uses the root folder that is closest to the given path', () => { atom.project.addPath(path.join(atom.project.getPaths()[0], 'a-dir')) - const inputPath = path.join(atom.project.getPaths()[1], 'somewhere/something.txt') + const inputPath = path.join( + atom.project.getPaths()[1], + 'somewhere/something.txt' + ) expect(atom.project.getDirectories()[0].contains(inputPath)).toBe(true) expect(atom.project.getDirectories()[1].contains(inputPath)).toBe(true) diff --git a/spec/reopen-project-menu-manager-spec.js b/spec/reopen-project-menu-manager-spec.js index b11561c31..100111242 100644 --- a/spec/reopen-project-menu-manager-spec.js +++ b/spec/reopen-project-menu-manager-spec.js @@ -1,19 +1,25 @@ /** @babel */ -import {it, fit, ffit, fffit, beforeEach, afterEach} from './async-spec-helpers' -import {Emitter, Disposable, CompositeDisposable} from 'event-kit' +import { + it, + fit, + ffit, + fffit, + beforeEach, + afterEach +} from './async-spec-helpers' +import { Emitter, Disposable, CompositeDisposable } from 'event-kit' const ReopenProjectMenuManager = require('../src/reopen-project-menu-manager') numberRange = (low, high) => { const size = high - low const result = new Array(size) - for (var i = 0; i < size; i++) - result[i] = low + i + for (var i = 0; i < size; i++) result[i] = low + i return result } -describe("ReopenProjectMenuManager", () => { +describe('ReopenProjectMenuManager', () => { let menuManager, commandRegistry, config, historyManager, reopenProjects let commandDisposable, configDisposable, historyDisposable @@ -28,43 +34,54 @@ describe("ReopenProjectMenuManager", () => { config = jasmine.createSpyObj('Config', ['onDidChange', 'get']) config.get.andReturn(10) configDisposable = jasmine.createSpyObj('Disposable', ['dispose']) - config.didChangeListener = { } + config.didChangeListener = {} config.onDidChange.andCallFake((key, fn) => { config.didChangeListener[key] = fn return configDisposable }) - historyManager = jasmine.createSpyObj('historyManager', ['getProjects','onDidChangeProjects']) + historyManager = jasmine.createSpyObj('historyManager', [ + 'getProjects', + 'onDidChangeProjects' + ]) historyManager.getProjects.andReturn([]) historyDisposable = jasmine.createSpyObj('Disposable', ['dispose']) - historyManager.onDidChangeProjects.andCallFake((fn) => { + historyManager.onDidChangeProjects.andCallFake(fn => { historyManager.changeProjectsListener = fn return historyDisposable }) openFunction = jasmine.createSpy() - reopenProjects = new ReopenProjectMenuManager({menu:menuManager, commands: commandRegistry, history: historyManager, config, open:openFunction}) + reopenProjects = new ReopenProjectMenuManager({ + menu: menuManager, + commands: commandRegistry, + history: historyManager, + config, + open: openFunction + }) }) - describe("constructor", () => { + describe('constructor', () => { it("registers the 'reopen-project' command function", () => { expect(commandRegistry.add).toHaveBeenCalled() const cmdCall = commandRegistry.add.calls[0] expect(cmdCall.args.length).toBe(2) expect(cmdCall.args[0]).toBe('atom-workspace') - expect(typeof cmdCall.args[1]['application:reopen-project']).toBe('function') + expect(typeof cmdCall.args[1]['application:reopen-project']).toBe( + 'function' + ) }) }) - describe("dispose", () => { - it("disposes of the history, command and config disposables", () => { + describe('dispose', () => { + it('disposes of the history, command and config disposables', () => { reopenProjects.dispose() expect(historyDisposable.dispose).toHaveBeenCalled() expect(configDisposable.dispose).toHaveBeenCalled() expect(commandDisposable.dispose).toHaveBeenCalled() }) - it("disposes of the menu disposable once used", () => { + it('disposes of the menu disposable once used', () => { const menuDisposable = jasmine.createSpyObj('Disposable', ['dispose']) menuManager.add.andReturn(menuDisposable) reopenProjects.update() @@ -74,36 +91,45 @@ describe("ReopenProjectMenuManager", () => { }) }) - describe("the command", () => { - it("calls open with the paths of the project specified by the detail index", () => { - historyManager.getProjects.andReturn([ { paths: ['/a'] }, { paths: ['/b', 'c:\\'] }]) + describe('the command', () => { + it('calls open with the paths of the project specified by the detail index', () => { + historyManager.getProjects.andReturn([ + { paths: ['/a'] }, + { paths: ['/b', 'c:\\'] } + ]) reopenProjects.update() - reopenProjectCommand = commandRegistry.add.calls[0].args[1]['application:reopen-project'] + reopenProjectCommand = + commandRegistry.add.calls[0].args[1]['application:reopen-project'] reopenProjectCommand({ detail: { index: 1 } }) expect(openFunction).toHaveBeenCalled() expect(openFunction.calls[0].args[0]).toEqual(['/b', 'c:\\']) }) - it("does not call open when no command detail is supplied", () => { - reopenProjectCommand = commandRegistry.add.calls[0].args[1]['application:reopen-project'] + it('does not call open when no command detail is supplied', () => { + reopenProjectCommand = + commandRegistry.add.calls[0].args[1]['application:reopen-project'] reopenProjectCommand({}) expect(openFunction).not.toHaveBeenCalled() }) - it("does not call open when no command detail index is supplied", () => { - reopenProjectCommand = commandRegistry.add.calls[0].args[1]['application:reopen-project'] + it('does not call open when no command detail index is supplied', () => { + reopenProjectCommand = + commandRegistry.add.calls[0].args[1]['application:reopen-project'] reopenProjectCommand({ detail: { anything: 'here' } }) expect(openFunction).not.toHaveBeenCalled() }) }) - describe("update", () => { - it("adds menu items to MenuManager based on projects from HistoryManager", () => { - historyManager.getProjects.andReturn([ { paths: ['/a'] }, { paths: ['/b', 'c:\\'] }]) + describe('update', () => { + it('adds menu items to MenuManager based on projects from HistoryManager', () => { + historyManager.getProjects.andReturn([ + { paths: ['/a'] }, + { paths: ['/b', 'c:\\'] } + ]) reopenProjects.update() expect(historyManager.getProjects).toHaveBeenCalled() expect(menuManager.add).toHaveBeenCalled() @@ -127,7 +153,9 @@ describe("ReopenProjectMenuManager", () => { }) it("adds only the number of menu items specified in the 'core.reopenProjectMenuCount' config", () => { - historyManager.getProjects.andReturn(numberRange(1, 100).map(i => ({ paths: [ '/test/' + i ] }))) + historyManager.getProjects.andReturn( + numberRange(1, 100).map(i => ({ paths: ['/test/' + i] })) + ) reopenProjects.update() expect(menuManager.add).toHaveBeenCalled() const menu = menuManager.add.calls[0].args[0][0] @@ -137,7 +165,7 @@ describe("ReopenProjectMenuManager", () => { expect(menu.submenu[0].submenu.length).toBe(10) }) - it("disposes the previously menu built", () => { + it('disposes the previously menu built', () => { const menuDisposable = jasmine.createSpyObj('Disposable', ['dispose']) menuManager.add.andReturn(menuDisposable) reopenProjects.update() @@ -147,10 +175,15 @@ describe("ReopenProjectMenuManager", () => { }) it("is called when the Config changes for 'core.reopenProjectMenuCount'", () => { - historyManager.getProjects.andReturn(numberRange(1, 100).map(i => ({ paths: [ '/test/' + i ] }))) + historyManager.getProjects.andReturn( + numberRange(1, 100).map(i => ({ paths: ['/test/' + i] })) + ) reopenProjects.update() config.get.andReturn(25) - config.didChangeListener['core.reopenProjectMenuCount']({oldValue:10, newValue: 25}) + config.didChangeListener['core.reopenProjectMenuCount']({ + oldValue: 10, + newValue: 25 + }) const finalArgs = menuManager.add.calls[1].args[0] const projectsMenu = finalArgs[0].submenu[0].submenu @@ -160,7 +193,10 @@ describe("ReopenProjectMenuManager", () => { it("is called when the HistoryManager's projects change", () => { reopenProjects.update() - historyManager.getProjects.andReturn([ { paths: ['/a'] }, { paths: ['/b', 'c:\\'] } ]) + historyManager.getProjects.andReturn([ + { paths: ['/a'] }, + { paths: ['/b', 'c:\\'] } + ]) historyManager.changeProjectsListener() expect(menuManager.add.calls.length).toBe(2) @@ -179,11 +215,11 @@ describe("ReopenProjectMenuManager", () => { }) }) - describe("updateProjects", () => { - it("creates correct menu items commands for recent projects", () => { + describe('updateProjects', () => { + it('creates correct menu items commands for recent projects', () => { const projects = [ - { paths: [ '/users/neila' ] }, - { paths: [ '/users/buzza', 'users/michaelc' ] } + { paths: ['/users/neila'] }, + { paths: ['/users/buzza', 'users/michaelc'] } ] const menu = ReopenProjectMenuManager.createProjectsMenu(projects) @@ -197,69 +233,81 @@ describe("ReopenProjectMenuManager", () => { const first = recentMenu.submenu[0] expect(first.label).toBe('/users/neila') expect(first.command).toBe('application:reopen-project') - expect(first.commandDetail).toEqual({index: 0}) + expect(first.commandDetail).toEqual({ index: 0 }) const second = recentMenu.submenu[1] expect(second.label).toBe('buzza, michaelc') expect(second.command).toBe('application:reopen-project') - expect(second.commandDetail).toEqual({index: 1}) + expect(second.commandDetail).toEqual({ index: 1 }) }) }) - describe("createLabel", () => { - it("returns the Unix path unchanged if there is only one", () => { - const label = ReopenProjectMenuManager.createLabel({ paths: ['/a/b/c/d/e/f'] }) + describe('createLabel', () => { + it('returns the Unix path unchanged if there is only one', () => { + const label = ReopenProjectMenuManager.createLabel({ + paths: ['/a/b/c/d/e/f'] + }) expect(label).toBe('/a/b/c/d/e/f') }) - it("returns the Windows path unchanged if there is only one", () => { - const label = ReopenProjectMenuManager.createLabel({ paths: ['c:\\missions\\apollo11'] }) + it('returns the Windows path unchanged if there is only one', () => { + const label = ReopenProjectMenuManager.createLabel({ + paths: ['c:\\missions\\apollo11'] + }) expect(label).toBe('c:\\missions\\apollo11') }) - it("returns the URL unchanged if there is only one", () => { - const label = ReopenProjectMenuManager.createLabel({ paths: ['https://launch.pad/apollo/11'] }) + it('returns the URL unchanged if there is only one', () => { + const label = ReopenProjectMenuManager.createLabel({ + paths: ['https://launch.pad/apollo/11'] + }) expect(label).toBe('https://launch.pad/apollo/11') }) - it("returns a comma-separated list of base names if there are multiple", () => { - const project = { paths: [ '/var/one', '/usr/bin/two', '/etc/mission/control/three' ] } + it('returns a comma-separated list of base names if there are multiple', () => { + const project = { + paths: ['/var/one', '/usr/bin/two', '/etc/mission/control/three'] + } const label = ReopenProjectMenuManager.createLabel(project) expect(label).toBe('one, two, three') }) - describe("betterBaseName", () => { - it("returns the standard base name for an absolute Unix path", () => { + describe('betterBaseName', () => { + it('returns the standard base name for an absolute Unix path', () => { const name = ReopenProjectMenuManager.betterBaseName('/one/to/three') expect(name).toBe('three') }) - it("returns the standard base name for a relative Windows path", () => { + it('returns the standard base name for a relative Windows path', () => { if (process.platform === 'win32') { const name = ReopenProjectMenuManager.betterBaseName('.\\one\\two') expect(name).toBe('two') } }) - it("returns the standard base name for an absolute Windows path", () => { + it('returns the standard base name for an absolute Windows path', () => { if (process.platform === 'win32') { - const name = ReopenProjectMenuManager.betterBaseName('c:\\missions\\apollo\\11') + const name = ReopenProjectMenuManager.betterBaseName( + 'c:\\missions\\apollo\\11' + ) expect(name).toBe('11') } }) - it("returns the drive root for a Windows drive name", () => { + it('returns the drive root for a Windows drive name', () => { const name = ReopenProjectMenuManager.betterBaseName('d:') expect(name).toBe('d:\\') }) - it("returns the drive root for a Windows drive root", () => { + it('returns the drive root for a Windows drive root', () => { const name = ReopenProjectMenuManager.betterBaseName('e:\\') expect(name).toBe('e:\\') }) - it("returns the final path for a URI", () => { - const name = ReopenProjectMenuManager.betterBaseName('https://something/else') + it('returns the final path for a URI', () => { + const name = ReopenProjectMenuManager.betterBaseName( + 'https://something/else' + ) expect(name).toBe('else') }) }) diff --git a/spec/selection-spec.js b/spec/selection-spec.js index e9cf1c617..5dc6cd199 100644 --- a/spec/selection-spec.js +++ b/spec/selection-spec.js @@ -5,7 +5,7 @@ describe('Selection', () => { beforeEach(() => { buffer = atom.project.bufferForPathSync('sample.js') - editor = new TextEditor({buffer, tabLength: 2}) + editor = new TextEditor({ buffer, tabLength: 2 }) selection = editor.getLastSelection() }) @@ -88,23 +88,31 @@ describe('Selection', () => { describe("when the selection's range is moved", () => { it('notifies ::onDidChangeRange observers', () => { selection.setBufferRange([[2, 0], [2, 10]]) - const changeScreenRangeHandler = jasmine.createSpy('changeScreenRangeHandler') + const changeScreenRangeHandler = jasmine.createSpy( + 'changeScreenRangeHandler' + ) selection.onDidChangeRange(changeScreenRangeHandler) buffer.insert([2, 5], 'abc') expect(changeScreenRangeHandler).toHaveBeenCalled() - expect(changeScreenRangeHandler.mostRecentCall.args[0]).not.toBeUndefined() - }); - }); + expect( + changeScreenRangeHandler.mostRecentCall.args[0] + ).not.toBeUndefined() + }) + }) describe("when only the selection's tail is moved (regression)", () => { it('notifies ::onDidChangeRange observers', () => { - selection.setBufferRange([[2, 0], [2, 10]], {reversed: true}) - const changeScreenRangeHandler = jasmine.createSpy('changeScreenRangeHandler') + selection.setBufferRange([[2, 0], [2, 10]], { reversed: true }) + const changeScreenRangeHandler = jasmine.createSpy( + 'changeScreenRangeHandler' + ) selection.onDidChangeRange(changeScreenRangeHandler) buffer.insert([2, 5], 'abc') expect(changeScreenRangeHandler).toHaveBeenCalled() - expect(changeScreenRangeHandler.mostRecentCall.args[0]).not.toBeUndefined() + expect( + changeScreenRangeHandler.mostRecentCall.args[0] + ).not.toBeUndefined() }) }) @@ -120,7 +128,7 @@ describe('Selection', () => { describe('.insertText(text, options)', () => { it('allows pasting white space only lines when autoIndent is enabled', () => { selection.setBufferRange([[0, 0], [0, 0]]) - selection.insertText(' \n \n\n', {autoIndent: true}) + selection.insertText(' \n \n\n', { autoIndent: true }) expect(buffer.lineForRow(0)).toBe(' ') expect(buffer.lineForRow(1)).toBe(' ') expect(buffer.lineForRow(2)).toBe('') @@ -128,19 +136,22 @@ describe('Selection', () => { it('auto-indents if only a newline is inserted', () => { selection.setBufferRange([[2, 0], [3, 0]]) - selection.insertText('\n', {autoIndent: true}) + selection.insertText('\n', { autoIndent: true }) expect(buffer.lineForRow(2)).toBe(' ') }) it('auto-indents if only a carriage return + newline is inserted', () => { selection.setBufferRange([[2, 0], [3, 0]]) - selection.insertText('\r\n', {autoIndent: true}) + selection.insertText('\r\n', { autoIndent: true }) expect(buffer.lineForRow(2)).toBe(' ') }) it('does not adjust the indent of trailing lines if preserveTrailingLineIndentation is true', () => { selection.setBufferRange([[5, 0], [5, 0]]) - selection.insertText(' foo\n bar\n', {preserveTrailingLineIndentation: true, indentBasis: 1}) + selection.insertText(' foo\n bar\n', { + preserveTrailingLineIndentation: true, + indentBasis: 1 + }) expect(buffer.lineForRow(6)).toBe(' bar') }) }) @@ -152,7 +163,9 @@ describe('Selection', () => { expect(selection.getScreenRange()).toEqual([[0, 4], [0, 4]]) expect(selection.getBufferRange()).toEqual([[1, 6], [1, 6]]) - expect(editor.lineTextForScreenRow(0)).toBe(`var${editor.displayLayer.foldCharacter}sort = function(items) {`) + expect(editor.lineTextForScreenRow(0)).toBe( + `var${editor.displayLayer.foldCharacter}sort = function(items) {` + ) expect(editor.isFoldedAtBufferRow(0)).toBe(true) }) @@ -162,7 +175,9 @@ describe('Selection', () => { expect(selection.getScreenRange()).toEqual([[0, 3], [0, 3]]) expect(selection.getBufferRange()).toEqual([[0, 3], [0, 3]]) - expect(editor.lineTextForScreenRow(0)).toBe('var quicksort = function () {') + expect(editor.lineTextForScreenRow(0)).toBe( + 'var quicksort = function () {' + ) expect(editor.isFoldedAtBufferRow(0)).toBe(false) }) }) @@ -261,11 +276,11 @@ describe('Selection', () => { { name: 'indentSelectedRows', op: opts => selection.indentSelectedRows(opts) - }, + } ] describe('without bypassReadOnly', () => { - for (const {name, op} of modifications) { + for (const { name, op } of modifications) { it(`throws an error on ${name}`, () => { expect(op).toThrow() }) @@ -273,9 +288,9 @@ describe('Selection', () => { }) describe('with bypassReadOnly', () => { - for (const {name, op} of modifications) { + for (const { name, op } of modifications) { it(`permits ${name}`, () => { - op({bypassReadOnly: true}) + op({ bypassReadOnly: true }) }) } }) diff --git a/spec/state-store-spec.js b/spec/state-store-spec.js index 0b62066c8..95583f8cd 100644 --- a/spec/state-store-spec.js +++ b/spec/state-store-spec.js @@ -1,68 +1,76 @@ /** @babel */ -import {it, fit, ffit, fffit, beforeEach, afterEach} from './async-spec-helpers' +import { + it, + fit, + ffit, + fffit, + beforeEach, + afterEach +} from './async-spec-helpers' const StateStore = require('../src/state-store.js') -describe("StateStore", () => { +describe('StateStore', () => { let databaseName = `test-database-${Date.now()}` let version = 1 - it("can save, load, and delete states", () => { + it('can save, load, and delete states', () => { const store = new StateStore(databaseName, version) - return store.save('key', {foo:'bar'}) + return store + .save('key', { foo: 'bar' }) .then(() => store.load('key')) - .then((state) => { - expect(state).toEqual({foo:'bar'}) + .then(state => { + expect(state).toEqual({ foo: 'bar' }) }) .then(() => store.delete('key')) .then(() => store.load('key')) - .then((value) => { + .then(value => { expect(value).toBeNull() }) .then(() => store.count()) - .then((count) => { + .then(count => { expect(count).toBe(0) }) }) - it("resolves with null when a non-existent key is loaded", () => { + it('resolves with null when a non-existent key is loaded', () => { const store = new StateStore(databaseName, version) - return store.load('no-such-key').then((value) => { + return store.load('no-such-key').then(value => { expect(value).toBeNull() }) }) - it("can clear the state object store", () => { + it('can clear the state object store', () => { const store = new StateStore(databaseName, version) - return store.save('key', {foo:'bar'}) + return store + .save('key', { foo: 'bar' }) .then(() => store.count()) - .then((count) => - expect(count).toBe(1) - ) + .then(count => expect(count).toBe(1)) .then(() => store.clear()) .then(() => store.count()) - .then((count) => { + .then(count => { expect(count).toBe(0) }) }) - describe("when there is an error reading from the database", () => { - it("rejects the promise returned by load", () => { + describe('when there is an error reading from the database', () => { + it('rejects the promise returned by load', () => { const store = new StateStore(databaseName, version) - const fakeErrorEvent = {target: {errorCode: "Something bad happened"}} + const fakeErrorEvent = { target: { errorCode: 'Something bad happened' } } - spyOn(IDBObjectStore.prototype, 'get').andCallFake((key) => { + spyOn(IDBObjectStore.prototype, 'get').andCallFake(key => { let request = {} process.nextTick(() => request.onerror(fakeErrorEvent)) return request }) - return store.load('nonexistentKey') + return store + .load('nonexistentKey') .then(() => { - throw new Error("Promise should have been rejected") + throw new Error('Promise should have been rejected') }) - .catch((event) => { + .catch(event => { expect(event).toBe(fakeErrorEvent) }) }) diff --git a/spec/style-manager-spec.js b/spec/style-manager-spec.js index 641c93709..e29dedb0c 100644 --- a/spec/style-manager-spec.js +++ b/spec/style-manager-spec.js @@ -5,13 +5,21 @@ describe('StyleManager', () => { let [styleManager, addEvents, removeEvents, updateEvents] = [] beforeEach(() => { - styleManager = new StyleManager({configDirPath: temp.mkdirSync('atom-config')}) + styleManager = new StyleManager({ + configDirPath: temp.mkdirSync('atom-config') + }) addEvents = [] removeEvents = [] updateEvents = [] - styleManager.onDidAddStyleElement((event) => { addEvents.push(event) }) - styleManager.onDidRemoveStyleElement((event) => { removeEvents.push(event) }) - styleManager.onDidUpdateStyleElement((event) => { updateEvents.push(event) }) + styleManager.onDidAddStyleElement(event => { + addEvents.push(event) + }) + styleManager.onDidRemoveStyleElement(event => { + removeEvents.push(event) + }) + styleManager.onDidUpdateStyleElement(event => { + updateEvents.push(event) + }) }) afterEach(() => { @@ -39,7 +47,9 @@ describe('StyleManager', () => { describe('atom-text-editor shadow DOM selectors upgrades', () => { beforeEach(() => { // attach styles element to the DOM to parse CSS rules - styleManager.onDidAddStyleElement((styleElement) => { jasmine.attachToDOM(styleElement) }) + styleManager.onDidAddStyleElement(styleElement => { + jasmine.attachToDOM(styleElement) + }) }) it('removes the ::shadow pseudo-element from atom-text-editor selectors', () => { @@ -51,25 +61,36 @@ describe('StyleManager', () => { atom-text-editor[data-grammar*=\"js\"]::shadow .class-6 { color: green; } atom-text-editor[mini].is-focused::shadow .class-7 { color: green; } `) - expect(Array.from(styleManager.getStyleElements()[0].sheet.cssRules).map((r) => r.selectorText)).toEqual([ + expect( + Array.from(styleManager.getStyleElements()[0].sheet.cssRules).map( + r => r.selectorText + ) + ).toEqual([ 'atom-text-editor.editor .class-1, atom-text-editor.editor .class-2', 'atom-text-editor.editor > .class-3', 'atom-text-editor .class-4', 'another-element::shadow .class-5', - 'atom-text-editor[data-grammar*=\"js\"].editor .class-6', + 'atom-text-editor[data-grammar*="js"].editor .class-6', 'atom-text-editor[mini].is-focused.editor .class-7' ]) }) describe('when a selector targets the atom-text-editor shadow DOM', () => { it('prepends "--syntax" to class selectors matching a grammar scope name and not already starting with "syntax--"', () => { - styleManager.addStyleSheet(` + styleManager.addStyleSheet( + ` .class-1 { color: red } .source > .js, .source.coffee { color: green } .syntax--source { color: gray } #id-1 { color: blue } - `, {context: 'atom-text-editor'}) - expect(Array.from(styleManager.getStyleElements()[0].sheet.cssRules).map((r) => r.selectorText)).toEqual([ + `, + { context: 'atom-text-editor' } + ) + expect( + Array.from(styleManager.getStyleElements()[0].sheet.cssRules).map( + r => r.selectorText + ) + ).toEqual([ '.class-1', '.syntax--source > .syntax--js, .syntax--source.syntax--coffee', '.syntax--source', @@ -82,7 +103,11 @@ describe('StyleManager', () => { atom-text-editor[mini].is-focused::shadow .source > .js { color: gray } atom-text-editor .source > .js { color: red } `) - expect(Array.from(styleManager.getStyleElements()[1].sheet.cssRules).map((r) => r.selectorText)).toEqual([ + expect( + Array.from(styleManager.getStyleElements()[1].sheet.cssRules).map( + r => r.selectorText + ) + ).toEqual([ '.source > .js, .source.coffee', 'atom-text-editor.editor .syntax--source > .syntax--js', 'atom-text-editor[mini].is-focused.editor .syntax--source > .syntax--js', @@ -92,14 +117,23 @@ describe('StyleManager', () => { }) it('replaces ":host" with "atom-text-editor" only when the context of a style sheet is "atom-text-editor"', () => { - styleManager.addStyleSheet(':host .class-1, :host .class-2 { color: red; }') - expect(Array.from(styleManager.getStyleElements()[0].sheet.cssRules).map((r) => r.selectorText)).toEqual([ - ':host .class-1, :host .class-2' - ]) - styleManager.addStyleSheet(':host .class-1, :host .class-2 { color: red; }', {context: 'atom-text-editor'}) - expect(Array.from(styleManager.getStyleElements()[1].sheet.cssRules).map((r) => r.selectorText)).toEqual([ - 'atom-text-editor .class-1, atom-text-editor .class-2' - ]) + styleManager.addStyleSheet( + ':host .class-1, :host .class-2 { color: red; }' + ) + expect( + Array.from(styleManager.getStyleElements()[0].sheet.cssRules).map( + r => r.selectorText + ) + ).toEqual([':host .class-1, :host .class-2']) + styleManager.addStyleSheet( + ':host .class-1, :host .class-2 { color: red; }', + { context: 'atom-text-editor' } + ) + expect( + Array.from(styleManager.getStyleElements()[1].sheet.cssRules).map( + r => r.selectorText + ) + ).toEqual(['atom-text-editor .class-1, atom-text-editor .class-2']) }) it('does not transform CSS rules with invalid syntax', () => { @@ -110,17 +144,23 @@ describe('StyleManager', () => { }) it('does not throw exceptions on rules with no selectors', () => { - styleManager.addStyleSheet('@media screen {font-size: 10px}', {context: 'atom-text-editor'}) + styleManager.addStyleSheet('@media screen {font-size: 10px}', { + context: 'atom-text-editor' + }) }) }) describe('when a sourcePath parameter is specified', () => { it('ensures a maximum of one style element for the given source path, updating a previous if it exists', () => { - const disposable1 = styleManager.addStyleSheet('a {color: red}', {sourcePath: '/foo/bar'}) + const disposable1 = styleManager.addStyleSheet('a {color: red}', { + sourcePath: '/foo/bar' + }) expect(addEvents.length).toBe(1) expect(addEvents[0].getAttribute('source-path')).toBe('/foo/bar') - const disposable2 = styleManager.addStyleSheet('a {color: blue}', {sourcePath: '/foo/bar'}) + const disposable2 = styleManager.addStyleSheet('a {color: blue}', { + sourcePath: '/foo/bar' + }) expect(addEvents.length).toBe(1) expect(updateEvents.length).toBe(1) expect(updateEvents[0].getAttribute('source-path')).toBe('/foo/bar') @@ -128,7 +168,9 @@ describe('StyleManager', () => { disposable2.dispose() addEvents = [] - styleManager.addStyleSheet('a {color: yellow}', {sourcePath: '/foo/bar'}) + styleManager.addStyleSheet('a {color: yellow}', { + sourcePath: '/foo/bar' + }) expect(addEvents.length).toBe(1) expect(addEvents[0].getAttribute('source-path')).toBe('/foo/bar') expect(addEvents[0].textContent).toBe('a {color: yellow}') @@ -137,11 +179,13 @@ describe('StyleManager', () => { describe('when a priority parameter is specified', () => { it('inserts the style sheet based on the priority', () => { - styleManager.addStyleSheet('a {color: red}', {priority: 1}) - styleManager.addStyleSheet('a {color: blue}', {priority: 0}) - styleManager.addStyleSheet('a {color: green}', {priority: 2}) - styleManager.addStyleSheet('a {color: yellow}', {priority: 1}) - expect(styleManager.getStyleElements().map((elt) => elt.textContent)).toEqual([ + styleManager.addStyleSheet('a {color: red}', { priority: 1 }) + styleManager.addStyleSheet('a {color: blue}', { priority: 0 }) + styleManager.addStyleSheet('a {color: green}', { priority: 2 }) + styleManager.addStyleSheet('a {color: yellow}', { priority: 1 }) + expect( + styleManager.getStyleElements().map(elt => elt.textContent) + ).toEqual([ 'a {color: blue}', 'a {color: red}', 'a {color: yellow}', diff --git a/spec/syntax-scope-map-spec.js b/spec/syntax-scope-map-spec.js index 15b44095c..ec52c24b6 100644 --- a/spec/syntax-scope-map-spec.js +++ b/spec/syntax-scope-map-spec.js @@ -5,7 +5,7 @@ describe('SyntaxScopeMap', () => { const map = new SyntaxScopeMap({ 'a > b > c': 'x', 'b > c': 'y', - 'c': 'z' + c: 'z' }) expect(map.get(['a', 'b', 'c'], [0, 0, 0])).toBe('x') @@ -20,7 +20,7 @@ describe('SyntaxScopeMap', () => { const map = new SyntaxScopeMap({ 'a > b': 'w', 'a > b:nth-child(1)': 'x', - 'b': 'y', + b: 'y', 'b:nth-child(2)': 'z' }) diff --git a/spec/text-editor-component-spec.js b/spec/text-editor-component-spec.js index dbad4a3e7..d58a749d6 100644 --- a/spec/text-editor-component-spec.js +++ b/spec/text-editor-component-spec.js @@ -1,19 +1,31 @@ -const {it, fit, ffit, fffit, beforeEach, afterEach, conditionPromise, timeoutPromise} = require('./async-spec-helpers') +const { + it, + fit, + ffit, + fffit, + beforeEach, + afterEach, + conditionPromise, + timeoutPromise +} = require('./async-spec-helpers') const Random = require('../script/node_modules/random-seed') -const {getRandomBufferRange, buildRandomLines} = require('./helpers/random') +const { getRandomBufferRange, buildRandomLines } = require('./helpers/random') const TextEditorComponent = require('../src/text-editor-component') const TextEditorElement = require('../src/text-editor-element') const TextEditor = require('../src/text-editor') const TextBuffer = require('text-buffer') -const {Point} = TextBuffer +const { Point } = TextBuffer const fs = require('fs') const path = require('path') const Grim = require('grim') const electron = require('electron') const clipboard = electron.clipboard -const SAMPLE_TEXT = fs.readFileSync(path.join(__dirname, 'fixtures', 'sample.js'), 'utf8') +const SAMPLE_TEXT = fs.readFileSync( + path.join(__dirname, 'fixtures', 'sample.js'), + 'utf8' +) document.registerElement('text-editor-component-test-element', { prototype: Object.create(HTMLElement.prototype, { @@ -34,11 +46,16 @@ describe('TextEditorComponent', () => { // Force scrollbars to be visible regardless of local system configuration const scrollbarStyle = document.createElement('style') - scrollbarStyle.textContent = 'atom-text-editor ::-webkit-scrollbar { -webkit-appearance: none }' + scrollbarStyle.textContent = + 'atom-text-editor ::-webkit-scrollbar { -webkit-appearance: none }' jasmine.attachToDOM(scrollbarStyle) if (verticalScrollbarWidth == null) { - const {component, element} = buildComponent({text: 'abcdefgh\n'.repeat(10), width: 30, height: 30}) + const { component, element } = buildComponent({ + text: 'abcdefgh\n'.repeat(10), + width: 30, + height: 30 + }) verticalScrollbarWidth = getVerticalScrollbarWidth(component) horizontalScrollbarHeight = getHorizontalScrollbarHeight(component) element.remove() @@ -54,7 +71,10 @@ describe('TextEditorComponent', () => { describe('rendering', () => { it('renders lines and line numbers for the visible region', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 3, autoHeight: false}) + const { component, element, editor } = buildComponent({ + rowsPerTile: 3, + autoHeight: false + }) expect(queryOnScreenLineNumberElements(element).length).toBe(13) expect(queryOnScreenLineElements(element).length).toBe(13) @@ -69,13 +89,19 @@ describe('TextEditorComponent', () => { // After scrolling down beyond > 3 rows, the order of line numbers and lines // in the DOM is a bit weird because the first tile is recycled to the bottom // when it is scrolled out of view - expect(queryOnScreenLineNumberElements(element).map(element => element.textContent.trim())).toEqual([ - '10', '11', '12', '4', '5', '6', '7', '8', '9' - ]) - expect(queryOnScreenLineElements(element).map(element => element.dataset.screenRow)).toEqual([ - '9', '10', '11', '3', '4', '5', '6', '7', '8' - ]) - expect(queryOnScreenLineElements(element).map(element => element.textContent)).toEqual([ + expect( + queryOnScreenLineNumberElements(element).map(element => + element.textContent.trim() + ) + ).toEqual(['10', '11', '12', '4', '5', '6', '7', '8', '9']) + expect( + queryOnScreenLineElements(element).map( + element => element.dataset.screenRow + ) + ).toEqual(['9', '10', '11', '3', '4', '5', '6', '7', '8']) + expect( + queryOnScreenLineElements(element).map(element => element.textContent) + ).toEqual([ editor.lineTextForScreenRow(9), ' ', // this line is blank in the model, but we render a space to prevent the line from collapsing vertically editor.lineTextForScreenRow(11), @@ -88,13 +114,19 @@ describe('TextEditorComponent', () => { ]) await setScrollTop(component, 2.5 * component.getLineHeight()) - expect(queryOnScreenLineNumberElements(element).map(element => element.textContent.trim())).toEqual([ - '1', '2', '3', '4', '5', '6', '7', '8', '9' - ]) - expect(queryOnScreenLineElements(element).map(element => element.dataset.screenRow)).toEqual([ - '0', '1', '2', '3', '4', '5', '6', '7', '8' - ]) - expect(queryOnScreenLineElements(element).map(element => element.textContent)).toEqual([ + expect( + queryOnScreenLineNumberElements(element).map(element => + element.textContent.trim() + ) + ).toEqual(['1', '2', '3', '4', '5', '6', '7', '8', '9']) + expect( + queryOnScreenLineElements(element).map( + element => element.dataset.screenRow + ) + ).toEqual(['0', '1', '2', '3', '4', '5', '6', '7', '8']) + expect( + queryOnScreenLineElements(element).map(element => element.textContent) + ).toEqual([ editor.lineTextForScreenRow(0), editor.lineTextForScreenRow(1), editor.lineTextForScreenRow(2), @@ -108,22 +140,30 @@ describe('TextEditorComponent', () => { }) it('bases the width of the lines div on the width of the longest initially-visible screen line', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 2, height: 20, width: 100}) + const { component, element, editor } = buildComponent({ + rowsPerTile: 2, + height: 20, + width: 100 + }) { expect(editor.getApproximateLongestScreenRow()).toBe(3) const expectedWidth = Math.ceil( component.pixelPositionForScreenPosition(Point(3, Infinity)).left + - component.getBaseCharacterWidth() + component.getBaseCharacterWidth() + ) + expect(element.querySelector('.lines').style.width).toBe( + expectedWidth + 'px' ) - expect(element.querySelector('.lines').style.width).toBe(expectedWidth + 'px') } { // Get the next update promise synchronously here to ensure we don't // miss the update while polling the condition. const nextUpdatePromise = component.getNextUpdatePromise() - await conditionPromise(() => editor.getApproximateLongestScreenRow() === 6) + await conditionPromise( + () => editor.getApproximateLongestScreenRow() === 6 + ) await nextUpdatePromise // Capture the width of the lines before requesting the width of @@ -131,7 +171,7 @@ describe('TextEditorComponent', () => { const actualWidth = element.querySelector('.lines').style.width const expectedWidth = Math.ceil( component.pixelPositionForScreenPosition(Point(6, Infinity)).left + - component.getBaseCharacterWidth() + component.getBaseCharacterWidth() ) expect(actualWidth).toBe(expectedWidth + 'px') } @@ -154,7 +194,10 @@ describe('TextEditorComponent', () => { }) it('re-renders lines when their height changes', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 3, autoHeight: false}) + const { component, element, editor } = buildComponent({ + rowsPerTile: 3, + autoHeight: false + }) element.style.height = 4 * component.measurements.lineHeight + 'px' await component.getNextUpdatePromise() expect(queryOnScreenLineNumberElements(element).length).toBe(9) @@ -192,84 +235,119 @@ describe('TextEditorComponent', () => { }) it('makes the content at least as tall as the scroll container client height', async () => { - const {component, element, editor} = buildComponent({text: 'a'.repeat(100), width: 50, height: 100}) - expect(component.refs.content.offsetHeight).toBe(100 - getHorizontalScrollbarHeight(component)) + const { component, element, editor } = buildComponent({ + text: 'a'.repeat(100), + width: 50, + height: 100 + }) + expect(component.refs.content.offsetHeight).toBe( + 100 - getHorizontalScrollbarHeight(component) + ) editor.setText('a\n'.repeat(30)) await component.getNextUpdatePromise() expect(component.refs.content.offsetHeight).toBeGreaterThan(100) - expect(component.refs.content.offsetHeight).toBe(component.getContentHeight()) + expect(component.refs.content.offsetHeight).toBe( + component.getContentHeight() + ) }) it('honors the scrollPastEnd option by adding empty space equivalent to the clientHeight to the end of the content area', async () => { - const {component, element, editor} = buildComponent({autoHeight: false, autoWidth: false}) - const {scrollContainer} = component.refs + const { component, element, editor } = buildComponent({ + autoHeight: false, + autoWidth: false + }) + const { scrollContainer } = component.refs - await editor.update({scrollPastEnd: true}) + await editor.update({ scrollPastEnd: true }) await setEditorHeightInLines(component, 6) // scroll to end await setScrollTop(component, Infinity) - expect(component.getFirstVisibleRow()).toBe(editor.getScreenLineCount() - 3) + expect(component.getFirstVisibleRow()).toBe( + editor.getScreenLineCount() - 3 + ) - editor.update({scrollPastEnd: false}) + editor.update({ scrollPastEnd: false }) await component.getNextUpdatePromise() // wait for scrollable content resize - expect(component.getFirstVisibleRow()).toBe(editor.getScreenLineCount() - 6) + expect(component.getFirstVisibleRow()).toBe( + editor.getScreenLineCount() - 6 + ) // Always allows at least 3 lines worth of overscroll if the editor is short await setEditorHeightInLines(component, 2) - await editor.update({scrollPastEnd: true}) + await editor.update({ scrollPastEnd: true }) await setScrollTop(component, Infinity) - expect(component.getFirstVisibleRow()).toBe(editor.getScreenLineCount() + 1) + expect(component.getFirstVisibleRow()).toBe( + editor.getScreenLineCount() + 1 + ) }) it('does not fire onDidChangeScrollTop listeners when assigning the same maximal value and the content height has fractional pixels (regression)', async () => { - const {component, element, editor} = buildComponent({autoHeight: false, autoWidth: false}) + const { component, element, editor } = buildComponent({ + autoHeight: false, + autoWidth: false + }) await setEditorHeightInLines(component, 3) // Force a fractional content height with a block decoration - const item = document.createElement("div") + const item = document.createElement('div') item.style.height = '10.6px' - editor.decorateMarker(editor.markBufferPosition([0, 0]), {type: "block", item}) + editor.decorateMarker(editor.markBufferPosition([0, 0]), { + type: 'block', + item + }) await component.getNextUpdatePromise() component.setScrollTop(Infinity) - element.onDidChangeScrollTop((newScrollTop) => { + element.onDidChangeScrollTop(newScrollTop => { throw new Error('Scroll top should not have changed') }) component.setScrollTop(component.getScrollTop()) }) it('gives the line number tiles an explicit width and height so their layout can be strictly contained', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 3}) + const { component, element, editor } = buildComponent({ rowsPerTile: 3 }) - const lineNumberGutterElement = component.refs.gutterContainer.refs.lineNumberGutter.element - expect(lineNumberGutterElement.offsetHeight).toBe(component.getScrollHeight()) + const lineNumberGutterElement = + component.refs.gutterContainer.refs.lineNumberGutter.element + expect(lineNumberGutterElement.offsetHeight).toBe( + component.getScrollHeight() + ) for (const child of lineNumberGutterElement.children) { expect(child.offsetWidth).toBe(lineNumberGutterElement.offsetWidth) if (!child.classList.contains('line-number')) { for (const lineNumberElement of child.children) { - expect(lineNumberElement.offsetWidth).toBe(lineNumberGutterElement.offsetWidth) + expect(lineNumberElement.offsetWidth).toBe( + lineNumberGutterElement.offsetWidth + ) } } } editor.setText('x\n'.repeat(99)) await component.getNextUpdatePromise() - expect(lineNumberGutterElement.offsetHeight).toBe(component.getScrollHeight()) + expect(lineNumberGutterElement.offsetHeight).toBe( + component.getScrollHeight() + ) for (const child of lineNumberGutterElement.children) { expect(child.offsetWidth).toBe(lineNumberGutterElement.offsetWidth) if (!child.classList.contains('line-number')) { for (const lineNumberElement of child.children) { - expect(lineNumberElement.offsetWidth).toBe(lineNumberGutterElement.offsetWidth) + expect(lineNumberElement.offsetWidth).toBe( + lineNumberGutterElement.offsetWidth + ) } } } }) it('keeps the number of tiles stable when the visible line count changes during vertical scrolling', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 3, autoHeight: false}) + const { component, element, editor } = buildComponent({ + rowsPerTile: 3, + autoHeight: false + }) await setEditorHeightInLines(component, 5.5) expect(component.refs.lineTiles.children.length).toBe(3 + 2) // account for cursors and highlights containers @@ -281,7 +359,10 @@ describe('TextEditorComponent', () => { }) it('recycles tiles on resize', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 2, autoHeight: false}) + const { component, element, editor } = buildComponent({ + rowsPerTile: 2, + autoHeight: false + }) await setEditorHeightInLines(component, 7) await setScrollTop(component, 3.5 * component.getLineHeight()) const lineNode = lineNodeForScreenRow(component, 7) @@ -289,42 +370,68 @@ describe('TextEditorComponent', () => { expect(lineNodeForScreenRow(component, 7)).toBe(lineNode) }) - it('updates lines numbers when a row\'s foldability changes (regression)', async () => { - const {component, element, editor} = buildComponent({text: 'abc\n'}) + it("updates lines numbers when a row's foldability changes (regression)", async () => { + const { component, element, editor } = buildComponent({ text: 'abc\n' }) editor.setCursorBufferPosition([1, 0]) await component.getNextUpdatePromise() - expect(lineNumberNodeForScreenRow(component, 0).querySelector('.foldable')).toBeNull() + expect( + lineNumberNodeForScreenRow(component, 0).querySelector('.foldable') + ).toBeNull() editor.insertText(' def') await component.getNextUpdatePromise() - expect(lineNumberNodeForScreenRow(component, 0).querySelector('.foldable')).toBeDefined() + expect( + lineNumberNodeForScreenRow(component, 0).querySelector('.foldable') + ).toBeDefined() editor.undo() await component.getNextUpdatePromise() - expect(lineNumberNodeForScreenRow(component, 0).querySelector('.foldable')).toBeNull() + expect( + lineNumberNodeForScreenRow(component, 0).querySelector('.foldable') + ).toBeNull() }) it('shows the foldable icon on the last screen row of a buffer row that can be folded', async () => { - const {component, element, editor} = buildComponent({text: 'abc\n de\nfghijklm\n no', softWrapped: true}) + const { component, element, editor } = buildComponent({ + text: 'abc\n de\nfghijklm\n no', + softWrapped: true + }) await setEditorWidthInCharacters(component, 5) - expect(lineNumberNodeForScreenRow(component, 0).classList.contains('foldable')).toBe(true) - expect(lineNumberNodeForScreenRow(component, 1).classList.contains('foldable')).toBe(false) - expect(lineNumberNodeForScreenRow(component, 2).classList.contains('foldable')).toBe(false) - expect(lineNumberNodeForScreenRow(component, 3).classList.contains('foldable')).toBe(true) - expect(lineNumberNodeForScreenRow(component, 4).classList.contains('foldable')).toBe(false) + expect( + lineNumberNodeForScreenRow(component, 0).classList.contains('foldable') + ).toBe(true) + expect( + lineNumberNodeForScreenRow(component, 1).classList.contains('foldable') + ).toBe(false) + expect( + lineNumberNodeForScreenRow(component, 2).classList.contains('foldable') + ).toBe(false) + expect( + lineNumberNodeForScreenRow(component, 3).classList.contains('foldable') + ).toBe(true) + expect( + lineNumberNodeForScreenRow(component, 4).classList.contains('foldable') + ).toBe(false) }) it('renders dummy vertical and horizontal scrollbars when content overflows', async () => { - const {component, element, editor} = buildComponent({height: 100, width: 100}) + const { component, element, editor } = buildComponent({ + height: 100, + width: 100 + }) const verticalScrollbar = component.refs.verticalScrollbar.element const horizontalScrollbar = component.refs.horizontalScrollbar.element expect(verticalScrollbar.scrollHeight).toBe(component.getContentHeight()) expect(horizontalScrollbar.scrollWidth).toBe(component.getContentWidth()) expect(getVerticalScrollbarWidth(component)).toBeGreaterThan(0) expect(getHorizontalScrollbarHeight(component)).toBeGreaterThan(0) - expect(verticalScrollbar.style.bottom).toBe(getVerticalScrollbarWidth(component) + 'px') + expect(verticalScrollbar.style.bottom).toBe( + getVerticalScrollbarWidth(component) + 'px' + ) expect(verticalScrollbar.style.visibility).toBe('') - expect(horizontalScrollbar.style.right).toBe(getHorizontalScrollbarHeight(component) + 'px') + expect(horizontalScrollbar.style.right).toBe( + getHorizontalScrollbarHeight(component) + 'px' + ) expect(horizontalScrollbar.style.visibility).toBe('') expect(component.refs.scrollbarCorner).toBeDefined() @@ -363,7 +470,10 @@ describe('TextEditorComponent', () => { describe('when scrollbar styles change or the editor element is detached and then reattached', () => { it('updates the bottom/right of dummy scrollbars and client height/width measurements', async () => { - const {component, element, editor} = buildComponent({height: 100, width: 100}) + const { component, element, editor } = buildComponent({ + height: 100, + width: 100 + }) expect(getHorizontalScrollbarHeight(component)).toBeGreaterThan(10) expect(getVerticalScrollbarWidth(component)).toBeGreaterThan(10) setScrollTop(component, 20) @@ -379,12 +489,18 @@ describe('TextEditorComponent', () => { expect(getHorizontalScrollbarHeight(component)).toBe(10) expect(getVerticalScrollbarWidth(component)).toBe(10) - expect(component.refs.horizontalScrollbar.element.style.right).toBe('10px') - expect(component.refs.verticalScrollbar.element.style.bottom).toBe('10px') + expect(component.refs.horizontalScrollbar.element.style.right).toBe( + '10px' + ) + expect(component.refs.verticalScrollbar.element.style.bottom).toBe( + '10px' + ) expect(component.refs.horizontalScrollbar.element.scrollLeft).toBe(10) expect(component.refs.verticalScrollbar.element.scrollTop).toBe(20) expect(component.getScrollContainerClientHeight()).toBe(100 - 10) - expect(component.getScrollContainerClientWidth()).toBe(100 - component.getGutterContainerWidth() - 10) + expect(component.getScrollContainerClientWidth()).toBe( + 100 - component.getGutterContainerWidth() - 10 + ) // Detaching and re-attaching the editor element. element.remove() @@ -392,15 +508,21 @@ describe('TextEditorComponent', () => { expect(getHorizontalScrollbarHeight(component)).toBe(10) expect(getVerticalScrollbarWidth(component)).toBe(10) - expect(component.refs.horizontalScrollbar.element.style.right).toBe('10px') - expect(component.refs.verticalScrollbar.element.style.bottom).toBe('10px') + expect(component.refs.horizontalScrollbar.element.style.right).toBe( + '10px' + ) + expect(component.refs.verticalScrollbar.element.style.bottom).toBe( + '10px' + ) expect(component.refs.horizontalScrollbar.element.scrollLeft).toBe(10) expect(component.refs.verticalScrollbar.element.scrollTop).toBe(20) expect(component.getScrollContainerClientHeight()).toBe(100 - 10) - expect(component.getScrollContainerClientWidth()).toBe(100 - component.getGutterContainerWidth() - 10) + expect(component.getScrollContainerClientWidth()).toBe( + 100 - component.getGutterContainerWidth() - 10 + ) // Ensure we don't throw an error trying to remeasure non-existent scrollbars for mini editors. - await editor.update({mini: true}) + await editor.update({ mini: true }) TextEditor.didUpdateScrollbarStyles() component.scheduleUpdate() await component.getNextUpdatePromise() @@ -408,19 +530,22 @@ describe('TextEditorComponent', () => { }) it('renders cursors within the visible row range', async () => { - const {component, element, editor} = buildComponent({height: 40, rowsPerTile: 2}) + const { component, element, editor } = buildComponent({ + height: 40, + rowsPerTile: 2 + }) await setScrollTop(component, 100) expect(component.getRenderedStartRow()).toBe(4) expect(component.getRenderedEndRow()).toBe(10) - editor.setCursorScreenPosition([0, 0], {autoscroll: false}) // out of view - editor.addCursorAtScreenPosition([2, 2], {autoscroll: false}) // out of view - editor.addCursorAtScreenPosition([4, 0], {autoscroll: false}) // line start - editor.addCursorAtScreenPosition([4, 4], {autoscroll: false}) // at token boundary - editor.addCursorAtScreenPosition([4, 6], {autoscroll: false}) // within token - editor.addCursorAtScreenPosition([5, Infinity], {autoscroll: false}) // line end - editor.addCursorAtScreenPosition([10, 2], {autoscroll: false}) // out of view + editor.setCursorScreenPosition([0, 0], { autoscroll: false }) // out of view + editor.addCursorAtScreenPosition([2, 2], { autoscroll: false }) // out of view + editor.addCursorAtScreenPosition([4, 0], { autoscroll: false }) // line start + editor.addCursorAtScreenPosition([4, 4], { autoscroll: false }) // at token boundary + editor.addCursorAtScreenPosition([4, 6], { autoscroll: false }) // within token + editor.addCursorAtScreenPosition([5, Infinity], { autoscroll: false }) // line end + editor.addCursorAtScreenPosition([10, 2], { autoscroll: false }) // out of view await component.getNextUpdatePromise() let cursorNodes = Array.from(element.querySelectorAll('.cursor')) @@ -430,31 +555,28 @@ describe('TextEditorComponent', () => { verifyCursorPosition(component, cursorNodes[2], 4, 6) verifyCursorPosition(component, cursorNodes[3], 5, 30) - editor.setCursorScreenPosition([8, 11], {autoscroll: false}) + editor.setCursorScreenPosition([8, 11], { autoscroll: false }) await component.getNextUpdatePromise() cursorNodes = Array.from(element.querySelectorAll('.cursor')) expect(cursorNodes.length).toBe(1) verifyCursorPosition(component, cursorNodes[0], 8, 11) - editor.setCursorScreenPosition([0, 0], {autoscroll: false}) + editor.setCursorScreenPosition([0, 0], { autoscroll: false }) await component.getNextUpdatePromise() cursorNodes = Array.from(element.querySelectorAll('.cursor')) expect(cursorNodes.length).toBe(0) - editor.setSelectedScreenRange([[8, 0], [12, 0]], {autoscroll: false}) + editor.setSelectedScreenRange([[8, 0], [12, 0]], { autoscroll: false }) await component.getNextUpdatePromise() cursorNodes = Array.from(element.querySelectorAll('.cursor')) expect(cursorNodes.length).toBe(0) }) it('hides cursors with non-empty selections when showCursorOnSelection is false', async () => { - const {component, element, editor} = buildComponent() - editor.setSelectedScreenRanges([ - [[0, 0], [0, 3]], - [[1, 0], [1, 0]] - ]) + const { component, element, editor } = buildComponent() + editor.setSelectedScreenRanges([[[0, 0], [0, 3]], [[1, 0], [1, 0]]]) await component.getNextUpdatePromise() { const cursorNodes = Array.from(element.querySelectorAll('.cursor')) @@ -463,7 +585,7 @@ describe('TextEditorComponent', () => { verifyCursorPosition(component, cursorNodes[1], 1, 0) } - editor.update({showCursorOnSelection: false}) + editor.update({ showCursorOnSelection: false }) await component.getNextUpdatePromise() { const cursorNodes = Array.from(element.querySelectorAll('.cursor')) @@ -471,10 +593,7 @@ describe('TextEditorComponent', () => { verifyCursorPosition(component, cursorNodes[0], 1, 0) } - editor.setSelectedScreenRanges([ - [[0, 0], [0, 3]], - [[1, 0], [1, 4]] - ]) + editor.setSelectedScreenRanges([[[0, 0], [0, 3]], [[1, 0], [1, 4]]]) await component.getNextUpdatePromise() { const cursorNodes = Array.from(element.querySelectorAll('.cursor')) @@ -484,7 +603,7 @@ describe('TextEditorComponent', () => { it('blinks cursors when the editor is focused and the cursors are not moving', async () => { assertDocumentFocused() - const {component, element, editor} = buildComponent() + const { component, element, editor } = buildComponent() component.props.cursorBlinkPeriod = 40 component.props.cursorBlinkResumeDelay = 40 editor.addCursorAtScreenPosition([1, 0]) @@ -493,14 +612,20 @@ describe('TextEditorComponent', () => { await component.getNextUpdatePromise() const [cursor1, cursor2] = element.querySelectorAll('.cursor') - await conditionPromise(() => - getComputedStyle(cursor1).opacity === '1' && getComputedStyle(cursor2).opacity === '1' + await conditionPromise( + () => + getComputedStyle(cursor1).opacity === '1' && + getComputedStyle(cursor2).opacity === '1' ) - await conditionPromise(() => - getComputedStyle(cursor1).opacity === '0' && getComputedStyle(cursor2).opacity === '0' + await conditionPromise( + () => + getComputedStyle(cursor1).opacity === '0' && + getComputedStyle(cursor2).opacity === '0' ) - await conditionPromise(() => - getComputedStyle(cursor1).opacity === '1' && getComputedStyle(cursor2).opacity === '1' + await conditionPromise( + () => + getComputedStyle(cursor1).opacity === '1' && + getComputedStyle(cursor2).opacity === '1' ) editor.moveRight() @@ -511,13 +636,15 @@ describe('TextEditorComponent', () => { }) it('gives cursors at the end of lines the width of an "x" character', async () => { - const {component, element, editor} = buildComponent() + const { component, element, editor } = buildComponent() editor.setText('abcde') await setEditorWidthInCharacters(component, 5.5) editor.setCursorScreenPosition([0, Infinity]) await component.getNextUpdatePromise() - expect(element.querySelector('.cursor').offsetWidth).toBe(Math.round(component.getBaseCharacterWidth())) + expect(element.querySelector('.cursor').offsetWidth).toBe( + Math.round(component.getBaseCharacterWidth()) + ) // Clip cursor width when soft-wrap is on and the cursor is at the end of // the line. This prevents the parent tile from disabling sub-pixel @@ -525,11 +652,13 @@ describe('TextEditorComponent', () => { // container doesn't solve this issue so we're adding this workaround instead. editor.setSoftWrapped(true) await component.getNextUpdatePromise() - expect(element.querySelector('.cursor').offsetWidth).toBeLessThan(Math.round(component.getBaseCharacterWidth())) + expect(element.querySelector('.cursor').offsetWidth).toBeLessThan( + Math.round(component.getBaseCharacterWidth()) + ) }) it('positions and sizes cursors correctly when they are located next to a fold marker', async () => { - const {component, element, editor} = buildComponent() + const { component, element, editor } = buildComponent() editor.foldBufferRange([[0, 3], [0, 6]]) editor.setCursorScreenPosition([0, 3]) @@ -542,7 +671,9 @@ describe('TextEditorComponent', () => { }) it('positions cursors and placeholder text correctly when the lines container has a margin and/or is padded', async () => { - const {component, element, editor} = buildComponent({placeholderText: 'testing'}) + const { component, element, editor } = buildComponent({ + placeholderText: 'testing' + }) component.refs.lineTiles.style.marginLeft = '10px' TextEditor.didUpdateStyles() @@ -569,14 +700,20 @@ describe('TextEditorComponent', () => { editor.setText('') await component.getNextUpdatePromise() - const placeholderTextLeft = element.querySelector('.placeholder-text').getBoundingClientRect().left + const placeholderTextLeft = element + .querySelector('.placeholder-text') + .getBoundingClientRect().left const linesLeft = component.refs.lineTiles.getBoundingClientRect().left expect(placeholderTextLeft).toBe(linesLeft) }) it('places the hidden input element at the location of the last cursor if it is visible', async () => { - const {component, element, editor} = buildComponent({height: 60, width: 120, rowsPerTile: 2}) - const {hiddenInput} = component.refs.cursorsAndInput.refs + const { component, element, editor } = buildComponent({ + height: 60, + width: 120, + rowsPerTile: 2 + }) + const { hiddenInput } = component.refs.cursorsAndInput.refs setScrollTop(component, 100) await setScrollLeft(component, 40) @@ -591,21 +728,25 @@ describe('TextEditorComponent', () => { // Otherwise it is positioned at the last cursor position editor.addCursorAtScreenPosition([7, 4]) await component.getNextUpdatePromise() - expect(hiddenInput.getBoundingClientRect().top).toBe(clientTopForLine(component, 7)) - expect(Math.round(hiddenInput.getBoundingClientRect().left)).toBe(clientLeftForCharacter(component, 7, 4)) + expect(hiddenInput.getBoundingClientRect().top).toBe( + clientTopForLine(component, 7) + ) + expect(Math.round(hiddenInput.getBoundingClientRect().left)).toBe( + clientLeftForCharacter(component, 7, 4) + ) }) it('soft wraps lines based on the content width when soft wrap is enabled', async () => { let baseCharacterWidth, gutterContainerWidth { - const {component, editor} = buildComponent() + const { component, editor } = buildComponent() baseCharacterWidth = component.getBaseCharacterWidth() gutterContainerWidth = component.getGutterContainerWidth() editor.destroy() } - const {component, element, editor} = buildComponent({ - width: gutterContainerWidth + (baseCharacterWidth * 55), + const { component, element, editor } = buildComponent({ + width: gutterContainerWidth + baseCharacterWidth * 55, attach: false }) editor.setSoftWrapped(true) @@ -627,13 +768,18 @@ describe('TextEditorComponent', () => { ' = [], right = [];' ) - const {scrollContainer} = component.refs + const { scrollContainer } = component.refs expect(scrollContainer.clientWidth).toBe(scrollContainer.scrollWidth) }) it('correctly forces the display layer to index visible rows when resizing (regression)', async () => { const text = 'a'.repeat(30) + '\n' + 'b'.repeat(1000) - const {component, element, editor} = buildComponent({height: 300, width: 800, attach: false, text}) + const { component, element, editor } = buildComponent({ + height: 300, + width: 800, + attach: false, + text + }) editor.setSoftWrapped(true) jasmine.attachToDOM(element) @@ -643,38 +789,45 @@ describe('TextEditorComponent', () => { }) it('decorates the line numbers of folded lines', async () => { - const {component, element, editor} = buildComponent() + const { component, element, editor } = buildComponent() editor.foldBufferRow(1) await component.getNextUpdatePromise() - expect(lineNumberNodeForScreenRow(component, 1).classList.contains('folded')).toBe(true) + expect( + lineNumberNodeForScreenRow(component, 1).classList.contains('folded') + ).toBe(true) }) it('makes lines at least as wide as the scrollContainer', async () => { - const {component, element, editor} = buildComponent() - const {scrollContainer, gutterContainer} = component.refs + const { component, element, editor } = buildComponent() + const { scrollContainer, gutterContainer } = component.refs editor.setText('a') await component.getNextUpdatePromise() - expect(element.querySelector('.line').offsetWidth).toBe(scrollContainer.offsetWidth - verticalScrollbarWidth) + expect(element.querySelector('.line').offsetWidth).toBe( + scrollContainer.offsetWidth - verticalScrollbarWidth + ) }) it('resizes based on the content when the autoHeight and/or autoWidth options are true', async () => { - const {component, element, editor} = buildComponent({autoHeight: true, autoWidth: true}) + const { component, element, editor } = buildComponent({ + autoHeight: true, + autoWidth: true + }) const editorPadding = 3 element.style.padding = editorPadding + 'px' - const {gutterContainer, scrollContainer} = component.refs + const { gutterContainer, scrollContainer } = component.refs const initialWidth = element.offsetWidth const initialHeight = element.offsetHeight expect(initialWidth).toBe( component.getGutterContainerWidth() + - component.getContentWidth() + - verticalScrollbarWidth + - 2 * editorPadding + component.getContentWidth() + + verticalScrollbarWidth + + 2 * editorPadding ) expect(initialHeight).toBe( component.getContentHeight() + - horizontalScrollbarHeight + - 2 * editorPadding + horizontalScrollbarHeight + + 2 * editorPadding ) // When autoWidth is enabled, width adjusts to content @@ -683,9 +836,9 @@ describe('TextEditorComponent', () => { await component.getNextUpdatePromise() expect(element.offsetWidth).toBe( component.getGutterContainerWidth() + - component.getContentWidth() + - verticalScrollbarWidth + - 2 * editorPadding + component.getContentWidth() + + verticalScrollbarWidth + + 2 * editorPadding ) expect(element.offsetWidth).toBeGreaterThan(initialWidth) @@ -694,48 +847,79 @@ describe('TextEditorComponent', () => { await component.getNextUpdatePromise() expect(element.offsetHeight).toBe( component.getContentHeight() + - horizontalScrollbarHeight + - 2 * editorPadding + horizontalScrollbarHeight + + 2 * editorPadding ) expect(element.offsetHeight).toBeGreaterThan(initialHeight) }) it('does not render the line number gutter at all if the isLineNumberGutterVisible parameter is false', () => { - const {component, element, editor} = buildComponent({lineNumberGutterVisible: false}) + const { component, element, editor } = buildComponent({ + lineNumberGutterVisible: false + }) expect(element.querySelector('.line-number')).toBe(null) }) it('does not render the line numbers but still renders the line number gutter if showLineNumbers is false', async () => { function checkScrollContainerLeft (component) { - const {scrollContainer, gutterContainer} = component.refs - expect(scrollContainer.getBoundingClientRect().left).toBe(Math.round(gutterContainer.element.getBoundingClientRect().right)) + const { scrollContainer, gutterContainer } = component.refs + expect(scrollContainer.getBoundingClientRect().left).toBe( + Math.round(gutterContainer.element.getBoundingClientRect().right) + ) } - const {component, element, editor} = buildComponent({showLineNumbers: false}) - expect(Array.from(element.querySelectorAll('.line-number')).every((e) => e.textContent === '')).toBe(true) + const { component, element, editor } = buildComponent({ + showLineNumbers: false + }) + expect( + Array.from(element.querySelectorAll('.line-number')).every( + e => e.textContent === '' + ) + ).toBe(true) checkScrollContainerLeft(component) - await editor.update({showLineNumbers: true}) - expect(Array.from(element.querySelectorAll('.line-number')).map((e) => e.textContent)).toEqual([ - '00', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13' + await editor.update({ showLineNumbers: true }) + expect( + Array.from(element.querySelectorAll('.line-number')).map( + e => e.textContent + ) + ).toEqual([ + '00', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + '10', + '11', + '12', + '13' ]) checkScrollContainerLeft(component) - await editor.update({showLineNumbers: false}) - expect(Array.from(element.querySelectorAll('.line-number')).every((e) => e.textContent === '')).toBe(true) + await editor.update({ showLineNumbers: false }) + expect( + Array.from(element.querySelectorAll('.line-number')).every( + e => e.textContent === '' + ) + ).toBe(true) checkScrollContainerLeft(component) }) it('supports the placeholderText parameter', () => { const placeholderText = 'Placeholder Test' - const {element} = buildComponent({placeholderText, text: ''}) + const { element } = buildComponent({ placeholderText, text: '' }) expect(element.textContent).toContain(placeholderText) }) it('adds the data-grammar attribute and updates it when the grammar changes', async () => { await atom.packages.activatePackage('language-javascript') - const {editor, element, component} = buildComponent() + const { editor, element, component } = buildComponent() expect(element.dataset.grammar).toBe('text plain null-grammar') atom.grammars.assignLanguageMode(editor.getBuffer(), 'source.js') @@ -744,7 +928,7 @@ describe('TextEditorComponent', () => { }) it('adds the data-encoding attribute and updates it when the encoding changes', async () => { - const {editor, element, component} = buildComponent() + const { editor, element, component } = buildComponent() expect(element.dataset.encoding).toBe('utf8') editor.setEncoding('ascii') @@ -753,61 +937,133 @@ describe('TextEditorComponent', () => { }) it('adds the has-selection class when the editor has a non-empty selection', async () => { - const {editor, element, component} = buildComponent() + const { editor, element, component } = buildComponent() expect(element.classList.contains('has-selection')).toBe(false) - editor.setSelectedBufferRanges([ - [[0, 0], [0, 0]], - [[1, 0], [1, 10]] - ]) + editor.setSelectedBufferRanges([[[0, 0], [0, 0]], [[1, 0], [1, 10]]]) await component.getNextUpdatePromise() expect(element.classList.contains('has-selection')).toBe(true) - editor.setSelectedBufferRanges([ - [[0, 0], [0, 0]], - [[1, 0], [1, 0]] - ]) + editor.setSelectedBufferRanges([[[0, 0], [0, 0]], [[1, 0], [1, 0]]]) await component.getNextUpdatePromise() expect(element.classList.contains('has-selection')).toBe(false) }) it('assigns buffer-row and screen-row to each line number as data fields', async () => { - const {editor, element, component} = buildComponent() + const { editor, element, component } = buildComponent() editor.setSoftWrapped(true) await component.getNextUpdatePromise() await setEditorWidthInCharacters(component, 40) { - const bufferRows = queryOnScreenLineNumberElements(element).map((e) => e.dataset.bufferRow) - const screenRows = queryOnScreenLineNumberElements(element).map((e) => e.dataset.screenRow) + const bufferRows = queryOnScreenLineNumberElements(element).map( + e => e.dataset.bufferRow + ) + const screenRows = queryOnScreenLineNumberElements(element).map( + e => e.dataset.screenRow + ) expect(bufferRows).toEqual([ - '0', '1', '2', '3', '3', '4', '5', '6', '6', '6', - '7', '8', '8', '8', '9', '10', '11', '11', '12' + '0', + '1', + '2', + '3', + '3', + '4', + '5', + '6', + '6', + '6', + '7', + '8', + '8', + '8', + '9', + '10', + '11', + '11', + '12' ]) expect(screenRows).toEqual([ - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - '10', '11', '12', '13', '14', '15', '16', '17', '18' + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + '10', + '11', + '12', + '13', + '14', + '15', + '16', + '17', + '18' ]) } editor.getBuffer().insert([2, 0], '\n') await component.getNextUpdatePromise() { - const bufferRows = queryOnScreenLineNumberElements(element).map((e) => e.dataset.bufferRow) - const screenRows = queryOnScreenLineNumberElements(element).map((e) => e.dataset.screenRow) + const bufferRows = queryOnScreenLineNumberElements(element).map( + e => e.dataset.bufferRow + ) + const screenRows = queryOnScreenLineNumberElements(element).map( + e => e.dataset.screenRow + ) expect(bufferRows).toEqual([ - '0', '1', '2', '3', '4', '4', '5', '6', '7', '7', - '7', '8', '9', '9', '9', '10', '11', '12', '12', '13' + '0', + '1', + '2', + '3', + '4', + '4', + '5', + '6', + '7', + '7', + '7', + '8', + '9', + '9', + '9', + '10', + '11', + '12', + '12', + '13' ]) expect(screenRows).toEqual([ - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - '10', '11', '12', '13', '14', '15', '16', '17', '18', '19' + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + '10', + '11', + '12', + '13', + '14', + '15', + '16', + '17', + '18', + '19' ]) } }) it('does not blow away class names added to the element by packages when changing the class name', async () => { assertDocumentFocused() - const {component, element, editor} = buildComponent() + const { component, element, editor } = buildComponent() element.classList.add('a', 'b') expect(element.className).toBe('editor a b') element.focus() @@ -820,18 +1076,20 @@ describe('TextEditorComponent', () => { it('does not blow away class names managed by the component when packages change the element class name', async () => { assertDocumentFocused() - const {component, element, editor} = buildComponent({mini: true}) + const { component, element, editor } = buildComponent({ mini: true }) element.classList.add('a', 'b') element.focus() await component.getNextUpdatePromise() expect(element.className).toBe('editor mini a b is-focused') - element.className = 'a c d'; + element.className = 'a c d' await component.getNextUpdatePromise() expect(element.className).toBe('a c d editor is-focused mini') }) it('ignores resize events when the editor is hidden', async () => { - const {component, element, editor} = buildComponent({autoHeight: false}) + const { component, element, editor } = buildComponent({ + autoHeight: false + }) element.style.height = 5 * component.getLineHeight() + 'px' await component.getNextUpdatePromise() const originalClientContainerHeight = component.getClientContainerHeight() @@ -848,16 +1106,28 @@ describe('TextEditorComponent', () => { expect(component.visible).toBe(true) component.didResize() component.didResizeGutterContainer() - expect(component.getClientContainerHeight()).toBe(originalClientContainerHeight) - expect(component.getGutterContainerWidth()).toBe(originalGutterContainerWidth) - expect(component.getLineNumberGutterWidth()).toBe(originalLineNumberGutterWidth) + expect(component.getClientContainerHeight()).toBe( + originalClientContainerHeight + ) + expect(component.getGutterContainerWidth()).toBe( + originalGutterContainerWidth + ) + expect(component.getLineNumberGutterWidth()).toBe( + originalLineNumberGutterWidth + ) // Ensure measurements stay the same after receiving the intersection // observer events. await conditionPromise(() => !component.visible) - expect(component.getClientContainerHeight()).toBe(originalClientContainerHeight) - expect(component.getGutterContainerWidth()).toBe(originalGutterContainerWidth) - expect(component.getLineNumberGutterWidth()).toBe(originalLineNumberGutterWidth) + expect(component.getClientContainerHeight()).toBe( + originalClientContainerHeight + ) + expect(component.getGutterContainerWidth()).toBe( + originalGutterContainerWidth + ) + expect(component.getLineNumberGutterWidth()).toBe( + originalLineNumberGutterWidth + ) }) describe('randomized tests', () => { @@ -881,7 +1151,10 @@ describe('TextEditorComponent', () => { const random = Random(seed) const rowsPerTile = random.intBetween(1, 6) - const {component, element, editor} = buildComponent({rowsPerTile, autoHeight: false}) + const { component, element, editor } = buildComponent({ + rowsPerTile, + autoHeight: false + }) editor.setSoftWrapped(Boolean(random(2))) await setEditorWidthInCharacters(component, random(20)) await setEditorHeightInLines(component, random(10)) @@ -918,20 +1191,35 @@ describe('TextEditorComponent', () => { } else if (k < 95) { editor.setSelectedBufferRange(range) } else { - if (random(2)) component.setScrollTop(random(component.getScrollHeight())) - if (random(2)) component.setScrollLeft(random(component.getScrollWidth())) + if (random(2)) + component.setScrollTop(random(component.getScrollHeight())) + if (random(2)) + component.setScrollLeft(random(component.getScrollWidth())) } component.scheduleUpdate() await component.getNextUpdatePromise() - const renderedLines = queryOnScreenLineElements(element).sort((a, b) => a.dataset.screenRow - b.dataset.screenRow) - const renderedLineNumbers = queryOnScreenLineNumberElements(element).sort((a, b) => a.dataset.screenRow - b.dataset.screenRow) + const renderedLines = queryOnScreenLineElements(element).sort( + (a, b) => a.dataset.screenRow - b.dataset.screenRow + ) + const renderedLineNumbers = queryOnScreenLineNumberElements( + element + ).sort((a, b) => a.dataset.screenRow - b.dataset.screenRow) const renderedStartRow = component.getRenderedStartRow() - const expectedLines = editor.displayLayer.getScreenLines(renderedStartRow, component.getRenderedEndRow()) + const expectedLines = editor.displayLayer.getScreenLines( + renderedStartRow, + component.getRenderedEndRow() + ) - expect(renderedLines.length).toBe(expectedLines.length, failureMessage) - expect(renderedLineNumbers.length).toBe(expectedLines.length, failureMessage) + expect(renderedLines.length).toBe( + expectedLines.length, + failureMessage + ) + expect(renderedLineNumbers.length).toBe( + expectedLines.length, + failureMessage + ) for (let k = 0; k < renderedLines.length; k++) { const expectedLine = expectedLines[k] const expectedText = expectedLine.lineText || ' ' @@ -942,12 +1230,21 @@ describe('TextEditorComponent', () => { // We append zero width NBSPs after folds at the end of the // line in order to support measurement. if (expectedText.endsWith(editor.displayLayer.foldCharacter)) { - renderedText = renderedText.substring(0, renderedText.length - 1) + renderedText = renderedText.substring( + 0, + renderedText.length - 1 + ) } expect(renderedText).toBe(expectedText, failureMessage) - expect(parseInt(renderedLine.dataset.screenRow)).toBe(renderedStartRow + k, failureMessage) - expect(parseInt(renderedLineNumber.dataset.screenRow)).toBe(renderedStartRow + k, failureMessage) + expect(parseInt(renderedLine.dataset.screenRow)).toBe( + renderedStartRow + k, + failureMessage + ) + expect(parseInt(renderedLineNumber.dataset.screenRow)).toBe( + renderedStartRow + k, + failureMessage + ) } } @@ -961,39 +1258,51 @@ describe('TextEditorComponent', () => { describe('mini editors', () => { it('adds the mini attribute and class even when the element is not attached', () => { { - const {element, editor} = buildComponent({mini: true}) + const { element, editor } = buildComponent({ mini: true }) expect(element.hasAttribute('mini')).toBe(true) expect(element.classList.contains('mini')).toBe(true) } { - const {element, editor} = buildComponent({mini: true, attach: false}) + const { element, editor } = buildComponent({ + mini: true, + attach: false + }) expect(element.hasAttribute('mini')).toBe(true) expect(element.classList.contains('mini')).toBe(true) } }) it('does not render the gutter container', () => { - const {component, element, editor} = buildComponent({mini: true}) + const { component, element, editor } = buildComponent({ mini: true }) expect(component.refs.gutterContainer).toBeUndefined() expect(element.querySelector('gutter-container')).toBeNull() }) it('does not render line decorations for the cursor line', async () => { - const {component, element, editor} = buildComponent({mini: true}) - expect(element.querySelector('.line').classList.contains('cursor-line')).toBe(false) + const { component, element, editor } = buildComponent({ mini: true }) + expect( + element.querySelector('.line').classList.contains('cursor-line') + ).toBe(false) - editor.update({mini: false}) + editor.update({ mini: false }) await component.getNextUpdatePromise() - expect(element.querySelector('.line').classList.contains('cursor-line')).toBe(true) + expect( + element.querySelector('.line').classList.contains('cursor-line') + ).toBe(true) - editor.update({mini: true}) + editor.update({ mini: true }) await component.getNextUpdatePromise() - expect(element.querySelector('.line').classList.contains('cursor-line')).toBe(false) + expect( + element.querySelector('.line').classList.contains('cursor-line') + ).toBe(false) }) it('does not render scrollbars', async () => { - const {component, element, editor} = buildComponent({mini: true, autoHeight: false}) + const { component, element, editor } = buildComponent({ + mini: true, + autoHeight: false + }) await setEditorWidthInCharacters(component, 10) editor.setText('x'.repeat(20) + 'y'.repeat(20)) @@ -1012,8 +1321,8 @@ describe('TextEditorComponent', () => { }) it('focuses the hidden input element and adds the is-focused class when focused', async () => { - const {component, element, editor} = buildComponent() - const {hiddenInput} = component.refs.cursorsAndInput.refs + const { component, element, editor } = buildComponent() + const { hiddenInput } = component.refs.cursorsAndInput.refs expect(document.activeElement).not.toBe(hiddenInput) element.focus() @@ -1032,8 +1341,8 @@ describe('TextEditorComponent', () => { }) it('updates the component when the hidden input is focused directly', async () => { - const {component, element, editor} = buildComponent() - const {hiddenInput} = component.refs.cursorsAndInput.refs + const { component, element, editor } = buildComponent() + const { hiddenInput } = component.refs.cursorsAndInput.refs expect(element.classList.contains('is-focused')).toBe(false) expect(document.activeElement).not.toBe(hiddenInput) @@ -1043,27 +1352,33 @@ describe('TextEditorComponent', () => { }) it('gracefully handles a focus event that occurs prior to the attachedCallback of the element', () => { - const {component, element, editor} = buildComponent({attach: false}) - const parent = document.createElement('text-editor-component-test-element') + const { component, element, editor } = buildComponent({ attach: false }) + const parent = document.createElement( + 'text-editor-component-test-element' + ) parent.appendChild(element) parent.didAttach = () => element.focus() jasmine.attachToDOM(parent) - expect(document.activeElement).toBe(component.refs.cursorsAndInput.refs.hiddenInput) + expect(document.activeElement).toBe( + component.refs.cursorsAndInput.refs.hiddenInput + ) }) it('gracefully handles a focus event that occurs prior to detecting the element has become visible', async () => { - const {component, element, editor} = buildComponent({attach: false}) + const { component, element, editor } = buildComponent({ attach: false }) element.style.display = 'none' jasmine.attachToDOM(element) element.style.display = 'block' element.focus() await component.getNextUpdatePromise() - expect(document.activeElement).toBe(component.refs.cursorsAndInput.refs.hiddenInput) + expect(document.activeElement).toBe( + component.refs.cursorsAndInput.refs.hiddenInput + ) }) it('emits blur events only when focus shifts to something other than the editor itself or its hidden input', () => { - const {element} = buildComponent() + const { element } = buildComponent() let blurEventCount = 0 element.addEventListener('blur', () => blurEventCount++) @@ -1079,20 +1394,29 @@ describe('TextEditorComponent', () => { describe('autoscroll', () => { it('automatically scrolls vertically when the requested range is within the vertical scroll margin of the top or bottom', async () => { - const {component, editor} = buildComponent({height: 120 + horizontalScrollbarHeight}) + const { component, editor } = buildComponent({ + height: 120 + horizontalScrollbarHeight + }) expect(component.getLastVisibleRow()).toBe(7) editor.scrollToScreenRange([[4, 0], [6, 0]]) await component.getNextUpdatePromise() - expect(component.getScrollBottom()).toBe((6 + 1 + editor.verticalScrollMargin) * component.getLineHeight()) + expect(component.getScrollBottom()).toBe( + (6 + 1 + editor.verticalScrollMargin) * component.getLineHeight() + ) editor.scrollToScreenPosition([8, 0]) await component.getNextUpdatePromise() - expect(component.getScrollBottom()).toBe((8 + 1 + editor.verticalScrollMargin) * component.measurements.lineHeight) + expect(component.getScrollBottom()).toBe( + (8 + 1 + editor.verticalScrollMargin) * + component.measurements.lineHeight + ) editor.scrollToScreenPosition([3, 0]) await component.getNextUpdatePromise() - expect(component.getScrollTop()).toBe((3 - editor.verticalScrollMargin) * component.measurements.lineHeight) + expect(component.getScrollTop()).toBe( + (3 - editor.verticalScrollMargin) * component.measurements.lineHeight + ) editor.scrollToScreenPosition([2, 0]) await component.getNextUpdatePromise() @@ -1100,47 +1424,64 @@ describe('TextEditorComponent', () => { }) it('does not vertically autoscroll by more than half of the visible lines if the editor is shorter than twice the scroll margin', async () => { - const {component, element, editor} = buildComponent({autoHeight: false}) - element.style.height = 5.5 * component.measurements.lineHeight + horizontalScrollbarHeight + 'px' + const { component, element, editor } = buildComponent({ + autoHeight: false + }) + element.style.height = + 5.5 * component.measurements.lineHeight + + horizontalScrollbarHeight + + 'px' await component.getNextUpdatePromise() expect(component.getLastVisibleRow()).toBe(5) const scrollMarginInLines = 2 editor.scrollToScreenPosition([6, 0]) await component.getNextUpdatePromise() - expect(component.getScrollBottom()).toBe((6 + 1 + scrollMarginInLines) * component.measurements.lineHeight) + expect(component.getScrollBottom()).toBe( + (6 + 1 + scrollMarginInLines) * component.measurements.lineHeight + ) editor.scrollToScreenPosition([6, 4]) await component.getNextUpdatePromise() - expect(component.getScrollBottom()).toBe((6 + 1 + scrollMarginInLines) * component.measurements.lineHeight) + expect(component.getScrollBottom()).toBe( + (6 + 1 + scrollMarginInLines) * component.measurements.lineHeight + ) editor.scrollToScreenRange([[4, 4], [6, 4]]) await component.getNextUpdatePromise() - expect(component.getScrollTop()).toBe((4 - scrollMarginInLines) * component.measurements.lineHeight) + expect(component.getScrollTop()).toBe( + (4 - scrollMarginInLines) * component.measurements.lineHeight + ) - editor.scrollToScreenRange([[4, 4], [6, 4]], {reversed: false}) + editor.scrollToScreenRange([[4, 4], [6, 4]], { reversed: false }) await component.getNextUpdatePromise() - expect(component.getScrollBottom()).toBe((6 + 1 + scrollMarginInLines) * component.measurements.lineHeight) + expect(component.getScrollBottom()).toBe( + (6 + 1 + scrollMarginInLines) * component.measurements.lineHeight + ) }) it('autoscrolls the given range to the center of the screen if the `center` option is true', async () => { - const {component, editor} = buildComponent({height: 50}) + const { component, editor } = buildComponent({ height: 50 }) expect(component.getLastVisibleRow()).toBe(2) - editor.scrollToScreenRange([[4, 0], [6, 0]], {center: true}) + editor.scrollToScreenRange([[4, 0], [6, 0]], { center: true }) await component.getNextUpdatePromise() - const actualScrollCenter = (component.getScrollTop() + component.getScrollBottom()) / 2 - const expectedScrollCenter = (4 + 7) / 2 * component.getLineHeight() + const actualScrollCenter = + (component.getScrollTop() + component.getScrollBottom()) / 2 + const expectedScrollCenter = ((4 + 7) / 2) * component.getLineHeight() expect(actualScrollCenter).toBeCloseTo(expectedScrollCenter, 0) }) it('automatically scrolls horizontally when the requested range is within the horizontal scroll margin of the right edge of the gutter or right edge of the scroll container', async () => { - const {component, element, editor} = buildComponent() - const {scrollContainer} = component.refs + const { component, element, editor } = buildComponent() + const { scrollContainer } = component.refs element.style.width = component.getGutterContainerWidth() + - 3 * editor.horizontalScrollMargin * component.measurements.baseCharacterWidth + 'px' + 3 * + editor.horizontalScrollMargin * + component.measurements.baseCharacterWidth + + 'px' await component.getNextUpdatePromise() editor.scrollToScreenRange([[1, 12], [2, 28]]) @@ -1148,59 +1489,78 @@ describe('TextEditorComponent', () => { let expectedScrollLeft = clientLeftForCharacter(component, 1, 12) - lineNodeForScreenRow(component, 1).getBoundingClientRect().left - - (editor.horizontalScrollMargin * component.measurements.baseCharacterWidth) + editor.horizontalScrollMargin * + component.measurements.baseCharacterWidth expect(component.getScrollLeft()).toBeCloseTo(expectedScrollLeft, 0) - editor.scrollToScreenRange([[1, 12], [2, 28]], {reversed: false}) + editor.scrollToScreenRange([[1, 12], [2, 28]], { reversed: false }) await component.getNextUpdatePromise() expectedScrollLeft = component.getGutterContainerWidth() + clientLeftForCharacter(component, 2, 28) - lineNodeForScreenRow(component, 2).getBoundingClientRect().left + - (editor.horizontalScrollMargin * component.measurements.baseCharacterWidth) - + editor.horizontalScrollMargin * + component.measurements.baseCharacterWidth - component.getScrollContainerClientWidth() expect(component.getScrollLeft()).toBeCloseTo(expectedScrollLeft, 0) }) it('does not horizontally autoscroll by more than half of the visible "base-width" characters if the editor is narrower than twice the scroll margin', async () => { - const {component, editor} = buildComponent({autoHeight: false}) - await setEditorWidthInCharacters(component, 1.5 * editor.horizontalScrollMargin) - const editorWidthInChars = component.getScrollContainerClientWidth() / component.getBaseCharacterWidth() + const { component, editor } = buildComponent({ autoHeight: false }) + await setEditorWidthInCharacters( + component, + 1.5 * editor.horizontalScrollMargin + ) + const editorWidthInChars = + component.getScrollContainerClientWidth() / + component.getBaseCharacterWidth() expect(Math.round(editorWidthInChars)).toBe(9) editor.scrollToScreenRange([[6, 10], [6, 15]]) await component.getNextUpdatePromise() let expectedScrollLeft = Math.floor( clientLeftForCharacter(component, 6, 10) - - lineNodeForScreenRow(component, 1).getBoundingClientRect().left - - Math.floor((editorWidthInChars - 1) / 2) * component.getBaseCharacterWidth() + lineNodeForScreenRow(component, 1).getBoundingClientRect().left - + Math.floor((editorWidthInChars - 1) / 2) * + component.getBaseCharacterWidth() ) expect(component.getScrollLeft()).toBe(expectedScrollLeft) }) it('correctly autoscrolls after inserting a line that exceeds the current content width', async () => { - const {component, element, editor} = buildComponent() - element.style.width = component.getGutterContainerWidth() + component.getContentWidth() + 'px' + const { component, element, editor } = buildComponent() + element.style.width = + component.getGutterContainerWidth() + component.getContentWidth() + 'px' await component.getNextUpdatePromise() editor.setCursorScreenPosition([0, Infinity]) editor.insertText('x'.repeat(100)) await component.getNextUpdatePromise() - expect(component.getScrollLeft()).toBe(component.getScrollWidth() - component.getScrollContainerClientWidth()) + expect(component.getScrollLeft()).toBe( + component.getScrollWidth() - component.getScrollContainerClientWidth() + ) }) it('does not try to measure lines that do not exist when the animation frame is delivered', async () => { - const {component, editor} = buildComponent({autoHeight: false, height: 30, rowsPerTile: 2}) + const { component, editor } = buildComponent({ + autoHeight: false, + height: 30, + rowsPerTile: 2 + }) editor.scrollToBufferPosition([11, 5]) editor.getBuffer().deleteRows(11, 12) await component.getNextUpdatePromise() - expect(component.getScrollBottom()).toBe((10 + 1) * component.measurements.lineHeight) + expect(component.getScrollBottom()).toBe( + (10 + 1) * component.measurements.lineHeight + ) }) it('accounts for the presence of horizontal scrollbars that appear during the same frame as the autoscroll', async () => { - const {component, element, editor} = buildComponent({autoHeight: false}) - const {scrollContainer} = component.refs + const { component, element, editor } = buildComponent({ + autoHeight: false + }) + const { scrollContainer } = component.refs element.style.height = component.getContentHeight() / 2 + 'px' element.style.width = component.getScrollWidth() + 'px' await component.getNextUpdatePromise() @@ -1209,8 +1569,12 @@ describe('TextEditorComponent', () => { editor.insertText('\n\n' + 'x'.repeat(100)) await component.getNextUpdatePromise() - expect(component.getScrollTop()).toBe(component.getScrollHeight() - component.getScrollContainerClientHeight()) - expect(component.getScrollLeft()).toBe(component.getScrollWidth() - component.getScrollContainerClientWidth()) + expect(component.getScrollTop()).toBe( + component.getScrollHeight() - component.getScrollContainerClientHeight() + ) + expect(component.getScrollLeft()).toBe( + component.getScrollWidth() - component.getScrollContainerClientWidth() + ) // Scrolling to the top should not throw an error. This failed // previously due to horizontalPositionsToMeasure not being empty after @@ -1223,7 +1587,10 @@ describe('TextEditorComponent', () => { describe('logical scroll positions', () => { it('allows the scrollTop to be changed and queried in terms of rows via setScrollTopRow and getScrollTopRow', () => { - const {component, element, editor} = buildComponent({attach: false, height: 80}) + const { component, element, editor } = buildComponent({ + attach: false, + height: 80 + }) // Caches the scrollTopRow if we don't have measurements component.setScrollTopRow(6) @@ -1234,30 +1601,43 @@ describe('TextEditorComponent', () => { const expectedScrollTop = Math.round(6 * component.getLineHeight()) expect(component.getScrollTopRow()).toBe(6) expect(component.getScrollTop()).toBe(expectedScrollTop) - expect(component.refs.content.style.transform).toBe(`translate(0px, -${expectedScrollTop}px)`) + expect(component.refs.content.style.transform).toBe( + `translate(0px, -${expectedScrollTop}px)` + ) // Allows the scrollTopRow to be updated while attached component.setScrollTopRow(4) expect(component.getScrollTopRow()).toBe(4) - expect(component.getScrollTop()).toBe(Math.round(4 * component.getLineHeight())) + expect(component.getScrollTop()).toBe( + Math.round(4 * component.getLineHeight()) + ) // Preserves the scrollTopRow when detached element.remove() expect(component.getScrollTopRow()).toBe(4) - expect(component.getScrollTop()).toBe(Math.round(4 * component.getLineHeight())) + expect(component.getScrollTop()).toBe( + Math.round(4 * component.getLineHeight()) + ) component.setScrollTopRow(6) expect(component.getScrollTopRow()).toBe(6) - expect(component.getScrollTop()).toBe(Math.round(6 * component.getLineHeight())) + expect(component.getScrollTop()).toBe( + Math.round(6 * component.getLineHeight()) + ) jasmine.attachToDOM(element) element.style.height = '60px' expect(component.getScrollTopRow()).toBe(6) - expect(component.getScrollTop()).toBe(Math.round(6 * component.getLineHeight())) + expect(component.getScrollTop()).toBe( + Math.round(6 * component.getLineHeight()) + ) }) it('allows the scrollLeft to be changed and queried in terms of base character columns via setScrollLeftColumn and getScrollLeftColumn', () => { - const {component, element} = buildComponent({attach: false, width: 80}) + const { component, element } = buildComponent({ + attach: false, + width: 80 + }) // Caches the scrollTopRow if we don't have measurements component.setScrollLeftColumn(2) @@ -1265,143 +1645,218 @@ describe('TextEditorComponent', () => { // Assigns the scrollTop based on the logical position when attached jasmine.attachToDOM(element) - expect(component.getScrollLeft()).toBeCloseTo(2 * component.getBaseCharacterWidth(), 0) + expect(component.getScrollLeft()).toBeCloseTo( + 2 * component.getBaseCharacterWidth(), + 0 + ) // Allows the scrollTopRow to be updated while attached component.setScrollLeftColumn(4) - expect(component.getScrollLeft()).toBeCloseTo(4 * component.getBaseCharacterWidth(), 0) + expect(component.getScrollLeft()).toBeCloseTo( + 4 * component.getBaseCharacterWidth(), + 0 + ) // Preserves the scrollTopRow when detached element.remove() - expect(component.getScrollLeft()).toBeCloseTo(4 * component.getBaseCharacterWidth(), 0) + expect(component.getScrollLeft()).toBeCloseTo( + 4 * component.getBaseCharacterWidth(), + 0 + ) component.setScrollLeftColumn(6) - expect(component.getScrollLeft()).toBeCloseTo(6 * component.getBaseCharacterWidth(), 0) + expect(component.getScrollLeft()).toBeCloseTo( + 6 * component.getBaseCharacterWidth(), + 0 + ) jasmine.attachToDOM(element) element.style.width = '60px' - expect(component.getScrollLeft()).toBeCloseTo(6 * component.getBaseCharacterWidth(), 0) + expect(component.getScrollLeft()).toBeCloseTo( + 6 * component.getBaseCharacterWidth(), + 0 + ) }) }) describe('scrolling via the mouse wheel', () => { it('scrolls vertically or horizontally depending on whether deltaX or deltaY is larger', () => { const scrollSensitivity = 30 - const {component, editor} = buildComponent({height: 50, width: 50, scrollSensitivity}) + const { component, editor } = buildComponent({ + height: 50, + width: 50, + scrollSensitivity + }) { const expectedScrollTop = 20 * (scrollSensitivity / 100) const expectedScrollLeft = component.getScrollLeft() - component.didMouseWheel({wheelDeltaX: -5, wheelDeltaY: -20}) + component.didMouseWheel({ wheelDeltaX: -5, wheelDeltaY: -20 }) expect(component.getScrollTop()).toBe(expectedScrollTop) expect(component.getScrollLeft()).toBe(expectedScrollLeft) - expect(component.refs.content.style.transform).toBe(`translate(${-expectedScrollLeft}px, ${-expectedScrollTop}px)`) + expect(component.refs.content.style.transform).toBe( + `translate(${-expectedScrollLeft}px, ${-expectedScrollTop}px)` + ) } { - const expectedScrollTop = component.getScrollTop() - (10 * (scrollSensitivity / 100)) + const expectedScrollTop = + component.getScrollTop() - 10 * (scrollSensitivity / 100) const expectedScrollLeft = component.getScrollLeft() - component.didMouseWheel({wheelDeltaX: -5, wheelDeltaY: 10}) + component.didMouseWheel({ wheelDeltaX: -5, wheelDeltaY: 10 }) expect(component.getScrollTop()).toBe(expectedScrollTop) expect(component.getScrollLeft()).toBe(expectedScrollLeft) - expect(component.refs.content.style.transform).toBe(`translate(${-expectedScrollLeft}px, ${-expectedScrollTop}px)`) + expect(component.refs.content.style.transform).toBe( + `translate(${-expectedScrollLeft}px, ${-expectedScrollTop}px)` + ) } { const expectedScrollTop = component.getScrollTop() const expectedScrollLeft = 20 * (scrollSensitivity / 100) - component.didMouseWheel({wheelDeltaX: -20, wheelDeltaY: 10}) + component.didMouseWheel({ wheelDeltaX: -20, wheelDeltaY: 10 }) expect(component.getScrollTop()).toBe(expectedScrollTop) expect(component.getScrollLeft()).toBe(expectedScrollLeft) - expect(component.refs.content.style.transform).toBe(`translate(${-expectedScrollLeft}px, ${-expectedScrollTop}px)`) + expect(component.refs.content.style.transform).toBe( + `translate(${-expectedScrollLeft}px, ${-expectedScrollTop}px)` + ) } { const expectedScrollTop = component.getScrollTop() - const expectedScrollLeft = component.getScrollLeft() - (10 * (scrollSensitivity / 100)) - component.didMouseWheel({wheelDeltaX: 10, wheelDeltaY: -8}) + const expectedScrollLeft = + component.getScrollLeft() - 10 * (scrollSensitivity / 100) + component.didMouseWheel({ wheelDeltaX: 10, wheelDeltaY: -8 }) expect(component.getScrollTop()).toBe(expectedScrollTop) expect(component.getScrollLeft()).toBe(expectedScrollLeft) - expect(component.refs.content.style.transform).toBe(`translate(${-expectedScrollLeft}px, ${-expectedScrollTop}px)`) + expect(component.refs.content.style.transform).toBe( + `translate(${-expectedScrollLeft}px, ${-expectedScrollTop}px)` + ) } }) it('inverts deltaX and deltaY when holding shift on Windows and Linux', async () => { const scrollSensitivity = 50 - const {component, editor} = buildComponent({height: 50, width: 50, scrollSensitivity}) + const { component, editor } = buildComponent({ + height: 50, + width: 50, + scrollSensitivity + }) component.props.platform = 'linux' { const expectedScrollTop = 20 * (scrollSensitivity / 100) - component.didMouseWheel({wheelDeltaX: 0, wheelDeltaY: -20}) + component.didMouseWheel({ wheelDeltaX: 0, wheelDeltaY: -20 }) expect(component.getScrollTop()).toBe(expectedScrollTop) - expect(component.refs.content.style.transform).toBe(`translate(0px, -${expectedScrollTop}px)`) + expect(component.refs.content.style.transform).toBe( + `translate(0px, -${expectedScrollTop}px)` + ) await setScrollTop(component, 0) } { const expectedScrollLeft = 20 * (scrollSensitivity / 100) - component.didMouseWheel({wheelDeltaX: 0, wheelDeltaY: -20, shiftKey: true}) + component.didMouseWheel({ + wheelDeltaX: 0, + wheelDeltaY: -20, + shiftKey: true + }) expect(component.getScrollLeft()).toBe(expectedScrollLeft) - expect(component.refs.content.style.transform).toBe(`translate(-${expectedScrollLeft}px, 0px)`) + expect(component.refs.content.style.transform).toBe( + `translate(-${expectedScrollLeft}px, 0px)` + ) await setScrollLeft(component, 0) } { const expectedScrollTop = 20 * (scrollSensitivity / 100) - component.didMouseWheel({wheelDeltaX: -20, wheelDeltaY: 0, shiftKey: true}) + component.didMouseWheel({ + wheelDeltaX: -20, + wheelDeltaY: 0, + shiftKey: true + }) expect(component.getScrollTop()).toBe(expectedScrollTop) - expect(component.refs.content.style.transform).toBe(`translate(0px, -${expectedScrollTop}px)`) + expect(component.refs.content.style.transform).toBe( + `translate(0px, -${expectedScrollTop}px)` + ) await setScrollTop(component, 0) } component.props.platform = 'win32' { const expectedScrollTop = 20 * (scrollSensitivity / 100) - component.didMouseWheel({wheelDeltaX: 0, wheelDeltaY: -20}) + component.didMouseWheel({ wheelDeltaX: 0, wheelDeltaY: -20 }) expect(component.getScrollTop()).toBe(expectedScrollTop) - expect(component.refs.content.style.transform).toBe(`translate(0px, -${expectedScrollTop}px)`) + expect(component.refs.content.style.transform).toBe( + `translate(0px, -${expectedScrollTop}px)` + ) await setScrollTop(component, 0) } { const expectedScrollLeft = 20 * (scrollSensitivity / 100) - component.didMouseWheel({wheelDeltaX: 0, wheelDeltaY: -20, shiftKey: true}) + component.didMouseWheel({ + wheelDeltaX: 0, + wheelDeltaY: -20, + shiftKey: true + }) expect(component.getScrollLeft()).toBe(expectedScrollLeft) - expect(component.refs.content.style.transform).toBe(`translate(-${expectedScrollLeft}px, 0px)`) + expect(component.refs.content.style.transform).toBe( + `translate(-${expectedScrollLeft}px, 0px)` + ) await setScrollLeft(component, 0) } { const expectedScrollTop = 20 * (scrollSensitivity / 100) - component.didMouseWheel({wheelDeltaX: -20, wheelDeltaY: 0, shiftKey: true}) + component.didMouseWheel({ + wheelDeltaX: -20, + wheelDeltaY: 0, + shiftKey: true + }) expect(component.getScrollTop()).toBe(expectedScrollTop) - expect(component.refs.content.style.transform).toBe(`translate(0px, -${expectedScrollTop}px)`) + expect(component.refs.content.style.transform).toBe( + `translate(0px, -${expectedScrollTop}px)` + ) await setScrollTop(component, 0) } component.props.platform = 'darwin' { const expectedScrollTop = 20 * (scrollSensitivity / 100) - component.didMouseWheel({wheelDeltaX: 0, wheelDeltaY: -20}) + component.didMouseWheel({ wheelDeltaX: 0, wheelDeltaY: -20 }) expect(component.getScrollTop()).toBe(expectedScrollTop) - expect(component.refs.content.style.transform).toBe(`translate(0px, -${expectedScrollTop}px)`) + expect(component.refs.content.style.transform).toBe( + `translate(0px, -${expectedScrollTop}px)` + ) await setScrollTop(component, 0) } { const expectedScrollTop = 20 * (scrollSensitivity / 100) - component.didMouseWheel({wheelDeltaX: 0, wheelDeltaY: -20, shiftKey: true}) + component.didMouseWheel({ + wheelDeltaX: 0, + wheelDeltaY: -20, + shiftKey: true + }) expect(component.getScrollTop()).toBe(expectedScrollTop) - expect(component.refs.content.style.transform).toBe(`translate(0px, -${expectedScrollTop}px)`) + expect(component.refs.content.style.transform).toBe( + `translate(0px, -${expectedScrollTop}px)` + ) await setScrollTop(component, 0) } { const expectedScrollLeft = 20 * (scrollSensitivity / 100) - component.didMouseWheel({wheelDeltaX: -20, wheelDeltaY: 0, shiftKey: true}) + component.didMouseWheel({ + wheelDeltaX: -20, + wheelDeltaY: 0, + shiftKey: true + }) expect(component.getScrollLeft()).toBe(expectedScrollLeft) - expect(component.refs.content.style.transform).toBe(`translate(-${expectedScrollLeft}px, 0px)`) + expect(component.refs.content.style.transform).toBe( + `translate(-${expectedScrollLeft}px, 0px)` + ) await setScrollLeft(component, 0) } }) @@ -1409,12 +1864,17 @@ describe('TextEditorComponent', () => { describe('scrolling via the API', () => { it('ignores scroll requests to NaN, null or undefined positions', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 2, autoHeight: false}) + const { component, element, editor } = buildComponent({ + rowsPerTile: 2, + autoHeight: false + }) await setEditorHeightInLines(component, 3) await setEditorWidthInCharacters(component, 10) const initialScrollTop = Math.round(2 * component.getLineHeight()) - const initialScrollLeft = Math.round(5 * component.getBaseCharacterWidth()) + const initialScrollLeft = Math.round( + 5 * component.getBaseCharacterWidth() + ) setScrollTop(component, initialScrollTop) setScrollLeft(component, initialScrollLeft) await component.getNextUpdatePromise() @@ -1441,7 +1901,9 @@ describe('TextEditorComponent', () => { describe('line and line number decorations', () => { it('adds decoration classes on screen lines spanned by decorated markers', async () => { - const {component, element, editor} = buildComponent({softWrapped: true}) + const { component, element, editor } = buildComponent({ + softWrapped: true + }) await setEditorWidthInCharacters(component, 55) expect(lineNodeForScreenRow(component, 3).textContent).toBe( ' var pivot = items.shift(), current, left = [], ' @@ -1455,141 +1917,311 @@ describe('TextEditorComponent', () => { const marker2 = layer.markScreenPosition([5, 0]) const marker3 = layer.markScreenPosition([8, 0]) const marker4 = layer.markScreenPosition([10, 0]) - const markerDecoration = editor.decorateMarker(marker1, {type: ['line', 'line-number'], class: 'a'}) - const layerDecoration = editor.decorateMarkerLayer(layer, {type: ['line', 'line-number'], class: 'b'}) - layerDecoration.setPropertiesForMarker(marker4, {type: 'line', class: 'c'}) + const markerDecoration = editor.decorateMarker(marker1, { + type: ['line', 'line-number'], + class: 'a' + }) + const layerDecoration = editor.decorateMarkerLayer(layer, { + type: ['line', 'line-number'], + class: 'b' + }) + layerDecoration.setPropertiesForMarker(marker4, { + type: 'line', + class: 'c' + }) await component.getNextUpdatePromise() - expect(lineNodeForScreenRow(component, 1).classList.contains('a')).toBe(true) - expect(lineNodeForScreenRow(component, 2).classList.contains('a')).toBe(true) - expect(lineNodeForScreenRow(component, 3).classList.contains('a')).toBe(true) - expect(lineNodeForScreenRow(component, 4).classList.contains('a')).toBe(false) - expect(lineNodeForScreenRow(component, 5).classList.contains('b')).toBe(true) - expect(lineNodeForScreenRow(component, 8).classList.contains('b')).toBe(true) - expect(lineNodeForScreenRow(component, 10).classList.contains('b')).toBe(false) - expect(lineNodeForScreenRow(component, 10).classList.contains('c')).toBe(true) + expect(lineNodeForScreenRow(component, 1).classList.contains('a')).toBe( + true + ) + expect(lineNodeForScreenRow(component, 2).classList.contains('a')).toBe( + true + ) + expect(lineNodeForScreenRow(component, 3).classList.contains('a')).toBe( + true + ) + expect(lineNodeForScreenRow(component, 4).classList.contains('a')).toBe( + false + ) + expect(lineNodeForScreenRow(component, 5).classList.contains('b')).toBe( + true + ) + expect(lineNodeForScreenRow(component, 8).classList.contains('b')).toBe( + true + ) + expect(lineNodeForScreenRow(component, 10).classList.contains('b')).toBe( + false + ) + expect(lineNodeForScreenRow(component, 10).classList.contains('c')).toBe( + true + ) - expect(lineNumberNodeForScreenRow(component, 1).classList.contains('a')).toBe(true) - expect(lineNumberNodeForScreenRow(component, 2).classList.contains('a')).toBe(true) - expect(lineNumberNodeForScreenRow(component, 3).classList.contains('a')).toBe(true) - expect(lineNumberNodeForScreenRow(component, 4).classList.contains('a')).toBe(false) - expect(lineNumberNodeForScreenRow(component, 5).classList.contains('b')).toBe(true) - expect(lineNumberNodeForScreenRow(component, 8).classList.contains('b')).toBe(true) - expect(lineNumberNodeForScreenRow(component, 10).classList.contains('b')).toBe(false) - expect(lineNumberNodeForScreenRow(component, 10).classList.contains('c')).toBe(false) + expect( + lineNumberNodeForScreenRow(component, 1).classList.contains('a') + ).toBe(true) + expect( + lineNumberNodeForScreenRow(component, 2).classList.contains('a') + ).toBe(true) + expect( + lineNumberNodeForScreenRow(component, 3).classList.contains('a') + ).toBe(true) + expect( + lineNumberNodeForScreenRow(component, 4).classList.contains('a') + ).toBe(false) + expect( + lineNumberNodeForScreenRow(component, 5).classList.contains('b') + ).toBe(true) + expect( + lineNumberNodeForScreenRow(component, 8).classList.contains('b') + ).toBe(true) + expect( + lineNumberNodeForScreenRow(component, 10).classList.contains('b') + ).toBe(false) + expect( + lineNumberNodeForScreenRow(component, 10).classList.contains('c') + ).toBe(false) marker1.setScreenRange([[5, 0], [8, 0]]) await component.getNextUpdatePromise() - expect(lineNodeForScreenRow(component, 1).classList.contains('a')).toBe(false) - expect(lineNodeForScreenRow(component, 2).classList.contains('a')).toBe(false) - expect(lineNodeForScreenRow(component, 3).classList.contains('a')).toBe(false) - expect(lineNodeForScreenRow(component, 4).classList.contains('a')).toBe(false) - expect(lineNodeForScreenRow(component, 5).classList.contains('a')).toBe(true) - expect(lineNodeForScreenRow(component, 5).classList.contains('b')).toBe(true) - expect(lineNodeForScreenRow(component, 6).classList.contains('a')).toBe(true) - expect(lineNodeForScreenRow(component, 7).classList.contains('a')).toBe(true) - expect(lineNodeForScreenRow(component, 8).classList.contains('a')).toBe(true) - expect(lineNodeForScreenRow(component, 8).classList.contains('b')).toBe(true) + expect(lineNodeForScreenRow(component, 1).classList.contains('a')).toBe( + false + ) + expect(lineNodeForScreenRow(component, 2).classList.contains('a')).toBe( + false + ) + expect(lineNodeForScreenRow(component, 3).classList.contains('a')).toBe( + false + ) + expect(lineNodeForScreenRow(component, 4).classList.contains('a')).toBe( + false + ) + expect(lineNodeForScreenRow(component, 5).classList.contains('a')).toBe( + true + ) + expect(lineNodeForScreenRow(component, 5).classList.contains('b')).toBe( + true + ) + expect(lineNodeForScreenRow(component, 6).classList.contains('a')).toBe( + true + ) + expect(lineNodeForScreenRow(component, 7).classList.contains('a')).toBe( + true + ) + expect(lineNodeForScreenRow(component, 8).classList.contains('a')).toBe( + true + ) + expect(lineNodeForScreenRow(component, 8).classList.contains('b')).toBe( + true + ) - expect(lineNumberNodeForScreenRow(component, 1).classList.contains('a')).toBe(false) - expect(lineNumberNodeForScreenRow(component, 2).classList.contains('a')).toBe(false) - expect(lineNumberNodeForScreenRow(component, 3).classList.contains('a')).toBe(false) - expect(lineNumberNodeForScreenRow(component, 4).classList.contains('a')).toBe(false) - expect(lineNumberNodeForScreenRow(component, 5).classList.contains('a')).toBe(true) - expect(lineNumberNodeForScreenRow(component, 5).classList.contains('b')).toBe(true) - expect(lineNumberNodeForScreenRow(component, 6).classList.contains('a')).toBe(true) - expect(lineNumberNodeForScreenRow(component, 7).classList.contains('a')).toBe(true) - expect(lineNumberNodeForScreenRow(component, 8).classList.contains('a')).toBe(true) - expect(lineNumberNodeForScreenRow(component, 8).classList.contains('b')).toBe(true) + expect( + lineNumberNodeForScreenRow(component, 1).classList.contains('a') + ).toBe(false) + expect( + lineNumberNodeForScreenRow(component, 2).classList.contains('a') + ).toBe(false) + expect( + lineNumberNodeForScreenRow(component, 3).classList.contains('a') + ).toBe(false) + expect( + lineNumberNodeForScreenRow(component, 4).classList.contains('a') + ).toBe(false) + expect( + lineNumberNodeForScreenRow(component, 5).classList.contains('a') + ).toBe(true) + expect( + lineNumberNodeForScreenRow(component, 5).classList.contains('b') + ).toBe(true) + expect( + lineNumberNodeForScreenRow(component, 6).classList.contains('a') + ).toBe(true) + expect( + lineNumberNodeForScreenRow(component, 7).classList.contains('a') + ).toBe(true) + expect( + lineNumberNodeForScreenRow(component, 8).classList.contains('a') + ).toBe(true) + expect( + lineNumberNodeForScreenRow(component, 8).classList.contains('b') + ).toBe(true) }) it('honors the onlyEmpty and onlyNonEmpty decoration options', async () => { - const {component, element, editor} = buildComponent() + const { component, element, editor } = buildComponent() const marker = editor.markScreenPosition([1, 0]) - editor.decorateMarker(marker, {type: ['line', 'line-number'], class: 'a', onlyEmpty: true}) - editor.decorateMarker(marker, {type: ['line', 'line-number'], class: 'b', onlyNonEmpty: true}) - editor.decorateMarker(marker, {type: ['line', 'line-number'], class: 'c'}) + editor.decorateMarker(marker, { + type: ['line', 'line-number'], + class: 'a', + onlyEmpty: true + }) + editor.decorateMarker(marker, { + type: ['line', 'line-number'], + class: 'b', + onlyNonEmpty: true + }) + editor.decorateMarker(marker, { + type: ['line', 'line-number'], + class: 'c' + }) await component.getNextUpdatePromise() - expect(lineNodeForScreenRow(component, 1).classList.contains('a')).toBe(true) - expect(lineNodeForScreenRow(component, 1).classList.contains('b')).toBe(false) - expect(lineNodeForScreenRow(component, 1).classList.contains('c')).toBe(true) - expect(lineNumberNodeForScreenRow(component, 1).classList.contains('a')).toBe(true) - expect(lineNumberNodeForScreenRow(component, 1).classList.contains('b')).toBe(false) - expect(lineNumberNodeForScreenRow(component, 1).classList.contains('c')).toBe(true) + expect(lineNodeForScreenRow(component, 1).classList.contains('a')).toBe( + true + ) + expect(lineNodeForScreenRow(component, 1).classList.contains('b')).toBe( + false + ) + expect(lineNodeForScreenRow(component, 1).classList.contains('c')).toBe( + true + ) + expect( + lineNumberNodeForScreenRow(component, 1).classList.contains('a') + ).toBe(true) + expect( + lineNumberNodeForScreenRow(component, 1).classList.contains('b') + ).toBe(false) + expect( + lineNumberNodeForScreenRow(component, 1).classList.contains('c') + ).toBe(true) marker.setScreenRange([[1, 0], [2, 4]]) await component.getNextUpdatePromise() - expect(lineNodeForScreenRow(component, 1).classList.contains('a')).toBe(false) - expect(lineNodeForScreenRow(component, 1).classList.contains('b')).toBe(true) - expect(lineNodeForScreenRow(component, 1).classList.contains('c')).toBe(true) - expect(lineNodeForScreenRow(component, 2).classList.contains('b')).toBe(true) - expect(lineNodeForScreenRow(component, 2).classList.contains('c')).toBe(true) - expect(lineNumberNodeForScreenRow(component, 1).classList.contains('a')).toBe(false) - expect(lineNumberNodeForScreenRow(component, 1).classList.contains('b')).toBe(true) - expect(lineNumberNodeForScreenRow(component, 1).classList.contains('c')).toBe(true) - expect(lineNumberNodeForScreenRow(component, 2).classList.contains('b')).toBe(true) - expect(lineNumberNodeForScreenRow(component, 2).classList.contains('c')).toBe(true) + expect(lineNodeForScreenRow(component, 1).classList.contains('a')).toBe( + false + ) + expect(lineNodeForScreenRow(component, 1).classList.contains('b')).toBe( + true + ) + expect(lineNodeForScreenRow(component, 1).classList.contains('c')).toBe( + true + ) + expect(lineNodeForScreenRow(component, 2).classList.contains('b')).toBe( + true + ) + expect(lineNodeForScreenRow(component, 2).classList.contains('c')).toBe( + true + ) + expect( + lineNumberNodeForScreenRow(component, 1).classList.contains('a') + ).toBe(false) + expect( + lineNumberNodeForScreenRow(component, 1).classList.contains('b') + ).toBe(true) + expect( + lineNumberNodeForScreenRow(component, 1).classList.contains('c') + ).toBe(true) + expect( + lineNumberNodeForScreenRow(component, 2).classList.contains('b') + ).toBe(true) + expect( + lineNumberNodeForScreenRow(component, 2).classList.contains('c') + ).toBe(true) }) it('honors the onlyHead option', async () => { - const {component, element, editor} = buildComponent() + const { component, element, editor } = buildComponent() const marker = editor.markScreenRange([[1, 4], [3, 4]]) - editor.decorateMarker(marker, {type: ['line', 'line-number'], class: 'a', onlyHead: true}) + editor.decorateMarker(marker, { + type: ['line', 'line-number'], + class: 'a', + onlyHead: true + }) await component.getNextUpdatePromise() - expect(lineNodeForScreenRow(component, 1).classList.contains('a')).toBe(false) - expect(lineNodeForScreenRow(component, 3).classList.contains('a')).toBe(true) - expect(lineNumberNodeForScreenRow(component, 1).classList.contains('a')).toBe(false) - expect(lineNumberNodeForScreenRow(component, 3).classList.contains('a')).toBe(true) + expect(lineNodeForScreenRow(component, 1).classList.contains('a')).toBe( + false + ) + expect(lineNodeForScreenRow(component, 3).classList.contains('a')).toBe( + true + ) + expect( + lineNumberNodeForScreenRow(component, 1).classList.contains('a') + ).toBe(false) + expect( + lineNumberNodeForScreenRow(component, 3).classList.contains('a') + ).toBe(true) }) it('only decorates the last row of non-empty ranges that end at column 0 if omitEmptyLastRow is false', async () => { - const {component, element, editor} = buildComponent() + const { component, element, editor } = buildComponent() const marker = editor.markScreenRange([[1, 0], [3, 0]]) - editor.decorateMarker(marker, {type: ['line', 'line-number'], class: 'a'}) - editor.decorateMarker(marker, {type: ['line', 'line-number'], class: 'b', omitEmptyLastRow: false}) + editor.decorateMarker(marker, { + type: ['line', 'line-number'], + class: 'a' + }) + editor.decorateMarker(marker, { + type: ['line', 'line-number'], + class: 'b', + omitEmptyLastRow: false + }) await component.getNextUpdatePromise() - expect(lineNodeForScreenRow(component, 1).classList.contains('a')).toBe(true) - expect(lineNodeForScreenRow(component, 2).classList.contains('a')).toBe(true) - expect(lineNodeForScreenRow(component, 3).classList.contains('a')).toBe(false) + expect(lineNodeForScreenRow(component, 1).classList.contains('a')).toBe( + true + ) + expect(lineNodeForScreenRow(component, 2).classList.contains('a')).toBe( + true + ) + expect(lineNodeForScreenRow(component, 3).classList.contains('a')).toBe( + false + ) - expect(lineNodeForScreenRow(component, 1).classList.contains('b')).toBe(true) - expect(lineNodeForScreenRow(component, 2).classList.contains('b')).toBe(true) - expect(lineNodeForScreenRow(component, 3).classList.contains('b')).toBe(true) + expect(lineNodeForScreenRow(component, 1).classList.contains('b')).toBe( + true + ) + expect(lineNodeForScreenRow(component, 2).classList.contains('b')).toBe( + true + ) + expect(lineNodeForScreenRow(component, 3).classList.contains('b')).toBe( + true + ) }) it('does not decorate invalidated markers', async () => { - const {component, element, editor} = buildComponent() - const marker = editor.markScreenRange([[1, 0], [3, 0]], {invalidate: 'touch'}) - editor.decorateMarker(marker, {type: ['line', 'line-number'], class: 'a'}) + const { component, element, editor } = buildComponent() + const marker = editor.markScreenRange([[1, 0], [3, 0]], { + invalidate: 'touch' + }) + editor.decorateMarker(marker, { + type: ['line', 'line-number'], + class: 'a' + }) await component.getNextUpdatePromise() - expect(lineNodeForScreenRow(component, 2).classList.contains('a')).toBe(true) + expect(lineNodeForScreenRow(component, 2).classList.contains('a')).toBe( + true + ) editor.getBuffer().insert([2, 0], 'x') expect(marker.isValid()).toBe(false) await component.getNextUpdatePromise() - expect(lineNodeForScreenRow(component, 2).classList.contains('a')).toBe(false) + expect(lineNodeForScreenRow(component, 2).classList.contains('a')).toBe( + false + ) }) }) describe('highlight decorations', () => { it('renders single-line highlights', async () => { - const {component, element, editor} = buildComponent() + const { component, element, editor } = buildComponent() const marker = editor.markScreenRange([[1, 2], [1, 10]]) - editor.decorateMarker(marker, {type: 'highlight', class: 'a'}) + editor.decorateMarker(marker, { type: 'highlight', class: 'a' }) await component.getNextUpdatePromise() { const regions = element.querySelectorAll('.highlight.a .region.a') expect(regions.length).toBe(1) const regionRect = regions[0].getBoundingClientRect() - expect(regionRect.top).toBe(lineNodeForScreenRow(component, 1).getBoundingClientRect().top) - expect(Math.round(regionRect.left)).toBe(clientLeftForCharacter(component, 1, 2)) - expect(Math.round(regionRect.right)).toBe(clientLeftForCharacter(component, 1, 10)) + expect(regionRect.top).toBe( + lineNodeForScreenRow(component, 1).getBoundingClientRect().top + ) + expect(Math.round(regionRect.left)).toBe( + clientLeftForCharacter(component, 1, 2) + ) + expect(Math.round(regionRect.right)).toBe( + clientLeftForCharacter(component, 1, 10) + ) } marker.setScreenRange([[1, 4], [1, 8]]) @@ -1599,17 +2231,25 @@ describe('TextEditorComponent', () => { const regions = element.querySelectorAll('.highlight.a .region.a') expect(regions.length).toBe(1) const regionRect = regions[0].getBoundingClientRect() - expect(regionRect.top).toBe(lineNodeForScreenRow(component, 1).getBoundingClientRect().top) - expect(regionRect.bottom).toBe(lineNodeForScreenRow(component, 1).getBoundingClientRect().bottom) - expect(Math.round(regionRect.left)).toBe(clientLeftForCharacter(component, 1, 4)) - expect(Math.round(regionRect.right)).toBe(clientLeftForCharacter(component, 1, 8)) + expect(regionRect.top).toBe( + lineNodeForScreenRow(component, 1).getBoundingClientRect().top + ) + expect(regionRect.bottom).toBe( + lineNodeForScreenRow(component, 1).getBoundingClientRect().bottom + ) + expect(Math.round(regionRect.left)).toBe( + clientLeftForCharacter(component, 1, 4) + ) + expect(Math.round(regionRect.right)).toBe( + clientLeftForCharacter(component, 1, 8) + ) } }) it('renders multi-line highlights', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 3}) + const { component, element, editor } = buildComponent({ rowsPerTile: 3 }) const marker = editor.markScreenRange([[2, 4], [3, 4]]) - editor.decorateMarker(marker, {type: 'highlight', class: 'a'}) + editor.decorateMarker(marker, { type: 'highlight', class: 'a' }) await component.getNextUpdatePromise() @@ -1619,16 +2259,32 @@ describe('TextEditorComponent', () => { const regions = element.querySelectorAll('.highlight.a .region.a') expect(regions.length).toBe(2) const region0Rect = regions[0].getBoundingClientRect() - expect(region0Rect.top).toBe(lineNodeForScreenRow(component, 2).getBoundingClientRect().top) - expect(region0Rect.bottom).toBe(lineNodeForScreenRow(component, 2).getBoundingClientRect().bottom) - expect(Math.round(region0Rect.left)).toBe(clientLeftForCharacter(component, 2, 4)) - expect(Math.round(region0Rect.right)).toBe(component.refs.content.getBoundingClientRect().right) + expect(region0Rect.top).toBe( + lineNodeForScreenRow(component, 2).getBoundingClientRect().top + ) + expect(region0Rect.bottom).toBe( + lineNodeForScreenRow(component, 2).getBoundingClientRect().bottom + ) + expect(Math.round(region0Rect.left)).toBe( + clientLeftForCharacter(component, 2, 4) + ) + expect(Math.round(region0Rect.right)).toBe( + component.refs.content.getBoundingClientRect().right + ) const region1Rect = regions[1].getBoundingClientRect() - expect(region1Rect.top).toBe(lineNodeForScreenRow(component, 3).getBoundingClientRect().top) - expect(region1Rect.bottom).toBe(lineNodeForScreenRow(component, 3).getBoundingClientRect().bottom) - expect(Math.round(region1Rect.left)).toBe(clientLeftForCharacter(component, 3, 0)) - expect(Math.round(region1Rect.right)).toBe(clientLeftForCharacter(component, 3, 4)) + expect(region1Rect.top).toBe( + lineNodeForScreenRow(component, 3).getBoundingClientRect().top + ) + expect(region1Rect.bottom).toBe( + lineNodeForScreenRow(component, 3).getBoundingClientRect().bottom + ) + expect(Math.round(region1Rect.left)).toBe( + clientLeftForCharacter(component, 3, 0) + ) + expect(Math.round(region1Rect.right)).toBe( + clientLeftForCharacter(component, 3, 4) + ) } marker.setScreenRange([[2, 4], [5, 4]]) @@ -1641,29 +2297,59 @@ describe('TextEditorComponent', () => { expect(regions.length).toBe(3) const region0Rect = regions[0].getBoundingClientRect() - expect(region0Rect.top).toBe(lineNodeForScreenRow(component, 2).getBoundingClientRect().top) - expect(region0Rect.bottom).toBe(lineNodeForScreenRow(component, 2).getBoundingClientRect().bottom) - expect(Math.round(region0Rect.left)).toBe(clientLeftForCharacter(component, 2, 4)) - expect(Math.round(region0Rect.right)).toBe(component.refs.content.getBoundingClientRect().right) + expect(region0Rect.top).toBe( + lineNodeForScreenRow(component, 2).getBoundingClientRect().top + ) + expect(region0Rect.bottom).toBe( + lineNodeForScreenRow(component, 2).getBoundingClientRect().bottom + ) + expect(Math.round(region0Rect.left)).toBe( + clientLeftForCharacter(component, 2, 4) + ) + expect(Math.round(region0Rect.right)).toBe( + component.refs.content.getBoundingClientRect().right + ) const region1Rect = regions[1].getBoundingClientRect() - expect(region1Rect.top).toBe(lineNodeForScreenRow(component, 3).getBoundingClientRect().top) - expect(region1Rect.bottom).toBe(lineNodeForScreenRow(component, 5).getBoundingClientRect().top) - expect(Math.round(region1Rect.left)).toBe(component.refs.content.getBoundingClientRect().left) - expect(Math.round(region1Rect.right)).toBe(component.refs.content.getBoundingClientRect().right) + expect(region1Rect.top).toBe( + lineNodeForScreenRow(component, 3).getBoundingClientRect().top + ) + expect(region1Rect.bottom).toBe( + lineNodeForScreenRow(component, 5).getBoundingClientRect().top + ) + expect(Math.round(region1Rect.left)).toBe( + component.refs.content.getBoundingClientRect().left + ) + expect(Math.round(region1Rect.right)).toBe( + component.refs.content.getBoundingClientRect().right + ) const region2Rect = regions[2].getBoundingClientRect() - expect(region2Rect.top).toBe(lineNodeForScreenRow(component, 5).getBoundingClientRect().top) - expect(region2Rect.bottom).toBe(lineNodeForScreenRow(component, 6).getBoundingClientRect().top) - expect(Math.round(region2Rect.left)).toBe(component.refs.content.getBoundingClientRect().left) - expect(Math.round(region2Rect.right)).toBe(clientLeftForCharacter(component, 5, 4)) + expect(region2Rect.top).toBe( + lineNodeForScreenRow(component, 5).getBoundingClientRect().top + ) + expect(region2Rect.bottom).toBe( + lineNodeForScreenRow(component, 6).getBoundingClientRect().top + ) + expect(Math.round(region2Rect.left)).toBe( + component.refs.content.getBoundingClientRect().left + ) + expect(Math.round(region2Rect.right)).toBe( + clientLeftForCharacter(component, 5, 4) + ) } }) it('can flash highlight decorations', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 3, height: 200}) + const { component, element, editor } = buildComponent({ + rowsPerTile: 3, + height: 200 + }) const marker = editor.markScreenRange([[2, 4], [3, 4]]) - const decoration = editor.decorateMarker(marker, {type: 'highlight', class: 'a'}) + const decoration = editor.decorateMarker(marker, { + type: 'highlight', + class: 'a' + }) decoration.flash('b', 10) // Flash on initial appearance of highlight @@ -1695,9 +2381,15 @@ describe('TextEditorComponent', () => { }) it("flashing a highlight decoration doesn't unflash other highlight decorations", async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 3, height: 200}) + const { component, element, editor } = buildComponent({ + rowsPerTile: 3, + height: 200 + }) const marker = editor.markScreenRange([[2, 4], [3, 4]]) - const decoration = editor.decorateMarker(marker, {type: 'highlight', class: 'a'}) + const decoration = editor.decorateMarker(marker, { + type: 'highlight', + class: 'a' + }) // Flash one class decoration.flash('c', 1000) @@ -1714,34 +2406,46 @@ describe('TextEditorComponent', () => { }) it('supports layer decorations', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 12}) + const { component, element, editor } = buildComponent({ rowsPerTile: 12 }) const markerLayer = editor.addMarkerLayer() const marker1 = markerLayer.markScreenRange([[2, 4], [3, 4]]) const marker2 = markerLayer.markScreenRange([[5, 6], [7, 8]]) - const decoration = editor.decorateMarkerLayer(markerLayer, {type: 'highlight', class: 'a'}) + const decoration = editor.decorateMarkerLayer(markerLayer, { + type: 'highlight', + class: 'a' + }) await component.getNextUpdatePromise() const highlights = element.querySelectorAll('.highlight') expect(highlights[0].classList.contains('a')).toBe(true) expect(highlights[1].classList.contains('a')).toBe(true) - decoration.setPropertiesForMarker(marker1, {type: 'highlight', class: 'b'}) + decoration.setPropertiesForMarker(marker1, { + type: 'highlight', + class: 'b' + }) await component.getNextUpdatePromise() expect(highlights[0].classList.contains('b')).toBe(true) expect(highlights[1].classList.contains('a')).toBe(true) decoration.setPropertiesForMarker(marker1, null) - decoration.setPropertiesForMarker(marker2, {type: 'highlight', class: 'c'}) + decoration.setPropertiesForMarker(marker2, { + type: 'highlight', + class: 'c' + }) await component.getNextUpdatePromise() expect(highlights[0].classList.contains('a')).toBe(true) expect(highlights[1].classList.contains('c')).toBe(true) }) it('clears highlights when recycling a tile that previously contained highlights and now does not', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 2, autoHeight: false}) + const { component, element, editor } = buildComponent({ + rowsPerTile: 2, + autoHeight: false + }) await setEditorHeightInLines(component, 2) const marker = editor.markScreenRange([[1, 2], [1, 10]]) - editor.decorateMarker(marker, {type: 'highlight', class: 'a'}) + editor.decorateMarker(marker, { type: 'highlight', class: 'a' }) await component.getNextUpdatePromise() expect(element.querySelectorAll('.highlight.a').length).toBe(1) @@ -1751,43 +2455,56 @@ describe('TextEditorComponent', () => { }) it('does not move existing highlights when adding or removing other highlight decorations (regression)', async () => { - const {component, element, editor} = buildComponent() + const { component, element, editor } = buildComponent() const marker1 = editor.markScreenRange([[1, 6], [1, 10]]) - editor.decorateMarker(marker1, {type: 'highlight', class: 'a'}) + editor.decorateMarker(marker1, { type: 'highlight', class: 'a' }) await component.getNextUpdatePromise() const marker1Region = element.querySelector('.highlight.a') - expect(Array.from(marker1Region.parentElement.children).indexOf(marker1Region)).toBe(0) + expect( + Array.from(marker1Region.parentElement.children).indexOf(marker1Region) + ).toBe(0) const marker2 = editor.markScreenRange([[1, 2], [1, 4]]) - editor.decorateMarker(marker2, {type: 'highlight', class: 'b'}) + editor.decorateMarker(marker2, { type: 'highlight', class: 'b' }) await component.getNextUpdatePromise() const marker2Region = element.querySelector('.highlight.b') - expect(Array.from(marker1Region.parentElement.children).indexOf(marker1Region)).toBe(0) - expect(Array.from(marker2Region.parentElement.children).indexOf(marker2Region)).toBe(1) + expect( + Array.from(marker1Region.parentElement.children).indexOf(marker1Region) + ).toBe(0) + expect( + Array.from(marker2Region.parentElement.children).indexOf(marker2Region) + ).toBe(1) marker2.destroy() await component.getNextUpdatePromise() - expect(Array.from(marker1Region.parentElement.children).indexOf(marker1Region)).toBe(0) + expect( + Array.from(marker1Region.parentElement.children).indexOf(marker1Region) + ).toBe(0) }) it('correctly positions highlights that end on rows preceding or following block decorations', async () => { - const {editor, element, component} = buildComponent() + const { editor, element, component } = buildComponent() const item1 = document.createElement('div') item1.style.height = '30px' item1.style.backgroundColor = 'blue' editor.decorateMarker(editor.markBufferPosition([4, 0]), { - type: 'block', position: 'after', item: item1 + type: 'block', + position: 'after', + item: item1 }) const item2 = document.createElement('div') item2.style.height = '30px' item2.style.backgroundColor = 'yellow' editor.decorateMarker(editor.markBufferPosition([4, 0]), { - type: 'block', position: 'before', item: item2 + type: 'block', + position: 'before', + item: item2 }) editor.decorateMarker(editor.markBufferRange([[3, 0], [4, Infinity]]), { - type: 'highlight', class: 'highlight' + type: 'highlight', + class: 'highlight' }) await component.getNextUpdatePromise() @@ -1806,13 +2523,21 @@ describe('TextEditorComponent', () => { fakeWindow.style.backgroundColor = 'blue' fakeWindow.appendChild(component.element) jasmine.attachToDOM(fakeWindow) - spyOn(component, 'getWindowInnerWidth').andCallFake(() => fakeWindow.getBoundingClientRect().width) - spyOn(component, 'getWindowInnerHeight').andCallFake(() => fakeWindow.getBoundingClientRect().height) + spyOn(component, 'getWindowInnerWidth').andCallFake( + () => fakeWindow.getBoundingClientRect().width + ) + spyOn(component, 'getWindowInnerHeight').andCallFake( + () => fakeWindow.getBoundingClientRect().height + ) return fakeWindow } it('renders overlay elements at the specified screen position unless it would overflow the window', async () => { - const {component, element, editor} = buildComponent({width: 200, height: 100, attach: false}) + const { component, element, editor } = buildComponent({ + width: 200, + height: 100, + attach: false + }) const fakeWindow = attachFakeWindow(component) await setScrollTop(component, 50) @@ -1826,62 +2551,94 @@ describe('TextEditorComponent', () => { overlayElement.style.margin = '3px' overlayElement.style.backgroundColor = 'red' - const decoration = editor.decorateMarker(marker, {type: 'overlay', item: overlayElement, class: 'a'}) + const decoration = editor.decorateMarker(marker, { + type: 'overlay', + item: overlayElement, + class: 'a' + }) await component.getNextUpdatePromise() const overlayComponent = component.overlayComponents.values().next().value const overlayWrapper = overlayElement.parentElement expect(overlayWrapper.classList.contains('a')).toBe(true) - expect(overlayWrapper.getBoundingClientRect().top).toBe(clientTopForLine(component, 5)) - expect(overlayWrapper.getBoundingClientRect().left).toBe(clientLeftForCharacter(component, 4, 25)) + expect(overlayWrapper.getBoundingClientRect().top).toBe( + clientTopForLine(component, 5) + ) + expect(overlayWrapper.getBoundingClientRect().left).toBe( + clientLeftForCharacter(component, 4, 25) + ) // Updates the horizontal position on scroll await setScrollLeft(component, 150) - expect(overlayWrapper.getBoundingClientRect().left).toBe(clientLeftForCharacter(component, 4, 25)) + expect(overlayWrapper.getBoundingClientRect().left).toBe( + clientLeftForCharacter(component, 4, 25) + ) // Shifts the overlay horizontally to ensure the overlay element does not // overflow the window await setScrollLeft(component, 30) - expect(overlayElement.getBoundingClientRect().right).toBe(fakeWindow.getBoundingClientRect().right) + expect(overlayElement.getBoundingClientRect().right).toBe( + fakeWindow.getBoundingClientRect().right + ) await setScrollLeft(component, 280) - expect(overlayElement.getBoundingClientRect().left).toBe(fakeWindow.getBoundingClientRect().left) + expect(overlayElement.getBoundingClientRect().left).toBe( + fakeWindow.getBoundingClientRect().left + ) // Updates the vertical position on scroll await setScrollTop(component, 60) - expect(overlayWrapper.getBoundingClientRect().top).toBe(clientTopForLine(component, 5)) + expect(overlayWrapper.getBoundingClientRect().top).toBe( + clientTopForLine(component, 5) + ) // Flips the overlay vertically to ensure the overlay element does not // overflow the bottom of the window setScrollLeft(component, 100) await setScrollTop(component, 0) - expect(overlayWrapper.getBoundingClientRect().bottom).toBe(clientTopForLine(component, 4)) + expect(overlayWrapper.getBoundingClientRect().bottom).toBe( + clientTopForLine(component, 4) + ) // Flips the overlay vertically on overlay resize if necessary await setScrollTop(component, 20) - expect(overlayWrapper.getBoundingClientRect().top).toBe(clientTopForLine(component, 5)) + expect(overlayWrapper.getBoundingClientRect().top).toBe( + clientTopForLine(component, 5) + ) overlayElement.style.height = 60 + 'px' await overlayComponent.getNextUpdatePromise() - expect(overlayWrapper.getBoundingClientRect().bottom).toBe(clientTopForLine(component, 4)) + expect(overlayWrapper.getBoundingClientRect().bottom).toBe( + clientTopForLine(component, 4) + ) // Does not flip the overlay vertically if it would overflow the top of the window overlayElement.style.height = 80 + 'px' await overlayComponent.getNextUpdatePromise() - expect(overlayWrapper.getBoundingClientRect().top).toBe(clientTopForLine(component, 5)) + expect(overlayWrapper.getBoundingClientRect().top).toBe( + clientTopForLine(component, 5) + ) // Can update overlay wrapper class - decoration.setProperties({type: 'overlay', item: overlayElement, class: 'b'}) + decoration.setProperties({ + type: 'overlay', + item: overlayElement, + class: 'b' + }) await component.getNextUpdatePromise() expect(overlayWrapper.classList.contains('a')).toBe(false) expect(overlayWrapper.classList.contains('b')).toBe(true) - decoration.setProperties({type: 'overlay', item: overlayElement}) + decoration.setProperties({ type: 'overlay', item: overlayElement }) await component.getNextUpdatePromise() expect(overlayWrapper.classList.contains('b')).toBe(false) }) it('does not attempt to avoid overflowing the window if `avoidOverflow` is false on the decoration', async () => { - const {component, element, editor} = buildComponent({width: 200, height: 100, attach: false}) + const { component, element, editor } = buildComponent({ + width: 200, + height: 100, + attach: false + }) const fakeWindow = attachFakeWindow(component) const overlayElement = document.createElement('div') overlayElement.style.width = '50px' @@ -1889,46 +2646,58 @@ describe('TextEditorComponent', () => { overlayElement.style.margin = '3px' overlayElement.style.backgroundColor = 'red' const marker = editor.markScreenPosition([4, 25]) - const decoration = editor.decorateMarker(marker, {type: 'overlay', item: overlayElement, avoidOverflow: false}) + const decoration = editor.decorateMarker(marker, { + type: 'overlay', + item: overlayElement, + avoidOverflow: false + }) await component.getNextUpdatePromise() await setScrollLeft(component, 30) - expect(overlayElement.getBoundingClientRect().right).toBeGreaterThan(fakeWindow.getBoundingClientRect().right) + expect(overlayElement.getBoundingClientRect().right).toBeGreaterThan( + fakeWindow.getBoundingClientRect().right + ) await setScrollLeft(component, 280) - expect(overlayElement.getBoundingClientRect().left).toBeLessThan(fakeWindow.getBoundingClientRect().left) + expect(overlayElement.getBoundingClientRect().left).toBeLessThan( + fakeWindow.getBoundingClientRect().left + ) }) }) describe('custom gutter decorations', () => { it('arranges custom gutters based on their priority', async () => { - const {component, element, editor} = buildComponent() - editor.addGutter({name: 'e', priority: 2}) - editor.addGutter({name: 'a', priority: -2}) - editor.addGutter({name: 'd', priority: 1}) - editor.addGutter({name: 'b', priority: -1}) - editor.addGutter({name: 'c', priority: 0}) + const { component, element, editor } = buildComponent() + editor.addGutter({ name: 'e', priority: 2 }) + editor.addGutter({ name: 'a', priority: -2 }) + editor.addGutter({ name: 'd', priority: 1 }) + editor.addGutter({ name: 'b', priority: -1 }) + editor.addGutter({ name: 'c', priority: 0 }) await component.getNextUpdatePromise() - const gutters = component.refs.gutterContainer.element.querySelectorAll('.gutter') - expect(Array.from(gutters).map((g) => g.getAttribute('gutter-name'))).toEqual([ - 'a', 'b', 'c', 'line-number', 'd', 'e' - ]) + const gutters = component.refs.gutterContainer.element.querySelectorAll( + '.gutter' + ) + expect( + Array.from(gutters).map(g => g.getAttribute('gutter-name')) + ).toEqual(['a', 'b', 'c', 'line-number', 'd', 'e']) }) it('adjusts the left edge of the scroll container based on changes to the gutter container width', async () => { - const {component, element, editor} = buildComponent() - const {scrollContainer, gutterContainer} = component.refs + const { component, element, editor } = buildComponent() + const { scrollContainer, gutterContainer } = component.refs function checkScrollContainerLeft () { - expect(scrollContainer.getBoundingClientRect().left).toBe(Math.round(gutterContainer.element.getBoundingClientRect().right)) + expect(scrollContainer.getBoundingClientRect().left).toBe( + Math.round(gutterContainer.element.getBoundingClientRect().right) + ) } checkScrollContainerLeft() - const gutterA = editor.addGutter({name: 'a'}) + const gutterA = editor.addGutter({ name: 'a' }) await component.getNextUpdatePromise() checkScrollContainerLeft() - const gutterB = editor.addGutter({name: 'b'}) + const gutterB = editor.addGutter({ name: 'b' }) await component.getNextUpdatePromise() checkScrollContainerLeft() @@ -1954,10 +2723,10 @@ describe('TextEditorComponent', () => { }) it('allows the element of custom gutters to be retrieved before being rendered in the editor component', async () => { - const {component, element, editor} = buildComponent() + const { component, element, editor } = buildComponent() const [lineNumberGutter] = editor.getGutters() - const gutterA = editor.addGutter({name: 'a', priority: -1}) - const gutterB = editor.addGutter({name: 'b', priority: 1}) + const gutterA = editor.addGutter({ name: 'a', priority: -1 }) + const gutterB = editor.addGutter({ name: 'b', priority: 1 }) const lineNumberGutterElement = lineNumberGutter.getElement() const gutterAElement = gutterA.getElement() @@ -1971,9 +2740,9 @@ describe('TextEditorComponent', () => { }) it('can show and hide custom gutters', async () => { - const {component, element, editor} = buildComponent() - const gutterA = editor.addGutter({name: 'a', priority: -1}) - const gutterB = editor.addGutter({name: 'b', priority: 1}) + const { component, element, editor } = buildComponent() + const gutterA = editor.addGutter({ name: 'a', priority: -1 }) + const gutterB = editor.addGutter({ name: 'b', priority: 1 }) const gutterAElement = gutterA.getElement() const gutterBElement = gutterB.getElement() @@ -1998,9 +2767,9 @@ describe('TextEditorComponent', () => { }) it('renders decorations in custom gutters', async () => { - const {component, element, editor} = buildComponent() - const gutterA = editor.addGutter({name: 'a', priority: -1}) - const gutterB = editor.addGutter({name: 'b', priority: 1}) + const { component, element, editor } = buildComponent() + const gutterA = editor.addGutter({ name: 'a', priority: -1 }) + const gutterB = editor.addGutter({ name: 'b', priority: 1 }) const marker1 = editor.markScreenRange([[2, 0], [4, 0]]) const marker2 = editor.markScreenRange([[6, 0], [7, 0]]) const marker3 = editor.markScreenRange([[9, 0], [12, 0]]) @@ -2009,42 +2778,68 @@ describe('TextEditorComponent', () => { // Packages may adopt this class name for decorations to be styled the same as line numbers decorationElement2.className = 'line-number' - const decoration1 = gutterA.decorateMarker(marker1, {class: 'a'}) - const decoration2 = gutterA.decorateMarker(marker2, {class: 'b', item: decorationElement1}) - const decoration3 = gutterB.decorateMarker(marker3, {item: decorationElement2}) + const decoration1 = gutterA.decorateMarker(marker1, { class: 'a' }) + const decoration2 = gutterA.decorateMarker(marker2, { + class: 'b', + item: decorationElement1 + }) + const decoration3 = gutterB.decorateMarker(marker3, { + item: decorationElement2 + }) await component.getNextUpdatePromise() - let [decorationNode1, decorationNode2] = gutterA.getElement().firstChild.children + let [ + decorationNode1, + decorationNode2 + ] = gutterA.getElement().firstChild.children const [decorationNode3] = gutterB.getElement().firstChild.children expect(decorationNode1.className).toBe('decoration a') - expect(decorationNode1.getBoundingClientRect().top).toBe(clientTopForLine(component, 2)) - expect(decorationNode1.getBoundingClientRect().bottom).toBe(clientTopForLine(component, 5)) + expect(decorationNode1.getBoundingClientRect().top).toBe( + clientTopForLine(component, 2) + ) + expect(decorationNode1.getBoundingClientRect().bottom).toBe( + clientTopForLine(component, 5) + ) expect(decorationNode1.firstChild).toBeNull() expect(decorationNode2.className).toBe('decoration b') - expect(decorationNode2.getBoundingClientRect().top).toBe(clientTopForLine(component, 6)) - expect(decorationNode2.getBoundingClientRect().bottom).toBe(clientTopForLine(component, 8)) + expect(decorationNode2.getBoundingClientRect().top).toBe( + clientTopForLine(component, 6) + ) + expect(decorationNode2.getBoundingClientRect().bottom).toBe( + clientTopForLine(component, 8) + ) expect(decorationNode2.firstChild).toBe(decorationElement1) expect(decorationElement1.offsetHeight).toBe(decorationNode2.offsetHeight) expect(decorationElement1.offsetWidth).toBe(decorationNode2.offsetWidth) expect(decorationNode3.className).toBe('decoration') - expect(decorationNode3.getBoundingClientRect().top).toBe(clientTopForLine(component, 9)) - expect(decorationNode3.getBoundingClientRect().bottom).toBe(clientTopForLine(component, 12) + component.getLineHeight()) + expect(decorationNode3.getBoundingClientRect().top).toBe( + clientTopForLine(component, 9) + ) + expect(decorationNode3.getBoundingClientRect().bottom).toBe( + clientTopForLine(component, 12) + component.getLineHeight() + ) expect(decorationNode3.firstChild).toBe(decorationElement2) expect(decorationElement2.offsetHeight).toBe(decorationNode3.offsetHeight) expect(decorationElement2.offsetWidth).toBe(decorationNode3.offsetWidth) // Inline styled height is updated when line height changes - element.style.fontSize = parseInt(getComputedStyle(element).fontSize) + 10 + 'px' + element.style.fontSize = + parseInt(getComputedStyle(element).fontSize) + 10 + 'px' TextEditor.didUpdateStyles() await component.getNextUpdatePromise() expect(decorationElement1.offsetHeight).toBe(decorationNode2.offsetHeight) expect(decorationElement2.offsetHeight).toBe(decorationNode3.offsetHeight) - decoration1.setProperties({type: 'gutter', gutterName: 'a', class: 'c', item: decorationElement1}) - decoration2.setProperties({type: 'gutter', gutterName: 'a'}) + decoration1.setProperties({ + type: 'gutter', + gutterName: 'a', + class: 'c', + item: decorationElement1 + }) + decoration2.setProperties({ type: 'gutter', gutterName: 'a' }) decoration3.destroy() await component.getNextUpdatePromise() expect(decorationNode1.className).toBe('decoration c') @@ -2056,44 +2851,62 @@ describe('TextEditorComponent', () => { }) it('renders custom line number gutters', async () => { - const {component, editor} = buildComponent() + const { component, editor } = buildComponent() const gutterA = editor.addGutter({ name: 'a', priority: 1, type: 'line-number', class: 'a-number', - labelFn: ({bufferRow}) => `a - ${bufferRow}` + labelFn: ({ bufferRow }) => `a - ${bufferRow}` }) const gutterB = editor.addGutter({ name: 'b', priority: 1, type: 'line-number', class: 'b-number', - labelFn: ({bufferRow}) => `b - ${bufferRow}` + labelFn: ({ bufferRow }) => `b - ${bufferRow}` }) editor.setText('0000\n0001\n0002\n0003\n0004\n') await component.getNextUpdatePromise() const gutterAElement = gutterA.getElement() - const aNumbers = gutterAElement.querySelectorAll('div.line-number[data-buffer-row]') + const aNumbers = gutterAElement.querySelectorAll( + 'div.line-number[data-buffer-row]' + ) const aLabels = Array.from(aNumbers, e => e.textContent) - expect(aLabels).toEqual(['a - 0', 'a - 1', 'a - 2', 'a - 3', 'a - 4', 'a - 5']) + expect(aLabels).toEqual([ + 'a - 0', + 'a - 1', + 'a - 2', + 'a - 3', + 'a - 4', + 'a - 5' + ]) const gutterBElement = gutterB.getElement() - const bNumbers = gutterBElement.querySelectorAll('div.line-number[data-buffer-row]') + const bNumbers = gutterBElement.querySelectorAll( + 'div.line-number[data-buffer-row]' + ) const bLabels = Array.from(bNumbers, e => e.textContent) - expect(bLabels).toEqual(['b - 0', 'b - 1', 'b - 2', 'b - 3', 'b - 4', 'b - 5']) + expect(bLabels).toEqual([ + 'b - 0', + 'b - 1', + 'b - 2', + 'b - 3', + 'b - 4', + 'b - 5' + ]) }) it("updates the editor's soft wrap width when a custom gutter's measurement is available", () => { - const {component, element, editor} = buildComponent({ + const { component, element, editor } = buildComponent({ lineNumberGutterVisible: false, width: 400, softWrapped: true, - attach: false, + attach: false }) - const gutter = editor.addGutter({name: 'a', priority: 10}) + const gutter = editor.addGutter({ name: 'a', priority: 10 }) gutter.getElement().style.width = '100px' jasmine.attachToDOM(element) @@ -2102,30 +2915,53 @@ describe('TextEditorComponent', () => { // Component client width - gutter container width - vertical scrollbar width const softWrapColumn = Math.floor( - (400 - 100 - component.getVerticalScrollbarWidth()) / component.getBaseCharacterWidth()) + (400 - 100 - component.getVerticalScrollbarWidth()) / + component.getBaseCharacterWidth() + ) expect(editor.getSoftWrapColumn()).toBe(softWrapColumn) }) }) describe('block decorations', () => { it('renders visible block decorations between the appropriate lines, refreshing and measuring them as needed', async () => { - const editor = buildEditor({autoHeight: false}) - const {item: item1, decoration: decoration1} = createBlockDecorationAtScreenRow(editor, 0, {height: 11, position: 'before'}) - const {item: item2, decoration: decoration2} = createBlockDecorationAtScreenRow(editor, 2, {height: 22, margin: 10, position: 'before'}) + const editor = buildEditor({ autoHeight: false }) + const { + item: item1, + decoration: decoration1 + } = createBlockDecorationAtScreenRow(editor, 0, { + height: 11, + position: 'before' + }) + const { + item: item2, + decoration: decoration2 + } = createBlockDecorationAtScreenRow(editor, 2, { + height: 22, + margin: 10, + position: 'before' + }) // render an editor that already contains some block decorations - const {component, element} = buildComponent({editor, rowsPerTile: 3}) - element.style.height = 4 * component.getLineHeight() + horizontalScrollbarHeight + 'px' + const { component, element } = buildComponent({ editor, rowsPerTile: 3 }) + element.style.height = + 4 * component.getLineHeight() + horizontalScrollbarHeight + 'px' await component.getNextUpdatePromise() expect(component.getRenderedStartRow()).toBe(0) expect(component.getRenderedEndRow()).toBe(9) expect(component.getScrollHeight()).toBe( editor.getScreenLineCount() * component.getLineHeight() + - getElementHeight(item1) + getElementHeight(item2) + getElementHeight(item1) + + getElementHeight(item2) ) assertTilesAreSizedAndPositionedCorrectly(component, [ - {tileStartRow: 0, height: 3 * component.getLineHeight() + getElementHeight(item1) + getElementHeight(item2)}, - {tileStartRow: 3, height: 3 * component.getLineHeight()} + { + tileStartRow: 0, + height: + 3 * component.getLineHeight() + + getElementHeight(item1) + + getElementHeight(item2) + }, + { tileStartRow: 3, height: 3 * component.getLineHeight() } ]) assertLinesAreAlignedWithLineNumbers(component) expect(queryOnScreenLineElements(element).length).toBe(9) @@ -2135,21 +2971,60 @@ describe('TextEditorComponent', () => { expect(item2.nextSibling).toBe(lineNodeForScreenRow(component, 2)) // add block decorations - const {item: item3, decoration: decoration3} = createBlockDecorationAtScreenRow(editor, 4, {height: 33, position: 'before'}) - const {item: item4, decoration: decoration4} = createBlockDecorationAtScreenRow(editor, 7, {height: 44, position: 'before'}) - const {item: item5, decoration: decoration5} = createBlockDecorationAtScreenRow(editor, 7, {height: 50, marginBottom: 5, position: 'after'}) - const {item: item6, decoration: decoration6} = createBlockDecorationAtScreenRow(editor, 12, {height: 60, marginTop: 6, position: 'after'}) + const { + item: item3, + decoration: decoration3 + } = createBlockDecorationAtScreenRow(editor, 4, { + height: 33, + position: 'before' + }) + const { + item: item4, + decoration: decoration4 + } = createBlockDecorationAtScreenRow(editor, 7, { + height: 44, + position: 'before' + }) + const { + item: item5, + decoration: decoration5 + } = createBlockDecorationAtScreenRow(editor, 7, { + height: 50, + marginBottom: 5, + position: 'after' + }) + const { + item: item6, + decoration: decoration6 + } = createBlockDecorationAtScreenRow(editor, 12, { + height: 60, + marginTop: 6, + position: 'after' + }) await component.getNextUpdatePromise() expect(component.getRenderedStartRow()).toBe(0) expect(component.getRenderedEndRow()).toBe(9) expect(component.getScrollHeight()).toBe( editor.getScreenLineCount() * component.getLineHeight() + - getElementHeight(item1) + getElementHeight(item2) + getElementHeight(item3) + - getElementHeight(item4) + getElementHeight(item5) + getElementHeight(item6) + getElementHeight(item1) + + getElementHeight(item2) + + getElementHeight(item3) + + getElementHeight(item4) + + getElementHeight(item5) + + getElementHeight(item6) ) assertTilesAreSizedAndPositionedCorrectly(component, [ - {tileStartRow: 0, height: 3 * component.getLineHeight() + getElementHeight(item1) + getElementHeight(item2)}, - {tileStartRow: 3, height: 3 * component.getLineHeight() + getElementHeight(item3)} + { + tileStartRow: 0, + height: + 3 * component.getLineHeight() + + getElementHeight(item1) + + getElementHeight(item2) + }, + { + tileStartRow: 3, + height: 3 * component.getLineHeight() + getElementHeight(item3) + } ]) assertLinesAreAlignedWithLineNumbers(component) expect(queryOnScreenLineElements(element).length).toBe(9) @@ -2170,12 +3045,21 @@ describe('TextEditorComponent', () => { expect(component.getRenderedEndRow()).toBe(9) expect(component.getScrollHeight()).toBe( editor.getScreenLineCount() * component.getLineHeight() + - getElementHeight(item2) + getElementHeight(item3) + - getElementHeight(item4) + getElementHeight(item5) + getElementHeight(item6) + getElementHeight(item2) + + getElementHeight(item3) + + getElementHeight(item4) + + getElementHeight(item5) + + getElementHeight(item6) ) assertTilesAreSizedAndPositionedCorrectly(component, [ - {tileStartRow: 0, height: 3 * component.getLineHeight() + getElementHeight(item2)}, - {tileStartRow: 3, height: 3 * component.getLineHeight() + getElementHeight(item3)} + { + tileStartRow: 0, + height: 3 * component.getLineHeight() + getElementHeight(item2) + }, + { + tileStartRow: 3, + height: 3 * component.getLineHeight() + getElementHeight(item3) + } ]) assertLinesAreAlignedWithLineNumbers(component) expect(queryOnScreenLineElements(element).length).toBe(9) @@ -2196,12 +3080,21 @@ describe('TextEditorComponent', () => { expect(component.getRenderedEndRow()).toBe(9) expect(component.getScrollHeight()).toBe( editor.getScreenLineCount() * component.getLineHeight() + - getElementHeight(item2) + getElementHeight(item3) + - getElementHeight(item4) + getElementHeight(item5) + getElementHeight(item6) + getElementHeight(item2) + + getElementHeight(item3) + + getElementHeight(item4) + + getElementHeight(item5) + + getElementHeight(item6) ) assertTilesAreSizedAndPositionedCorrectly(component, [ - {tileStartRow: 0, height: 3 * component.getLineHeight() + getElementHeight(item2) + getElementHeight(item3)}, - {tileStartRow: 3, height: 3 * component.getLineHeight()} + { + tileStartRow: 0, + height: + 3 * component.getLineHeight() + + getElementHeight(item2) + + getElementHeight(item3) + }, + { tileStartRow: 3, height: 3 * component.getLineHeight() } ]) assertLinesAreAlignedWithLineNumbers(component) expect(queryOnScreenLineElements(element).length).toBe(9) @@ -2221,12 +3114,21 @@ describe('TextEditorComponent', () => { expect(component.getRenderedEndRow()).toBe(9) expect(component.getScrollHeight()).toBe( editor.getScreenLineCount() * component.getLineHeight() + - getElementHeight(item2) + getElementHeight(item3) + - getElementHeight(item4) + getElementHeight(item5) + getElementHeight(item6) + getElementHeight(item2) + + getElementHeight(item3) + + getElementHeight(item4) + + getElementHeight(item5) + + getElementHeight(item6) ) assertTilesAreSizedAndPositionedCorrectly(component, [ - {tileStartRow: 0, height: 3 * component.getLineHeight() + getElementHeight(item3)}, - {tileStartRow: 3, height: 3 * component.getLineHeight() + getElementHeight(item2)} + { + tileStartRow: 0, + height: 3 * component.getLineHeight() + getElementHeight(item3) + }, + { + tileStartRow: 3, + height: 3 * component.getLineHeight() + getElementHeight(item2) + } ]) assertLinesAreAlignedWithLineNumbers(component) expect(queryOnScreenLineElements(element).length).toBe(9) @@ -2240,17 +3142,26 @@ describe('TextEditorComponent', () => { expect(element.contains(item6)).toBe(false) // scroll past the first tile - await setScrollTop(component, 3 * component.getLineHeight() + getElementHeight(item3)) + await setScrollTop( + component, + 3 * component.getLineHeight() + getElementHeight(item3) + ) expect(component.getRenderedStartRow()).toBe(3) expect(component.getRenderedEndRow()).toBe(12) expect(component.getScrollHeight()).toBe( editor.getScreenLineCount() * component.getLineHeight() + - getElementHeight(item2) + getElementHeight(item3) + - getElementHeight(item4) + getElementHeight(item5) + getElementHeight(item6) + getElementHeight(item2) + + getElementHeight(item3) + + getElementHeight(item4) + + getElementHeight(item5) + + getElementHeight(item6) ) assertTilesAreSizedAndPositionedCorrectly(component, [ - {tileStartRow: 3, height: 3 * component.getLineHeight() + getElementHeight(item2)}, - {tileStartRow: 6, height: 3 * component.getLineHeight()} + { + tileStartRow: 3, + height: 3 * component.getLineHeight() + getElementHeight(item2) + }, + { tileStartRow: 6, height: 3 * component.getLineHeight() } ]) assertLinesAreAlignedWithLineNumbers(component) expect(queryOnScreenLineElements(element).length).toBe(9) @@ -2270,12 +3181,21 @@ describe('TextEditorComponent', () => { expect(component.getRenderedEndRow()).toBe(9) expect(component.getScrollHeight()).toBe( editor.getScreenLineCount() * component.getLineHeight() + - getElementHeight(item2) + getElementHeight(item3) + - getElementHeight(item4) + getElementHeight(item5) + getElementHeight(item6) + getElementHeight(item2) + + getElementHeight(item3) + + getElementHeight(item4) + + getElementHeight(item5) + + getElementHeight(item6) ) assertTilesAreSizedAndPositionedCorrectly(component, [ - {tileStartRow: 0, height: 3 * component.getLineHeight() + getElementHeight(item2) + getElementHeight(item3)}, - {tileStartRow: 3, height: 3 * component.getLineHeight()} + { + tileStartRow: 0, + height: + 3 * component.getLineHeight() + + getElementHeight(item2) + + getElementHeight(item3) + }, + { tileStartRow: 3, height: 3 * component.getLineHeight() } ]) assertLinesAreAlignedWithLineNumbers(component) expect(queryOnScreenLineElements(element).length).toBe(9) @@ -2300,12 +3220,21 @@ describe('TextEditorComponent', () => { expect(component.getRenderedEndRow()).toBe(9) expect(component.getScrollHeight()).toBe( editor.getScreenLineCount() * component.getLineHeight() + - getElementHeight(item2) + getElementHeight(item3) + - getElementHeight(item4) + getElementHeight(item5) + getElementHeight(item6) + getElementHeight(item2) + + getElementHeight(item3) + + getElementHeight(item4) + + getElementHeight(item5) + + getElementHeight(item6) ) assertTilesAreSizedAndPositionedCorrectly(component, [ - {tileStartRow: 0, height: 3 * component.getLineHeight() + getElementHeight(item2) + getElementHeight(item3)}, - {tileStartRow: 3, height: 3 * component.getLineHeight()} + { + tileStartRow: 0, + height: + 3 * component.getLineHeight() + + getElementHeight(item2) + + getElementHeight(item3) + }, + { tileStartRow: 3, height: 3 * component.getLineHeight() } ]) assertLinesAreAlignedWithLineNumbers(component) expect(queryOnScreenLineElements(element).length).toBe(9) @@ -2323,27 +3252,39 @@ describe('TextEditorComponent', () => { item3.style.margin = '' item3.style.width = '' item3.style.wordWrap = 'break-word' - const contentWidthInCharacters = Math.floor(component.getScrollContainerClientWidth() / component.getBaseCharacterWidth()) + const contentWidthInCharacters = Math.floor( + component.getScrollContainerClientWidth() / + component.getBaseCharacterWidth() + ) item3.textContent = 'x'.repeat(contentWidthInCharacters * 2) await component.getNextUpdatePromise() // make the editor wider, so that the decoration doesn't wrap anymore. - component.element.style.width = ( + component.element.style.width = component.getGutterContainerWidth() + component.getScrollContainerClientWidth() * 2 + - verticalScrollbarWidth - ) + 'px' + verticalScrollbarWidth + + 'px' await component.getNextUpdatePromise() expect(component.getRenderedStartRow()).toBe(0) expect(component.getRenderedEndRow()).toBe(9) expect(component.getScrollHeight()).toBe( editor.getScreenLineCount() * component.getLineHeight() + - getElementHeight(item2) + getElementHeight(item3) + - getElementHeight(item4) + getElementHeight(item5) + getElementHeight(item6) + getElementHeight(item2) + + getElementHeight(item3) + + getElementHeight(item4) + + getElementHeight(item5) + + getElementHeight(item6) ) assertTilesAreSizedAndPositionedCorrectly(component, [ - {tileStartRow: 0, height: 3 * component.getLineHeight() + getElementHeight(item2) + getElementHeight(item3)}, - {tileStartRow: 3, height: 3 * component.getLineHeight()} + { + tileStartRow: 0, + height: + 3 * component.getLineHeight() + + getElementHeight(item2) + + getElementHeight(item3) + }, + { tileStartRow: 3, height: 3 * component.getLineHeight() } ]) assertLinesAreAlignedWithLineNumbers(component) expect(queryOnScreenLineElements(element).length).toBe(9) @@ -2364,13 +3305,28 @@ describe('TextEditorComponent', () => { expect(component.getRenderedEndRow()).toBe(13) expect(component.getScrollHeight()).toBe( editor.getScreenLineCount() * component.getLineHeight() + - getElementHeight(item2) + getElementHeight(item3) + - getElementHeight(item4) + getElementHeight(item5) + getElementHeight(item6) + getElementHeight(item2) + + getElementHeight(item3) + + getElementHeight(item4) + + getElementHeight(item5) + + getElementHeight(item6) ) assertTilesAreSizedAndPositionedCorrectly(component, [ - {tileStartRow: 0, height: 3 * component.getLineHeight() + getElementHeight(item2) + getElementHeight(item3)}, - {tileStartRow: 3, height: 3 * component.getLineHeight()}, - {tileStartRow: 6, height: 3 * component.getLineHeight() + getElementHeight(item4) + getElementHeight(item5)}, + { + tileStartRow: 0, + height: + 3 * component.getLineHeight() + + getElementHeight(item2) + + getElementHeight(item3) + }, + { tileStartRow: 3, height: 3 * component.getLineHeight() }, + { + tileStartRow: 6, + height: + 3 * component.getLineHeight() + + getElementHeight(item4) + + getElementHeight(item5) + } ]) assertLinesAreAlignedWithLineNumbers(component) expect(queryOnScreenLineElements(element).length).toBe(13) @@ -2387,47 +3343,72 @@ describe('TextEditorComponent', () => { }) it('correctly positions line numbers when block decorations are located at tile boundaries', async () => { - const {editor, component, element} = buildComponent({rowsPerTile: 3}) - createBlockDecorationAtScreenRow(editor, 0, {height: 5, position: 'before'}) - createBlockDecorationAtScreenRow(editor, 2, {height: 7, position: 'after'}) - createBlockDecorationAtScreenRow(editor, 3, {height: 9, position: 'before'}) - createBlockDecorationAtScreenRow(editor, 3, {height: 11, position: 'after'}) - createBlockDecorationAtScreenRow(editor, 5, {height: 13, position: 'after'}) + const { editor, component, element } = buildComponent({ rowsPerTile: 3 }) + createBlockDecorationAtScreenRow(editor, 0, { + height: 5, + position: 'before' + }) + createBlockDecorationAtScreenRow(editor, 2, { + height: 7, + position: 'after' + }) + createBlockDecorationAtScreenRow(editor, 3, { + height: 9, + position: 'before' + }) + createBlockDecorationAtScreenRow(editor, 3, { + height: 11, + position: 'after' + }) + createBlockDecorationAtScreenRow(editor, 5, { + height: 13, + position: 'after' + }) await component.getNextUpdatePromise() assertLinesAreAlignedWithLineNumbers(component) assertTilesAreSizedAndPositionedCorrectly(component, [ - {tileStartRow: 0, height: 3 * component.getLineHeight() + 5 + 7}, - {tileStartRow: 3, height: 3 * component.getLineHeight() + 9 + 11 + 13}, - {tileStartRow: 6, height: 3 * component.getLineHeight()} + { tileStartRow: 0, height: 3 * component.getLineHeight() + 5 + 7 }, + { + tileStartRow: 3, + height: 3 * component.getLineHeight() + 9 + 11 + 13 + }, + { tileStartRow: 6, height: 3 * component.getLineHeight() } ]) }) it('removes block decorations whose markers have been destroyed', async () => { - const {editor, component, element} = buildComponent({rowsPerTile: 3}) - const {marker} = createBlockDecorationAtScreenRow(editor, 2, {height: 5, position: 'before'}) + const { editor, component, element } = buildComponent({ rowsPerTile: 3 }) + const { marker } = createBlockDecorationAtScreenRow(editor, 2, { + height: 5, + position: 'before' + }) await component.getNextUpdatePromise() assertLinesAreAlignedWithLineNumbers(component) assertTilesAreSizedAndPositionedCorrectly(component, [ - {tileStartRow: 0, height: 3 * component.getLineHeight() + 5}, - {tileStartRow: 3, height: 3 * component.getLineHeight()}, - {tileStartRow: 6, height: 3 * component.getLineHeight()} + { tileStartRow: 0, height: 3 * component.getLineHeight() + 5 }, + { tileStartRow: 3, height: 3 * component.getLineHeight() }, + { tileStartRow: 6, height: 3 * component.getLineHeight() } ]) marker.destroy() await component.getNextUpdatePromise() assertLinesAreAlignedWithLineNumbers(component) assertTilesAreSizedAndPositionedCorrectly(component, [ - {tileStartRow: 0, height: 3 * component.getLineHeight()}, - {tileStartRow: 3, height: 3 * component.getLineHeight()}, - {tileStartRow: 6, height: 3 * component.getLineHeight()} + { tileStartRow: 0, height: 3 * component.getLineHeight() }, + { tileStartRow: 3, height: 3 * component.getLineHeight() }, + { tileStartRow: 6, height: 3 * component.getLineHeight() } ]) }) it('removes block decorations whose markers are invalidated, and adds them back when they become valid again', async () => { - const editor = buildEditor({rowsPerTile: 3, autoHeight: false}) - const {item, decoration, marker} = createBlockDecorationAtScreenRow(editor, 3, {height: 44, position: 'before', invalidate: 'touch'}) - const {component, element} = buildComponent({editor, rowsPerTile: 3}) + const editor = buildEditor({ rowsPerTile: 3, autoHeight: false }) + const { item, decoration, marker } = createBlockDecorationAtScreenRow( + editor, + 3, + { height: 44, position: 'before', invalidate: 'touch' } + ) + const { component, element } = buildComponent({ editor, rowsPerTile: 3 }) // Invalidating the marker removes the block decoration. editor.getBuffer().deleteRows(2, 3) @@ -2435,9 +3416,9 @@ describe('TextEditorComponent', () => { expect(item.parentElement).toBeNull() assertLinesAreAlignedWithLineNumbers(component) assertTilesAreSizedAndPositionedCorrectly(component, [ - {tileStartRow: 0, height: 3 * component.getLineHeight()}, - {tileStartRow: 3, height: 3 * component.getLineHeight()}, - {tileStartRow: 6, height: 3 * component.getLineHeight()} + { tileStartRow: 0, height: 3 * component.getLineHeight() }, + { tileStartRow: 3, height: 3 * component.getLineHeight() }, + { tileStartRow: 6, height: 3 * component.getLineHeight() } ]) // Moving invalid markers is ignored. @@ -2446,9 +3427,9 @@ describe('TextEditorComponent', () => { expect(item.parentElement).toBeNull() assertLinesAreAlignedWithLineNumbers(component) assertTilesAreSizedAndPositionedCorrectly(component, [ - {tileStartRow: 0, height: 3 * component.getLineHeight()}, - {tileStartRow: 3, height: 3 * component.getLineHeight()}, - {tileStartRow: 6, height: 3 * component.getLineHeight()} + { tileStartRow: 0, height: 3 * component.getLineHeight() }, + { tileStartRow: 3, height: 3 * component.getLineHeight() }, + { tileStartRow: 6, height: 3 * component.getLineHeight() } ]) // Making the marker valid again adds back the block decoration. @@ -2458,9 +3439,9 @@ describe('TextEditorComponent', () => { expect(item.nextSibling).toBe(lineNodeForScreenRow(component, 3)) assertLinesAreAlignedWithLineNumbers(component) assertTilesAreSizedAndPositionedCorrectly(component, [ - {tileStartRow: 0, height: 3 * component.getLineHeight()}, - {tileStartRow: 3, height: 3 * component.getLineHeight() + 44}, - {tileStartRow: 6, height: 3 * component.getLineHeight()} + { tileStartRow: 0, height: 3 * component.getLineHeight() }, + { tileStartRow: 3, height: 3 * component.getLineHeight() + 44 }, + { tileStartRow: 6, height: 3 * component.getLineHeight() } ]) // Destroying the decoration and invalidating the marker at the same time @@ -2471,30 +3452,34 @@ describe('TextEditorComponent', () => { expect(item.parentElement).toBeNull() assertLinesAreAlignedWithLineNumbers(component) assertTilesAreSizedAndPositionedCorrectly(component, [ - {tileStartRow: 0, height: 3 * component.getLineHeight()}, - {tileStartRow: 3, height: 3 * component.getLineHeight()}, - {tileStartRow: 6, height: 3 * component.getLineHeight()} + { tileStartRow: 0, height: 3 * component.getLineHeight() }, + { tileStartRow: 3, height: 3 * component.getLineHeight() }, + { tileStartRow: 6, height: 3 * component.getLineHeight() } ]) }) it('does not render block decorations when decorating invalid markers', async () => { - const editor = buildEditor({rowsPerTile: 3, autoHeight: false}) - const {component, element} = buildComponent({editor, rowsPerTile: 3}) + const editor = buildEditor({ rowsPerTile: 3, autoHeight: false }) + const { component, element } = buildComponent({ editor, rowsPerTile: 3 }) - const marker = editor.markScreenPosition([3, 0], {invalidate: 'touch'}) + const marker = editor.markScreenPosition([3, 0], { invalidate: 'touch' }) const item = document.createElement('div') item.style.height = 30 + 'px' item.style.width = 30 + 'px' editor.getBuffer().deleteRows(1, 4) - const decoration = editor.decorateMarker(marker, {type: 'block', item, position: 'before'}) + const decoration = editor.decorateMarker(marker, { + type: 'block', + item, + position: 'before' + }) await component.getNextUpdatePromise() expect(item.parentElement).toBeNull() assertLinesAreAlignedWithLineNumbers(component) assertTilesAreSizedAndPositionedCorrectly(component, [ - {tileStartRow: 0, height: 3 * component.getLineHeight()}, - {tileStartRow: 3, height: 3 * component.getLineHeight()}, - {tileStartRow: 6, height: 3 * component.getLineHeight()} + { tileStartRow: 0, height: 3 * component.getLineHeight() }, + { tileStartRow: 3, height: 3 * component.getLineHeight() }, + { tileStartRow: 6, height: 3 * component.getLineHeight() } ]) // Making the marker valid again causes the corresponding block decoration @@ -2505,16 +3490,20 @@ describe('TextEditorComponent', () => { expect(item.nextSibling).toBe(lineNodeForScreenRow(component, 2)) assertLinesAreAlignedWithLineNumbers(component) assertTilesAreSizedAndPositionedCorrectly(component, [ - {tileStartRow: 0, height: 3 * component.getLineHeight() + 30}, - {tileStartRow: 3, height: 3 * component.getLineHeight()}, - {tileStartRow: 6, height: 3 * component.getLineHeight()} + { tileStartRow: 0, height: 3 * component.getLineHeight() + 30 }, + { tileStartRow: 3, height: 3 * component.getLineHeight() }, + { tileStartRow: 6, height: 3 * component.getLineHeight() } ]) }) it('does not try to remeasure block decorations whose markers are invalid (regression)', async () => { - const editor = buildEditor({rowsPerTile: 3, autoHeight: false}) - const {component, element} = buildComponent({editor, rowsPerTile: 3}) - const {decoration, marker} = createBlockDecorationAtScreenRow(editor, 2, {height: '12px', invalidate: 'touch'}) + const editor = buildEditor({ rowsPerTile: 3, autoHeight: false }) + const { component, element } = buildComponent({ editor, rowsPerTile: 3 }) + const { decoration, marker } = createBlockDecorationAtScreenRow( + editor, + 2, + { height: '12px', invalidate: 'touch' } + ) editor.getBuffer().deleteRows(0, 3) await component.getNextUpdatePromise() @@ -2522,19 +3511,21 @@ describe('TextEditorComponent', () => { await setEditorWidthInCharacters(component, 20) assertLinesAreAlignedWithLineNumbers(component) assertTilesAreSizedAndPositionedCorrectly(component, [ - {tileStartRow: 0, height: 3 * component.getLineHeight()}, - {tileStartRow: 3, height: 3 * component.getLineHeight()}, - {tileStartRow: 6, height: 3 * component.getLineHeight()} + { tileStartRow: 0, height: 3 * component.getLineHeight() }, + { tileStartRow: 3, height: 3 * component.getLineHeight() }, + { tileStartRow: 6, height: 3 * component.getLineHeight() } ]) }) it('does not throw exceptions when destroying a block decoration inside a marker change event (regression)', async () => { - const {editor, component} = buildComponent({rowsPerTile: 3}) + const { editor, component } = buildComponent({ rowsPerTile: 3 }) const marker = editor.markScreenPosition([2, 0]) - marker.onDidChange(() => { marker.destroy() }) + marker.onDidChange(() => { + marker.destroy() + }) const item = document.createElement('div') - editor.decorateMarker(marker, {type: 'block', item}) + editor.decorateMarker(marker, { type: 'block', item }) await component.getNextUpdatePromise() expect(item.nextSibling).toBe(lineNodeForScreenRow(component, 2)) @@ -2547,18 +3538,25 @@ describe('TextEditorComponent', () => { }) it('does not attempt to render block decorations located outside the visible range', async () => { - const {editor, component} = buildComponent({autoHeight: false, rowsPerTile: 2}) + const { editor, component } = buildComponent({ + autoHeight: false, + rowsPerTile: 2 + }) await setEditorHeightInLines(component, 2) expect(component.getRenderedStartRow()).toBe(0) expect(component.getRenderedEndRow()).toBe(4) - const marker1 = editor.markScreenRange([[3, 0], [5, 0]], {reversed: false}) + const marker1 = editor.markScreenRange([[3, 0], [5, 0]], { + reversed: false + }) const item1 = document.createElement('div') - editor.decorateMarker(marker1, {type: 'block', item: item1}) + editor.decorateMarker(marker1, { type: 'block', item: item1 }) - const marker2 = editor.markScreenRange([[3, 0], [5, 0]], {reversed: true}) + const marker2 = editor.markScreenRange([[3, 0], [5, 0]], { + reversed: true + }) const item2 = document.createElement('div') - editor.decorateMarker(marker2, {type: 'block', item: item2}) + editor.decorateMarker(marker2, { type: 'block', item: item2 }) await component.getNextUpdatePromise() expect(item1.parentElement).toBeNull() @@ -2573,22 +3571,35 @@ describe('TextEditorComponent', () => { it('measures block decorations correctly when they are added before the component width has been updated', async () => { { - const {editor, component, element} = buildComponent({autoHeight: false, width: 500, attach: false}) + const { editor, component, element } = buildComponent({ + autoHeight: false, + width: 500, + attach: false + }) const marker = editor.markScreenPosition([0, 0]) const item = document.createElement('div') item.textContent = 'block decoration' - const decoration = editor.decorateMarker(marker, {type: 'block', item}) + const decoration = editor.decorateMarker(marker, { + type: 'block', + item + }) jasmine.attachToDOM(element) assertLinesAreAlignedWithLineNumbers(component) } { - const {editor, component, element} = buildComponent({autoHeight: false, width: 800}) + const { editor, component, element } = buildComponent({ + autoHeight: false, + width: 800 + }) const marker = editor.markScreenPosition([0, 0]) const item = document.createElement('div') item.textContent = 'block decoration that could wrap many times' - const decoration = editor.decorateMarker(marker, {type: 'block', item}) + const decoration = editor.decorateMarker(marker, { + type: 'block', + item + }) element.style.width = '50px' await component.getNextUpdatePromise() @@ -2597,16 +3608,23 @@ describe('TextEditorComponent', () => { }) it('bases the width of the block decoration measurement area on the editor scroll width', async () => { - const {component, element} = buildComponent({autoHeight: false, width: 150}) - expect(component.refs.blockDecorationMeasurementArea.offsetWidth).toBe(component.getScrollWidth()) + const { component, element } = buildComponent({ + autoHeight: false, + width: 150 + }) + expect(component.refs.blockDecorationMeasurementArea.offsetWidth).toBe( + component.getScrollWidth() + ) element.style.width = '800px' await component.getNextUpdatePromise() - expect(component.refs.blockDecorationMeasurementArea.offsetWidth).toBe(component.getScrollWidth()) + expect(component.refs.blockDecorationMeasurementArea.offsetWidth).toBe( + component.getScrollWidth() + ) }) it('does not change the cursor position when clicking on a block decoration', async () => { - const {editor, component} = buildComponent() + const { editor, component } = buildComponent() const decorationElement = document.createElement('div') decorationElement.textContent = 'Parent' @@ -2614,7 +3632,7 @@ describe('TextEditorComponent', () => { childElement.textContent = 'Child' decorationElement.appendChild(childElement) const marker = editor.markScreenPosition([4, 0]) - editor.decorateMarker(marker, {type: 'block', item: decorationElement}) + editor.decorateMarker(marker, { type: 'block', item: decorationElement }) await component.getNextUpdatePromise() const decorationElementClientRect = decorationElement.getBoundingClientRect() @@ -2639,38 +3657,64 @@ describe('TextEditorComponent', () => { }) it('uses the order property to control the order of block decorations at the same screen row', async () => { - const editor = buildEditor({autoHeight: false}) - const {component, element} = buildComponent({editor}) - element.style.height = 10 * component.getLineHeight() + horizontalScrollbarHeight + 'px' + const editor = buildEditor({ autoHeight: false }) + const { component, element } = buildComponent({ editor }) + element.style.height = + 10 * component.getLineHeight() + horizontalScrollbarHeight + 'px' await component.getNextUpdatePromise() // Order parameters that differ from creation order; that collide; and that are not provided. - const [beforeItems, beforeDecorations] = [30, 20, undefined, 20, 10, undefined].map(order => { - return createBlockDecorationAtScreenRow(editor, 2, {height: 10, position: 'before', order}) - }).reduce((lists, result) => { - lists[0].push(result.item) - lists[1].push(result.decoration) - return lists - }, [[], []]) + const [beforeItems, beforeDecorations] = [ + 30, + 20, + undefined, + 20, + 10, + undefined + ] + .map(order => { + return createBlockDecorationAtScreenRow(editor, 2, { + height: 10, + position: 'before', + order + }) + }) + .reduce((lists, result) => { + lists[0].push(result.item) + lists[1].push(result.decoration) + return lists + }, [[], []]) - const [afterItems, afterDecorations] = [undefined, 1, 6, undefined, 6, 2].map(order => { - return createBlockDecorationAtScreenRow(editor, 2, {height: 10, position: 'after', order}) - }).reduce((lists, result) => { - lists[0].push(result.item) - lists[1].push(result.decoration) - return lists - }, [[], []]) + const [afterItems, afterDecorations] = [undefined, 1, 6, undefined, 6, 2] + .map(order => { + return createBlockDecorationAtScreenRow(editor, 2, { + height: 10, + position: 'after', + order + }) + }) + .reduce((lists, result) => { + lists[0].push(result.item) + lists[1].push(result.decoration) + return lists + }, [[], []]) await component.getNextUpdatePromise() - expect(beforeItems[4].previousSibling).toBe(lineNodeForScreenRow(component, 1)) + expect(beforeItems[4].previousSibling).toBe( + lineNodeForScreenRow(component, 1) + ) expect(beforeItems[4].nextSibling).toBe(beforeItems[1]) expect(beforeItems[1].nextSibling).toBe(beforeItems[3]) expect(beforeItems[3].nextSibling).toBe(beforeItems[0]) expect(beforeItems[0].nextSibling).toBe(beforeItems[2]) expect(beforeItems[2].nextSibling).toBe(beforeItems[5]) - expect(beforeItems[5].nextSibling).toBe(lineNodeForScreenRow(component, 2)) - expect(afterItems[1].previousSibling).toBe(lineNodeForScreenRow(component, 2)) + expect(beforeItems[5].nextSibling).toBe( + lineNodeForScreenRow(component, 2) + ) + expect(afterItems[1].previousSibling).toBe( + lineNodeForScreenRow(component, 2) + ) expect(afterItems[1].nextSibling).toBe(afterItems[5]) expect(afterItems[5].nextSibling).toBe(afterItems[2]) expect(afterItems[2].nextSibling).toBe(afterItems[4]) @@ -2678,7 +3722,11 @@ describe('TextEditorComponent', () => { expect(afterItems[0].nextSibling).toBe(afterItems[3]) // Create a decoration somewhere else and move it to the same screen row as the existing decorations - const {item: later, decoration} = createBlockDecorationAtScreenRow(editor, 4, {height: 20, position: 'after', order: 3}) + const { item: later, decoration } = createBlockDecorationAtScreenRow( + editor, + 4, + { height: 20, position: 'after', order: 3 } + ) await component.getNextUpdatePromise() expect(later.previousSibling).toBe(lineNodeForScreenRow(component, 4)) expect(later.nextSibling).toBe(lineNodeForScreenRow(component, 5)) @@ -2691,38 +3739,63 @@ describe('TextEditorComponent', () => { // Move a decoration away from its screen row and ensure the rest maintain their order beforeDecorations[3].getMarker().setHeadScreenPosition([5, 0]) await component.getNextUpdatePromise() - expect(beforeItems[3].previousSibling).toBe(lineNodeForScreenRow(component, 4)) - expect(beforeItems[3].nextSibling).toBe(lineNodeForScreenRow(component, 5)) + expect(beforeItems[3].previousSibling).toBe( + lineNodeForScreenRow(component, 4) + ) + expect(beforeItems[3].nextSibling).toBe( + lineNodeForScreenRow(component, 5) + ) - expect(beforeItems[4].previousSibling).toBe(lineNodeForScreenRow(component, 1)) + expect(beforeItems[4].previousSibling).toBe( + lineNodeForScreenRow(component, 1) + ) expect(beforeItems[4].nextSibling).toBe(beforeItems[1]) expect(beforeItems[1].nextSibling).toBe(beforeItems[0]) expect(beforeItems[0].nextSibling).toBe(beforeItems[2]) expect(beforeItems[2].nextSibling).toBe(beforeItems[5]) - expect(beforeItems[5].nextSibling).toBe(lineNodeForScreenRow(component, 2)) - }); + expect(beforeItems[5].nextSibling).toBe( + lineNodeForScreenRow(component, 2) + ) + }) - function createBlockDecorationAtScreenRow(editor, screenRow, {height, margin, marginTop, marginBottom, position, order, invalidate}) { - const marker = editor.markScreenPosition([screenRow, 0], {invalidate: invalidate || 'never'}) + function createBlockDecorationAtScreenRow ( + editor, + screenRow, + { height, margin, marginTop, marginBottom, position, order, invalidate } + ) { + const marker = editor.markScreenPosition([screenRow, 0], { + invalidate: invalidate || 'never' + }) const item = document.createElement('div') item.style.height = height + 'px' if (margin != null) item.style.margin = margin + 'px' if (marginTop != null) item.style.marginTop = marginTop + 'px' if (marginBottom != null) item.style.marginBottom = marginBottom + 'px' item.style.width = 30 + 'px' - const decoration = editor.decorateMarker(marker, {type: 'block', item, position, order}) - return {item, decoration, marker} + const decoration = editor.decorateMarker(marker, { + type: 'block', + item, + position, + order + }) + return { item, decoration, marker } } function assertTilesAreSizedAndPositionedCorrectly (component, tiles) { let top = 0 for (let tile of tiles) { - const linesTileElement = lineNodeForScreenRow(component, tile.tileStartRow).parentElement + const linesTileElement = lineNodeForScreenRow( + component, + tile.tileStartRow + ).parentElement const linesTileBoundingRect = linesTileElement.getBoundingClientRect() expect(linesTileBoundingRect.height).toBe(tile.height) expect(linesTileBoundingRect.top).toBe(top) - const lineNumbersTileElement = lineNumberNodeForScreenRow(component, tile.tileStartRow).parentElement + const lineNumbersTileElement = lineNumberNodeForScreenRow( + component, + tile.tileStartRow + ).parentElement const lineNumbersTileBoundingRect = lineNumbersTileElement.getBoundingClientRect() expect(lineNumbersTileBoundingRect.height).toBe(tile.height) expect(lineNumbersTileBoundingRect.top).toBe(top) @@ -2737,27 +3810,37 @@ describe('TextEditorComponent', () => { for (let row = startRow; row < endRow; row++) { const lineNode = lineNodeForScreenRow(component, row) const lineNumberNode = lineNumberNodeForScreenRow(component, row) - expect(lineNumberNode.getBoundingClientRect().top).toBe(lineNode.getBoundingClientRect().top) + expect(lineNumberNode.getBoundingClientRect().top).toBe( + lineNode.getBoundingClientRect().top + ) } } }) describe('cursor decorations', () => { it('allows default cursors to be customized', async () => { - const {component, element, editor} = buildComponent() + const { component, element, editor } = buildComponent() editor.addCursorAtScreenPosition([1, 0]) - const [cursorMarker1, cursorMarker2] = editor.getCursors().map(c => c.getMarker()) + const [cursorMarker1, cursorMarker2] = editor + .getCursors() + .map(c => c.getMarker()) - editor.decorateMarker(cursorMarker1, {type: 'cursor', class: 'a'}) - editor.decorateMarker(cursorMarker2, {type: 'cursor', class: 'b', style: {visibility: 'hidden'}}) - editor.decorateMarker(cursorMarker2, {type: 'cursor', style: {backgroundColor: 'red'}}) + editor.decorateMarker(cursorMarker1, { type: 'cursor', class: 'a' }) + editor.decorateMarker(cursorMarker2, { + type: 'cursor', + class: 'b', + style: { visibility: 'hidden' } + }) + editor.decorateMarker(cursorMarker2, { + type: 'cursor', + style: { backgroundColor: 'red' } + }) await component.getNextUpdatePromise() const cursorNodes = element.querySelectorAll('.cursor') expect(cursorNodes.length).toBe(2) - expect(cursorNodes[0].className).toBe('cursor a') expect(cursorNodes[1].className).toBe('cursor b') expect(cursorNodes[1].style.visibility).toBe('hidden') @@ -2765,9 +3848,9 @@ describe('TextEditorComponent', () => { }) it('allows markers that are not actually associated with cursors to be decorated as if they were cursors', async () => { - const {component, element, editor} = buildComponent() + const { component, element, editor } = buildComponent() const marker = editor.markScreenPosition([1, 0]) - editor.decorateMarker(marker, {type: 'cursor', class: 'a'}) + editor.decorateMarker(marker, { type: 'cursor', class: 'a' }) await component.getNextUpdatePromise() const cursorNodes = element.querySelectorAll('.cursor') @@ -2779,30 +3862,60 @@ describe('TextEditorComponent', () => { describe('text decorations', () => { it('injects spans with custom class names and inline styles based on text decorations', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 2}) + const { component, element, editor } = buildComponent({ rowsPerTile: 2 }) const markerLayer = editor.addMarkerLayer() const marker1 = markerLayer.markBufferRange([[0, 2], [2, 7]]) const marker2 = markerLayer.markBufferRange([[0, 2], [3, 8]]) const marker3 = markerLayer.markBufferRange([[1, 13], [2, 7]]) - editor.decorateMarker(marker1, {type: 'text', class: 'a', style: {color: 'red'}}) - editor.decorateMarker(marker2, {type: 'text', class: 'b', style: {color: 'blue'}}) - editor.decorateMarker(marker3, {type: 'text', class: 'c', style: {color: 'green'}}) + editor.decorateMarker(marker1, { + type: 'text', + class: 'a', + style: { color: 'red' } + }) + editor.decorateMarker(marker2, { + type: 'text', + class: 'b', + style: { color: 'blue' } + }) + editor.decorateMarker(marker3, { + type: 'text', + class: 'c', + style: { color: 'green' } + }) await component.getNextUpdatePromise() - expect(textContentOnRowMatchingSelector(component, 0, '.a')).toBe(editor.lineTextForScreenRow(0).slice(2)) - expect(textContentOnRowMatchingSelector(component, 1, '.a')).toBe(editor.lineTextForScreenRow(1)) - expect(textContentOnRowMatchingSelector(component, 2, '.a')).toBe(editor.lineTextForScreenRow(2).slice(0, 7)) + expect(textContentOnRowMatchingSelector(component, 0, '.a')).toBe( + editor.lineTextForScreenRow(0).slice(2) + ) + expect(textContentOnRowMatchingSelector(component, 1, '.a')).toBe( + editor.lineTextForScreenRow(1) + ) + expect(textContentOnRowMatchingSelector(component, 2, '.a')).toBe( + editor.lineTextForScreenRow(2).slice(0, 7) + ) expect(textContentOnRowMatchingSelector(component, 3, '.a')).toBe('') - expect(textContentOnRowMatchingSelector(component, 0, '.b')).toBe(editor.lineTextForScreenRow(0).slice(2)) - expect(textContentOnRowMatchingSelector(component, 1, '.b')).toBe(editor.lineTextForScreenRow(1)) - expect(textContentOnRowMatchingSelector(component, 2, '.b')).toBe(editor.lineTextForScreenRow(2)) - expect(textContentOnRowMatchingSelector(component, 3, '.b')).toBe(editor.lineTextForScreenRow(3).slice(0, 8)) + expect(textContentOnRowMatchingSelector(component, 0, '.b')).toBe( + editor.lineTextForScreenRow(0).slice(2) + ) + expect(textContentOnRowMatchingSelector(component, 1, '.b')).toBe( + editor.lineTextForScreenRow(1) + ) + expect(textContentOnRowMatchingSelector(component, 2, '.b')).toBe( + editor.lineTextForScreenRow(2) + ) + expect(textContentOnRowMatchingSelector(component, 3, '.b')).toBe( + editor.lineTextForScreenRow(3).slice(0, 8) + ) expect(textContentOnRowMatchingSelector(component, 0, '.c')).toBe('') - expect(textContentOnRowMatchingSelector(component, 1, '.c')).toBe(editor.lineTextForScreenRow(1).slice(13)) - expect(textContentOnRowMatchingSelector(component, 2, '.c')).toBe(editor.lineTextForScreenRow(2).slice(0, 7)) + expect(textContentOnRowMatchingSelector(component, 1, '.c')).toBe( + editor.lineTextForScreenRow(1).slice(13) + ) + expect(textContentOnRowMatchingSelector(component, 2, '.c')).toBe( + editor.lineTextForScreenRow(2).slice(0, 7) + ) expect(textContentOnRowMatchingSelector(component, 3, '.c')).toBe('') for (const span of element.querySelectorAll('.a:not(.c)')) { @@ -2817,11 +3930,16 @@ describe('TextEditorComponent', () => { marker2.setHeadScreenPosition([3, 10]) await component.getNextUpdatePromise() - expect(textContentOnRowMatchingSelector(component, 3, '.b')).toBe(editor.lineTextForScreenRow(3).slice(0, 10)) + expect(textContentOnRowMatchingSelector(component, 3, '.b')).toBe( + editor.lineTextForScreenRow(3).slice(0, 10) + ) }) it('correctly handles text decorations starting before the first rendered row and/or ending after the last rendered row', async () => { - const {component, element, editor} = buildComponent({autoHeight: false, rowsPerTile: 1}) + const { component, element, editor } = buildComponent({ + autoHeight: false, + rowsPerTile: 1 + }) element.style.height = 4 * component.getLineHeight() + 'px' await component.getNextUpdatePromise() await setScrollTop(component, 4 * component.getLineHeight()) @@ -2831,11 +3949,13 @@ describe('TextEditorComponent', () => { const markerLayer = editor.addMarkerLayer() const marker1 = markerLayer.markBufferRange([[0, 0], [4, 5]]) const marker2 = markerLayer.markBufferRange([[7, 2], [10, 8]]) - editor.decorateMarker(marker1, {type: 'text', class: 'a'}) - editor.decorateMarker(marker2, {type: 'text', class: 'b'}) + editor.decorateMarker(marker1, { type: 'text', class: 'a' }) + editor.decorateMarker(marker2, { type: 'text', class: 'b' }) await component.getNextUpdatePromise() - expect(textContentOnRowMatchingSelector(component, 4, '.a')).toBe(editor.lineTextForScreenRow(4).slice(0, 5)) + expect(textContentOnRowMatchingSelector(component, 4, '.a')).toBe( + editor.lineTextForScreenRow(4).slice(0, 5) + ) expect(textContentOnRowMatchingSelector(component, 5, '.a')).toBe('') expect(textContentOnRowMatchingSelector(component, 6, '.a')).toBe('') expect(textContentOnRowMatchingSelector(component, 7, '.a')).toBe('') @@ -2844,17 +3964,21 @@ describe('TextEditorComponent', () => { expect(textContentOnRowMatchingSelector(component, 4, '.b')).toBe('') expect(textContentOnRowMatchingSelector(component, 5, '.b')).toBe('') expect(textContentOnRowMatchingSelector(component, 6, '.b')).toBe('') - expect(textContentOnRowMatchingSelector(component, 7, '.b')).toBe(editor.lineTextForScreenRow(7).slice(2)) - expect(textContentOnRowMatchingSelector(component, 8, '.b')).toBe(editor.lineTextForScreenRow(8)) + expect(textContentOnRowMatchingSelector(component, 7, '.b')).toBe( + editor.lineTextForScreenRow(7).slice(2) + ) + expect(textContentOnRowMatchingSelector(component, 8, '.b')).toBe( + editor.lineTextForScreenRow(8) + ) }) it('does not create empty spans when a text decoration contains a row but another text decoration starts or ends at the beginning of it', async () => { - const {component, element, editor} = buildComponent() + const { component, element, editor } = buildComponent() const markerLayer = editor.addMarkerLayer() const marker1 = markerLayer.markBufferRange([[0, 2], [4, 0]]) const marker2 = markerLayer.markBufferRange([[2, 0], [5, 8]]) - editor.decorateMarker(marker1, {type: 'text', class: 'a'}) - editor.decorateMarker(marker2, {type: 'text', class: 'b'}) + editor.decorateMarker(marker1, { type: 'text', class: 'a' }) + editor.decorateMarker(marker2, { type: 'text', class: 'b' }) await component.getNextUpdatePromise() for (const decorationSpan of element.querySelectorAll('.a, .b')) { expect(decorationSpan.textContent).not.toBe('') @@ -2862,9 +3986,9 @@ describe('TextEditorComponent', () => { }) it('does not create empty text nodes when a text decoration ends right after a text tag', async () => { - const {component, element, editor} = buildComponent() + const { component, element, editor } = buildComponent() const marker = editor.markBufferRange([[0, 8], [0, 29]]) - editor.decorateMarker(marker, {type: 'text', class: 'a'}) + editor.decorateMarker(marker, { type: 'text', class: 'a' }) await component.getNextUpdatePromise() for (const textNode of textNodesForScreenRow(component, 0)) { expect(textNode.textContent).not.toBe('') @@ -2872,8 +3996,10 @@ describe('TextEditorComponent', () => { }) function textContentOnRowMatchingSelector (component, row, selector) { - return Array.from(lineNodeForScreenRow(component, row).querySelectorAll(selector)) - .map((span) => span.textContent) + return Array.from( + lineNodeForScreenRow(component, row).querySelectorAll(selector) + ) + .map(span => span.textContent) .join('') } }) @@ -2883,10 +4009,12 @@ describe('TextEditorComponent', () => { describe('when there is only one cursor', () => { it('positions the cursor on single-click or when middle-clicking', async () => { for (const button of [0, 1]) { - const {component, element, editor} = buildComponent() - const {lineHeight} = component.measurements + const { component, element, editor } = buildComponent() + const { lineHeight } = component.measurements - editor.setCursorScreenPosition([Infinity, Infinity], {autoscroll: false}) + editor.setCursorScreenPosition([Infinity, Infinity], { + autoscroll: false + }) component.didMouseDownOnContent({ detail: 1, button, @@ -2896,27 +4024,48 @@ describe('TextEditorComponent', () => { expect(editor.getCursorScreenPosition()).toEqual([0, 0]) const maxRow = editor.getLastScreenRow() - editor.setCursorScreenPosition([Infinity, Infinity], {autoscroll: false}) + editor.setCursorScreenPosition([Infinity, Infinity], { + autoscroll: false + }) component.didMouseDownOnContent({ detail: 1, button, - clientX: clientLeftForCharacter(component, maxRow, editor.lineLengthForScreenRow(maxRow)) + 1, + clientX: + clientLeftForCharacter( + component, + maxRow, + editor.lineLengthForScreenRow(maxRow) + ) + 1, clientY: clientTopForLine(component, maxRow) + 1 }) - expect(editor.getCursorScreenPosition()).toEqual([maxRow, editor.lineLengthForScreenRow(maxRow)]) + expect(editor.getCursorScreenPosition()).toEqual([ + maxRow, + editor.lineLengthForScreenRow(maxRow) + ]) component.didMouseDownOnContent({ detail: 1, button, - clientX: clientLeftForCharacter(component, 0, editor.lineLengthForScreenRow(0)) + 1, + clientX: + clientLeftForCharacter( + component, + 0, + editor.lineLengthForScreenRow(0) + ) + 1, clientY: clientTopForLine(component, 0) + lineHeight / 2 }) - expect(editor.getCursorScreenPosition()).toEqual([0, editor.lineLengthForScreenRow(0)]) + expect(editor.getCursorScreenPosition()).toEqual([ + 0, + editor.lineLengthForScreenRow(0) + ]) component.didMouseDownOnContent({ detail: 1, button, - clientX: (clientLeftForCharacter(component, 3, 0) + clientLeftForCharacter(component, 3, 1)) / 2, + clientX: + (clientLeftForCharacter(component, 3, 0) + + clientLeftForCharacter(component, 3, 1)) / + 2, clientY: clientTopForLine(component, 1) + lineHeight / 2 }) expect(editor.getCursorScreenPosition()).toEqual([1, 0]) @@ -2924,7 +4073,10 @@ describe('TextEditorComponent', () => { component.didMouseDownOnContent({ detail: 1, button, - clientX: (clientLeftForCharacter(component, 3, 14) + clientLeftForCharacter(component, 3, 15)) / 2, + clientX: + (clientLeftForCharacter(component, 3, 14) + + clientLeftForCharacter(component, 3, 15)) / + 2, clientY: clientTopForLine(component, 3) + lineHeight / 2 }) expect(editor.getCursorScreenPosition()).toEqual([3, 14]) @@ -2932,7 +4084,11 @@ describe('TextEditorComponent', () => { component.didMouseDownOnContent({ detail: 1, button, - clientX: (clientLeftForCharacter(component, 3, 14) + clientLeftForCharacter(component, 3, 15)) / 2 + 1, + clientX: + (clientLeftForCharacter(component, 3, 14) + + clientLeftForCharacter(component, 3, 15)) / + 2 + + 1, clientY: clientTopForLine(component, 3) + lineHeight / 2 }) expect(editor.getCursorScreenPosition()).toEqual([3, 15]) @@ -2943,7 +4099,10 @@ describe('TextEditorComponent', () => { component.didMouseDownOnContent({ detail: 1, button, - clientX: (clientLeftForCharacter(component, 3, 14) + clientLeftForCharacter(component, 3, 16)) / 2, + clientX: + (clientLeftForCharacter(component, 3, 14) + + clientLeftForCharacter(component, 3, 16)) / + 2, clientY: clientTopForLine(component, 3) + lineHeight / 2 }) expect(editor.getCursorScreenPosition()).toEqual([3, 14]) @@ -2951,7 +4110,11 @@ describe('TextEditorComponent', () => { component.didMouseDownOnContent({ detail: 1, button, - clientX: (clientLeftForCharacter(component, 3, 14) + clientLeftForCharacter(component, 3, 16)) / 2 + 1, + clientX: + (clientLeftForCharacter(component, 3, 14) + + clientLeftForCharacter(component, 3, 16)) / + 2 + + 1, clientY: clientTopForLine(component, 3) + lineHeight / 2 }) expect(editor.getCursorScreenPosition()).toEqual([3, 16]) @@ -2963,26 +4126,59 @@ describe('TextEditorComponent', () => { describe('when the input is for the primary mouse button', () => { it('selects words on double-click', () => { - const {component, editor} = buildComponent() - const {clientX, clientY} = clientPositionForCharacter(component, 1, 16) - component.didMouseDownOnContent({detail: 1, button: 0, clientX, clientY}) - component.didMouseDownOnContent({detail: 2, button: 0, clientX, clientY}) + const { component, editor } = buildComponent() + const { clientX, clientY } = clientPositionForCharacter( + component, + 1, + 16 + ) + component.didMouseDownOnContent({ + detail: 1, + button: 0, + clientX, + clientY + }) + component.didMouseDownOnContent({ + detail: 2, + button: 0, + clientX, + clientY + }) expect(editor.getSelectedScreenRange()).toEqual([[1, 13], [1, 21]]) expect(editor.testAutoscrollRequests).toEqual([]) }) it('selects lines on triple-click', () => { - const {component, editor} = buildComponent() - const {clientX, clientY} = clientPositionForCharacter(component, 1, 16) - component.didMouseDownOnContent({detail: 1, button: 0, clientX, clientY}) - component.didMouseDownOnContent({detail: 2, button: 0, clientX, clientY}) - component.didMouseDownOnContent({detail: 3, button: 0, clientX, clientY}) + const { component, editor } = buildComponent() + const { clientX, clientY } = clientPositionForCharacter( + component, + 1, + 16 + ) + component.didMouseDownOnContent({ + detail: 1, + button: 0, + clientX, + clientY + }) + component.didMouseDownOnContent({ + detail: 2, + button: 0, + clientX, + clientY + }) + component.didMouseDownOnContent({ + detail: 3, + button: 0, + clientX, + clientY + }) expect(editor.getSelectedScreenRange()).toEqual([[1, 0], [2, 0]]) expect(editor.testAutoscrollRequests).toEqual([]) }) it('adds or removes cursors when holding cmd or ctrl when single-clicking', () => { - const {component, editor} = buildComponent({platform: 'darwin'}) + const { component, editor } = buildComponent({ platform: 'darwin' }) expect(editor.getCursorScreenPositions()).toEqual([[0, 0]]) // add cursor at 1, 16 @@ -3016,7 +4212,9 @@ describe('TextEditorComponent', () => { expect(editor.getCursorScreenPositions()).toEqual([[1, 16]]) // cmd-clicking within a selection destroys it - editor.addSelectionForScreenRange([[2, 10], [2, 15]], {autoscroll: false}) + editor.addSelectionForScreenRange([[2, 10], [2, 15]], { + autoscroll: false + }) expect(editor.getSelectedScreenRanges()).toEqual([ [[1, 16], [1, 16]], [[2, 10], [2, 15]] @@ -3028,9 +4226,7 @@ describe('TextEditorComponent', () => { metaKey: true }) ) - expect(editor.getSelectedScreenRanges()).toEqual([ - [[1, 16], [1, 16]] - ]) + expect(editor.getSelectedScreenRanges()).toEqual([[[1, 16], [1, 16]]]) // ctrl-click does not add cursors on macOS, nor does it move the cursor component.didMouseDownOnContent( @@ -3040,13 +4236,11 @@ describe('TextEditorComponent', () => { ctrlKey: true }) ) - expect(editor.getSelectedScreenRanges()).toEqual([ - [[1, 16], [1, 16]] - ]) + expect(editor.getSelectedScreenRanges()).toEqual([[[1, 16], [1, 16]]]) // ctrl-click adds cursors on platforms *other* than macOS component.props.platform = 'win32' - editor.setCursorScreenPosition([1, 4], {autoscroll: false}) + editor.setCursorScreenPosition([1, 4], { autoscroll: false }) component.didMouseDownOnContent( Object.assign(clientPositionForCharacter(component, 1, 16), { detail: 1, @@ -3060,8 +4254,8 @@ describe('TextEditorComponent', () => { }) it('adds word selections when holding cmd or ctrl when double-clicking', () => { - const {component, editor} = buildComponent() - editor.addCursorAtScreenPosition([1, 16], {autoscroll: false}) + const { component, editor } = buildComponent() + editor.addCursorAtScreenPosition([1, 16], { autoscroll: false }) expect(editor.getCursorScreenPositions()).toEqual([[0, 0], [1, 16]]) component.didMouseDownOnContent( @@ -3086,14 +4280,36 @@ describe('TextEditorComponent', () => { }) it('adds line selections when holding cmd or ctrl when triple-clicking', () => { - const {component, editor} = buildComponent() - editor.addCursorAtScreenPosition([1, 16], {autoscroll: false}) + const { component, editor } = buildComponent() + editor.addCursorAtScreenPosition([1, 16], { autoscroll: false }) expect(editor.getCursorScreenPositions()).toEqual([[0, 0], [1, 16]]) - const {clientX, clientY} = clientPositionForCharacter(component, 1, 16) - component.didMouseDownOnContent({detail: 1, button: 0, metaKey: true, clientX, clientY}) - component.didMouseDownOnContent({detail: 2, button: 0, metaKey: true, clientX, clientY}) - component.didMouseDownOnContent({detail: 3, button: 0, metaKey: true, clientX, clientY}) + const { clientX, clientY } = clientPositionForCharacter( + component, + 1, + 16 + ) + component.didMouseDownOnContent({ + detail: 1, + button: 0, + metaKey: true, + clientX, + clientY + }) + component.didMouseDownOnContent({ + detail: 2, + button: 0, + metaKey: true, + clientX, + clientY + }) + component.didMouseDownOnContent({ + detail: 3, + button: 0, + metaKey: true, + clientX, + clientY + }) expect(editor.getSelectedScreenRanges()).toEqual([ [[0, 0], [0, 0]], @@ -3103,73 +4319,111 @@ describe('TextEditorComponent', () => { }) it('expands the last selection on shift-click', () => { - const {component, element, editor} = buildComponent() + const { component, element, editor } = buildComponent() - editor.setCursorScreenPosition([2, 18], {autoscroll: false}) - component.didMouseDownOnContent(Object.assign({ - detail: 1, - button: 0, - shiftKey: true - }, clientPositionForCharacter(component, 1, 4))) + editor.setCursorScreenPosition([2, 18], { autoscroll: false }) + component.didMouseDownOnContent( + Object.assign( + { + detail: 1, + button: 0, + shiftKey: true + }, + clientPositionForCharacter(component, 1, 4) + ) + ) expect(editor.getSelectedScreenRange()).toEqual([[1, 4], [2, 18]]) - component.didMouseDownOnContent(Object.assign({ - detail: 1, - button: 0, - shiftKey: true - }, clientPositionForCharacter(component, 4, 4))) + component.didMouseDownOnContent( + Object.assign( + { + detail: 1, + button: 0, + shiftKey: true + }, + clientPositionForCharacter(component, 4, 4) + ) + ) expect(editor.getSelectedScreenRange()).toEqual([[2, 18], [4, 4]]) // reorients word-wise selections to keep the word selected regardless of // where the subsequent shift-click occurs - editor.setCursorScreenPosition([2, 18], {autoscroll: false}) - editor.getLastSelection().selectWord({autoscroll: false}) - component.didMouseDownOnContent(Object.assign({ - detail: 1, - button: 0, - shiftKey: true - }, clientPositionForCharacter(component, 1, 4))) + editor.setCursorScreenPosition([2, 18], { autoscroll: false }) + editor.getLastSelection().selectWord({ autoscroll: false }) + component.didMouseDownOnContent( + Object.assign( + { + detail: 1, + button: 0, + shiftKey: true + }, + clientPositionForCharacter(component, 1, 4) + ) + ) expect(editor.getSelectedScreenRange()).toEqual([[1, 2], [2, 20]]) - component.didMouseDownOnContent(Object.assign({ - detail: 1, - button: 0, - shiftKey: true - }, clientPositionForCharacter(component, 3, 11))) + component.didMouseDownOnContent( + Object.assign( + { + detail: 1, + button: 0, + shiftKey: true + }, + clientPositionForCharacter(component, 3, 11) + ) + ) expect(editor.getSelectedScreenRange()).toEqual([[2, 14], [3, 13]]) // reorients line-wise selections to keep the line selected regardless of // where the subsequent shift-click occurs - editor.setCursorScreenPosition([2, 18], {autoscroll: false}) - editor.getLastSelection().selectLine(null, {autoscroll: false}) - component.didMouseDownOnContent(Object.assign({ - detail: 1, - button: 0, - shiftKey: true - }, clientPositionForCharacter(component, 1, 4))) + editor.setCursorScreenPosition([2, 18], { autoscroll: false }) + editor.getLastSelection().selectLine(null, { autoscroll: false }) + component.didMouseDownOnContent( + Object.assign( + { + detail: 1, + button: 0, + shiftKey: true + }, + clientPositionForCharacter(component, 1, 4) + ) + ) expect(editor.getSelectedScreenRange()).toEqual([[1, 0], [3, 0]]) - component.didMouseDownOnContent(Object.assign({ - detail: 1, - button: 0, - shiftKey: true - }, clientPositionForCharacter(component, 3, 11))) + component.didMouseDownOnContent( + Object.assign( + { + detail: 1, + button: 0, + shiftKey: true + }, + clientPositionForCharacter(component, 3, 11) + ) + ) expect(editor.getSelectedScreenRange()).toEqual([[2, 0], [4, 0]]) expect(editor.testAutoscrollRequests).toEqual([]) }) it('expands the last selection on drag', () => { - const {component, editor} = buildComponent() + const { component, editor } = buildComponent() spyOn(component, 'handleMouseDragUntilMouseUp') - component.didMouseDownOnContent(Object.assign({ - detail: 1, - button: 0, - }, clientPositionForCharacter(component, 1, 4))) + component.didMouseDownOnContent( + Object.assign( + { + detail: 1, + button: 0 + }, + clientPositionForCharacter(component, 1, 4) + ) + ) { - const {didDrag, didStopDragging} = component.handleMouseDragUntilMouseUp.argsForCall[0][0] + const { + didDrag, + didStopDragging + } = component.handleMouseDragUntilMouseUp.argsForCall[0][0] didDrag(clientPositionForCharacter(component, 8, 8)) expect(editor.getSelectedScreenRange()).toEqual([[1, 4], [8, 8]]) didDrag(clientPositionForCharacter(component, 4, 8)) @@ -3180,13 +4434,21 @@ describe('TextEditorComponent', () => { // Click-drag a second selection... selections are not merged until the // drag stops. - component.didMouseDownOnContent(Object.assign({ - detail: 1, - button: 0, - metaKey: 1, - }, clientPositionForCharacter(component, 8, 8))) + component.didMouseDownOnContent( + Object.assign( + { + detail: 1, + button: 0, + metaKey: 1 + }, + clientPositionForCharacter(component, 8, 8) + ) + ) { - const {didDrag, didStopDragging} = component.handleMouseDragUntilMouseUp.argsForCall[1][0] + const { + didDrag, + didStopDragging + } = component.handleMouseDragUntilMouseUp.argsForCall[1][0] didDrag(clientPositionForCharacter(component, 2, 8)) expect(editor.getSelectedScreenRanges()).toEqual([ [[1, 4], [4, 8]], @@ -3203,26 +4465,37 @@ describe('TextEditorComponent', () => { [[2, 8], [8, 8]] ]) didStopDragging() - expect(editor.getSelectedScreenRanges()).toEqual([ - [[1, 4], [8, 8]] - ]) + expect(editor.getSelectedScreenRanges()).toEqual([[[1, 4], [8, 8]]]) } }) it('expands the selection word-wise on double-click-drag', () => { - const {component, editor} = buildComponent() + const { component, editor } = buildComponent() spyOn(component, 'handleMouseDragUntilMouseUp') - component.didMouseDownOnContent(Object.assign({ - detail: 1, - button: 0, - }, clientPositionForCharacter(component, 1, 4))) - component.didMouseDownOnContent(Object.assign({ - detail: 2, - button: 0, - }, clientPositionForCharacter(component, 1, 4))) + component.didMouseDownOnContent( + Object.assign( + { + detail: 1, + button: 0 + }, + clientPositionForCharacter(component, 1, 4) + ) + ) + component.didMouseDownOnContent( + Object.assign( + { + detail: 2, + button: 0 + }, + clientPositionForCharacter(component, 1, 4) + ) + ) - const {didDrag, didStopDragging} = component.handleMouseDragUntilMouseUp.argsForCall[1][0] + const { + didDrag, + didStopDragging + } = component.handleMouseDragUntilMouseUp.argsForCall[1][0] didDrag(clientPositionForCharacter(component, 0, 8)) expect(editor.getSelectedScreenRange()).toEqual([[0, 4], [1, 5]]) didDrag(clientPositionForCharacter(component, 2, 10)) @@ -3230,15 +4503,28 @@ describe('TextEditorComponent', () => { }) it('expands the selection line-wise on triple-click-drag', () => { - const {component, editor} = buildComponent() + const { component, editor } = buildComponent() spyOn(component, 'handleMouseDragUntilMouseUp') - const tripleClickPosition = clientPositionForCharacter(component, 2, 8) - component.didMouseDownOnContent(Object.assign({detail: 1, button: 0}, tripleClickPosition)) - component.didMouseDownOnContent(Object.assign({detail: 2, button: 0}, tripleClickPosition)) - component.didMouseDownOnContent(Object.assign({detail: 3, button: 0}, tripleClickPosition)) + const tripleClickPosition = clientPositionForCharacter( + component, + 2, + 8 + ) + component.didMouseDownOnContent( + Object.assign({ detail: 1, button: 0 }, tripleClickPosition) + ) + component.didMouseDownOnContent( + Object.assign({ detail: 2, button: 0 }, tripleClickPosition) + ) + component.didMouseDownOnContent( + Object.assign({ detail: 3, button: 0 }, tripleClickPosition) + ) - const {didDrag, didStopDragging} = component.handleMouseDragUntilMouseUp.argsForCall[2][0] + const { + didDrag, + didStopDragging + } = component.handleMouseDragUntilMouseUp.argsForCall[2][0] didDrag(clientPositionForCharacter(component, 1, 8)) expect(editor.getSelectedScreenRange()).toEqual([[1, 0], [3, 0]]) didDrag(clientPositionForCharacter(component, 4, 10)) @@ -3246,19 +4532,32 @@ describe('TextEditorComponent', () => { }) it('destroys folds when clicking on their fold markers', async () => { - const {component, element, editor} = buildComponent() + const { component, element, editor } = buildComponent() editor.foldBufferRow(1) await component.getNextUpdatePromise() const target = element.querySelector('.fold-marker') - const {clientX, clientY} = clientPositionForCharacter(component, 1, editor.lineLengthForScreenRow(1)) - component.didMouseDownOnContent({detail: 1, button: 0, target, clientX, clientY}) + const { clientX, clientY } = clientPositionForCharacter( + component, + 1, + editor.lineLengthForScreenRow(1) + ) + component.didMouseDownOnContent({ + detail: 1, + button: 0, + target, + clientX, + clientY + }) expect(editor.isFoldedAtBufferRow(1)).toBe(false) expect(editor.getCursorScreenPosition()).toEqual([0, 0]) }) it('autoscrolls the content when dragging near the edge of the scroll container', async () => { - const {component, element, editor} = buildComponent({width: 200, height: 200}) + const { component, element, editor } = buildComponent({ + width: 200, + height: 200 + }) spyOn(component, 'handleMouseDragUntilMouseUp') let previousScrollTop = 0 @@ -3266,7 +4565,9 @@ describe('TextEditorComponent', () => { function assertScrolledDownAndRight () { expect(component.getScrollTop()).toBeGreaterThan(previousScrollTop) previousScrollTop = component.getScrollTop() - expect(component.getScrollLeft()).toBeGreaterThan(previousScrollLeft) + expect(component.getScrollLeft()).toBeGreaterThan( + previousScrollLeft + ) previousScrollLeft = component.getScrollLeft() } @@ -3277,26 +4578,46 @@ describe('TextEditorComponent', () => { previousScrollLeft = component.getScrollLeft() } - component.didMouseDownOnContent({detail: 1, button: 0, clientX: 100, clientY: 100}) - const {didDrag, didStopDragging} = component.handleMouseDragUntilMouseUp.argsForCall[0][0] + component.didMouseDownOnContent({ + detail: 1, + button: 0, + clientX: 100, + clientY: 100 + }) + const { + didDrag, + didStopDragging + } = component.handleMouseDragUntilMouseUp.argsForCall[0][0] - didDrag({clientX: 199, clientY: 199}) + didDrag({ clientX: 199, clientY: 199 }) assertScrolledDownAndRight() - didDrag({clientX: 199, clientY: 199}) + didDrag({ clientX: 199, clientY: 199 }) assertScrolledDownAndRight() - didDrag({clientX: 199, clientY: 199}) + didDrag({ clientX: 199, clientY: 199 }) assertScrolledDownAndRight() - didDrag({clientX: component.getGutterContainerWidth() + 1, clientY: 1}) + didDrag({ + clientX: component.getGutterContainerWidth() + 1, + clientY: 1 + }) assertScrolledUpAndLeft() - didDrag({clientX: component.getGutterContainerWidth() + 1, clientY: 1}) + didDrag({ + clientX: component.getGutterContainerWidth() + 1, + clientY: 1 + }) assertScrolledUpAndLeft() - didDrag({clientX: component.getGutterContainerWidth() + 1, clientY: 1}) + didDrag({ + clientX: component.getGutterContainerWidth() + 1, + clientY: 1 + }) assertScrolledUpAndLeft() // Don't artificially update scroll position beyond possible values expect(component.getScrollTop()).toBe(0) expect(component.getScrollLeft()).toBe(0) - didDrag({clientX: component.getGutterContainerWidth() + 1, clientY: 1}) + didDrag({ + clientX: component.getGutterContainerWidth() + 1, + clientY: 1 + }) expect(component.getScrollTop()).toBe(0) expect(component.getScrollLeft()).toBe(0) @@ -3305,22 +4626,25 @@ describe('TextEditorComponent', () => { setScrollTop(component, maxScrollTop) await setScrollLeft(component, maxScrollLeft) - didDrag({clientX: 199, clientY: 199}) - didDrag({clientX: 199, clientY: 199}) - didDrag({clientX: 199, clientY: 199}) + didDrag({ clientX: 199, clientY: 199 }) + didDrag({ clientX: 199, clientY: 199 }) + didDrag({ clientX: 199, clientY: 199 }) expect(component.getScrollTop()).toBe(maxScrollTop) expect(component.getScrollLeft()).toBe(maxScrollLeft) }) }) it('pastes the previously selected text when clicking the middle mouse button on Linux', async () => { - spyOn(electron.ipcRenderer, 'send').andCallFake(function (eventName, selectedText) { + spyOn(electron.ipcRenderer, 'send').andCallFake(function ( + eventName, + selectedText + ) { if (eventName === 'write-text-to-selection-clipboard') { clipboard.writeText(selectedText, 'selection') } }) - const {component, editor} = buildComponent({platform: 'linux'}) + const { component, editor } = buildComponent({ platform: 'linux' }) // Middle mouse pasting. editor.setSelectedBufferRange([[1, 6], [1, 10]]) @@ -3352,13 +4676,19 @@ describe('TextEditorComponent', () => { }) it('does not paste into a read only editor when clicking the middle mouse button on Linux', async () => { - spyOn(electron.ipcRenderer, 'send').andCallFake(function (eventName, selectedText) { + spyOn(electron.ipcRenderer, 'send').andCallFake(function ( + eventName, + selectedText + ) { if (eventName === 'write-text-to-selection-clipboard') { clipboard.writeText(selectedText, 'selection') } }) - const {component, editor} = buildComponent({platform: 'linux', readOnly: true}) + const { component, editor } = buildComponent({ + platform: 'linux', + readOnly: true + }) // Select the word 'sort' on line 2 and copy to clipboard editor.setSelectedBufferRange([[1, 6], [1, 10]]) @@ -3379,7 +4709,7 @@ describe('TextEditorComponent', () => { describe('on the line number gutter', () => { it('selects all buffer rows intersecting the clicked screen row when a line number is clicked', async () => { - const {component, editor} = buildComponent() + const { component, editor } = buildComponent() spyOn(component, 'handleMouseDragUntilMouseUp') editor.setSoftWrapped(true) await component.getNextUpdatePromise() @@ -3407,7 +4737,7 @@ describe('TextEditorComponent', () => { }) it('adds new selections when a line number is meta-clicked', async () => { - const {component, editor} = buildComponent() + const { component, editor } = buildComponent() editor.setSoftWrapped(true) await component.getNextUpdatePromise() @@ -3450,7 +4780,7 @@ describe('TextEditorComponent', () => { }) it('expands the last selection when a line number is shift-clicked', async () => { - const {component, editor} = buildComponent() + const { component, editor } = buildComponent() spyOn(component, 'handleMouseDragUntilMouseUp') editor.setSoftWrapped(true) await component.getNextUpdatePromise() @@ -3473,7 +4803,10 @@ describe('TextEditorComponent', () => { ]) // Original selection is preserved when shift-click-dragging - const {didDrag, didStopDragging} = component.handleMouseDragUntilMouseUp.argsForCall[0][0] + const { + didDrag, + didStopDragging + } = component.handleMouseDragUntilMouseUp.argsForCall[0][0] didDrag({ clientY: clientTopForLine(component, 1) }) @@ -3487,13 +4820,11 @@ describe('TextEditorComponent', () => { }) didStopDragging() - expect(editor.getSelectedBufferRanges()).toEqual([ - [[2, 10], [8, 0]] - ]) + expect(editor.getSelectedBufferRanges()).toEqual([[[2, 10], [8, 0]]]) }) it('expands the selection when dragging', async () => { - const {component, editor} = buildComponent() + const { component, editor } = buildComponent() spyOn(component, 'handleMouseDragUntilMouseUp') editor.setSoftWrapped(true) await component.getNextUpdatePromise() @@ -3510,7 +4841,10 @@ describe('TextEditorComponent', () => { clientY: clientTopForLine(component, 2) }) - const {didDrag, didStopDragging} = component.handleMouseDragUntilMouseUp.argsForCall[0][0] + const { + didDrag, + didStopDragging + } = component.handleMouseDragUntilMouseUp.argsForCall[0][0] didDrag({ clientY: clientTopForLine(component, 1) @@ -3538,21 +4872,29 @@ describe('TextEditorComponent', () => { ]) didStopDragging() - expect(editor.getSelectedScreenRanges()).toEqual([ - [[2, 0], [4, 4]] - ]) + expect(editor.getSelectedScreenRanges()).toEqual([[[2, 0], [4, 4]]]) }) it('toggles folding when clicking on the right icon of a foldable line number', async () => { - const {component, element, editor} = buildComponent() - let target = element.querySelectorAll('.line-number')[1].querySelector('.icon-right') + const { component, element, editor } = buildComponent() + let target = element + .querySelectorAll('.line-number')[1] + .querySelector('.icon-right') expect(editor.isFoldedAtScreenRow(1)).toBe(false) - component.didMouseDownOnLineNumberGutter({target, button: 0, clientY: clientTopForLine(component, 1)}) + component.didMouseDownOnLineNumberGutter({ + target, + button: 0, + clientY: clientTopForLine(component, 1) + }) expect(editor.isFoldedAtScreenRow(1)).toBe(true) await component.getNextUpdatePromise() - component.didMouseDownOnLineNumberGutter({target, button: 0, clientY: clientTopForLine(component, 1)}) + component.didMouseDownOnLineNumberGutter({ + target, + button: 0, + clientY: clientTopForLine(component, 1) + }) await component.getNextUpdatePromise() expect(editor.isFoldedAtScreenRow(1)).toBe(false) @@ -3560,14 +4902,23 @@ describe('TextEditorComponent', () => { await component.getNextUpdatePromise() expect(editor.isFoldedAtScreenRow(5)).toBe(true) - target = element.querySelectorAll('.line-number')[4].querySelector('.icon-right') - component.didMouseDownOnLineNumberGutter({target, button: 0, clientY: clientTopForLine(component, 4)}) + target = element + .querySelectorAll('.line-number')[4] + .querySelector('.icon-right') + component.didMouseDownOnLineNumberGutter({ + target, + button: 0, + clientY: clientTopForLine(component, 4) + }) expect(editor.isFoldedAtScreenRow(4)).toBe(false) }) it('autoscrolls when dragging near the top or bottom of the gutter', async () => { - const {component, editor} = buildComponent({width: 200, height: 200}) - const {scrollContainer} = component.refs + const { component, editor } = buildComponent({ + width: 200, + height: 200 + }) + const { scrollContainer } = component.refs spyOn(component, 'handleMouseDragUntilMouseUp') let previousScrollTop = 0 @@ -3586,26 +4937,46 @@ describe('TextEditorComponent', () => { previousScrollLeft = component.getScrollLeft() } - component.didMouseDownOnLineNumberGutter({detail: 1, button: 0, clientX: 0, clientY: 100}) - const {didDrag, didStopDragging} = component.handleMouseDragUntilMouseUp.argsForCall[0][0] - didDrag({clientX: 199, clientY: 199}) + component.didMouseDownOnLineNumberGutter({ + detail: 1, + button: 0, + clientX: 0, + clientY: 100 + }) + const { + didDrag, + didStopDragging + } = component.handleMouseDragUntilMouseUp.argsForCall[0][0] + didDrag({ clientX: 199, clientY: 199 }) assertScrolledDown() - didDrag({clientX: 199, clientY: 199}) + didDrag({ clientX: 199, clientY: 199 }) assertScrolledDown() - didDrag({clientX: 199, clientY: 199}) + didDrag({ clientX: 199, clientY: 199 }) assertScrolledDown() - didDrag({clientX: component.getGutterContainerWidth() + 1, clientY: 1}) + didDrag({ + clientX: component.getGutterContainerWidth() + 1, + clientY: 1 + }) assertScrolledUp() - didDrag({clientX: component.getGutterContainerWidth() + 1, clientY: 1}) + didDrag({ + clientX: component.getGutterContainerWidth() + 1, + clientY: 1 + }) assertScrolledUp() - didDrag({clientX: component.getGutterContainerWidth() + 1, clientY: 1}) + didDrag({ + clientX: component.getGutterContainerWidth() + 1, + clientY: 1 + }) assertScrolledUp() // Don't artificially update scroll measurements beyond the minimum or // maximum possible scroll positions expect(component.getScrollTop()).toBe(0) expect(component.getScrollLeft()).toBe(0) - didDrag({clientX: component.getGutterContainerWidth() + 1, clientY: 1}) + didDrag({ + clientX: component.getGutterContainerWidth() + 1, + clientY: 1 + }) expect(component.getScrollTop()).toBe(0) expect(component.getScrollLeft()).toBe(0) @@ -3614,9 +4985,9 @@ describe('TextEditorComponent', () => { setScrollTop(component, maxScrollTop) await setScrollLeft(component, maxScrollLeft) - didDrag({clientX: 199, clientY: 199}) - didDrag({clientX: 199, clientY: 199}) - didDrag({clientX: 199, clientY: 199}) + didDrag({ clientX: 199, clientY: 199 }) + didDrag({ clientX: 199, clientY: 199 }) + didDrag({ clientX: 199, clientY: 199 }) expect(component.getScrollTop()).toBe(maxScrollTop) expect(component.getScrollLeft()).toBe(maxScrollLeft) }) @@ -3624,13 +4995,17 @@ describe('TextEditorComponent', () => { describe('on the scrollbars', () => { it('delegates the mousedown events to the parent component unless the mousedown was on the actual scrollbar', async () => { - const {component, element, editor} = buildComponent({height: 100}) + const { component, element, editor } = buildComponent({ height: 100 }) await setEditorWidthInCharacters(component, 6) const verticalScrollbar = component.refs.verticalScrollbar const horizontalScrollbar = component.refs.horizontalScrollbar - const leftEdgeOfVerticalScrollbar = verticalScrollbar.element.getBoundingClientRect().right - verticalScrollbarWidth - const topEdgeOfHorizontalScrollbar = horizontalScrollbar.element.getBoundingClientRect().bottom - horizontalScrollbarHeight + const leftEdgeOfVerticalScrollbar = + verticalScrollbar.element.getBoundingClientRect().right - + verticalScrollbarWidth + const topEdgeOfHorizontalScrollbar = + horizontalScrollbar.element.getBoundingClientRect().bottom - + horizontalScrollbarHeight verticalScrollbar.didMouseDown({ button: 0, @@ -3669,7 +5044,7 @@ describe('TextEditorComponent', () => { describe('paste event', () => { it("prevents the browser's default processing for the event on Linux", () => { - const {component} = buildComponent({platform: 'linux'}) + const { component } = buildComponent({ platform: 'linux' }) const event = { preventDefault: () => {} } spyOn(event, 'preventDefault') @@ -3680,194 +5055,293 @@ describe('TextEditorComponent', () => { describe('keyboard input', () => { it('handles inserted accented characters via the press-and-hold menu on macOS correctly', () => { - const {editor, component, element} = buildComponent({text: '', chromeVersion: 57}) + const { editor, component, element } = buildComponent({ + text: '', + chromeVersion: 57 + }) editor.insertText('x') editor.setCursorBufferPosition([0, 1]) // Simulate holding the A key to open the press-and-hold menu, // then closing it via ESC. - component.didKeydown({code: 'KeyA'}) - component.didKeypress({code: 'KeyA'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didKeydown({code: 'KeyA'}) - component.didKeydown({code: 'KeyA'}) - component.didKeyup({code: 'KeyA'}) - component.didKeydown({code: 'Escape'}) - component.didKeyup({code: 'Escape'}) + component.didKeydown({ code: 'KeyA' }) + component.didKeypress({ code: 'KeyA' }) + component.didTextInput({ + data: 'a', + stopPropagation: () => {}, + preventDefault: () => {} + }) + component.didKeydown({ code: 'KeyA' }) + component.didKeydown({ code: 'KeyA' }) + component.didKeyup({ code: 'KeyA' }) + component.didKeydown({ code: 'Escape' }) + component.didKeyup({ code: 'Escape' }) expect(editor.getText()).toBe('xa') // Ensure another "a" can be typed correctly. - component.didKeydown({code: 'KeyA'}) - component.didKeypress({code: 'KeyA'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didKeyup({code: 'KeyA'}) + component.didKeydown({ code: 'KeyA' }) + component.didKeypress({ code: 'KeyA' }) + component.didTextInput({ + data: 'a', + stopPropagation: () => {}, + preventDefault: () => {} + }) + component.didKeyup({ code: 'KeyA' }) expect(editor.getText()).toBe('xaa') editor.undo() expect(editor.getText()).toBe('x') // Simulate holding the A key to open the press-and-hold menu, // then selecting an alternative by typing a number. - component.didKeydown({code: 'KeyA'}) - component.didKeypress({code: 'KeyA'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didKeydown({code: 'KeyA'}) - component.didKeydown({code: 'KeyA'}) - component.didKeyup({code: 'KeyA'}) - component.didKeydown({code: 'Digit2'}) - component.didKeyup({code: 'Digit2'}) - component.didTextInput({data: 'á', stopPropagation: () => {}, preventDefault: () => {}}) + component.didKeydown({ code: 'KeyA' }) + component.didKeypress({ code: 'KeyA' }) + component.didTextInput({ + data: 'a', + stopPropagation: () => {}, + preventDefault: () => {} + }) + component.didKeydown({ code: 'KeyA' }) + component.didKeydown({ code: 'KeyA' }) + component.didKeyup({ code: 'KeyA' }) + component.didKeydown({ code: 'Digit2' }) + component.didKeyup({ code: 'Digit2' }) + component.didTextInput({ + data: 'á', + stopPropagation: () => {}, + preventDefault: () => {} + }) expect(editor.getText()).toBe('xá') // Ensure another "a" can be typed correctly. - component.didKeydown({code: 'KeyA'}) - component.didKeypress({code: 'KeyA'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didKeyup({code: 'KeyA'}) + component.didKeydown({ code: 'KeyA' }) + component.didKeypress({ code: 'KeyA' }) + component.didTextInput({ + data: 'a', + stopPropagation: () => {}, + preventDefault: () => {} + }) + component.didKeyup({ code: 'KeyA' }) expect(editor.getText()).toBe('xáa') editor.undo() expect(editor.getText()).toBe('x') // Simulate holding the A key to open the press-and-hold menu, // then selecting an alternative by clicking on it. - component.didKeydown({code: 'KeyA'}) - component.didKeypress({code: 'KeyA'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didKeydown({code: 'KeyA'}) - component.didKeydown({code: 'KeyA'}) - component.didKeyup({code: 'KeyA'}) - component.didTextInput({data: 'á', stopPropagation: () => {}, preventDefault: () => {}}) + component.didKeydown({ code: 'KeyA' }) + component.didKeypress({ code: 'KeyA' }) + component.didTextInput({ + data: 'a', + stopPropagation: () => {}, + preventDefault: () => {} + }) + component.didKeydown({ code: 'KeyA' }) + component.didKeydown({ code: 'KeyA' }) + component.didKeyup({ code: 'KeyA' }) + component.didTextInput({ + data: 'á', + stopPropagation: () => {}, + preventDefault: () => {} + }) expect(editor.getText()).toBe('xá') // Ensure another "a" can be typed correctly. - component.didKeydown({code: 'KeyA'}) - component.didKeypress({code: 'KeyA'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didKeyup({code: 'KeyA'}) + component.didKeydown({ code: 'KeyA' }) + component.didKeypress({ code: 'KeyA' }) + component.didTextInput({ + data: 'a', + stopPropagation: () => {}, + preventDefault: () => {} + }) + component.didKeyup({ code: 'KeyA' }) expect(editor.getText()).toBe('xáa') editor.undo() expect(editor.getText()).toBe('x') // Simulate holding the A key to open the press-and-hold menu, // cycling through the alternatives with the arrows, then selecting one of them with Enter. - component.didKeydown({code: 'KeyA'}) - component.didKeypress({code: 'KeyA'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didKeydown({code: 'KeyA'}) - component.didKeydown({code: 'KeyA'}) - component.didKeyup({code: 'KeyA'}) - component.didKeydown({code: 'ArrowRight'}) - component.didCompositionStart({data: ''}) - component.didCompositionUpdate({data: 'à'}) - component.didKeyup({code: 'ArrowRight'}) + component.didKeydown({ code: 'KeyA' }) + component.didKeypress({ code: 'KeyA' }) + component.didTextInput({ + data: 'a', + stopPropagation: () => {}, + preventDefault: () => {} + }) + component.didKeydown({ code: 'KeyA' }) + component.didKeydown({ code: 'KeyA' }) + component.didKeyup({ code: 'KeyA' }) + component.didKeydown({ code: 'ArrowRight' }) + component.didCompositionStart({ data: '' }) + component.didCompositionUpdate({ data: 'à' }) + component.didKeyup({ code: 'ArrowRight' }) expect(editor.getText()).toBe('xà') - component.didKeydown({code: 'ArrowRight'}) - component.didCompositionUpdate({data: 'á'}) - component.didKeyup({code: 'ArrowRight'}) + component.didKeydown({ code: 'ArrowRight' }) + component.didCompositionUpdate({ data: 'á' }) + component.didKeyup({ code: 'ArrowRight' }) expect(editor.getText()).toBe('xá') - component.didKeydown({code: 'Enter'}) - component.didCompositionUpdate({data: 'á'}) - component.didTextInput({data: 'á', stopPropagation: () => {}, preventDefault: () => {}}) - component.didCompositionEnd({data: 'á', target: component.refs.cursorsAndInput.refs.hiddenInput}) - component.didKeyup({code: 'Enter'}) + component.didKeydown({ code: 'Enter' }) + component.didCompositionUpdate({ data: 'á' }) + component.didTextInput({ + data: 'á', + stopPropagation: () => {}, + preventDefault: () => {} + }) + component.didCompositionEnd({ + data: 'á', + target: component.refs.cursorsAndInput.refs.hiddenInput + }) + component.didKeyup({ code: 'Enter' }) expect(editor.getText()).toBe('xá') // Ensure another "a" can be typed correctly. - component.didKeydown({code: 'KeyA'}) - component.didKeypress({code: 'KeyA'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didKeyup({code: 'KeyA'}) + component.didKeydown({ code: 'KeyA' }) + component.didKeypress({ code: 'KeyA' }) + component.didTextInput({ + data: 'a', + stopPropagation: () => {}, + preventDefault: () => {} + }) + component.didKeyup({ code: 'KeyA' }) expect(editor.getText()).toBe('xáa') editor.undo() expect(editor.getText()).toBe('x') // Simulate holding the A key to open the press-and-hold menu, // cycling through the alternatives with the arrows, then closing it via ESC. - component.didKeydown({code: 'KeyA'}) - component.didKeypress({code: 'KeyA'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didKeydown({code: 'KeyA'}) - component.didKeydown({code: 'KeyA'}) - component.didKeyup({code: 'KeyA'}) - component.didKeydown({code: 'ArrowRight'}) - component.didCompositionStart({data: ''}) - component.didCompositionUpdate({data: 'à'}) - component.didKeyup({code: 'ArrowRight'}) + component.didKeydown({ code: 'KeyA' }) + component.didKeypress({ code: 'KeyA' }) + component.didTextInput({ + data: 'a', + stopPropagation: () => {}, + preventDefault: () => {} + }) + component.didKeydown({ code: 'KeyA' }) + component.didKeydown({ code: 'KeyA' }) + component.didKeyup({ code: 'KeyA' }) + component.didKeydown({ code: 'ArrowRight' }) + component.didCompositionStart({ data: '' }) + component.didCompositionUpdate({ data: 'à' }) + component.didKeyup({ code: 'ArrowRight' }) expect(editor.getText()).toBe('xà') - component.didKeydown({code: 'ArrowRight'}) - component.didCompositionUpdate({data: 'á'}) - component.didKeyup({code: 'ArrowRight'}) + component.didKeydown({ code: 'ArrowRight' }) + component.didCompositionUpdate({ data: 'á' }) + component.didKeyup({ code: 'ArrowRight' }) expect(editor.getText()).toBe('xá') - component.didKeydown({code: 'Escape'}) - component.didCompositionUpdate({data: 'a'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didCompositionEnd({data: 'a', target: component.refs.cursorsAndInput.refs.hiddenInput}) - component.didKeyup({code: 'Escape'}) + component.didKeydown({ code: 'Escape' }) + component.didCompositionUpdate({ data: 'a' }) + component.didTextInput({ + data: 'a', + stopPropagation: () => {}, + preventDefault: () => {} + }) + component.didCompositionEnd({ + data: 'a', + target: component.refs.cursorsAndInput.refs.hiddenInput + }) + component.didKeyup({ code: 'Escape' }) expect(editor.getText()).toBe('xa') // Ensure another "a" can be typed correctly. - component.didKeydown({code: 'KeyA'}) - component.didKeypress({code: 'KeyA'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didKeyup({code: 'KeyA'}) + component.didKeydown({ code: 'KeyA' }) + component.didKeypress({ code: 'KeyA' }) + component.didTextInput({ + data: 'a', + stopPropagation: () => {}, + preventDefault: () => {} + }) + component.didKeyup({ code: 'KeyA' }) expect(editor.getText()).toBe('xaa') editor.undo() expect(editor.getText()).toBe('x') // Simulate pressing the O key and holding the A key to open the press-and-hold menu right before releasing the O key, // cycling through the alternatives with the arrows, then closing it via ESC. - component.didKeydown({code: 'KeyO'}) - component.didKeypress({code: 'KeyO'}) - component.didTextInput({data: 'o', stopPropagation: () => {}, preventDefault: () => {}}) - component.didKeydown({code: 'KeyA'}) - component.didKeypress({code: 'KeyA'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didKeyup({code: 'KeyO'}) - component.didKeydown({code: 'KeyA'}) - component.didKeydown({code: 'KeyA'}) - component.didKeydown({code: 'ArrowRight'}) - component.didCompositionStart({data: ''}) - component.didCompositionUpdate({data: 'à'}) - component.didKeyup({code: 'ArrowRight'}) + component.didKeydown({ code: 'KeyO' }) + component.didKeypress({ code: 'KeyO' }) + component.didTextInput({ + data: 'o', + stopPropagation: () => {}, + preventDefault: () => {} + }) + component.didKeydown({ code: 'KeyA' }) + component.didKeypress({ code: 'KeyA' }) + component.didTextInput({ + data: 'a', + stopPropagation: () => {}, + preventDefault: () => {} + }) + component.didKeyup({ code: 'KeyO' }) + component.didKeydown({ code: 'KeyA' }) + component.didKeydown({ code: 'KeyA' }) + component.didKeydown({ code: 'ArrowRight' }) + component.didCompositionStart({ data: '' }) + component.didCompositionUpdate({ data: 'à' }) + component.didKeyup({ code: 'ArrowRight' }) expect(editor.getText()).toBe('xoà') - component.didKeydown({code: 'ArrowRight'}) - component.didCompositionUpdate({data: 'á'}) - component.didKeyup({code: 'ArrowRight'}) + component.didKeydown({ code: 'ArrowRight' }) + component.didCompositionUpdate({ data: 'á' }) + component.didKeyup({ code: 'ArrowRight' }) expect(editor.getText()).toBe('xoá') - component.didKeydown({code: 'Escape'}) - component.didCompositionUpdate({data: 'a'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didCompositionEnd({data: 'a', target: component.refs.cursorsAndInput.refs.hiddenInput}) - component.didKeyup({code: 'Escape'}) + component.didKeydown({ code: 'Escape' }) + component.didCompositionUpdate({ data: 'a' }) + component.didTextInput({ + data: 'a', + stopPropagation: () => {}, + preventDefault: () => {} + }) + component.didCompositionEnd({ + data: 'a', + target: component.refs.cursorsAndInput.refs.hiddenInput + }) + component.didKeyup({ code: 'Escape' }) expect(editor.getText()).toBe('xoa') // Ensure another "a" can be typed correctly. - component.didKeydown({code: 'KeyA'}) - component.didKeypress({code: 'KeyA'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didKeyup({code: 'KeyA'}) + component.didKeydown({ code: 'KeyA' }) + component.didKeypress({ code: 'KeyA' }) + component.didTextInput({ + data: 'a', + stopPropagation: () => {}, + preventDefault: () => {} + }) + component.didKeyup({ code: 'KeyA' }) editor.undo() expect(editor.getText()).toBe('x') // Simulate holding the A key to open the press-and-hold menu, // cycling through the alternatives with the arrows, then closing it by changing focus. - component.didKeydown({code: 'KeyA'}) - component.didKeypress({code: 'KeyA'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didKeydown({code: 'KeyA'}) - component.didKeydown({code: 'KeyA'}) - component.didKeyup({code: 'KeyA'}) - component.didKeydown({code: 'ArrowRight'}) - component.didCompositionStart({data: ''}) - component.didCompositionUpdate({data: 'à'}) - component.didKeyup({code: 'ArrowRight'}) + component.didKeydown({ code: 'KeyA' }) + component.didKeypress({ code: 'KeyA' }) + component.didTextInput({ + data: 'a', + stopPropagation: () => {}, + preventDefault: () => {} + }) + component.didKeydown({ code: 'KeyA' }) + component.didKeydown({ code: 'KeyA' }) + component.didKeyup({ code: 'KeyA' }) + component.didKeydown({ code: 'ArrowRight' }) + component.didCompositionStart({ data: '' }) + component.didCompositionUpdate({ data: 'à' }) + component.didKeyup({ code: 'ArrowRight' }) expect(editor.getText()).toBe('xà') - component.didKeydown({code: 'ArrowRight'}) - component.didCompositionUpdate({data: 'á'}) - component.didKeyup({code: 'ArrowRight'}) + component.didKeydown({ code: 'ArrowRight' }) + component.didCompositionUpdate({ data: 'á' }) + component.didKeyup({ code: 'ArrowRight' }) expect(editor.getText()).toBe('xá') - component.didCompositionUpdate({data: 'á'}) - component.didTextInput({data: 'á', stopPropagation: () => {}, preventDefault: () => {}}) - component.didCompositionEnd({data: 'á', target: component.refs.cursorsAndInput.refs.hiddenInput}) + component.didCompositionUpdate({ data: 'á' }) + component.didTextInput({ + data: 'á', + stopPropagation: () => {}, + preventDefault: () => {} + }) + component.didCompositionEnd({ + data: 'á', + target: component.refs.cursorsAndInput.refs.hiddenInput + }) expect(editor.getText()).toBe('xá') // Ensure another "a" can be typed correctly. - component.didKeydown({code: 'KeyA'}) - component.didKeypress({code: 'KeyA'}) - component.didTextInput({data: 'a', stopPropagation: () => {}, preventDefault: () => {}}) - component.didKeyup({code: 'KeyA'}) + component.didKeydown({ code: 'KeyA' }) + component.didKeypress({ code: 'KeyA' }) + component.didTextInput({ + data: 'a', + stopPropagation: () => {}, + preventDefault: () => {} + }) + component.didKeyup({ code: 'KeyA' }) expect(editor.getText()).toBe('xáa') editor.undo() expect(editor.getText()).toBe('x') @@ -3876,9 +5350,12 @@ describe('TextEditorComponent', () => { describe('styling changes', () => { it('updates the rendered content based on new measurements when the font dimensions change', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 1, autoHeight: false}) + const { component, element, editor } = buildComponent({ + rowsPerTile: 1, + autoHeight: false + }) await setEditorHeightInLines(component, 3) - editor.setCursorScreenPosition([1, 29], {autoscroll: false}) + editor.setCursorScreenPosition([1, 29], { autoscroll: false }) await component.getNextUpdatePromise() let cursorNode = element.querySelector('.cursor') @@ -3901,26 +5378,49 @@ describe('TextEditorComponent', () => { element.style.fontSize = initialFontSize - 5 + 'px' TextEditor.didUpdateStyles() await component.getNextUpdatePromise() - expect(editor.getDefaultCharWidth()).toBeLessThan(initialBaseCharacterWidth) - expect(editor.getDoubleWidthCharWidth()).toBeLessThan(initialDoubleCharacterWidth) - expect(editor.getHalfWidthCharWidth()).toBeLessThan(initialHalfCharacterWidth) - expect(editor.getKoreanCharWidth()).toBeLessThan(initialKoreanCharacterWidth) - expect(queryOnScreenLineElements(element).length).toBeGreaterThan(initialRenderedLineCount) + expect(editor.getDefaultCharWidth()).toBeLessThan( + initialBaseCharacterWidth + ) + expect(editor.getDoubleWidthCharWidth()).toBeLessThan( + initialDoubleCharacterWidth + ) + expect(editor.getHalfWidthCharWidth()).toBeLessThan( + initialHalfCharacterWidth + ) + expect(editor.getKoreanCharWidth()).toBeLessThan( + initialKoreanCharacterWidth + ) + expect(queryOnScreenLineElements(element).length).toBeGreaterThan( + initialRenderedLineCount + ) verifyCursorPosition(component, cursorNode, 1, 29) element.style.fontSize = initialFontSize + 10 + 'px' TextEditor.didUpdateStyles() await component.getNextUpdatePromise() - expect(editor.getDefaultCharWidth()).toBeGreaterThan(initialBaseCharacterWidth) - expect(editor.getDoubleWidthCharWidth()).toBeGreaterThan(initialDoubleCharacterWidth) - expect(editor.getHalfWidthCharWidth()).toBeGreaterThan(initialHalfCharacterWidth) - expect(editor.getKoreanCharWidth()).toBeGreaterThan(initialKoreanCharacterWidth) - expect(queryOnScreenLineElements(element).length).toBeLessThan(initialRenderedLineCount) + expect(editor.getDefaultCharWidth()).toBeGreaterThan( + initialBaseCharacterWidth + ) + expect(editor.getDoubleWidthCharWidth()).toBeGreaterThan( + initialDoubleCharacterWidth + ) + expect(editor.getHalfWidthCharWidth()).toBeGreaterThan( + initialHalfCharacterWidth + ) + expect(editor.getKoreanCharWidth()).toBeGreaterThan( + initialKoreanCharacterWidth + ) + expect(queryOnScreenLineElements(element).length).toBeLessThan( + initialRenderedLineCount + ) verifyCursorPosition(component, cursorNode, 1, 29) }) it('maintains the scrollTopRow and scrollLeftColumn when the font size changes', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 1, autoHeight: false}) + const { component, element, editor } = buildComponent({ + rowsPerTile: 1, + autoHeight: false + }) await setEditorHeightInLines(component, 3) await setEditorWidthInCharacters(component, 20) component.setScrollTopRow(4) @@ -3940,19 +5440,25 @@ describe('TextEditorComponent', () => { }) it('gracefully handles the editor being hidden after a styling change', async () => { - const {component, element, editor} = buildComponent({autoHeight: false}) - element.style.fontSize = parseInt(getComputedStyle(element).fontSize) + 5 + 'px' + const { component, element, editor } = buildComponent({ + autoHeight: false + }) + element.style.fontSize = + parseInt(getComputedStyle(element).fontSize) + 5 + 'px' TextEditor.didUpdateStyles() element.style.display = 'none' await component.getNextUpdatePromise() }) it('does not throw an exception when the editor is soft-wrapped and changing the font size changes also the longest screen line', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 3, autoHeight: false}) + const { component, element, editor } = buildComponent({ + rowsPerTile: 3, + autoHeight: false + }) editor.setText( 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do\n' + - 'eiusmod tempor incididunt ut labore et dolore magna' + - 'aliqua. Ut enim ad minim veniam, quis nostrud exercitation' + 'eiusmod tempor incididunt ut labore et dolore magna' + + 'aliqua. Ut enim ad minim veniam, quis nostrud exercitation' ) editor.setSoftWrapped(true) await setEditorHeightInLines(component, 2) @@ -3965,12 +5471,15 @@ describe('TextEditorComponent', () => { }) it('updates the width of the lines div based on the longest screen line', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 1, autoHeight: false}) + const { component, element, editor } = buildComponent({ + rowsPerTile: 1, + autoHeight: false + }) editor.setText( 'Lorem ipsum dolor sit\n' + - 'amet, consectetur adipisicing\n' + - 'elit, sed do\n' + - 'eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation' + 'amet, consectetur adipisicing\n' + + 'elit, sed do\n' + + 'eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation' ) await setEditorHeightInLines(component, 2) @@ -3983,7 +5492,7 @@ describe('TextEditorComponent', () => { const actualWidth = element.querySelector('.lines').style.width const expectedWidth = Math.ceil( component.pixelPositionForScreenPosition(Point(3, Infinity)).left + - component.getBaseCharacterWidth() + component.getBaseCharacterWidth() ) expect(actualWidth).toBe(expectedWidth + 'px') }) @@ -3993,26 +5502,36 @@ describe('TextEditorComponent', () => { let editorElementWasUpdatedSynchronously beforeEach(() => { - editorElementWasUpdatedSynchronously = TextEditorElement.prototype.updatedSynchronously + editorElementWasUpdatedSynchronously = + TextEditorElement.prototype.updatedSynchronously }) afterEach(() => { - TextEditorElement.prototype.setUpdatedSynchronously(editorElementWasUpdatedSynchronously) + TextEditorElement.prototype.setUpdatedSynchronously( + editorElementWasUpdatedSynchronously + ) }) it('updates synchronously when updatedSynchronously is true', () => { const editor = buildEditor() - const {element} = new TextEditorComponent({model: editor, updatedSynchronously: true}) + const { element } = new TextEditorComponent({ + model: editor, + updatedSynchronously: true + }) jasmine.attachToDOM(element) editor.setText('Lorem ipsum dolor') - expect(queryOnScreenLineElements(element).map(l => l.textContent)).toEqual([ - editor.lineTextForScreenRow(0) - ]) + expect( + queryOnScreenLineElements(element).map(l => l.textContent) + ).toEqual([editor.lineTextForScreenRow(0)]) }) it('does not throw an exception on attachment when setting the soft-wrap column', () => { - const {component, element, editor} = buildComponent({width: 435, attach: false, updatedSynchronously: true}) + const { component, element, editor } = buildComponent({ + width: 435, + attach: false, + updatedSynchronously: true + }) editor.setSoftWrapped(true) spyOn(window, 'onerror').andCallThrough() jasmine.attachToDOM(element) // should not throw an exception @@ -4026,14 +5545,14 @@ describe('TextEditorComponent', () => { jasmine.attachToDOM(element) editor.setText('Lorem ipsum dolor') - expect(queryOnScreenLineElements(element).map(l => l.textContent)).toEqual([ - editor.lineTextForScreenRow(0) - ]) + expect( + queryOnScreenLineElements(element).map(l => l.textContent) + ).toEqual([editor.lineTextForScreenRow(0)]) }) it('measures dimensions synchronously when measureDimensions is called on the component', () => { TextEditorElement.prototype.setUpdatedSynchronously(true) - const editor = buildEditor({autoHeight: false}) + const editor = buildEditor({ autoHeight: false }) const element = editor.element jasmine.attachToDOM(element) @@ -4046,62 +5565,113 @@ describe('TextEditorComponent', () => { describe('pixelPositionForScreenPosition(point)', () => { it('returns the pixel position for the given point, regardless of whether or not it is currently on screen', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 2, autoHeight: false}) + const { component, element, editor } = buildComponent({ + rowsPerTile: 2, + autoHeight: false + }) await setEditorHeightInLines(component, 3) await setScrollTop(component, 3 * component.getLineHeight()) - const {component: referenceComponent} = buildComponent() + const { component: referenceComponent } = buildComponent() const referenceContentRect = referenceComponent.refs.content.getBoundingClientRect() { - const {top, left} = component.pixelPositionForScreenPosition({row: 0, column: 0}) - expect(top).toBe(clientTopForLine(referenceComponent, 0) - referenceContentRect.top) - expect(left).toBe(clientLeftForCharacter(referenceComponent, 0, 0) - referenceContentRect.left) + const { top, left } = component.pixelPositionForScreenPosition({ + row: 0, + column: 0 + }) + expect(top).toBe( + clientTopForLine(referenceComponent, 0) - referenceContentRect.top + ) + expect(left).toBe( + clientLeftForCharacter(referenceComponent, 0, 0) - + referenceContentRect.left + ) } { - const {top, left} = component.pixelPositionForScreenPosition({row: 0, column: 5}) - expect(top).toBe(clientTopForLine(referenceComponent, 0) - referenceContentRect.top) - expect(left).toBe(clientLeftForCharacter(referenceComponent, 0, 5) - referenceContentRect.left) + const { top, left } = component.pixelPositionForScreenPosition({ + row: 0, + column: 5 + }) + expect(top).toBe( + clientTopForLine(referenceComponent, 0) - referenceContentRect.top + ) + expect(left).toBe( + clientLeftForCharacter(referenceComponent, 0, 5) - + referenceContentRect.left + ) } { - const {top, left} = component.pixelPositionForScreenPosition({row: 12, column: 1}) - expect(top).toBe(clientTopForLine(referenceComponent, 12) - referenceContentRect.top) - expect(left).toBe(clientLeftForCharacter(referenceComponent, 12, 1) - referenceContentRect.left) + const { top, left } = component.pixelPositionForScreenPosition({ + row: 12, + column: 1 + }) + expect(top).toBe( + clientTopForLine(referenceComponent, 12) - referenceContentRect.top + ) + expect(left).toBe( + clientLeftForCharacter(referenceComponent, 12, 1) - + referenceContentRect.left + ) } // Measuring a currently rendered line while an autoscroll that causes // that line to go off-screen is in progress. { editor.setCursorScreenPosition([10, 0]) - const {top, left} = component.pixelPositionForScreenPosition({row: 3, column: 5}) - expect(top).toBe(clientTopForLine(referenceComponent, 3) - referenceContentRect.top) - expect(left).toBe(clientLeftForCharacter(referenceComponent, 3, 5) - referenceContentRect.left) + const { top, left } = component.pixelPositionForScreenPosition({ + row: 3, + column: 5 + }) + expect(top).toBe( + clientTopForLine(referenceComponent, 3) - referenceContentRect.top + ) + expect(left).toBe( + clientLeftForCharacter(referenceComponent, 3, 5) - + referenceContentRect.left + ) } }) it('does not get the component into an inconsistent state when the model has unflushed changes (regression)', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 2, autoHeight: false, text: ''}) + const { component, element, editor } = buildComponent({ + rowsPerTile: 2, + autoHeight: false, + text: '' + }) await setEditorHeightInLines(component, 10) - const updatePromise = editor.getBuffer().append("hi\n") - component.screenPositionForPixelPosition({top: 800, left: 1}) + const updatePromise = editor.getBuffer().append('hi\n') + component.screenPositionForPixelPosition({ top: 800, left: 1 }) await updatePromise }) it('does not shift cursors downward or render off-screen content when measuring off-screen lines (regression)', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 2, autoHeight: false}) + const { component, element, editor } = buildComponent({ + rowsPerTile: 2, + autoHeight: false + }) await setEditorHeightInLines(component, 3) - const {top, left} = component.pixelPositionForScreenPosition({row: 12, column: 1}) + const { top, left } = component.pixelPositionForScreenPosition({ + row: 12, + column: 1 + }) - expect(element.querySelector('.cursor').getBoundingClientRect().top).toBe(component.refs.lineTiles.getBoundingClientRect().top) - expect(element.querySelector('.line[data-screen-row="12"]').style.visibility).toBe('hidden') + expect(element.querySelector('.cursor').getBoundingClientRect().top).toBe( + component.refs.lineTiles.getBoundingClientRect().top + ) + expect( + element.querySelector('.line[data-screen-row="12"]').style.visibility + ).toBe('hidden') // Ensure previously measured off screen lines don't have any weird // styling when they come on screen in the next frame await setEditorHeightInLines(component, 13) - const previouslyMeasuredLineElement = element.querySelector('.line[data-screen-row="12"]') + const previouslyMeasuredLineElement = element.querySelector( + '.line[data-screen-row="12"]' + ) expect(previouslyMeasuredLineElement.style.display).toBe('') expect(previouslyMeasuredLineElement.style.visibility).toBe('') }) @@ -4109,54 +5679,79 @@ describe('TextEditorComponent', () => { describe('screenPositionForPixelPosition', () => { it('returns the screen position for the given pixel position, regardless of whether or not it is currently on screen', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 2, autoHeight: false}) + const { component, element, editor } = buildComponent({ + rowsPerTile: 2, + autoHeight: false + }) await setEditorHeightInLines(component, 3) await setScrollTop(component, 3 * component.getLineHeight()) - const {component: referenceComponent} = buildComponent() + const { component: referenceComponent } = buildComponent() { - const pixelPosition = referenceComponent.pixelPositionForScreenPosition({row: 0, column: 0}) + const pixelPosition = referenceComponent.pixelPositionForScreenPosition( + { row: 0, column: 0 } + ) pixelPosition.top += component.getLineHeight() / 3 pixelPosition.left += component.getBaseCharacterWidth() / 3 - expect(component.screenPositionForPixelPosition(pixelPosition)).toEqual([0, 0]) + expect(component.screenPositionForPixelPosition(pixelPosition)).toEqual( + [0, 0] + ) } { - const pixelPosition = referenceComponent.pixelPositionForScreenPosition({row: 0, column: 5}) + const pixelPosition = referenceComponent.pixelPositionForScreenPosition( + { row: 0, column: 5 } + ) pixelPosition.top += component.getLineHeight() / 3 pixelPosition.left += component.getBaseCharacterWidth() / 3 - expect(component.screenPositionForPixelPosition(pixelPosition)).toEqual([0, 5]) + expect(component.screenPositionForPixelPosition(pixelPosition)).toEqual( + [0, 5] + ) } { - const pixelPosition = referenceComponent.pixelPositionForScreenPosition({row: 5, column: 7}) + const pixelPosition = referenceComponent.pixelPositionForScreenPosition( + { row: 5, column: 7 } + ) pixelPosition.top += component.getLineHeight() / 3 pixelPosition.left += component.getBaseCharacterWidth() / 3 - expect(component.screenPositionForPixelPosition(pixelPosition)).toEqual([5, 7]) + expect(component.screenPositionForPixelPosition(pixelPosition)).toEqual( + [5, 7] + ) } { - const pixelPosition = referenceComponent.pixelPositionForScreenPosition({row: 12, column: 1}) + const pixelPosition = referenceComponent.pixelPositionForScreenPosition( + { row: 12, column: 1 } + ) pixelPosition.top += component.getLineHeight() / 3 pixelPosition.left += component.getBaseCharacterWidth() / 3 - expect(component.screenPositionForPixelPosition(pixelPosition)).toEqual([12, 1]) + expect(component.screenPositionForPixelPosition(pixelPosition)).toEqual( + [12, 1] + ) } // Measuring a currently rendered line while an autoscroll that causes // that line to go off-screen is in progress. { - const pixelPosition = referenceComponent.pixelPositionForScreenPosition({row: 3, column: 4}) + const pixelPosition = referenceComponent.pixelPositionForScreenPosition( + { row: 3, column: 4 } + ) pixelPosition.top += component.getLineHeight() / 3 pixelPosition.left += component.getBaseCharacterWidth() / 3 editor.setCursorBufferPosition([10, 0]) - expect(component.screenPositionForPixelPosition(pixelPosition)).toEqual([3, 4]) + expect(component.screenPositionForPixelPosition(pixelPosition)).toEqual( + [3, 4] + ) } }) }) describe('model methods that delegate to the component / element', () => { it('delegates setHeight and getHeight to the component', async () => { - const {component, element, editor} = buildComponent({autoHeight: false}) + const { component, element, editor } = buildComponent({ + autoHeight: false + }) spyOn(Grim, 'deprecate') expect(editor.getHeight()).toBe(component.getScrollContainerHeight()) expect(Grim.deprecate.callCount).toBe(1) @@ -4168,7 +5763,7 @@ describe('TextEditorComponent', () => { }) it('delegates setWidth and getWidth to the component', async () => { - const {component, element, editor} = buildComponent() + const { component, element, editor } = buildComponent() spyOn(Grim, 'deprecate') expect(editor.getWidth()).toBe(component.getScrollContainerWidth()) expect(Grim.deprecate.callCount).toBe(1) @@ -4180,42 +5775,67 @@ describe('TextEditorComponent', () => { }) it('delegates getFirstVisibleScreenRow, getLastVisibleScreenRow, and getVisibleRowRange to the component', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 3, autoHeight: false}) + const { component, element, editor } = buildComponent({ + rowsPerTile: 3, + autoHeight: false + }) element.style.height = 4 * component.measurements.lineHeight + 'px' await component.getNextUpdatePromise() await setScrollTop(component, 5 * component.getLineHeight()) - expect(editor.getFirstVisibleScreenRow()).toBe(component.getFirstVisibleRow()) - expect(editor.getLastVisibleScreenRow()).toBe(component.getLastVisibleRow()) - expect(editor.getVisibleRowRange()).toEqual([component.getFirstVisibleRow(), component.getLastVisibleRow()]) + expect(editor.getFirstVisibleScreenRow()).toBe( + component.getFirstVisibleRow() + ) + expect(editor.getLastVisibleScreenRow()).toBe( + component.getLastVisibleRow() + ) + expect(editor.getVisibleRowRange()).toEqual([ + component.getFirstVisibleRow(), + component.getLastVisibleRow() + ]) }) it('assigns scrollTop on the component when calling setFirstVisibleScreenRow', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 3, autoHeight: false}) - element.style.height = 4 * component.measurements.lineHeight + horizontalScrollbarHeight + 'px' + const { component, element, editor } = buildComponent({ + rowsPerTile: 3, + autoHeight: false + }) + element.style.height = + 4 * component.measurements.lineHeight + horizontalScrollbarHeight + 'px' await component.getNextUpdatePromise() expect(component.getMaxScrollTop() / component.getLineHeight()).toBe(9) - expect(component.refs.verticalScrollbar.element.scrollTop).toBe(0 * component.getLineHeight()) + expect(component.refs.verticalScrollbar.element.scrollTop).toBe( + 0 * component.getLineHeight() + ) editor.setFirstVisibleScreenRow(1) expect(component.getFirstVisibleRow()).toBe(1) await component.getNextUpdatePromise() - expect(component.refs.verticalScrollbar.element.scrollTop).toBe(1 * component.getLineHeight()) + expect(component.refs.verticalScrollbar.element.scrollTop).toBe( + 1 * component.getLineHeight() + ) editor.setFirstVisibleScreenRow(5) expect(component.getFirstVisibleRow()).toBe(5) await component.getNextUpdatePromise() - expect(component.refs.verticalScrollbar.element.scrollTop).toBe(5 * component.getLineHeight()) + expect(component.refs.verticalScrollbar.element.scrollTop).toBe( + 5 * component.getLineHeight() + ) editor.setFirstVisibleScreenRow(11) expect(component.getFirstVisibleRow()).toBe(9) await component.getNextUpdatePromise() - expect(component.refs.verticalScrollbar.element.scrollTop).toBe(9 * component.getLineHeight()) + expect(component.refs.verticalScrollbar.element.scrollTop).toBe( + 9 * component.getLineHeight() + ) }) it('delegates setFirstVisibleScreenColumn and getFirstVisibleScreenColumn to the component', async () => { - const {component, element, editor} = buildComponent({rowsPerTile: 3, autoHeight: false}) + const { component, element, editor } = buildComponent({ + rowsPerTile: 3, + autoHeight: false + }) element.style.width = 30 * component.getBaseCharacterWidth() + 'px' await component.getNextUpdatePromise() expect(editor.getFirstVisibleScreenColumn()).toBe(0) @@ -4224,27 +5844,38 @@ describe('TextEditorComponent', () => { setScrollLeft(component, 5.5 * component.getBaseCharacterWidth()) expect(editor.getFirstVisibleScreenColumn()).toBe(5) await component.getNextUpdatePromise() - expect(component.refs.horizontalScrollbar.element.scrollLeft).toBeCloseTo(5.5 * component.getBaseCharacterWidth(), -1) + expect(component.refs.horizontalScrollbar.element.scrollLeft).toBeCloseTo( + 5.5 * component.getBaseCharacterWidth(), + -1 + ) editor.setFirstVisibleScreenColumn(12) - expect(component.getScrollLeft()).toBeCloseTo(12 * component.getBaseCharacterWidth(), -1) + expect(component.getScrollLeft()).toBeCloseTo( + 12 * component.getBaseCharacterWidth(), + -1 + ) await component.getNextUpdatePromise() - expect(component.refs.horizontalScrollbar.element.scrollLeft).toBeCloseTo(12 * component.getBaseCharacterWidth(), -1) + expect(component.refs.horizontalScrollbar.element.scrollLeft).toBeCloseTo( + 12 * component.getBaseCharacterWidth(), + -1 + ) }) }) describe('handleMouseDragUntilMouseUp', () => { it('repeatedly schedules `didDrag` calls on new animation frames after moving the mouse, and calls `didStopDragging` on mouseup', async () => { - const {component} = buildComponent() + const { component } = buildComponent() let dragEvents let dragging = false component.handleMouseDragUntilMouseUp({ - didDrag: (event) => { + didDrag: event => { dragging = true dragEvents.push(event) }, - didStopDragging: () => { dragging = false } + didStopDragging: () => { + dragging = false + } }) expect(dragging).toBe(false) @@ -4282,13 +5913,17 @@ describe('TextEditorComponent', () => { }) it('calls `didStopDragging` if the user interacts with the keyboard while dragging', async () => { - const {component, editor} = buildComponent() + const { component, editor } = buildComponent() let dragging = false function startDragging () { component.handleMouseDragUntilMouseUp({ - didDrag: (event) => { dragging = true }, - didStopDragging: () => { dragging = false } + didDrag: event => { + dragging = true + }, + didStopDragging: () => { + dragging = false + } }) } @@ -4302,7 +5937,7 @@ describe('TextEditorComponent', () => { expect(dragging).toBe(true) // Keyboard interaction prevents users from dragging further. - component.didKeydown({code: 'KeyX'}) + component.didKeydown({ code: 'KeyX' }) expect(dragging).toBe(false) window.dispatchEvent(new MouseEvent('mousemove')) @@ -4314,31 +5949,42 @@ describe('TextEditorComponent', () => { window.dispatchEvent(new MouseEvent('mousemove')) await getNextAnimationFramePromise() expect(dragging).toBe(true) - component.didKeydown({key: 'Control'}) - component.didKeydown({key: 'Alt'}) - component.didKeydown({key: 'Shift'}) - component.didKeydown({key: 'Meta'}) + component.didKeydown({ key: 'Control' }) + component.didKeydown({ key: 'Alt' }) + component.didKeydown({ key: 'Shift' }) + component.didKeydown({ key: 'Meta' }) expect(dragging).toBe(true) }) function getNextAnimationFramePromise () { - return new Promise((resolve) => requestAnimationFrame(resolve)) + return new Promise(resolve => requestAnimationFrame(resolve)) } }) }) function buildEditor (params = {}) { const text = params.text != null ? params.text : SAMPLE_TEXT - const buffer = new TextBuffer({text}) - const editorParams = {buffer, readOnly: params.readOnly} + const buffer = new TextBuffer({ text }) + const editorParams = { buffer, readOnly: params.readOnly } if (params.height != null) params.autoHeight = false - for (const paramName of ['mini', 'autoHeight', 'autoWidth', 'lineNumberGutterVisible', 'showLineNumbers', 'placeholderText', 'softWrapped', 'scrollSensitivity']) { + for (const paramName of [ + 'mini', + 'autoHeight', + 'autoWidth', + 'lineNumberGutterVisible', + 'showLineNumbers', + 'placeholderText', + 'softWrapped', + 'scrollSensitivity' + ]) { if (params[paramName] != null) editorParams[paramName] = params[paramName] } atom.grammars.autoAssignLanguageMode(buffer) const editor = new TextEditor(editorParams) editor.testAutoscrollRequests = [] - editor.onDidRequestAutoscroll((request) => { editor.testAutoscrollRequests.push(request) }) + editor.onDidRequestAutoscroll(request => { + editor.testAutoscrollRequests.push(request) + }) editors.push(editor) return editor } @@ -4352,7 +5998,7 @@ function buildComponent (params = {}) { platform: params.platform, chromeVersion: params.chromeVersion }) - const {element} = component + const { element } = component if (!editor.getAutoHeight()) { element.style.height = params.height ? params.height + 'px' : '600px' } @@ -4360,15 +6006,18 @@ function buildComponent (params = {}) { element.style.width = params.width ? params.width + 'px' : '800px' } if (params.attach !== false) jasmine.attachToDOM(element) - return {component, element, editor} + return { component, element, editor } } function getEditorWidthInBaseCharacters (component) { - return Math.round(component.getScrollContainerWidth() / component.getBaseCharacterWidth()) + return Math.round( + component.getScrollContainerWidth() / component.getBaseCharacterWidth() + ) } -async function setEditorHeightInLines(component, heightInLines) { - component.element.style.height = component.getLineHeight() * heightInLines + 'px' +async function setEditorHeightInLines (component, heightInLines) { + component.element.style.height = + component.getLineHeight() * heightInLines + 'px' await component.getNextUpdatePromise() } @@ -4384,7 +6033,9 @@ async function setEditorWidthInCharacters (component, widthInCharacters) { function verifyCursorPosition (component, cursorNode, row, column) { const rect = cursorNode.getBoundingClientRect() expect(Math.round(rect.top)).toBe(clientTopForLine(component, row)) - expect(Math.round(rect.left)).toBe(Math.round(clientLeftForCharacter(component, row, column))) + expect(Math.round(rect.left)).toBe( + Math.round(clientLeftForCharacter(component, row, column)) + ) } function clientTopForLine (component, row) { @@ -4420,7 +6071,8 @@ function clientPositionForCharacter (component, row, column) { } function lineNumberNodeForScreenRow (component, row) { - const gutterElement = component.refs.gutterContainer.refs.lineNumberGutter.element + const gutterElement = + component.refs.gutterContainer.refs.lineNumberGutter.element const tileStartRow = component.tileStartRowForRow(row) const tileIndex = component.renderedTileStartRows.indexOf(tileStartRow) return gutterElement.children[tileIndex + 1].children[row - tileStartRow] @@ -4428,7 +6080,8 @@ function lineNumberNodeForScreenRow (component, row) { function lineNodeForScreenRow (component, row) { const renderedScreenLine = component.renderedScreenLineForRow(row) - return component.lineComponentsByScreenLineId.get(renderedScreenLine.id).element + return component.lineComponentsByScreenLineId.get(renderedScreenLine.id) + .element } function textNodesForScreenRow (component, row) { @@ -4486,7 +6139,7 @@ function getElementHeight (element) { } function getNextTickPromise () { - return new Promise((resolve) => process.nextTick(resolve)) + return new Promise(resolve => process.nextTick(resolve)) } function queryOnScreenLineNumberElements (element) { @@ -4494,5 +6147,7 @@ function queryOnScreenLineNumberElements (element) { } function queryOnScreenLineElements (element) { - return Array.from(element.querySelectorAll('.line:not(.dummy):not([data-off-screen])')) + return Array.from( + element.querySelectorAll('.line:not(.dummy):not([data-off-screen])') + ) } diff --git a/spec/text-editor-element-spec.js b/spec/text-editor-element-spec.js index d6c33e7ad..b22d2c782 100644 --- a/spec/text-editor-element-spec.js +++ b/spec/text-editor-element-spec.js @@ -1,4 +1,13 @@ -const {it, fit, ffit, fffit, beforeEach, afterEach, conditionPromise, timeoutPromise} = require('./async-spec-helpers') +const { + it, + fit, + ffit, + fffit, + beforeEach, + afterEach, + conditionPromise, + timeoutPromise +} = require('./async-spec-helpers') const TextEditor = require('../src/text-editor') const TextEditorElement = require('../src/text-editor-element') @@ -9,7 +18,8 @@ describe('TextEditorElement', () => { jasmineContent = document.body.querySelector('#jasmine-content') // Force scrollbars to be visible regardless of local system configuration const scrollbarStyle = document.createElement('style') - scrollbarStyle.textContent = 'atom-text-editor ::-webkit-scrollbar { -webkit-appearance: none }' + scrollbarStyle.textContent = + 'atom-text-editor ::-webkit-scrollbar { -webkit-appearance: none }' jasmine.attachToDOM(scrollbarStyle) }) @@ -53,7 +63,7 @@ describe('TextEditorElement', () => { }) it("only assigns 'placeholder-text' on the model if the attribute is present", () => { - const editor = new TextEditor({placeholderText: 'placeholder'}) + const editor = new TextEditor({ placeholderText: 'placeholder' }) editor.getElement() expect(editor.getPlaceholderText()).toBe('placeholder') }) @@ -70,8 +80,8 @@ describe('TextEditorElement', () => { expect(element.getModel().isLineNumberGutterVisible()).toBe(false) }) - it("honors the 'readonly' attribute", async function() { - jasmineContent.innerHTML = "" + it("honors the 'readonly' attribute", async function () { + jasmineContent.innerHTML = '' const element = jasmineContent.firstChild expect(element.getComponent().isInputEnabled()).toBe(false) @@ -108,11 +118,10 @@ describe('TextEditorElement', () => { describe('when the model is assigned', () => it("adds the 'mini' attribute if .isMini() returns true on the model", async () => { const element = buildTextEditorElement() - element.getModel().update({mini: true}) + element.getModel().update({ mini: true }) await atom.views.getNextUpdatePromise() expect(element.hasAttribute('mini')).toBe(true) - }) - ) + })) describe('when the editor is attached to the DOM', () => it('mounts the component and unmounts when removed from the dom', () => { @@ -125,8 +134,7 @@ describe('TextEditorElement', () => { jasmine.attachToDOM(element) expect(element.component.attached).toBe(true) - }) - ) + })) describe('when the editor is detached from the DOM and then reattached', () => { it('does not render duplicate line numbers', () => { @@ -145,17 +153,23 @@ describe('TextEditorElement', () => { it('does not render duplicate decorations in custom gutters', () => { const editor = new TextEditor() editor.setText('1\n2\n3') - editor.addGutter({name: 'test-gutter'}) + editor.addGutter({ name: 'test-gutter' }) const marker = editor.markBufferRange([[0, 0], [2, 0]]) - editor.decorateMarker(marker, {type: 'gutter', gutterName: 'test-gutter'}) + editor.decorateMarker(marker, { + type: 'gutter', + gutterName: 'test-gutter' + }) const element = editor.getElement() jasmine.attachToDOM(element) - const initialDecorationCount = element.querySelectorAll('.decoration').length + const initialDecorationCount = element.querySelectorAll('.decoration') + .length element.remove() jasmine.attachToDOM(element) - expect(element.querySelectorAll('.decoration').length).toBe(initialDecorationCount) + expect(element.querySelectorAll('.decoration').length).toBe( + initialDecorationCount + ) }) it('can be re-focused using the previous `document.activeElement`', () => { @@ -194,7 +208,9 @@ describe('TextEditorElement', () => { it("doesn't trigger a blur event on the editor element when focusing an already focused editor element", () => { let blurCalled = false const element = buildTextEditorElement() - element.addEventListener('blur', () => { blurCalled = true }) + element.addEventListener('blur', () => { + blurCalled = true + }) jasmineContent.appendChild(element) expect(document.activeElement).toBe(document.body) @@ -216,13 +232,15 @@ describe('TextEditorElement', () => { } } - document.registerElement('element-that-focuses-child', - {prototype: ElementThatFocusesChild.prototype} - ) + document.registerElement('element-that-focuses-child', { + prototype: ElementThatFocusesChild.prototype + }) it('proxies the focus event to the hidden input', () => { const element = buildTextEditorElement() - const parentElement = document.createElement('element-that-focuses-child') + const parentElement = document.createElement( + 'element-that-focuses-child' + ) parentElement.appendChild(element) jasmineContent.appendChild(parentElement) expect(document.activeElement).toBe(element.querySelector('input')) @@ -236,7 +254,7 @@ describe('TextEditorElement', () => { parentElement.style.width = '0px' parentElement.style.height = '0px' - const element = buildTextEditorElement({attach: false}) + const element = buildTextEditorElement({ attach: false }) parentElement.appendChild(element) jasmineContent.appendChild(parentElement) @@ -249,7 +267,7 @@ describe('TextEditorElement', () => { describe('::setModel', () => { describe('when the element does not have an editor yet', () => { it('uses the supplied one', () => { - const element = buildTextEditorElement({attach: false}) + const element = buildTextEditorElement({ attach: false }) const editor = new TextEditor() element.setModel(editor) jasmine.attachToDOM(element) @@ -260,7 +278,7 @@ describe('TextEditorElement', () => { describe('when the element already has an editor', () => { it('unbinds it and then swaps it with the supplied one', async () => { - const element = buildTextEditorElement({attach: true}) + const element = buildTextEditorElement({ attach: true }) const previousEditor = element.getModel() expect(previousEditor.element).toBe(element) @@ -275,7 +293,7 @@ describe('TextEditorElement', () => { describe('::onDidAttach and ::onDidDetach', () => it('invokes callbacks when the element is attached and detached', () => { - const element = buildTextEditorElement({attach: false}) + const element = buildTextEditorElement({ attach: false }) const attachedCallback = jasmine.createSpy('attachedCallback') const detachedCallback = jasmine.createSpy('detachedCallback') @@ -292,8 +310,7 @@ describe('TextEditorElement', () => { expect(attachedCallback).not.toHaveBeenCalled() expect(detachedCallback).toHaveBeenCalled() - }) - ) + })) describe('::setUpdatedSynchronously', () => { it('controls whether the text editor is updated synchronously', () => { @@ -318,7 +335,7 @@ describe('TextEditorElement', () => { describe('::getDefaultCharacterWidth', () => { it('returns 0 before the element is attached', () => { - const element = buildTextEditorElement({attach: false}) + const element = buildTextEditorElement({ attach: false }) expect(element.getDefaultCharacterWidth()).toBe(0) }) @@ -341,7 +358,7 @@ describe('TextEditorElement', () => { const horizontalScrollbarHeight = element.component.getHorizontalScrollbarHeight() expect(element.getMaxScrollTop()).toBe(0) - await editor.update({autoHeight: false}) + await editor.update({ autoHeight: false }) element.style.height = 100 + horizontalScrollbarHeight + 'px' await element.getNextUpdatePromise() @@ -354,13 +371,12 @@ describe('TextEditorElement', () => { element.style.height = 200 + horizontalScrollbarHeight + 'px' await element.getNextUpdatePromise() expect(element.getMaxScrollTop()).toBe(0) - }) - ) + })) describe('::setScrollTop and ::setScrollLeft', () => { it('changes the scroll position', async () => { element = buildTextEditorElement() - element.getModel().update({autoHeight: false}) + element.getModel().update({ autoHeight: false }) element.getModel().setText('lorem\nipsum\ndolor\nsit\namet') element.setHeight(20) await element.getNextUpdatePromise() @@ -387,8 +403,7 @@ describe('TextEditorElement', () => { element.getModel().setMini(false) await element.getNextUpdatePromise() expect(element.hasAttribute('mini')).toBe(false) - }) - ) + })) describe('::intersectsVisibleRowRange(start, end)', () => { it('returns true if the given row range intersects the visible row range', async () => { @@ -396,7 +411,7 @@ describe('TextEditorElement', () => { const editor = element.getModel() const horizontalScrollbarHeight = element.component.getHorizontalScrollbarHeight() - editor.update({autoHeight: false}) + editor.update({ autoHeight: false }) element.getModel().setText('x\n'.repeat(20)) element.style.height = 120 + horizontalScrollbarHeight + 'px' await element.getNextUpdatePromise() @@ -419,7 +434,7 @@ describe('TextEditorElement', () => { const editor = element.getModel() const horizontalScrollbarHeight = element.component.getHorizontalScrollbarHeight() - editor.update({autoHeight: false}) + editor.update({ autoHeight: false }) element.getModel().setText('xxxxxxxxxxxxxxxxxxxxxx\n'.repeat(20)) element.style.height = 120 + horizontalScrollbarHeight + 'px' await element.getNextUpdatePromise() @@ -445,7 +460,7 @@ describe('TextEditorElement', () => { beforeEach(async () => { element = buildTextEditorElement() - element.getModel().update({autoHeight: false}) + element.getModel().update({ autoHeight: false }) element.getModel().setText('lorem\nipsum\ndolor\nsit\namet') element.setHeight(20) await element.getNextUpdatePromise() @@ -456,7 +471,9 @@ describe('TextEditorElement', () => { describe('::onDidChangeScrollTop(callback)', () => it('triggers even when subscribing before attaching the element', () => { const positions = [] - const subscription1 = element.onDidChangeScrollTop(p => positions.push(p)) + const subscription1 = element.onDidChangeScrollTop(p => + positions.push(p) + ) element.onDidChangeScrollTop(p => positions.push(p)) positions.length = 0 @@ -475,13 +492,14 @@ describe('TextEditorElement', () => { positions.length = 0 element.setScrollTop(30) expect(positions).toEqual([30]) - }) - ) + })) describe('::onDidChangeScrollLeft(callback)', () => it('triggers even when subscribing before attaching the element', () => { const positions = [] - const subscription1 = element.onDidChangeScrollLeft(p => positions.push(p)) + const subscription1 = element.onDidChangeScrollLeft(p => + positions.push(p) + ) element.onDidChangeScrollLeft(p => positions.push(p)) positions.length = 0 @@ -500,7 +518,6 @@ describe('TextEditorElement', () => { positions.length = 0 element.setScrollLeft(30) expect(positions).toEqual([30]) - }) - ) + })) }) }) diff --git a/spec/text-editor-registry-spec.js b/spec/text-editor-registry-spec.js index 4c6d680eb..c6303e4fd 100644 --- a/spec/text-editor-registry-spec.js +++ b/spec/text-editor-registry-spec.js @@ -1,8 +1,8 @@ const TextEditorRegistry = require('../src/text-editor-registry') const TextEditor = require('../src/text-editor') const TextBuffer = require('text-buffer') -const {Point, Range} = TextBuffer -const {it, fit, ffit, fffit} = require('./async-spec-helpers') +const { Point, Range } = TextBuffer +const { it, fit, ffit, fffit } = require('./async-spec-helpers') const dedent = require('dedent') describe('TextEditorRegistry', function () { @@ -15,11 +15,13 @@ describe('TextEditorRegistry', function () { assert: atom.assert, config: atom.config, grammarRegistry: atom.grammars, - packageManager: {deferredActivationHooks: null} + packageManager: { deferredActivationHooks: null } }) - editor = new TextEditor({autoHeight: false}) - expect(atom.grammars.assignLanguageMode(editor, 'text.plain.null-grammar')).toBe(true) + editor = new TextEditor({ autoHeight: false }) + expect( + atom.grammars.assignLanguageMode(editor, 'text.plain.null-grammar') + ).toBe(true) }) afterEach(function () { @@ -68,9 +70,11 @@ describe('TextEditorRegistry', function () { await atom.packages.activatePackage('language-javascript') await atom.packages.activatePackage('language-c') - atom.config.set('editor.tabLength', 8, {scope: '.source.js'}) + atom.config.set('editor.tabLength', 8, { scope: '.source.js' }) - const editor = registry.build({buffer: new TextBuffer({filePath: 'test.js'})}) + const editor = registry.build({ + buffer: new TextBuffer({ filePath: 'test.js' }) + }) expect(editor.getTabLength()).toBe(8) }) }) @@ -87,14 +91,22 @@ describe('TextEditorRegistry', function () { registry.maintainConfig(editor2) await initialPackageActivation - expect(editor.getRootScopeDescriptor().getScopesArray()).toEqual(['text.plain.null-grammar']) - expect(editor2.getRootScopeDescriptor().getScopesArray()).toEqual(['source.js']) + expect(editor.getRootScopeDescriptor().getScopesArray()).toEqual([ + 'text.plain.null-grammar' + ]) + expect(editor2.getRootScopeDescriptor().getScopesArray()).toEqual([ + 'source.js' + ]) expect(editor.getEncoding()).toBe('utf8') expect(editor2.getEncoding()).toBe('utf8') - atom.config.set('core.fileEncoding', 'utf16le', {scopeSelector: '.text.plain.null-grammar'}) - atom.config.set('core.fileEncoding', 'utf16be', {scopeSelector: '.source.js'}) + atom.config.set('core.fileEncoding', 'utf16le', { + scopeSelector: '.text.plain.null-grammar' + }) + atom.config.set('core.fileEncoding', 'utf16be', { + scopeSelector: '.source.js' + }) expect(editor.getEncoding()).toBe('utf16le') expect(editor2.getEncoding()).toBe('utf16be') @@ -131,23 +143,29 @@ describe('TextEditorRegistry', function () { expect(editor.getEncoding()).toBe('utf16be') }) - it('updates the editor\'s settings when its grammar changes', async function () { + it("updates the editor's settings when its grammar changes", async function () { await atom.packages.activatePackage('language-javascript') registry.maintainConfig(editor) await initialPackageActivation - atom.config.set('core.fileEncoding', 'utf16be', {scopeSelector: '.source.js'}) + atom.config.set('core.fileEncoding', 'utf16be', { + scopeSelector: '.source.js' + }) expect(editor.getEncoding()).toBe('utf8') - atom.config.set('core.fileEncoding', 'utf16le', {scopeSelector: '.source.js'}) + atom.config.set('core.fileEncoding', 'utf16le', { + scopeSelector: '.source.js' + }) expect(editor.getEncoding()).toBe('utf8') atom.grammars.assignLanguageMode(editor, 'source.js') await initialPackageActivation expect(editor.getEncoding()).toBe('utf16le') - atom.config.set('core.fileEncoding', 'utf16be', {scopeSelector: '.source.js'}) + atom.config.set('core.fileEncoding', 'utf16be', { + scopeSelector: '.source.js' + }) expect(editor.getEncoding()).toBe('utf16be') atom.grammars.assignLanguageMode(editor, 'text.plain.null-grammar') @@ -155,7 +173,7 @@ describe('TextEditorRegistry', function () { expect(editor.getEncoding()).toBe('utf8') }) - it('preserves editor settings that haven\'t changed between previous and current language modes', async function () { + it("preserves editor settings that haven't changed between previous and current language modes", async function () { await atom.packages.activatePackage('language-javascript') registry.maintainConfig(editor) @@ -182,8 +200,12 @@ describe('TextEditorRegistry', function () { await initialPackageActivation expect(editor.getEncoding()).toBe('utf8') - atom.config.set('core.fileEncoding', 'utf16be', {scopeSelector: '.text.plain.null-grammar'}) - atom.config.set('core.fileEncoding', 'utf16le', {scopeSelector: '.source.js'}) + atom.config.set('core.fileEncoding', 'utf16be', { + scopeSelector: '.text.plain.null-grammar' + }) + atom.config.set('core.fileEncoding', 'utf16le', { + scopeSelector: '.source.js' + }) expect(editor.getEncoding()).toBe('utf16be') editor.setEncoding('utf8') @@ -194,13 +216,15 @@ describe('TextEditorRegistry', function () { expect(editor.getEncoding()).toBe('utf16le') }) - it('returns a disposable that can be used to stop the registry from updating the editor\'s config', async function () { + it("returns a disposable that can be used to stop the registry from updating the editor's config", async function () { await atom.packages.activatePackage('language-javascript') const previousSubscriptionCount = getSubscriptionCount(editor) const disposable = registry.maintainConfig(editor) await initialPackageActivation - expect(getSubscriptionCount(editor)).toBeGreaterThan(previousSubscriptionCount) + expect(getSubscriptionCount(editor)).toBeGreaterThan( + previousSubscriptionCount + ) expect(registry.editorsWithMaintainedConfig.size).toBe(1) atom.config.set('core.fileEncoding', 'utf16be') @@ -217,7 +241,7 @@ describe('TextEditorRegistry', function () { }) it('sets the encoding based on the config', async function () { - editor.update({encoding: 'utf8'}) + editor.update({ encoding: 'utf8' }) expect(editor.getEncoding()).toBe('utf8') atom.config.set('core.fileEncoding', 'utf16le') @@ -230,7 +254,7 @@ describe('TextEditorRegistry', function () { }) it('sets the tab length based on the config', async function () { - editor.update({tabLength: 4}) + editor.update({ tabLength: 4 }) expect(editor.getTabLength()).toBe(4) atom.config.set('editor.tabLength', 8) @@ -257,7 +281,7 @@ describe('TextEditorRegistry', function () { }) describe('when the "tabType" config setting is "auto"', function () { - it('enables or disables soft tabs based on the editor\'s content', async function () { + it("enables or disables soft tabs based on the editor's content", async function () { await initialPackageActivation await atom.packages.activatePackage('language-javascript') atom.grammars.assignLanguageMode(editor, 'source.js') @@ -282,11 +306,14 @@ describe('TextEditorRegistry', function () { disposable = registry.maintainConfig(editor) expect(editor.getSoftTabs()).toBe(false) - editor.setTextInBufferRange(new Range(Point.ZERO, Point.ZERO), dedent` + editor.setTextInBufferRange( + new Range(Point.ZERO, Point.ZERO), + dedent` /* * Comment with a leading space. */ - ` + '\n') + ` + '\n' + ) disposable.dispose() disposable = registry.maintainConfig(editor) expect(editor.getSoftTabs()).toBe(false) @@ -335,7 +362,7 @@ describe('TextEditorRegistry', function () { }) it('enables or disables soft tabs based on the config', async function () { - editor.update({softTabs: true}) + editor.update({ softTabs: true }) expect(editor.getSoftTabs()).toBe(true) atom.config.set('editor.tabType', 'hard') @@ -352,7 +379,7 @@ describe('TextEditorRegistry', function () { }) it('enables or disables atomic soft tabs based on the config', async function () { - editor.update({atomicSoftTabs: true}) + editor.update({ atomicSoftTabs: true }) expect(editor.hasAtomicSoftTabs()).toBe(true) atom.config.set('editor.atomicSoftTabs', false) @@ -365,7 +392,7 @@ describe('TextEditorRegistry', function () { }) it('enables or disables cursor on selection visibility based on the config', async function () { - editor.update({showCursorOnSelection: true}) + editor.update({ showCursorOnSelection: true }) expect(editor.getShowCursorOnSelection()).toBe(true) atom.config.set('editor.showCursorOnSelection', false) @@ -378,7 +405,7 @@ describe('TextEditorRegistry', function () { }) it('enables or disables line numbers based on the config', async function () { - editor.update({showLineNumbers: true}) + editor.update({ showLineNumbers: true }) expect(editor.showLineNumbers).toBe(true) atom.config.set('editor.showLineNumbers', false) @@ -391,8 +418,8 @@ describe('TextEditorRegistry', function () { }) it('sets the invisibles based on the config', async function () { - const invisibles1 = {'tab': 'a', 'cr': false, eol: false, space: false} - const invisibles2 = {'tab': 'b', 'cr': false, eol: false, space: false} + const invisibles1 = { tab: 'a', cr: false, eol: false, space: false } + const invisibles2 = { tab: 'b', cr: false, eol: false, space: false } editor.update({ showInvisibles: true, @@ -414,7 +441,7 @@ describe('TextEditorRegistry', function () { }) it('enables or disables the indent guide based on the config', async function () { - editor.update({showIndentGuide: true}) + editor.update({ showIndentGuide: true }) expect(editor.doesShowIndentGuide()).toBe(true) atom.config.set('editor.showIndentGuide', false) @@ -427,7 +454,7 @@ describe('TextEditorRegistry', function () { }) it('enables or disables soft wrap based on the config', async function () { - editor.update({softWrapped: true}) + editor.update({ softWrapped: true }) expect(editor.isSoftWrapped()).toBe(true) atom.config.set('editor.softWrap', false) @@ -440,7 +467,7 @@ describe('TextEditorRegistry', function () { }) it('sets the soft wrap indent length based on the config', async function () { - editor.update({softWrapHangingIndentLength: 4}) + editor.update({ softWrapHangingIndentLength: 4 }) expect(editor.getSoftWrapHangingIndentLength()).toBe(4) atom.config.set('editor.softWrapHangingIndent', 2) @@ -457,7 +484,7 @@ describe('TextEditorRegistry', function () { softWrapped: true, preferredLineLength: 80, editorWidthInChars: 120, - softWrapAtPreferredLineLength: true, + softWrapAtPreferredLineLength: true }) expect(editor.getSoftWrapColumn()).toBe(80) @@ -475,7 +502,7 @@ describe('TextEditorRegistry', function () { it('allows for custom definition of maximum soft wrap based on config', async function () { editor.update({ softWrapped: false, - maxScreenLineLength: 1500, + maxScreenLineLength: 1500 }) expect(editor.getSoftWrapColumn()).toBe(1500) @@ -488,7 +515,7 @@ describe('TextEditorRegistry', function () { }) it('sets the preferred line length based on the config', async function () { - editor.update({preferredLineLength: 80}) + editor.update({ preferredLineLength: 80 }) expect(editor.getPreferredLineLength()).toBe(80) atom.config.set('editor.preferredLineLength', 110) @@ -501,7 +528,7 @@ describe('TextEditorRegistry', function () { }) it('enables or disables auto-indent based on the config', async function () { - editor.update({autoIndent: true}) + editor.update({ autoIndent: true }) expect(editor.shouldAutoIndent()).toBe(true) atom.config.set('editor.autoIndent', false) @@ -514,7 +541,7 @@ describe('TextEditorRegistry', function () { }) it('enables or disables auto-indent-on-paste based on the config', async function () { - editor.update({autoIndentOnPaste: true}) + editor.update({ autoIndentOnPaste: true }) expect(editor.shouldAutoIndentOnPaste()).toBe(true) atom.config.set('editor.autoIndentOnPaste', false) @@ -527,7 +554,7 @@ describe('TextEditorRegistry', function () { }) it('enables or disables scrolling past the end of the buffer based on the config', async function () { - editor.update({scrollPastEnd: true}) + editor.update({ scrollPastEnd: true }) expect(editor.getScrollPastEnd()).toBe(true) atom.config.set('editor.scrollPastEnd', false) @@ -540,7 +567,7 @@ describe('TextEditorRegistry', function () { }) it('sets the undo grouping interval based on the config', async function () { - editor.update({undoGroupingInterval: 300}) + editor.update({ undoGroupingInterval: 300 }) expect(editor.getUndoGroupingInterval()).toBe(300) atom.config.set('editor.undoGroupingInterval', 600) @@ -553,7 +580,7 @@ describe('TextEditorRegistry', function () { }) it('sets the scroll sensitivity based on the config', async function () { - editor.update({scrollSensitivity: 50}) + editor.update({ scrollSensitivity: 50 }) expect(editor.getScrollSensitivity()).toBe(50) atom.config.set('editor.scrollSensitivity', 60) @@ -567,7 +594,7 @@ describe('TextEditorRegistry', function () { describe('when called twice with a given editor', function () { it('does nothing the second time', async function () { - editor.update({scrollSensitivity: 50}) + editor.update({ scrollSensitivity: 50 }) const disposable1 = registry.maintainConfig(editor) const disposable2 = registry.maintainConfig(editor) @@ -589,10 +616,12 @@ describe('TextEditorRegistry', function () { }) function getSubscriptionCount (editor) { - return editor.emitter.getTotalListenerCount() + + return ( + editor.emitter.getTotalListenerCount() + editor.tokenizedBuffer.emitter.getTotalListenerCount() + editor.buffer.emitter.getTotalListenerCount() + editor.displayLayer.emitter.getTotalListenerCount() + ) } function retainedEditorCount (registry) { diff --git a/spec/text-editor-spec.js b/spec/text-editor-spec.js index 908ea8082..60c8076df 100644 --- a/spec/text-editor-spec.js +++ b/spec/text-editor-spec.js @@ -1,10 +1,19 @@ -const {it, fit, ffit, fffit, beforeEach, afterEach, conditionPromise, timeoutPromise} = require('./async-spec-helpers') +const { + it, + fit, + ffit, + fffit, + beforeEach, + afterEach, + conditionPromise, + timeoutPromise +} = require('./async-spec-helpers') const fs = require('fs') const path = require('path') const temp = require('temp').track() const dedent = require('dedent') -const {clipboard} = require('electron') +const { clipboard } = require('electron') const TextEditor = require('../src/text-editor') const TextBuffer = require('text-buffer') const TextMateLanguageMode = require('../src/text-mate-language-mode') @@ -16,7 +25,7 @@ describe('TextEditor', () => { beforeEach(async () => { editor = await atom.workspace.open('sample.js') buffer = editor.buffer - editor.update({autoIndent: false}) + editor.update({ autoIndent: false }) lineLengths = buffer.getLines().map(line => line.length) await atom.packages.activatePackage('language-javascript') }) @@ -24,8 +33,8 @@ describe('TextEditor', () => { it('generates unique ids for each editor', async () => { // Deserialized editors are initialized with the serialized id. We can // initialize an editor with what we expect to be the next id: - const deserialized = new TextEditor({id: editor.id+1}) - expect(deserialized.id).toEqual(editor.id+1) + const deserialized = new TextEditor({ id: editor.id + 1 }) + expect(deserialized.id).toEqual(editor.id + 1) // The id generator should skip the id used up by the deserialized one: const fresh = new TextEditor() @@ -35,7 +44,7 @@ describe('TextEditor', () => { describe('when the editor is deserialized', () => { it('restores selections and folds based on markers in the buffer', async () => { editor.setSelectedBufferRange([[1, 2], [3, 4]]) - editor.addSelectionForBufferRange([[5, 6], [7, 5]], {reversed: true}) + editor.addSelectionForBufferRange([[5, 6], [7, 5]], { reversed: true }) editor.foldBufferRow(4) expect(editor.isFoldedAtBufferRow(4)).toBeTruthy() @@ -43,12 +52,19 @@ describe('TextEditor', () => { const editor2 = TextEditor.deserialize(editor.serialize(), { assert: atom.assert, textEditors: atom.textEditors, - project: {bufferForIdSync () { return buffer2 }} + project: { + bufferForIdSync () { + return buffer2 + } + } }) expect(editor2.id).toBe(editor.id) expect(editor2.getBuffer().getPath()).toBe(editor.getBuffer().getPath()) - expect(editor2.getSelectedBufferRanges()).toEqual([[[1, 2], [3, 4]], [[5, 6], [7, 5]]]) + expect(editor2.getSelectedBufferRanges()).toEqual([ + [[1, 2], [3, 4]], + [[5, 6], [7, 5]] + ]) expect(editor2.getSelections()[1].isReversed()).toBeTruthy() expect(editor2.isFoldedAtBufferRow(4)).toBeTruthy() editor2.destroy() @@ -62,7 +78,7 @@ describe('TextEditor', () => { softWrapped: true, softWrapAtPreferredLineLength: true, softWrapHangingIndentLength: 8, - invisibles: {space: 'S'}, + invisibles: { space: 'S' }, showInvisibles: true, editorWidthInChars: 120 }) @@ -73,25 +89,39 @@ describe('TextEditor', () => { const editor2 = TextEditor.deserialize(editor.serialize(), { assert: atom.assert, textEditors: atom.textEditors, - project: {bufferForIdSync () { return buffer2 }} + project: { + bufferForIdSync () { + return buffer2 + } + } }) expect(editor2.getSoftTabs()).toBe(editor.getSoftTabs()) expect(editor2.hasAtomicSoftTabs()).toBe(editor.hasAtomicSoftTabs()) expect(editor2.getTabLength()).toBe(editor.getTabLength()) expect(editor2.getSoftWrapColumn()).toBe(editor.getSoftWrapColumn()) - expect(editor2.getSoftWrapHangingIndentLength()).toBe(editor.getSoftWrapHangingIndentLength()) + expect(editor2.getSoftWrapHangingIndentLength()).toBe( + editor.getSoftWrapHangingIndentLength() + ) expect(editor2.getInvisibles()).toEqual(editor.getInvisibles()) - expect(editor2.getEditorWidthInChars()).toBe(editor.getEditorWidthInChars()) + expect(editor2.getEditorWidthInChars()).toBe( + editor.getEditorWidthInChars() + ) expect(editor2.displayLayer.tabLength).toBe(editor2.getTabLength()) - expect(editor2.displayLayer.softWrapColumn).toBe(editor2.getSoftWrapColumn()) + expect(editor2.displayLayer.softWrapColumn).toBe( + editor2.getSoftWrapColumn() + ) }) it('ignores buffers with retired IDs', () => { const editor2 = TextEditor.deserialize(editor.serialize(), { assert: atom.assert, textEditors: atom.textEditors, - project: {bufferForIdSync () { return null }} + project: { + bufferForIdSync () { + return null + } + } }) expect(editor2).toBeNull() @@ -109,9 +139,9 @@ describe('TextEditor', () => { element.setWidth(100) jasmine.attachToDOM(element) - editor.update({showCursorOnSelection: false}) + editor.update({ showCursorOnSelection: false }) editor.setSelectedBufferRange([[1, 2], [3, 4]]) - editor.addSelectionForBufferRange([[5, 6], [7, 8]], {reversed: true}) + editor.addSelectionForBufferRange([[5, 6], [7, 8]], { reversed: true }) editor.setScrollTopRow(3) expect(editor.getScrollTopRow()).toBe(3) editor.setScrollLeftColumn(4) @@ -125,7 +155,9 @@ describe('TextEditor', () => { element2.setWidth(100) jasmine.attachToDOM(element2) expect(editor2.id).not.toBe(editor.id) - expect(editor2.getSelectedBufferRanges()).toEqual(editor.getSelectedBufferRanges()) + expect(editor2.getSelectedBufferRanges()).toEqual( + editor.getSelectedBufferRanges() + ) expect(editor2.getSelections()[1].isReversed()).toBeTruthy() expect(editor2.getScrollTopRow()).toBe(3) expect(editor2.getScrollLeftColumn()).toBe(4) @@ -136,9 +168,13 @@ describe('TextEditor', () => { // editor2 can now diverge from its origin edit session editor2.getLastSelection().setBufferRange([[2, 1], [4, 3]]) - expect(editor2.getSelectedBufferRanges()).not.toEqual(editor.getSelectedBufferRanges()) + expect(editor2.getSelectedBufferRanges()).not.toEqual( + editor.getSelectedBufferRanges() + ) editor2.unfoldBufferRow(4) - expect(editor2.isFoldedAtBufferRow(4)).not.toBe(editor.isFoldedAtBufferRow(4)) + expect(editor2.isFoldedAtBufferRow(4)).not.toBe( + editor.isFoldedAtBufferRow(4) + ) }) }) @@ -147,8 +183,8 @@ describe('TextEditor', () => { let changeSpy const { element } = editor // force element initialization element.setUpdatedSynchronously(false) - editor.update({showInvisibles: true}) - editor.onDidChange(changeSpy = jasmine.createSpy('onDidChange')) + editor.update({ showInvisibles: true }) + editor.onDidChange((changeSpy = jasmine.createSpy('onDidChange'))) const returnedPromise = editor.update({ tabLength: 6, @@ -194,8 +230,12 @@ describe('TextEditor', () => { }) it("returns ' — ' when opened files have identical file names", async () => { - const editor1 = await atom.workspace.open(path.join('sample-theme-1', 'readme')) - const editor2 = await atom.workspace.open(path.join('sample-theme-2', 'readme')) + const editor1 = await atom.workspace.open( + path.join('sample-theme-1', 'readme') + ) + const editor2 = await atom.workspace.open( + path.join('sample-theme-2', 'readme') + ) expect(editor1.getLongTitle()).toBe('readme \u2014 sample-theme-1') expect(editor2.getLongTitle()).toBe('readme \u2014 sample-theme-2') }) @@ -210,10 +250,16 @@ describe('TextEditor', () => { }) it("returns ' — ' when opened files have identical file and same parent dir name", async () => { - const editor1 = await atom.workspace.open(path.join('sample-theme-2', 'src', 'js', 'main.js')) - const editor2 = await atom.workspace.open(path.join('sample-theme-2', 'src', 'js', 'plugin', 'main.js')) + const editor1 = await atom.workspace.open( + path.join('sample-theme-2', 'src', 'js', 'main.js') + ) + const editor2 = await atom.workspace.open( + path.join('sample-theme-2', 'src', 'js', 'plugin', 'main.js') + ) expect(editor1.getLongTitle()).toBe('main.js \u2014 js') - expect(editor2.getLongTitle()).toBe(`main.js \u2014 ${path.join('js', 'plugin')}`) + expect(editor2.getLongTitle()).toBe( + `main.js \u2014 ${path.join('js', 'plugin')}` + ) }) it('returns the filename when the editor is not in the workspace', async () => { @@ -298,7 +344,9 @@ describe('TextEditor', () => { it('emits an event with the old position, new position, and the cursor that moved', () => { const cursorCallback = jasmine.createSpy('cursor-changed-position') - const editorCallback = jasmine.createSpy('editor-changed-cursor-position') + const editorCallback = jasmine.createSpy( + 'editor-changed-cursor-position' + ) editor.getLastCursor().onDidChangePosition(cursorCallback) editor.onDidChangeCursorPosition(editorCallback) @@ -321,7 +369,7 @@ describe('TextEditor', () => { describe('.setCursorScreenPosition(screenPosition)', () => { it('clears a goal column established by vertical movement', () => { // set a goal column by moving down - editor.setCursorScreenPosition({row: 3, column: lineLengths[3]}) + editor.setCursorScreenPosition({ row: 3, column: lineLengths[3] }) editor.moveDown() expect(editor.getCursorScreenPosition().column).not.toBe(6) @@ -367,7 +415,7 @@ describe('TextEditor', () => { it('retains the goal column across lines of differing length', () => { expect(lineLengths[6]).toBeGreaterThan(32) - editor.setCursorScreenPosition({row: 6, column: 32}) + editor.setCursorScreenPosition({ row: 6, column: 32 }) editor.moveUp() expect(editor.getCursorScreenPosition().column).toBe(lineLengths[5]) @@ -432,7 +480,7 @@ describe('TextEditor', () => { }) it('retains the goal column across lines of differing length', () => { - editor.setCursorScreenPosition({row: 3, column: lineLengths[3]}) + editor.setCursorScreenPosition({ row: 3, column: lineLengths[3] }) editor.moveDown() expect(editor.getCursorScreenPosition().column).toBe(lineLengths[4]) @@ -450,12 +498,20 @@ describe('TextEditor', () => { const lastLine = buffer.lineForRow(lastLineIndex) expect(lastLine.length).toBeGreaterThan(0) - editor.setCursorScreenPosition({row: lastLineIndex, column: editor.getTabLength()}) + editor.setCursorScreenPosition({ + row: lastLineIndex, + column: editor.getTabLength() + }) editor.moveDown() - expect(editor.getCursorScreenPosition()).toEqual({row: lastLineIndex, column: lastLine.length}) + expect(editor.getCursorScreenPosition()).toEqual({ + row: lastLineIndex, + column: lastLine.length + }) editor.moveUp() - expect(editor.getCursorScreenPosition().column).toBe(editor.getTabLength()) + expect(editor.getCursorScreenPosition().column).toBe( + editor.getTabLength() + ) }) it('retains a goal column of 0 when moving back up', () => { @@ -463,7 +519,7 @@ describe('TextEditor', () => { const lastLine = buffer.lineForRow(lastLineIndex) expect(lastLine.length).toBeGreaterThan(0) - editor.setCursorScreenPosition({row: lastLineIndex, column: 0}) + editor.setCursorScreenPosition({ row: lastLineIndex, column: 0 }) editor.moveDown() editor.moveUp() expect(editor.getCursorScreenPosition().column).toBe(0) @@ -531,9 +587,12 @@ describe('TextEditor', () => { describe('when the cursor is in the first column', () => { describe('when there is a previous line', () => { it('wraps to the end of the previous line', () => { - editor.setCursorScreenPosition({row: 1, column: 0}) + editor.setCursorScreenPosition({ row: 1, column: 0 }) editor.moveLeft() - expect(editor.getCursorScreenPosition()).toEqual({row: 0, column: buffer.lineForRow(0).length}) + expect(editor.getCursorScreenPosition()).toEqual({ + row: 0, + column: buffer.lineForRow(0).length + }) }) it('moves the cursor by one row up and n columns to the left', () => { @@ -567,9 +626,12 @@ describe('TextEditor', () => { describe('when the cursor is on the first line', () => { it('remains in the same position (0,0)', () => { - editor.setCursorScreenPosition({row: 0, column: 0}) + editor.setCursorScreenPosition({ row: 0, column: 0 }) editor.moveLeft() - expect(editor.getCursorScreenPosition()).toEqual({row: 0, column: 0}) + expect(editor.getCursorScreenPosition()).toEqual({ + row: 0, + column: 0 + }) }) it('remains in the same position (0,0) when columnCount is specified', () => { @@ -667,7 +729,7 @@ describe('TextEditor', () => { const lastLine = buffer.lineForRow(lastLineIndex) expect(lastLine.length).toBeGreaterThan(0) - const lastPosition = {row: lastLineIndex, column: lastLine.length} + const lastPosition = { row: lastLineIndex, column: lastLine.length } editor.setCursorScreenPosition(lastPosition) editor.moveRight() @@ -840,7 +902,7 @@ describe('TextEditor', () => { describe('when invisible characters are enabled with soft tabs', () => { it('moves to the first character of the current line without being confused by the invisible characters', () => { - editor.update({showInvisibles: true}) + editor.update({ showInvisibles: true }) editor.setCursorScreenPosition([1, 7]) editor.moveToFirstCharacterOfLine() expect(editor.getCursorBufferPosition()).toEqual([1, 2]) @@ -851,8 +913,10 @@ describe('TextEditor', () => { describe('when invisible characters are enabled with hard tabs', () => { it('moves to the first character of the current line without being confused by the invisible characters', () => { - editor.update({showInvisibles: true}) - buffer.setTextInRange([[1, 0], [1, Infinity]], '\t\t\ta', {normalizeLineEndings: false}) + editor.update({ showInvisibles: true }) + buffer.setTextInRange([[1, 0], [1, Infinity]], '\t\t\ta', { + normalizeLineEndings: false + }) editor.setCursorScreenPosition([1, 7]) editor.moveToFirstCharacterOfLine() @@ -863,7 +927,7 @@ describe('TextEditor', () => { }) }) - it("clears the goal column", () => { + it('clears the goal column', () => { editor.setText('first\n\nthird') editor.setCursorScreenPosition([0, 3]) editor.moveDown() @@ -1332,7 +1396,9 @@ describe('TextEditor', () => { describe('.getCurrentParagraphBufferRange()', () => { it('returns the buffer range of the current paragraph, delimited by blank lines or the beginning / end of the file', () => { - buffer.setText(' ' + dedent` + buffer.setText( + ' ' + + dedent` I am the first paragraph, bordered by the beginning of the file @@ -1344,17 +1410,27 @@ describe('TextEditor', () => { I am the last paragraph, bordered by the end of the file.\ - `) + ` + ) // in a paragraph editor.setCursorBufferPosition([1, 7]) - expect(editor.getCurrentParagraphBufferRange()).toEqual([[0, 0], [2, 8]]) + expect(editor.getCurrentParagraphBufferRange()).toEqual([ + [0, 0], + [2, 8] + ]) editor.setCursorBufferPosition([7, 1]) - expect(editor.getCurrentParagraphBufferRange()).toEqual([[5, 0], [7, 3]]) + expect(editor.getCurrentParagraphBufferRange()).toEqual([ + [5, 0], + [7, 3] + ]) editor.setCursorBufferPosition([9, 10]) - expect(editor.getCurrentParagraphBufferRange()).toEqual([[9, 0], [10, 32]]) + expect(editor.getCurrentParagraphBufferRange()).toEqual([ + [9, 0], + [10, 32] + ]) // between paragraphs editor.setCursorBufferPosition([3, 1]) @@ -1415,7 +1491,9 @@ describe('TextEditor', () => { describe('getCursorAtScreenPosition(screenPosition)', () => { it('returns the cursor at the given screenPosition', () => { const cursor1 = editor.addCursorAtScreenPosition([0, 2]) - const cursor2 = editor.getCursorAtScreenPosition(cursor1.getScreenPosition()) + const cursor2 = editor.getCursorAtScreenPosition( + cursor1.getScreenPosition() + ) expect(cursor2).toBe(cursor1) }) }) @@ -1425,7 +1503,11 @@ describe('TextEditor', () => { editor.foldBufferRow(4) const cursor1 = editor.addCursorAtBufferPosition([8, 5]) const cursor2 = editor.addCursorAtBufferPosition([3, 5]) - expect(editor.getCursorScreenPositions()).toEqual([[0, 0], [5, 5], [3, 5]]) + expect(editor.getCursorScreenPositions()).toEqual([ + [0, 0], + [5, 5], + [3, 5] + ]) }) }) @@ -1434,7 +1516,11 @@ describe('TextEditor', () => { const originalCursor = editor.getLastCursor() const cursor1 = editor.addCursorAtBufferPosition([8, 5]) const cursor2 = editor.addCursorAtBufferPosition([4, 5]) - expect(editor.getCursorsOrderedByBufferPosition()).toEqual([originalCursor, cursor2, cursor1]) + expect(editor.getCursorsOrderedByBufferPosition()).toEqual([ + originalCursor, + cursor2, + cursor1 + ]) }) }) @@ -1476,7 +1562,10 @@ describe('TextEditor', () => { describe('.getLastSelection()', () => { it('creates a new selection at (0, 0) if the last selection has been destroyed', () => { editor.getLastSelection().destroy() - expect(editor.getLastSelection().getBufferRange()).toEqual([[0, 0], [0, 0]]) + expect(editor.getLastSelection().getBufferRange()).toEqual([ + [0, 0], + [0, 0] + ]) }) it("doesn't get stuck in a infinite loop when called from ::onDidAddCursor after the last selection has been destroyed (regression)", () => { @@ -1486,7 +1575,10 @@ describe('TextEditor', () => { callCount++ editor.getLastSelection() }) - expect(editor.getLastSelection().getBufferRange()).toEqual([[0, 0], [0, 0]]) + expect(editor.getLastSelection().getBufferRange()).toEqual([ + [0, 0], + [0, 0] + ]) expect(callCount).toBe(1) }) }) @@ -1494,7 +1586,10 @@ describe('TextEditor', () => { describe('.getSelections()', () => { it('creates a new selection at (0, 0) if the last selection has been destroyed', () => { editor.getLastSelection().destroy() - expect(editor.getSelections()[0].getBufferRange()).toEqual([[0, 0], [0, 0]]) + expect(editor.getSelections()[0].getBufferRange()).toEqual([ + [0, 0], + [0, 0] + ]) }) }) @@ -1503,7 +1598,9 @@ describe('TextEditor', () => { let rangeChangedHandler editor.setSelectedBufferRange([[3, 0], [4, 5]]) - editor.onDidChangeSelectionRange(rangeChangedHandler = jasmine.createSpy()) + editor.onDidChangeSelectionRange( + (rangeChangedHandler = jasmine.createSpy()) + ) editor.selectToBufferPosition([6, 2]) expect(rangeChangedHandler).toHaveBeenCalled() @@ -1541,7 +1638,11 @@ describe('TextEditor', () => { }) it('merges selections when they intersect when moving down', () => { - editor.setSelectedBufferRanges([[[0, 9], [0, 13]], [[1, 10], [1, 20]], [[2, 15], [3, 25]]]) + editor.setSelectedBufferRanges([ + [[0, 9], [0, 13]], + [[1, 10], [1, 20]], + [[2, 15], [3, 25]] + ]) const [selection1, selection2, selection3] = editor.getSelections() editor.selectDown() @@ -1551,7 +1652,10 @@ describe('TextEditor', () => { }) it('merges selections when they intersect when moving up', () => { - editor.setSelectedBufferRanges([[[0, 9], [0, 13]], [[1, 10], [1, 20]]], {reversed: true}) + editor.setSelectedBufferRanges( + [[[0, 9], [0, 13]], [[1, 10], [1, 20]]], + { reversed: true } + ) const [selection1, selection2] = editor.getSelections() editor.selectUp() @@ -1562,7 +1666,10 @@ describe('TextEditor', () => { }) it('merges selections when they intersect when moving left', () => { - editor.setSelectedBufferRanges([[[0, 9], [0, 13]], [[0, 13], [1, 20]]], {reversed: true}) + editor.setSelectedBufferRanges( + [[[0, 9], [0, 13]], [[0, 13], [1, 20]]], + { reversed: true } + ) const [selection1, selection2] = editor.getSelections() editor.selectLeft() @@ -1583,7 +1690,10 @@ describe('TextEditor', () => { describe('when counts are passed into the selection functions', () => { it("expands each selection to its cursor's new location", () => { - editor.setSelectedBufferRanges([[[0, 9], [0, 13]], [[3, 16], [3, 21]]]) + editor.setSelectedBufferRanges([ + [[0, 9], [0, 13]], + [[3, 16], [3, 21]] + ]) const [selection1, selection2] = editor.getSelections() editor.selectRight(2) @@ -1687,8 +1797,8 @@ describe('TextEditor', () => { editor.selectToScreenPosition([4, 11]) selections = editor.getSelections() - expect(selections.length).toBe(1); - [selection1] = selections + expect(selections.length).toBe(1) + ;[selection1] = selections expect(selection1.getScreenRange()).toEqual([[3, 10], [7, 4]]) expect(selection1.isReversed()).toBeTruthy() }) @@ -1701,7 +1811,10 @@ describe('TextEditor', () => { editor.selectToTop() expect(editor.getCursors().length).toBe(1) expect(editor.getCursorBufferPosition()).toEqual([0, 0]) - expect(editor.getLastSelection().getBufferRange()).toEqual([[0, 0], [11, 2]]) + expect(editor.getLastSelection().getBufferRange()).toEqual([ + [0, 0], + [11, 2] + ]) expect(editor.getLastSelection().isReversed()).toBeTruthy() }) }) @@ -1713,7 +1826,10 @@ describe('TextEditor', () => { editor.selectToBottom() expect(editor.getCursors().length).toBe(1) expect(editor.getCursorBufferPosition()).toEqual([12, 2]) - expect(editor.getLastSelection().getBufferRange()).toEqual([[9, 3], [12, 2]]) + expect(editor.getLastSelection().getBufferRange()).toEqual([ + [9, 3], + [12, 2] + ]) expect(editor.getLastSelection().isReversed()).toBeFalsy() }) }) @@ -1721,7 +1837,9 @@ describe('TextEditor', () => { describe('.selectAll()', () => { it('selects the entire buffer', () => { editor.selectAll() - expect(editor.getLastSelection().getBufferRange()).toEqual(buffer.getRange()) + expect(editor.getLastSelection().getBufferRange()).toEqual( + buffer.getRange() + ) }) }) @@ -1772,7 +1890,9 @@ describe('TextEditor', () => { editor.setCursorScreenPosition([1, 2]) editor.selectLinesContainingCursors() expect(editor.getSelectedBufferRange()).toEqual([[1, 0], [2, 0]]) - expect(editor.getSelectedText()).toBe(' var sort = function(items) {\n') + expect(editor.getSelectedText()).toBe( + ' var sort = function(items) {\n' + ) editor.setCursorScreenPosition([12, 2]) editor.selectLinesContainingCursors() @@ -1867,7 +1987,12 @@ describe('TextEditor', () => { editor.selectToPreviousWordBoundary() expect(editor.getSelections().length).toBe(4) - const [selection1, selection2, selection3, selection4] = editor.getSelections() + const [ + selection1, + selection2, + selection3, + selection4 + ] = editor.getSelections() expect(selection1.getBufferRange()).toEqual([[0, 8], [0, 4]]) expect(selection1.isReversed()).toBeTruthy() expect(selection2.getBufferRange()).toEqual([[2, 0], [1, 30]]) @@ -1889,7 +2014,12 @@ describe('TextEditor', () => { editor.selectToNextWordBoundary() expect(editor.getSelections().length).toBe(4) - const [selection1, selection2, selection3, selection4] = editor.getSelections() + const [ + selection1, + selection2, + selection3, + selection4 + ] = editor.getSelections() expect(selection1.getBufferRange()).toEqual([[0, 8], [0, 13]]) expect(selection1.isReversed()).toBeFalsy() expect(selection2.getBufferRange()).toEqual([[2, 40], [3, 0]]) @@ -1912,7 +2042,12 @@ describe('TextEditor', () => { editor.addCursorAtBufferPosition([1, 7]) editor.addCursorAtBufferPosition([2, 5]) editor.addCursorAtBufferPosition([3, 3]) - const [selection1, selection2, selection3, selection4] = editor.getSelections() + const [ + selection1, + selection2, + selection3, + selection4 + ] = editor.getSelections() editor.selectToPreviousSubwordBoundary() expect(selection1.getBufferRange()).toEqual([[0, 1], [0, 5]]) @@ -1937,7 +2072,12 @@ describe('TextEditor', () => { editor.addCursorAtBufferPosition([1, 7]) editor.addCursorAtBufferPosition([2, 2]) editor.addCursorAtBufferPosition([3, 1]) - const [selection1, selection2, selection3, selection4] = editor.getSelections() + const [ + selection1, + selection2, + selection3, + selection4 + ] = editor.getSelections() editor.selectToNextSubwordBoundary() expect(selection1.getBufferRange()).toEqual([[0, 1], [0, 4]]) @@ -2083,13 +2223,23 @@ describe('TextEditor', () => { editor.setCursorBufferPosition([0, 1]) editor.addCursorAtBufferPosition([0, 12]) - const scopeDescriptors = editor.getCursors().map(c => c.getScopeDescriptor()) + const scopeDescriptors = editor + .getCursors() + .map(c => c.getScopeDescriptor()) expect(scopeDescriptors[0].getScopesArray()).toEqual(['source.js']) - expect(scopeDescriptors[1].getScopesArray()).toEqual(['source.js', 'string.quoted']) + expect(scopeDescriptors[1].getScopesArray()).toEqual([ + 'source.js', + 'string.quoted' + ]) - spyOn(editor.getBuffer().getLanguageMode(), 'getNonWordCharacters').andCallFake(function (position) { - const result = '/\()"\':,.;<>~!@#$%^&*|+=[]{}`?' - const scopes = this.scopeDescriptorForPosition(position).getScopesArray() + spyOn( + editor.getBuffer().getLanguageMode(), + 'getNonWordCharacters' + ).andCallFake(function (position) { + const result = '/()"\':,.;<>~!@#$%^&*|+=[]{}`?' + const scopes = this.scopeDescriptorForPosition( + position + ).getScopesArray() if (scopes.some(scope => scope.startsWith('string'))) { return result } else { @@ -2122,8 +2272,8 @@ describe('TextEditor', () => { expect(selection2.getBufferRange()).toEqual([[1, 2], [1, 7]]) expect(selection2.isReversed()).toBeTruthy() - editor.selectToFirstCharacterOfLine(); - [selection1, selection2] = editor.getSelections() + editor.selectToFirstCharacterOfLine() + ;[selection1, selection2] = editor.getSelections() expect(selection1.getBufferRange()).toEqual([[0, 0], [0, 5]]) expect(selection1.isReversed()).toBeTruthy() expect(selection2.getBufferRange()).toEqual([[1, 0], [1, 7]]) @@ -2134,7 +2284,10 @@ describe('TextEditor', () => { describe('.setSelectedBufferRanges(ranges)', () => { it('clears existing selections and creates selections for each of the given ranges', () => { editor.setSelectedBufferRanges([[[2, 2], [3, 3]], [[4, 4], [5, 5]]]) - expect(editor.getSelectedBufferRanges()).toEqual([[[2, 2], [3, 3]], [[4, 4], [5, 5]]]) + expect(editor.getSelectedBufferRanges()).toEqual([ + [[2, 2], [3, 3]], + [[4, 4], [5, 5]] + ]) editor.setSelectedBufferRanges([[[5, 5], [6, 6]]]) expect(editor.getSelectedBufferRanges()).toEqual([[[5, 5], [6, 6]]]) @@ -2147,7 +2300,10 @@ describe('TextEditor', () => { it('does not merge non-empty adjacent selections', () => { editor.setSelectedBufferRanges([[[2, 2], [3, 3]], [[3, 3], [5, 5]]]) - expect(editor.getSelectedBufferRanges()).toEqual([[[2, 2], [3, 3]], [[3, 3], [5, 5]]]) + expect(editor.getSelectedBufferRanges()).toEqual([ + [[2, 2], [3, 3]], + [[3, 3], [5, 5]] + ]) }) it('recycles existing selection instances', () => { @@ -2183,7 +2339,9 @@ describe('TextEditor', () => { editor.setSelectedBufferRange([[0, 0], [0, 0]]) editor.foldBufferRowRange(1, 4) editor.foldBufferRowRange(6, 8) - editor.setSelectedBufferRanges([[[2, 2], [3, 3]], [[6, 0], [6, 1]]], {preserveFolds: true}) + editor.setSelectedBufferRanges([[[2, 2], [3, 3]], [[6, 0], [6, 1]]], { + preserveFolds: true + }) expect(editor.isFoldedAtBufferRow(1)).toBeTruthy() expect(editor.isFoldedAtBufferRow(6)).toBeTruthy() }) @@ -2195,7 +2353,10 @@ describe('TextEditor', () => { it('clears existing selections and creates selections for each of the given ranges', () => { editor.setSelectedScreenRanges([[[3, 4], [3, 7]], [[5, 4], [5, 7]]]) - expect(editor.getSelectedBufferRanges()).toEqual([[[3, 4], [3, 7]], [[8, 4], [8, 7]]]) + expect(editor.getSelectedBufferRanges()).toEqual([ + [[3, 4], [3, 7]], + [[8, 4], [8, 7]] + ]) editor.setSelectedScreenRanges([[[6, 2], [6, 4]]]) expect(editor.getSelectedScreenRanges()).toEqual([[[6, 2], [6, 4]]]) @@ -2241,7 +2402,10 @@ describe('TextEditor', () => { describe('.addSelectionForBufferRange(bufferRange)', () => { it('adds a selection for the specified buffer range', () => { editor.addSelectionForBufferRange([[3, 4], [5, 6]]) - expect(editor.getSelectedBufferRanges()).toEqual([[[0, 0], [0, 0]], [[3, 4], [5, 6]]]) + expect(editor.getSelectedBufferRanges()).toEqual([ + [[0, 0], [0, 0]], + [[3, 4], [5, 6]] + ]) }) }) @@ -2316,7 +2480,10 @@ describe('TextEditor', () => { }) it('takes atomic tokens into account', async () => { - editor = await atom.workspace.open('sample-with-tabs-and-leading-comment.coffee', {autoIndent: false}) + editor = await atom.workspace.open( + 'sample-with-tabs-and-leading-comment.coffee', + { autoIndent: false } + ) editor.setSelectedBufferRange([[2, 1], [2, 3]]) editor.addSelectionBelow() expect(editor.getSelectedBufferRanges()).toEqual([ @@ -2392,7 +2559,9 @@ describe('TextEditor', () => { editor.setCursorBufferPosition([0, 1]) let addedSelectionCount = 0 - editor.onDidAddSelection(() => { addedSelectionCount++ }) + editor.onDidAddSelection(() => { + addedSelectionCount++ + }) editor.addSelectionBelow() editor.addSelectionBelow() @@ -2451,7 +2620,10 @@ describe('TextEditor', () => { }) it('takes atomic tokens into account', async () => { - editor = await atom.workspace.open('sample-with-tabs-and-leading-comment.coffee', {autoIndent: false}) + editor = await atom.workspace.open( + 'sample-with-tabs-and-leading-comment.coffee', + { autoIndent: false } + ) editor.setSelectedBufferRange([[3, 1], [3, 2]]) editor.addSelectionAbove() expect(editor.getSelectedBufferRanges()).toEqual([ @@ -2527,7 +2699,9 @@ describe('TextEditor', () => { editor.setCursorBufferPosition([4, 1]) let addedSelectionCount = 0 - editor.onDidAddSelection(() => { addedSelectionCount++ }) + editor.onDidAddSelection(() => { + addedSelectionCount++ + }) editor.addSelectionAbove() editor.addSelectionAbove() @@ -2565,7 +2739,12 @@ describe('TextEditor', () => { const selection2 = editor.addSelectionForBufferRange([[3, 25], [3, 34]]) const selection3 = editor.addSelectionForBufferRange([[8, 4], [8, 10]]) const selection4 = editor.addSelectionForBufferRange([[1, 6], [1, 10]]) - expect(editor.getSelections()).toEqual([selection, selection2, selection3, selection4]) + expect(editor.getSelections()).toEqual([ + selection, + selection2, + selection3, + selection4 + ]) return [selection, selection2, selection3, selection4] } @@ -2582,7 +2761,10 @@ describe('TextEditor', () => { expect(editor.getSelections()).toEqual([selection1]) expect(autoscrollEvents).toEqual([ - {screenRange: selection1.getScreenRange(), options: {center: true, reversed: false}} + { + screenRange: selection1.getScreenRange(), + options: { center: true, reversed: false } + } ]) }) }) @@ -2620,7 +2802,9 @@ describe('TextEditor', () => { expect(editor2.getText()).toBe(editor.getText()) editor.setSelectedBufferRanges([[[1, 2], [3, 4]], [[5, 6], [7, 8]]]) editor2.setSelectedBufferRanges([[[8, 7], [6, 5]], [[4, 3], [2, 1]]]) - expect(editor2.getSelectedBufferRanges()).not.toEqual(editor.getSelectedBufferRanges()) + expect(editor2.getSelectedBufferRanges()).not.toEqual( + editor.getSelectedBufferRanges() + ) }) }) @@ -2629,13 +2813,15 @@ describe('TextEditor', () => { it('moves the line under the cursor up', () => { editor.setCursorBufferPosition([1, 0]) editor.moveLineUp() - expect(editor.getTextInBufferRange([[0, 0], [0, 30]])).toBe(' var sort = function(items) {') + expect(editor.getTextInBufferRange([[0, 0], [0, 30]])).toBe( + ' var sort = function(items) {' + ) expect(editor.indentationForBufferRow(0)).toBe(1) expect(editor.indentationForBufferRow(1)).toBe(0) }) it("updates the line's indentation when the the autoIndent setting is true", () => { - editor.update({autoIndent: true}) + editor.update({ autoIndent: true }) editor.setCursorBufferPosition([1, 0]) editor.moveLineUp() expect(editor.indentationForBufferRow(0)).toBe(0) @@ -2646,24 +2832,35 @@ describe('TextEditor', () => { describe('when the selection spans a single line', () => { describe('when there is no fold in the preceeding row', () => it('moves the line to the preceding row', () => { - expect(editor.lineTextForBufferRow(2)).toBe(' if (items.length <= 1) return items;') - expect(editor.lineTextForBufferRow(3)).toBe(' var pivot = items.shift(), current, left = [], right = [];') + expect(editor.lineTextForBufferRow(2)).toBe( + ' if (items.length <= 1) return items;' + ) + expect(editor.lineTextForBufferRow(3)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) editor.setSelectedBufferRange([[3, 2], [3, 9]]) editor.moveLineUp() expect(editor.getSelectedBufferRange()).toEqual([[2, 2], [2, 9]]) - expect(editor.lineTextForBufferRow(2)).toBe(' var pivot = items.shift(), current, left = [], right = [];') - expect(editor.lineTextForBufferRow(3)).toBe(' if (items.length <= 1) return items;') - }) - ) + expect(editor.lineTextForBufferRow(2)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) + expect(editor.lineTextForBufferRow(3)).toBe( + ' if (items.length <= 1) return items;' + ) + })) describe('when the cursor is at the beginning of a fold', () => it('moves the line to the previous row without breaking the fold', () => { - expect(editor.lineTextForBufferRow(4)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(4)).toBe( + ' while(items.length > 0) {' + ) editor.foldBufferRowRange(4, 7) - editor.setSelectedBufferRange([[4, 2], [4, 9]], {preserveFolds: true}) + editor.setSelectedBufferRange([[4, 2], [4, 9]], { + preserveFolds: true + }) expect(editor.getSelectedBufferRange()).toEqual([[4, 2], [4, 9]]) expect(editor.isFoldedAtBufferRow(4)).toBeTruthy() @@ -2675,20 +2872,25 @@ describe('TextEditor', () => { editor.moveLineUp() expect(editor.getSelectedBufferRange()).toEqual([[3, 2], [3, 9]]) - expect(editor.lineTextForBufferRow(3)).toBe(' while(items.length > 0) {') - expect(editor.lineTextForBufferRow(7)).toBe(' var pivot = items.shift(), current, left = [], right = [];') + expect(editor.lineTextForBufferRow(3)).toBe( + ' while(items.length > 0) {' + ) + expect(editor.lineTextForBufferRow(7)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) expect(editor.isFoldedAtBufferRow(3)).toBeTruthy() expect(editor.isFoldedAtBufferRow(4)).toBeTruthy() expect(editor.isFoldedAtBufferRow(5)).toBeTruthy() expect(editor.isFoldedAtBufferRow(6)).toBeTruthy() expect(editor.isFoldedAtBufferRow(7)).toBeFalsy() - }) - ) + })) describe('when the preceding row consists of folded code', () => it('moves the line above the folded row and perseveres the correct folds', () => { - expect(editor.lineTextForBufferRow(8)).toBe(' return sort(left).concat(pivot).concat(sort(right));') + expect(editor.lineTextForBufferRow(8)).toBe( + ' return sort(left).concat(pivot).concat(sort(right));' + ) expect(editor.lineTextForBufferRow(9)).toBe(' };') editor.foldBufferRowRange(4, 7) @@ -2703,38 +2905,57 @@ describe('TextEditor', () => { editor.moveLineUp() expect(editor.getSelectedBufferRange()).toEqual([[4, 0], [4, 4]]) - expect(editor.lineTextForBufferRow(4)).toBe(' return sort(left).concat(pivot).concat(sort(right));') - expect(editor.lineTextForBufferRow(5)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(4)).toBe( + ' return sort(left).concat(pivot).concat(sort(right));' + ) + expect(editor.lineTextForBufferRow(5)).toBe( + ' while(items.length > 0) {' + ) expect(editor.isFoldedAtBufferRow(5)).toBeTruthy() expect(editor.isFoldedAtBufferRow(6)).toBeTruthy() expect(editor.isFoldedAtBufferRow(7)).toBeTruthy() expect(editor.isFoldedAtBufferRow(8)).toBeTruthy() expect(editor.isFoldedAtBufferRow(9)).toBeFalsy() - }) - ) + })) }) describe('when the selection spans multiple lines', () => { it('moves the lines spanned by the selection to the preceding row', () => { - expect(editor.lineTextForBufferRow(2)).toBe(' if (items.length <= 1) return items;') - expect(editor.lineTextForBufferRow(3)).toBe(' var pivot = items.shift(), current, left = [], right = [];') - expect(editor.lineTextForBufferRow(4)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(2)).toBe( + ' if (items.length <= 1) return items;' + ) + expect(editor.lineTextForBufferRow(3)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) + expect(editor.lineTextForBufferRow(4)).toBe( + ' while(items.length > 0) {' + ) editor.setSelectedBufferRange([[3, 2], [4, 9]]) editor.moveLineUp() expect(editor.getSelectedBufferRange()).toEqual([[2, 2], [3, 9]]) - expect(editor.lineTextForBufferRow(2)).toBe(' var pivot = items.shift(), current, left = [], right = [];') - expect(editor.lineTextForBufferRow(3)).toBe(' while(items.length > 0) {') - expect(editor.lineTextForBufferRow(4)).toBe(' if (items.length <= 1) return items;') + expect(editor.lineTextForBufferRow(2)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) + expect(editor.lineTextForBufferRow(3)).toBe( + ' while(items.length > 0) {' + ) + expect(editor.lineTextForBufferRow(4)).toBe( + ' if (items.length <= 1) return items;' + ) }) describe("when the selection's end intersects a fold", () => it('moves the lines to the previous row without breaking the fold', () => { - expect(editor.lineTextForBufferRow(4)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(4)).toBe( + ' while(items.length > 0) {' + ) editor.foldBufferRowRange(4, 7) - editor.setSelectedBufferRange([[3, 2], [4, 9]], {preserveFolds: true}) + editor.setSelectedBufferRange([[3, 2], [4, 9]], { + preserveFolds: true + }) expect(editor.isFoldedAtBufferRow(3)).toBeFalsy() expect(editor.isFoldedAtBufferRow(4)).toBeTruthy() @@ -2746,9 +2967,15 @@ describe('TextEditor', () => { editor.moveLineUp() expect(editor.getSelectedBufferRange()).toEqual([[2, 2], [3, 9]]) - expect(editor.lineTextForBufferRow(2)).toBe(' var pivot = items.shift(), current, left = [], right = [];') - expect(editor.lineTextForBufferRow(3)).toBe(' while(items.length > 0) {') - expect(editor.lineTextForBufferRow(7)).toBe(' if (items.length <= 1) return items;') + expect(editor.lineTextForBufferRow(2)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) + expect(editor.lineTextForBufferRow(3)).toBe( + ' while(items.length > 0) {' + ) + expect(editor.lineTextForBufferRow(7)).toBe( + ' if (items.length <= 1) return items;' + ) expect(editor.isFoldedAtBufferRow(2)).toBeFalsy() expect(editor.isFoldedAtBufferRow(3)).toBeTruthy() @@ -2756,15 +2983,18 @@ describe('TextEditor', () => { expect(editor.isFoldedAtBufferRow(5)).toBeTruthy() expect(editor.isFoldedAtBufferRow(6)).toBeTruthy() expect(editor.isFoldedAtBufferRow(7)).toBeFalsy() - }) - ) + })) describe("when the selection's start intersects a fold", () => it('moves the lines to the previous row without breaking the fold', () => { - expect(editor.lineTextForBufferRow(4)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(4)).toBe( + ' while(items.length > 0) {' + ) editor.foldBufferRowRange(4, 7) - editor.setSelectedBufferRange([[4, 2], [8, 9]], {preserveFolds: true}) + editor.setSelectedBufferRange([[4, 2], [8, 9]], { + preserveFolds: true + }) expect(editor.isFoldedAtBufferRow(4)).toBeTruthy() expect(editor.isFoldedAtBufferRow(5)).toBeTruthy() @@ -2776,9 +3006,15 @@ describe('TextEditor', () => { editor.moveLineUp() expect(editor.getSelectedBufferRange()).toEqual([[3, 2], [7, 9]]) - expect(editor.lineTextForBufferRow(3)).toBe(' while(items.length > 0) {') - expect(editor.lineTextForBufferRow(7)).toBe(' return sort(left).concat(pivot).concat(sort(right));') - expect(editor.lineTextForBufferRow(8)).toBe(' var pivot = items.shift(), current, left = [], right = [];') + expect(editor.lineTextForBufferRow(3)).toBe( + ' while(items.length > 0) {' + ) + expect(editor.lineTextForBufferRow(7)).toBe( + ' return sort(left).concat(pivot).concat(sort(right));' + ) + expect(editor.lineTextForBufferRow(8)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) expect(editor.isFoldedAtBufferRow(3)).toBeTruthy() expect(editor.isFoldedAtBufferRow(4)).toBeTruthy() @@ -2786,29 +3022,42 @@ describe('TextEditor', () => { expect(editor.isFoldedAtBufferRow(6)).toBeTruthy() expect(editor.isFoldedAtBufferRow(7)).toBeFalsy() expect(editor.isFoldedAtBufferRow(8)).toBeFalsy() - }) - ) + })) }) describe('when the selection spans multiple lines, but ends at column 0', () => { it('does not move the last line of the selection', () => { - expect(editor.lineTextForBufferRow(2)).toBe(' if (items.length <= 1) return items;') - expect(editor.lineTextForBufferRow(3)).toBe(' var pivot = items.shift(), current, left = [], right = [];') - expect(editor.lineTextForBufferRow(4)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(2)).toBe( + ' if (items.length <= 1) return items;' + ) + expect(editor.lineTextForBufferRow(3)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) + expect(editor.lineTextForBufferRow(4)).toBe( + ' while(items.length > 0) {' + ) editor.setSelectedBufferRange([[3, 2], [4, 0]]) editor.moveLineUp() expect(editor.getSelectedBufferRange()).toEqual([[2, 2], [3, 0]]) - expect(editor.lineTextForBufferRow(2)).toBe(' var pivot = items.shift(), current, left = [], right = [];') - expect(editor.lineTextForBufferRow(3)).toBe(' if (items.length <= 1) return items;') - expect(editor.lineTextForBufferRow(4)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(2)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) + expect(editor.lineTextForBufferRow(3)).toBe( + ' if (items.length <= 1) return items;' + ) + expect(editor.lineTextForBufferRow(4)).toBe( + ' while(items.length > 0) {' + ) }) }) describe('when the preceeding row is a folded row', () => { it('moves the lines spanned by the selection to the preceeding row, but preserves the folded code', () => { - expect(editor.lineTextForBufferRow(8)).toBe(' return sort(left).concat(pivot).concat(sort(right));') + expect(editor.lineTextForBufferRow(8)).toBe( + ' return sort(left).concat(pivot).concat(sort(right));' + ) expect(editor.lineTextForBufferRow(9)).toBe(' };') editor.foldBufferRowRange(4, 7) @@ -2822,9 +3071,13 @@ describe('TextEditor', () => { editor.moveLineUp() expect(editor.getSelectedBufferRange()).toEqual([[4, 0], [5, 2]]) - expect(editor.lineTextForBufferRow(4)).toBe(' return sort(left).concat(pivot).concat(sort(right));') + expect(editor.lineTextForBufferRow(4)).toBe( + ' return sort(left).concat(pivot).concat(sort(right));' + ) expect(editor.lineTextForBufferRow(5)).toBe(' };') - expect(editor.lineTextForBufferRow(6)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(6)).toBe( + ' while(items.length > 0) {' + ) expect(editor.isFoldedAtBufferRow(5)).toBeFalsy() expect(editor.isFoldedAtBufferRow(6)).toBeTruthy() expect(editor.isFoldedAtBufferRow(7)).toBeTruthy() @@ -2839,28 +3092,49 @@ describe('TextEditor', () => { describe('when all the selections span different lines', () => { describe('when there is no folds', () => it('moves all lines that are spanned by a selection to the preceding row', () => { - editor.setSelectedBufferRanges([[[1, 2], [1, 9]], [[3, 2], [3, 9]], [[5, 2], [5, 9]]]) + editor.setSelectedBufferRanges([ + [[1, 2], [1, 9]], + [[3, 2], [3, 9]], + [[5, 2], [5, 9]] + ]) editor.moveLineUp() - expect(editor.getSelectedBufferRanges()).toEqual([[[0, 2], [0, 9]], [[2, 2], [2, 9]], [[4, 2], [4, 9]]]) - expect(editor.lineTextForBufferRow(0)).toBe(' var sort = function(items) {') - expect(editor.lineTextForBufferRow(1)).toBe('var quicksort = function () {') - expect(editor.lineTextForBufferRow(2)).toBe(' var pivot = items.shift(), current, left = [], right = [];') - expect(editor.lineTextForBufferRow(3)).toBe(' if (items.length <= 1) return items;') - expect(editor.lineTextForBufferRow(4)).toBe(' current = items.shift();') - expect(editor.lineTextForBufferRow(5)).toBe(' while(items.length > 0) {') - }) - ) + expect(editor.getSelectedBufferRanges()).toEqual([ + [[0, 2], [0, 9]], + [[2, 2], [2, 9]], + [[4, 2], [4, 9]] + ]) + expect(editor.lineTextForBufferRow(0)).toBe( + ' var sort = function(items) {' + ) + expect(editor.lineTextForBufferRow(1)).toBe( + 'var quicksort = function () {' + ) + expect(editor.lineTextForBufferRow(2)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) + expect(editor.lineTextForBufferRow(3)).toBe( + ' if (items.length <= 1) return items;' + ) + expect(editor.lineTextForBufferRow(4)).toBe( + ' current = items.shift();' + ) + expect(editor.lineTextForBufferRow(5)).toBe( + ' while(items.length > 0) {' + ) + })) describe('when one selection intersects a fold', () => it('moves the lines to the previous row without breaking the fold', () => { - expect(editor.lineTextForBufferRow(4)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(4)).toBe( + ' while(items.length > 0) {' + ) editor.foldBufferRowRange(4, 7) - editor.setSelectedBufferRanges([ - [[2, 2], [2, 9]], - [[4, 2], [4, 9]] - ], {preserveFolds: true}) + editor.setSelectedBufferRanges( + [[[2, 2], [2, 9]], [[4, 2], [4, 9]]], + { preserveFolds: true } + ) expect(editor.isFoldedAtBufferRow(2)).toBeFalsy() expect(editor.isFoldedAtBufferRow(3)).toBeFalsy() @@ -2878,10 +3152,18 @@ describe('TextEditor', () => { [[3, 2], [3, 9]] ]) - expect(editor.lineTextForBufferRow(1)).toBe(' if (items.length <= 1) return items;') - expect(editor.lineTextForBufferRow(2)).toBe(' var sort = function(items) {') - expect(editor.lineTextForBufferRow(3)).toBe(' while(items.length > 0) {') - expect(editor.lineTextForBufferRow(7)).toBe(' var pivot = items.shift(), current, left = [], right = [];') + expect(editor.lineTextForBufferRow(1)).toBe( + ' if (items.length <= 1) return items;' + ) + expect(editor.lineTextForBufferRow(2)).toBe( + ' var sort = function(items) {' + ) + expect(editor.lineTextForBufferRow(3)).toBe( + ' while(items.length > 0) {' + ) + expect(editor.lineTextForBufferRow(7)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) expect(editor.isFoldedAtBufferRow(1)).toBeFalsy() expect(editor.isFoldedAtBufferRow(2)).toBeFalsy() @@ -2891,8 +3173,7 @@ describe('TextEditor', () => { expect(editor.isFoldedAtBufferRow(6)).toBeTruthy() expect(editor.isFoldedAtBufferRow(7)).toBeFalsy() expect(editor.isFoldedAtBufferRow(8)).toBeFalsy() - }) - ) + })) describe('when there is a fold', () => it('moves all lines that spanned by a selection to preceding row, preserving all folds', () => { @@ -2904,24 +3185,35 @@ describe('TextEditor', () => { expect(editor.isFoldedAtBufferRow(7)).toBeTruthy() expect(editor.isFoldedAtBufferRow(8)).toBeFalsy() - editor.setSelectedBufferRanges([[[8, 0], [8, 3]], [[11, 0], [11, 5]]]) + editor.setSelectedBufferRanges([ + [[8, 0], [8, 3]], + [[11, 0], [11, 5]] + ]) editor.moveLineUp() - expect(editor.getSelectedBufferRanges()).toEqual([[[4, 0], [4, 3]], [[10, 0], [10, 5]]]) - expect(editor.lineTextForBufferRow(4)).toBe(' return sort(left).concat(pivot).concat(sort(right));') - expect(editor.lineTextForBufferRow(10)).toBe(' return sort(Array.apply(this, arguments));') + expect(editor.getSelectedBufferRanges()).toEqual([ + [[4, 0], [4, 3]], + [[10, 0], [10, 5]] + ]) + expect(editor.lineTextForBufferRow(4)).toBe( + ' return sort(left).concat(pivot).concat(sort(right));' + ) + expect(editor.lineTextForBufferRow(10)).toBe( + ' return sort(Array.apply(this, arguments));' + ) expect(editor.isFoldedAtBufferRow(5)).toBeTruthy() expect(editor.isFoldedAtBufferRow(6)).toBeTruthy() expect(editor.isFoldedAtBufferRow(7)).toBeTruthy() expect(editor.isFoldedAtBufferRow(8)).toBeTruthy() expect(editor.isFoldedAtBufferRow(9)).toBeFalsy() - }) - ) + })) }) describe('when there are many folds', () => { beforeEach(async () => { - editor = await atom.workspace.open('sample-with-many-folds.js', {autoIndent: false}) + editor = await atom.workspace.open('sample-with-many-folds.js', { + autoIndent: false + }) }) describe('and many selections intersects folded rows', () => @@ -2929,10 +3221,10 @@ describe('TextEditor', () => { editor.foldBufferRowRange(2, 4) editor.foldBufferRowRange(7, 9) - editor.setSelectedBufferRanges([ - [[1, 0], [5, 4]], - [[7, 0], [7, 4]] - ], {preserveFolds: true}) + editor.setSelectedBufferRanges( + [[[1, 0], [5, 4]], [[7, 0], [7, 4]]], + { preserveFolds: true } + ) editor.moveLineUp() @@ -2951,27 +3243,42 @@ describe('TextEditor', () => { expect(editor.isFoldedAtBufferRow(7)).toBeTruthy() expect(editor.isFoldedAtBufferRow(8)).toBeTruthy() expect(editor.isFoldedAtBufferRow(9)).toBeFalsy() - }) - ) + })) }) describe('when some of the selections span the same lines', () => { it('moves lines that contain multiple selections correctly', () => { - editor.setSelectedBufferRanges([[[3, 2], [3, 9]], [[3, 12], [3, 13]]]) + editor.setSelectedBufferRanges([ + [[3, 2], [3, 9]], + [[3, 12], [3, 13]] + ]) editor.moveLineUp() - expect(editor.getSelectedBufferRanges()).toEqual([[[2, 2], [2, 9]], [[2, 12], [2, 13]]]) - expect(editor.lineTextForBufferRow(2)).toBe(' var pivot = items.shift(), current, left = [], right = [];') + expect(editor.getSelectedBufferRanges()).toEqual([ + [[2, 2], [2, 9]], + [[2, 12], [2, 13]] + ]) + expect(editor.lineTextForBufferRow(2)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) }) }) describe('when one of the selections spans line 0', () => { it("doesn't move any lines, since line 0 can't move", () => { - editor.setSelectedBufferRanges([[[0, 2], [1, 9]], [[2, 2], [2, 9]], [[4, 2], [4, 9]]]) + editor.setSelectedBufferRanges([ + [[0, 2], [1, 9]], + [[2, 2], [2, 9]], + [[4, 2], [4, 9]] + ]) editor.moveLineUp() - expect(editor.getSelectedBufferRanges()).toEqual([[[0, 2], [1, 9]], [[2, 2], [2, 9]], [[4, 2], [4, 9]]]) + expect(editor.getSelectedBufferRanges()).toEqual([ + [[0, 2], [1, 9]], + [[2, 2], [2, 9]], + [[4, 2], [4, 9]] + ]) expect(buffer.isModified()).toBe(false) }) }) @@ -2979,11 +3286,19 @@ describe('TextEditor', () => { describe('when one of the selections spans the last line, and it is empty', () => { it("doesn't move any lines, since the last line can't move", () => { buffer.append('\n') - editor.setSelectedBufferRanges([[[0, 2], [1, 9]], [[2, 2], [2, 9]], [[13, 0], [13, 0]]]) + editor.setSelectedBufferRanges([ + [[0, 2], [1, 9]], + [[2, 2], [2, 9]], + [[13, 0], [13, 0]] + ]) editor.moveLineUp() - expect(editor.getSelectedBufferRanges()).toEqual([[[0, 2], [1, 9]], [[2, 2], [2, 9]], [[13, 0], [13, 0]]]) + expect(editor.getSelectedBufferRanges()).toEqual([ + [[0, 2], [1, 9]], + [[2, 2], [2, 9]], + [[13, 0], [13, 0]] + ]) }) }) }) @@ -2993,13 +3308,15 @@ describe('TextEditor', () => { it('moves the line under the cursor down', () => { editor.setCursorBufferPosition([0, 0]) editor.moveLineDown() - expect(editor.getTextInBufferRange([[1, 0], [1, 31]])).toBe('var quicksort = function () {') + expect(editor.getTextInBufferRange([[1, 0], [1, 31]])).toBe( + 'var quicksort = function () {' + ) expect(editor.indentationForBufferRow(0)).toBe(1) expect(editor.indentationForBufferRow(1)).toBe(0) }) it("updates the line's indentation when the editor.autoIndent setting is true", () => { - editor.update({autoIndent: true}) + editor.update({ autoIndent: true }) editor.setCursorBufferPosition([0, 0]) editor.moveLineDown() expect(editor.indentationForBufferRow(0)).toBe(1) @@ -3010,24 +3327,35 @@ describe('TextEditor', () => { describe('when the selection spans a single line', () => { describe('when there is no fold in the following row', () => it('moves the line to the following row', () => { - expect(editor.lineTextForBufferRow(2)).toBe(' if (items.length <= 1) return items;') - expect(editor.lineTextForBufferRow(3)).toBe(' var pivot = items.shift(), current, left = [], right = [];') + expect(editor.lineTextForBufferRow(2)).toBe( + ' if (items.length <= 1) return items;' + ) + expect(editor.lineTextForBufferRow(3)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) editor.setSelectedBufferRange([[2, 2], [2, 9]]) editor.moveLineDown() expect(editor.getSelectedBufferRange()).toEqual([[3, 2], [3, 9]]) - expect(editor.lineTextForBufferRow(2)).toBe(' var pivot = items.shift(), current, left = [], right = [];') - expect(editor.lineTextForBufferRow(3)).toBe(' if (items.length <= 1) return items;') - }) - ) + expect(editor.lineTextForBufferRow(2)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) + expect(editor.lineTextForBufferRow(3)).toBe( + ' if (items.length <= 1) return items;' + ) + })) describe('when the cursor is at the beginning of a fold', () => it('moves the line to the following row without breaking the fold', () => { - expect(editor.lineTextForBufferRow(4)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(4)).toBe( + ' while(items.length > 0) {' + ) editor.foldBufferRowRange(4, 7) - editor.setSelectedBufferRange([[4, 2], [4, 9]], {preserveFolds: true}) + editor.setSelectedBufferRange([[4, 2], [4, 9]], { + preserveFolds: true + }) expect(editor.isFoldedAtBufferRow(4)).toBeTruthy() expect(editor.isFoldedAtBufferRow(5)).toBeTruthy() @@ -3038,21 +3366,28 @@ describe('TextEditor', () => { editor.moveLineDown() expect(editor.getSelectedBufferRange()).toEqual([[5, 2], [5, 9]]) - expect(editor.lineTextForBufferRow(4)).toBe(' return sort(left).concat(pivot).concat(sort(right));') - expect(editor.lineTextForBufferRow(5)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(4)).toBe( + ' return sort(left).concat(pivot).concat(sort(right));' + ) + expect(editor.lineTextForBufferRow(5)).toBe( + ' while(items.length > 0) {' + ) expect(editor.isFoldedAtBufferRow(5)).toBeTruthy() expect(editor.isFoldedAtBufferRow(6)).toBeTruthy() expect(editor.isFoldedAtBufferRow(7)).toBeTruthy() expect(editor.isFoldedAtBufferRow(8)).toBeTruthy() expect(editor.isFoldedAtBufferRow(9)).toBeFalsy() - }) - ) + })) describe('when the following row is a folded row', () => it('moves the line below the folded row and preserves the fold', () => { - expect(editor.lineTextForBufferRow(3)).toBe(' var pivot = items.shift(), current, left = [], right = [];') - expect(editor.lineTextForBufferRow(4)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(3)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) + expect(editor.lineTextForBufferRow(4)).toBe( + ' while(items.length > 0) {' + ) editor.foldBufferRowRange(4, 7) @@ -3066,56 +3401,87 @@ describe('TextEditor', () => { editor.moveLineDown() expect(editor.getSelectedBufferRange()).toEqual([[7, 0], [7, 4]]) - expect(editor.lineTextForBufferRow(3)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(3)).toBe( + ' while(items.length > 0) {' + ) expect(editor.isFoldedAtBufferRow(3)).toBeTruthy() expect(editor.isFoldedAtBufferRow(4)).toBeTruthy() expect(editor.isFoldedAtBufferRow(5)).toBeTruthy() expect(editor.isFoldedAtBufferRow(6)).toBeTruthy() expect(editor.isFoldedAtBufferRow(7)).toBeFalsy() - expect(editor.lineTextForBufferRow(7)).toBe(' var pivot = items.shift(), current, left = [], right = [];') - }) - ) + expect(editor.lineTextForBufferRow(7)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) + })) }) describe('when the selection spans multiple lines', () => { it('moves the lines spanned by the selection to the following row', () => { - expect(editor.lineTextForBufferRow(2)).toBe(' if (items.length <= 1) return items;') - expect(editor.lineTextForBufferRow(3)).toBe(' var pivot = items.shift(), current, left = [], right = [];') - expect(editor.lineTextForBufferRow(4)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(2)).toBe( + ' if (items.length <= 1) return items;' + ) + expect(editor.lineTextForBufferRow(3)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) + expect(editor.lineTextForBufferRow(4)).toBe( + ' while(items.length > 0) {' + ) editor.setSelectedBufferRange([[2, 2], [3, 9]]) editor.moveLineDown() expect(editor.getSelectedBufferRange()).toEqual([[3, 2], [4, 9]]) - expect(editor.lineTextForBufferRow(2)).toBe(' while(items.length > 0) {') - expect(editor.lineTextForBufferRow(3)).toBe(' if (items.length <= 1) return items;') - expect(editor.lineTextForBufferRow(4)).toBe(' var pivot = items.shift(), current, left = [], right = [];') + expect(editor.lineTextForBufferRow(2)).toBe( + ' while(items.length > 0) {' + ) + expect(editor.lineTextForBufferRow(3)).toBe( + ' if (items.length <= 1) return items;' + ) + expect(editor.lineTextForBufferRow(4)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) }) }) describe('when the selection spans multiple lines, but ends at column 0', () => { it('does not move the last line of the selection', () => { - expect(editor.lineTextForBufferRow(2)).toBe(' if (items.length <= 1) return items;') - expect(editor.lineTextForBufferRow(3)).toBe(' var pivot = items.shift(), current, left = [], right = [];') - expect(editor.lineTextForBufferRow(4)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(2)).toBe( + ' if (items.length <= 1) return items;' + ) + expect(editor.lineTextForBufferRow(3)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) + expect(editor.lineTextForBufferRow(4)).toBe( + ' while(items.length > 0) {' + ) editor.setSelectedBufferRange([[2, 2], [3, 0]]) editor.moveLineDown() expect(editor.getSelectedBufferRange()).toEqual([[3, 2], [4, 0]]) - expect(editor.lineTextForBufferRow(2)).toBe(' var pivot = items.shift(), current, left = [], right = [];') - expect(editor.lineTextForBufferRow(3)).toBe(' if (items.length <= 1) return items;') - expect(editor.lineTextForBufferRow(4)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(2)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) + expect(editor.lineTextForBufferRow(3)).toBe( + ' if (items.length <= 1) return items;' + ) + expect(editor.lineTextForBufferRow(4)).toBe( + ' while(items.length > 0) {' + ) }) }) describe("when the selection's end intersects a fold", () => { it('moves the lines to the following row without breaking the fold', () => { - expect(editor.lineTextForBufferRow(4)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(4)).toBe( + ' while(items.length > 0) {' + ) editor.foldBufferRowRange(4, 7) - editor.setSelectedBufferRange([[3, 2], [4, 9]], {preserveFolds: true}) + editor.setSelectedBufferRange([[3, 2], [4, 9]], { + preserveFolds: true + }) expect(editor.isFoldedAtBufferRow(3)).toBeFalsy() expect(editor.isFoldedAtBufferRow(4)).toBeTruthy() @@ -3127,9 +3493,15 @@ describe('TextEditor', () => { editor.moveLineDown() expect(editor.getSelectedBufferRange()).toEqual([[4, 2], [5, 9]]) - expect(editor.lineTextForBufferRow(3)).toBe(' return sort(left).concat(pivot).concat(sort(right));') - expect(editor.lineTextForBufferRow(4)).toBe(' var pivot = items.shift(), current, left = [], right = [];') - expect(editor.lineTextForBufferRow(5)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(3)).toBe( + ' return sort(left).concat(pivot).concat(sort(right));' + ) + expect(editor.lineTextForBufferRow(4)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) + expect(editor.lineTextForBufferRow(5)).toBe( + ' while(items.length > 0) {' + ) expect(editor.isFoldedAtBufferRow(4)).toBeFalsy() expect(editor.isFoldedAtBufferRow(5)).toBeTruthy() @@ -3142,10 +3514,14 @@ describe('TextEditor', () => { describe("when the selection's start intersects a fold", () => { it('moves the lines to the following row without breaking the fold', () => { - expect(editor.lineTextForBufferRow(4)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(4)).toBe( + ' while(items.length > 0) {' + ) editor.foldBufferRowRange(4, 7) - editor.setSelectedBufferRange([[4, 2], [8, 9]], {preserveFolds: true}) + editor.setSelectedBufferRange([[4, 2], [8, 9]], { + preserveFolds: true + }) expect(editor.isFoldedAtBufferRow(4)).toBeTruthy() expect(editor.isFoldedAtBufferRow(5)).toBeTruthy() @@ -3158,8 +3534,12 @@ describe('TextEditor', () => { expect(editor.getSelectedBufferRange()).toEqual([[5, 2], [9, 9]]) expect(editor.lineTextForBufferRow(4)).toBe(' };') - expect(editor.lineTextForBufferRow(5)).toBe(' while(items.length > 0) {') - expect(editor.lineTextForBufferRow(9)).toBe(' return sort(left).concat(pivot).concat(sort(right));') + expect(editor.lineTextForBufferRow(5)).toBe( + ' while(items.length > 0) {' + ) + expect(editor.lineTextForBufferRow(9)).toBe( + ' return sort(left).concat(pivot).concat(sort(right));' + ) expect(editor.isFoldedAtBufferRow(4)).toBeFalsy() expect(editor.isFoldedAtBufferRow(5)).toBeTruthy() @@ -3173,8 +3553,12 @@ describe('TextEditor', () => { describe('when the following row is a folded row', () => { it('moves the lines spanned by the selection to the following row, but preserves the folded code', () => { - expect(editor.lineTextForBufferRow(2)).toBe(' if (items.length <= 1) return items;') - expect(editor.lineTextForBufferRow(3)).toBe(' var pivot = items.shift(), current, left = [], right = [];') + expect(editor.lineTextForBufferRow(2)).toBe( + ' if (items.length <= 1) return items;' + ) + expect(editor.lineTextForBufferRow(3)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) editor.foldBufferRowRange(4, 7) expect(editor.isFoldedAtBufferRow(4)).toBeTruthy() @@ -3187,14 +3571,18 @@ describe('TextEditor', () => { editor.moveLineDown() expect(editor.getSelectedBufferRange()).toEqual([[6, 0], [7, 2]]) - expect(editor.lineTextForBufferRow(2)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(2)).toBe( + ' while(items.length > 0) {' + ) expect(editor.isFoldedAtBufferRow(1)).toBeFalsy() expect(editor.isFoldedAtBufferRow(2)).toBeTruthy() expect(editor.isFoldedAtBufferRow(3)).toBeTruthy() expect(editor.isFoldedAtBufferRow(4)).toBeTruthy() expect(editor.isFoldedAtBufferRow(5)).toBeTruthy() expect(editor.isFoldedAtBufferRow(6)).toBeFalsy() - expect(editor.lineTextForBufferRow(6)).toBe(' if (items.length <= 1) return items;') + expect(editor.lineTextForBufferRow(6)).toBe( + ' if (items.length <= 1) return items;' + ) }) }) @@ -3202,7 +3590,9 @@ describe('TextEditor', () => { it('appends line ending to last line and moves the lines spanned by the selection to the preceeding row', () => { expect(editor.lineTextForBufferRow(9)).toBe(' };') expect(editor.lineTextForBufferRow(10)).toBe('') - expect(editor.lineTextForBufferRow(11)).toBe(' return sort(Array.apply(this, arguments));') + expect(editor.lineTextForBufferRow(11)).toBe( + ' return sort(Array.apply(this, arguments));' + ) expect(editor.lineTextForBufferRow(12)).toBe('};') editor.setSelectedBufferRange([[10, 0], [12, 2]]) @@ -3210,7 +3600,9 @@ describe('TextEditor', () => { expect(editor.getSelectedBufferRange()).toEqual([[9, 0], [11, 2]]) expect(editor.lineTextForBufferRow(9)).toBe('') - expect(editor.lineTextForBufferRow(10)).toBe(' return sort(Array.apply(this, arguments));') + expect(editor.lineTextForBufferRow(10)).toBe( + ' return sort(Array.apply(this, arguments));' + ) expect(editor.lineTextForBufferRow(11)).toBe('};') expect(editor.lineTextForBufferRow(12)).toBe(' };') }) @@ -3221,22 +3613,43 @@ describe('TextEditor', () => { describe('when all the selections span different lines', () => { describe('when there is no folds', () => it('moves all lines that are spanned by a selection to the following row', () => { - editor.setSelectedBufferRanges([[[1, 2], [1, 9]], [[3, 2], [3, 9]], [[5, 2], [5, 9]]]) + editor.setSelectedBufferRanges([ + [[1, 2], [1, 9]], + [[3, 2], [3, 9]], + [[5, 2], [5, 9]] + ]) editor.moveLineDown() - expect(editor.getSelectedBufferRanges()).toEqual([[[6, 2], [6, 9]], [[4, 2], [4, 9]], [[2, 2], [2, 9]]]) - expect(editor.lineTextForBufferRow(1)).toBe(' if (items.length <= 1) return items;') - expect(editor.lineTextForBufferRow(2)).toBe(' var sort = function(items) {') - expect(editor.lineTextForBufferRow(3)).toBe(' while(items.length > 0) {') - expect(editor.lineTextForBufferRow(4)).toBe(' var pivot = items.shift(), current, left = [], right = [];') - expect(editor.lineTextForBufferRow(5)).toBe(' current < pivot ? left.push(current) : right.push(current);') - expect(editor.lineTextForBufferRow(6)).toBe(' current = items.shift();') - }) - ) + expect(editor.getSelectedBufferRanges()).toEqual([ + [[6, 2], [6, 9]], + [[4, 2], [4, 9]], + [[2, 2], [2, 9]] + ]) + expect(editor.lineTextForBufferRow(1)).toBe( + ' if (items.length <= 1) return items;' + ) + expect(editor.lineTextForBufferRow(2)).toBe( + ' var sort = function(items) {' + ) + expect(editor.lineTextForBufferRow(3)).toBe( + ' while(items.length > 0) {' + ) + expect(editor.lineTextForBufferRow(4)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) + expect(editor.lineTextForBufferRow(5)).toBe( + ' current < pivot ? left.push(current) : right.push(current);' + ) + expect(editor.lineTextForBufferRow(6)).toBe( + ' current = items.shift();' + ) + })) describe('when there are many folds', () => { beforeEach(async () => { - editor = await atom.workspace.open('sample-with-many-folds.js', {autoIndent: false}) + editor = await atom.workspace.open('sample-with-many-folds.js', { + autoIndent: false + }) }) describe('and many selections intersects folded rows', () => @@ -3244,18 +3657,22 @@ describe('TextEditor', () => { editor.foldBufferRowRange(2, 4) editor.foldBufferRowRange(7, 9) - editor.setSelectedBufferRanges([ - [[2, 0], [2, 4]], - [[6, 0], [10, 4]] - ], {preserveFolds: true}) + editor.setSelectedBufferRanges( + [[[2, 0], [2, 4]], [[6, 0], [10, 4]]], + { preserveFolds: true } + ) editor.moveLineDown() expect(editor.lineTextForBufferRow(2)).toEqual('6;') - expect(editor.lineTextForBufferRow(3)).toEqual('function f3() {') + expect(editor.lineTextForBufferRow(3)).toEqual( + 'function f3() {' + ) expect(editor.lineTextForBufferRow(6)).toEqual('12;') expect(editor.lineTextForBufferRow(7)).toEqual('7;') - expect(editor.lineTextForBufferRow(8)).toEqual('function f8() {') + expect(editor.lineTextForBufferRow(8)).toEqual( + 'function f8() {' + ) expect(editor.lineTextForBufferRow(11)).toEqual('11;') expect(editor.isFoldedAtBufferRow(2)).toBeFalsy() @@ -3268,8 +3685,7 @@ describe('TextEditor', () => { expect(editor.isFoldedAtBufferRow(9)).toBeTruthy() expect(editor.isFoldedAtBufferRow(10)).toBeTruthy() expect(editor.isFoldedAtBufferRow(11)).toBeFalsy() - }) - ) + })) }) describe('when there is a fold below one of the selected row', () => @@ -3282,20 +3698,33 @@ describe('TextEditor', () => { expect(editor.isFoldedAtBufferRow(7)).toBeTruthy() expect(editor.isFoldedAtBufferRow(8)).toBeFalsy() - editor.setSelectedBufferRanges([[[1, 2], [1, 6]], [[3, 0], [3, 4]], [[8, 0], [8, 3]]]) + editor.setSelectedBufferRanges([ + [[1, 2], [1, 6]], + [[3, 0], [3, 4]], + [[8, 0], [8, 3]] + ]) editor.moveLineDown() - expect(editor.getSelectedBufferRanges()).toEqual([[[9, 0], [9, 3]], [[7, 0], [7, 4]], [[2, 2], [2, 6]]]) - expect(editor.lineTextForBufferRow(2)).toBe(' var sort = function(items) {') + expect(editor.getSelectedBufferRanges()).toEqual([ + [[9, 0], [9, 3]], + [[7, 0], [7, 4]], + [[2, 2], [2, 6]] + ]) + expect(editor.lineTextForBufferRow(2)).toBe( + ' var sort = function(items) {' + ) expect(editor.isFoldedAtBufferRow(3)).toBeTruthy() expect(editor.isFoldedAtBufferRow(4)).toBeTruthy() expect(editor.isFoldedAtBufferRow(5)).toBeTruthy() expect(editor.isFoldedAtBufferRow(6)).toBeTruthy() expect(editor.isFoldedAtBufferRow(7)).toBeFalsy() - expect(editor.lineTextForBufferRow(7)).toBe(' var pivot = items.shift(), current, left = [], right = [];') - expect(editor.lineTextForBufferRow(9)).toBe(' return sort(left).concat(pivot).concat(sort(right));') - }) - ) + expect(editor.lineTextForBufferRow(7)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) + expect(editor.lineTextForBufferRow(9)).toBe( + ' return sort(left).concat(pivot).concat(sort(right));' + ) + })) describe('when there is a fold below a group of multiple selections without any lines with no selection in-between', () => it('moves all the lines below the fold, preserving the fold', () => { @@ -3307,31 +3736,44 @@ describe('TextEditor', () => { expect(editor.isFoldedAtBufferRow(7)).toBeTruthy() expect(editor.isFoldedAtBufferRow(8)).toBeFalsy() - editor.setSelectedBufferRanges([[[2, 2], [2, 6]], [[3, 0], [3, 4]]]) + editor.setSelectedBufferRanges([ + [[2, 2], [2, 6]], + [[3, 0], [3, 4]] + ]) editor.moveLineDown() - expect(editor.getSelectedBufferRanges()).toEqual([[[7, 0], [7, 4]], [[6, 2], [6, 6]]]) - expect(editor.lineTextForBufferRow(2)).toBe(' while(items.length > 0) {') + expect(editor.getSelectedBufferRanges()).toEqual([ + [[7, 0], [7, 4]], + [[6, 2], [6, 6]] + ]) + expect(editor.lineTextForBufferRow(2)).toBe( + ' while(items.length > 0) {' + ) expect(editor.isFoldedAtBufferRow(2)).toBeTruthy() expect(editor.isFoldedAtBufferRow(3)).toBeTruthy() expect(editor.isFoldedAtBufferRow(4)).toBeTruthy() expect(editor.isFoldedAtBufferRow(5)).toBeTruthy() expect(editor.isFoldedAtBufferRow(6)).toBeFalsy() - expect(editor.lineTextForBufferRow(6)).toBe(' if (items.length <= 1) return items;') - expect(editor.lineTextForBufferRow(7)).toBe(' var pivot = items.shift(), current, left = [], right = [];') - }) - ) + expect(editor.lineTextForBufferRow(6)).toBe( + ' if (items.length <= 1) return items;' + ) + expect(editor.lineTextForBufferRow(7)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) + })) }) describe('when one selection intersects a fold', () => { it('moves the lines to the previous row without breaking the fold', () => { - expect(editor.lineTextForBufferRow(4)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(4)).toBe( + ' while(items.length > 0) {' + ) editor.foldBufferRowRange(4, 7) - editor.setSelectedBufferRanges([ - [[2, 2], [2, 9]], - [[4, 2], [4, 9]] - ], {preserveFolds: true}) + editor.setSelectedBufferRanges( + [[[2, 2], [2, 9]], [[4, 2], [4, 9]]], + { preserveFolds: true } + ) expect(editor.isFoldedAtBufferRow(2)).toBeFalsy() expect(editor.isFoldedAtBufferRow(3)).toBeFalsy() @@ -3349,11 +3791,19 @@ describe('TextEditor', () => { [[3, 2], [3, 9]] ]) - expect(editor.lineTextForBufferRow(2)).toBe(' var pivot = items.shift(), current, left = [], right = [];') - expect(editor.lineTextForBufferRow(3)).toBe(' if (items.length <= 1) return items;') - expect(editor.lineTextForBufferRow(4)).toBe(' return sort(left).concat(pivot).concat(sort(right));') + expect(editor.lineTextForBufferRow(2)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) + expect(editor.lineTextForBufferRow(3)).toBe( + ' if (items.length <= 1) return items;' + ) + expect(editor.lineTextForBufferRow(4)).toBe( + ' return sort(left).concat(pivot).concat(sort(right));' + ) - expect(editor.lineTextForBufferRow(5)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(5)).toBe( + ' while(items.length > 0) {' + ) expect(editor.lineTextForBufferRow(9)).toBe(' };') expect(editor.isFoldedAtBufferRow(2)).toBeFalsy() @@ -3369,11 +3819,19 @@ describe('TextEditor', () => { describe('when some of the selections span the same lines', () => { it('moves lines that contain multiple selections correctly', () => { - editor.setSelectedBufferRanges([[[3, 2], [3, 9]], [[3, 12], [3, 13]]]) + editor.setSelectedBufferRanges([ + [[3, 2], [3, 9]], + [[3, 12], [3, 13]] + ]) editor.moveLineDown() - expect(editor.getSelectedBufferRanges()).toEqual([[[4, 12], [4, 13]], [[4, 2], [4, 9]]]) - expect(editor.lineTextForBufferRow(3)).toBe(' while(items.length > 0) {') + expect(editor.getSelectedBufferRanges()).toEqual([ + [[4, 12], [4, 13]], + [[4, 2], [4, 9]] + ]) + expect(editor.lineTextForBufferRow(3)).toBe( + ' while(items.length > 0) {' + ) }) }) @@ -3381,7 +3839,7 @@ describe('TextEditor', () => { beforeEach(() => { editor.setSoftWrapped(true) editor.setEditorWidthInChars(80) - editor.setText(dedent ` + editor.setText(dedent` 1 2 Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. @@ -3418,7 +3876,7 @@ describe('TextEditor', () => { it('replaces the selection with the given text', () => { const range = editor.insertText('xxx') - expect(range).toEqual([ [[1, 0], [1, 3]] ]) + expect(range).toEqual([[[1, 0], [1, 3]]]) expect(buffer.lineForRow(1)).toBe('xxxvar sort = function(items) {') }) }) @@ -3431,7 +3889,9 @@ describe('TextEditor', () => { editor.insertText('xxx') - expect(buffer.lineForRow(1)).toBe(' xxxvarxxx sort = function(items) {') + expect(buffer.lineForRow(1)).toBe( + ' xxxvarxxx sort = function(items) {' + ) const [cursor1, cursor2] = editor.getCursors() expect(cursor1.getBufferPosition()).toEqual([1, 5]) @@ -3446,8 +3906,12 @@ describe('TextEditor', () => { editor.insertText('xxx') - expect(buffer.lineForRow(1)).toBe(' xxxvar sort = function(items) {') - expect(buffer.lineForRow(2)).toBe(' xxxif (items.length <= 1) return items;') + expect(buffer.lineForRow(1)).toBe( + ' xxxvar sort = function(items) {' + ) + expect(buffer.lineForRow(2)).toBe( + ' xxxif (items.length <= 1) return items;' + ) const [cursor1, cursor2] = editor.getCursors() expect(cursor1.getBufferPosition()).toEqual([1, 5]) @@ -3459,7 +3923,10 @@ describe('TextEditor', () => { describe('when there are multiple non-empty selections', () => { describe('when the selections are on the same line', () => { it('replaces each selection range with the inserted characters', () => { - editor.setSelectedBufferRanges([[[0, 4], [0, 13]], [[0, 22], [0, 24]]]) + editor.setSelectedBufferRanges([ + [[0, 4], [0, 13]], + [[0, 22], [0, 24]] + ]) editor.insertText('x') const [cursor1, cursor2] = editor.getCursors() @@ -3481,7 +3948,9 @@ describe('TextEditor', () => { editor.insertText('xxx') expect(buffer.lineForRow(1)).toBe('xxxvar sort = function(items) {') - expect(buffer.lineForRow(2)).toBe('xxxif (items.length <= 1) return items;') + expect(buffer.lineForRow(2)).toBe( + 'xxxif (items.length <= 1) return items;' + ) const [selection1, selection2] = editor.getSelections() expect(selection1.isEmpty()).toBeTruthy() @@ -3505,9 +3974,21 @@ describe('TextEditor', () => { beforeEach(() => editor.setSelectedBufferRange([[1, 0], [1, 2]])) it('notifies the observers when inserting text', () => { - const willInsertSpy = jasmine.createSpy().andCallFake(() => expect(buffer.lineForRow(1)).toBe(' var sort = function(items) {')) + const willInsertSpy = jasmine + .createSpy() + .andCallFake(() => + expect(buffer.lineForRow(1)).toBe( + ' var sort = function(items) {' + ) + ) - const didInsertSpy = jasmine.createSpy().andCallFake(() => expect(buffer.lineForRow(1)).toBe('xxxvar sort = function(items) {')) + const didInsertSpy = jasmine + .createSpy() + .andCallFake(() => + expect(buffer.lineForRow(1)).toBe( + 'xxxvar sort = function(items) {' + ) + ) editor.onWillInsertText(willInsertSpy) editor.onDidInsertText(didInsertSpy) @@ -3527,7 +4008,9 @@ describe('TextEditor', () => { }) it('cancels text insertion when an ::onWillInsertText observer calls cancel on an event', () => { - const willInsertSpy = jasmine.createSpy().andCallFake(({cancel}) => cancel()) + const willInsertSpy = jasmine + .createSpy() + .andCallFake(({ cancel }) => cancel()) const didInsertSpy = jasmine.createSpy() @@ -3544,12 +4027,9 @@ describe('TextEditor', () => { describe("when the undo option is set to 'skip'", () => { it('groups the change with the previous change for purposes of undo and redo', () => { - editor.setSelectedBufferRanges([ - [[0, 0], [0, 0]], - [[1, 0], [1, 0]] - ]) + editor.setSelectedBufferRanges([[[0, 0], [0, 0]], [[1, 0], [1, 0]]]) editor.insertText('x') - editor.insertText('y', {undo: 'skip'}) + editor.insertText('y', { undo: 'skip' }) editor.undo() expect(buffer.lineForRow(0)).toBe('var quicksort = function () {') expect(buffer.lineForRow(1)).toBe(' var sort = function(items) {') @@ -3561,18 +4041,21 @@ describe('TextEditor', () => { describe('when there is a single cursor', () => { describe('when the cursor is at the beginning of a line', () => { it('inserts an empty line before it', () => { - editor.setCursorScreenPosition({row: 1, column: 0}) + editor.setCursorScreenPosition({ row: 1, column: 0 }) editor.insertNewline() expect(buffer.lineForRow(1)).toBe('') - expect(editor.getCursorScreenPosition()).toEqual({row: 2, column: 0}) + expect(editor.getCursorScreenPosition()).toEqual({ + row: 2, + column: 0 + }) }) }) describe('when the cursor is in the middle of a line', () => { it('splits the current line to form a new line', () => { - editor.setCursorScreenPosition({row: 1, column: 6}) + editor.setCursorScreenPosition({ row: 1, column: 6 }) const originalLine = buffer.lineForRow(1) const lineBelowOriginalLine = buffer.lineForRow(2) @@ -3581,18 +4064,27 @@ describe('TextEditor', () => { expect(buffer.lineForRow(1)).toBe(originalLine.slice(0, 6)) expect(buffer.lineForRow(2)).toBe(originalLine.slice(6)) expect(buffer.lineForRow(3)).toBe(lineBelowOriginalLine) - expect(editor.getCursorScreenPosition()).toEqual({row: 2, column: 0}) + expect(editor.getCursorScreenPosition()).toEqual({ + row: 2, + column: 0 + }) }) }) describe('when the cursor is on the end of a line', () => { it('inserts an empty line after it', () => { - editor.setCursorScreenPosition({row: 1, column: buffer.lineForRow(1).length}) + editor.setCursorScreenPosition({ + row: 1, + column: buffer.lineForRow(1).length + }) editor.insertNewline() expect(buffer.lineForRow(2)).toBe('') - expect(editor.getCursorScreenPosition()).toEqual({row: 2, column: 0}) + expect(editor.getCursorScreenPosition()).toEqual({ + row: 2, + column: 0 + }) }) }) }) @@ -3606,9 +4098,15 @@ describe('TextEditor', () => { editor.insertNewline() expect(editor.lineTextForBufferRow(3)).toBe(' var pivot') - expect(editor.lineTextForBufferRow(4)).toBe(' = items.shift(), current') - expect(editor.lineTextForBufferRow(5)).toBe(', left = [], right = [];') - expect(editor.lineTextForBufferRow(6)).toBe(' while(items.length > 0) {') + expect(editor.lineTextForBufferRow(4)).toBe( + ' = items.shift(), current' + ) + expect(editor.lineTextForBufferRow(5)).toBe( + ', left = [], right = [];' + ) + expect(editor.lineTextForBufferRow(6)).toBe( + ' while(items.length > 0) {' + ) const [cursor1, cursor2] = editor.getCursors() expect(cursor1.getBufferPosition()).toEqual([4, 0]) @@ -3623,11 +4121,19 @@ describe('TextEditor', () => { editor.insertText('\n') expect(editor.lineTextForBufferRow(3)).toBe('') - expect(editor.lineTextForBufferRow(4)).toBe(' var pivot = items.shift(), current, left = [], right = [];') - expect(editor.lineTextForBufferRow(5)).toBe(' while(items.length > 0) {') - expect(editor.lineTextForBufferRow(6)).toBe(' current = items.shift();') + expect(editor.lineTextForBufferRow(4)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) + expect(editor.lineTextForBufferRow(5)).toBe( + ' while(items.length > 0) {' + ) + expect(editor.lineTextForBufferRow(6)).toBe( + ' current = items.shift();' + ) expect(editor.lineTextForBufferRow(7)).toBe('') - expect(editor.lineTextForBufferRow(8)).toBe(' current < pivot ? left.push(current) : right.push(current);') + expect(editor.lineTextForBufferRow(8)).toBe( + ' current < pivot ? left.push(current) : right.push(current);' + ) expect(editor.lineTextForBufferRow(9)).toBe(' }') const [cursor1, cursor2] = editor.getCursors() @@ -3650,7 +4156,7 @@ describe('TextEditor', () => { }) it("inserts a newline below the cursor's current line, autoindents it, and moves the cursor to the end of the line", () => { - editor.update({autoIndent: true}) + editor.update({ autoIndent: true }) editor.insertNewlineBelow() expect(buffer.lineForRow(0)).toBe('var quicksort = function () {') expect(buffer.lineForRow(1)).toBe(' ') @@ -3665,7 +4171,9 @@ describe('TextEditor', () => { editor.insertNewlineAbove() expect(editor.getCursorBufferPosition()).toEqual([0, 0]) expect(editor.lineTextForBufferRow(0)).toBe('') - expect(editor.lineTextForBufferRow(1)).toBe('var quicksort = function () {') + expect(editor.lineTextForBufferRow(1)).toBe( + 'var quicksort = function () {' + ) expect(editor.buffer.getLineCount()).toBe(14) }) }) @@ -3676,7 +4184,9 @@ describe('TextEditor', () => { editor.insertNewlineAbove() expect(editor.getCursorBufferPosition()).toEqual([3, 0]) expect(editor.lineTextForBufferRow(3)).toBe('') - expect(editor.lineTextForBufferRow(4)).toBe(' var pivot = items.shift(), current, left = [], right = [];') + expect(editor.lineTextForBufferRow(4)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) expect(editor.buffer.getLineCount()).toBe(14) editor.undo() @@ -3685,7 +4195,7 @@ describe('TextEditor', () => { }) it('indents the new line to the correct level when editor.autoIndent is true', () => { - editor.update({autoIndent: true}) + editor.update({ autoIndent: true }) editor.setText(' var test') editor.setCursorBufferPosition([0, 2]) @@ -3718,7 +4228,7 @@ describe('TextEditor', () => { describe('.insertNewLine()', () => { describe('when a new line is appended before a closing tag (e.g. by pressing enter before a selection)', () => { it('moves the line down and keeps the indentation level the same when editor.autoIndent is true', () => { - editor.update({autoIndent: true}) + editor.update({ autoIndent: true }) editor.setCursorBufferPosition([9, 2]) editor.insertNewline() expect(editor.lineTextForBufferRow(10)).toBe(' };') @@ -3727,7 +4237,7 @@ describe('TextEditor', () => { describe('when a newline is appended with a trailing closing tag behind the cursor (e.g. by pressing enter in the middel of a line)', () => { it('indents the new line to the correct level when editor.autoIndent is true and using a curly-bracket language', () => { - editor.update({autoIndent: true}) + editor.update({ autoIndent: true }) atom.grammars.assignLanguageMode(editor, 'source.js') editor.setText('var test = () => {\n return true;};') editor.setCursorBufferPosition([1, 14]) @@ -3738,7 +4248,7 @@ describe('TextEditor', () => { it('indents the new line to the current level when editor.autoIndent is true and no increaseIndentPattern is specified', () => { atom.grammars.assignLanguageMode(editor, null) - editor.update({autoIndent: true}) + editor.update({ autoIndent: true }) editor.setText(' if true') editor.setCursorBufferPosition([0, 8]) editor.insertNewline() @@ -3749,7 +4259,7 @@ describe('TextEditor', () => { it('indents the new line to the correct level when editor.autoIndent is true and using an off-side rule language', async () => { await atom.packages.activatePackage('language-coffee-script') - editor.update({autoIndent: true}) + editor.update({ autoIndent: true }) atom.grammars.assignLanguageMode(editor, 'source.coffee') editor.setText('if true\n return trueelse\n return false') editor.setCursorBufferPosition([1, 13]) @@ -3763,7 +4273,7 @@ describe('TextEditor', () => { describe('when a newline is appended on a line that matches the decreaseNextIndentPattern', () => { it('indents the new line to the correct level when editor.autoIndent is true', async () => { await atom.packages.activatePackage('language-go') - editor.update({autoIndent: true}) + editor.update({ autoIndent: true }) atom.grammars.assignLanguageMode(editor, 'source.go') editor.setText('fmt.Printf("some%s",\n "thing")') editor.setCursorBufferPosition([1, 10]) @@ -3780,20 +4290,25 @@ describe('TextEditor', () => { beforeEach(() => { const selection = editor.getLastSelection() - changeScreenRangeHandler = jasmine.createSpy('changeScreenRangeHandler') + changeScreenRangeHandler = jasmine.createSpy( + 'changeScreenRangeHandler' + ) selection.onDidChangeRange(changeScreenRangeHandler) }) describe('when the cursor is on the middle of the line', () => { it('removes the character before the cursor', () => { - editor.setCursorScreenPosition({row: 1, column: 7}) + editor.setCursorScreenPosition({ row: 1, column: 7 }) expect(buffer.lineForRow(1)).toBe(' var sort = function(items) {') editor.backspace() const line = buffer.lineForRow(1) expect(line).toBe(' var ort = function(items) {') - expect(editor.getCursorScreenPosition()).toEqual({row: 1, column: 6}) + expect(editor.getCursorScreenPosition()).toEqual({ + row: 1, + column: 6 + }) expect(changeScreenRangeHandler).toHaveBeenCalled() }) }) @@ -3804,14 +4319,19 @@ describe('TextEditor', () => { expect(originalLine0).toBe('var quicksort = function () {') expect(buffer.lineForRow(1)).toBe(' var sort = function(items) {') - editor.setCursorScreenPosition({row: 1, column: 0}) + editor.setCursorScreenPosition({ row: 1, column: 0 }) editor.backspace() const line0 = buffer.lineForRow(0) const line1 = buffer.lineForRow(1) - expect(line0).toBe('var quicksort = function () { var sort = function(items) {') + expect(line0).toBe( + 'var quicksort = function () { var sort = function(items) {' + ) expect(line1).toBe(' if (items.length <= 1) return items;') - expect(editor.getCursorScreenPosition()).toEqual([0, originalLine0.length]) + expect(editor.getCursorScreenPosition()).toEqual([ + 0, + originalLine0.length + ]) expect(changeScreenRangeHandler).toHaveBeenCalled() }) @@ -3819,7 +4339,7 @@ describe('TextEditor', () => { describe('when the cursor is at the first column of the first line', () => { it("does nothing, but doesn't raise an error", () => { - editor.setCursorScreenPosition({row: 0, column: 0}) + editor.setCursorScreenPosition({ row: 0, column: 0 }) editor.backspace() }) }) @@ -3843,7 +4363,9 @@ describe('TextEditor', () => { editor.backspace() expect(buffer.lineForRow(7)).toBe(' }') - expect(buffer.lineForRow(8)).toBe(' eturn sort(left).concat(pivot).concat(sort(right));') + expect(buffer.lineForRow(8)).toBe( + ' eturn sort(left).concat(pivot).concat(sort(right));' + ) }) }) @@ -3853,7 +4375,9 @@ describe('TextEditor', () => { editor.foldCurrentRow() editor.backspace() - expect(buffer.lineForRow(1)).toBe(' var sort = function(items) var pivot = items.shift(), current, left = [], right = [];') + expect(buffer.lineForRow(1)).toBe( + ' var sort = function(items) var pivot = items.shift(), current, left = [], right = [];' + ) expect(editor.getCursorScreenPosition()).toEqual([1, 29]) }) }) @@ -3867,7 +4391,9 @@ describe('TextEditor', () => { editor.backspace() - expect(editor.lineTextForBufferRow(3)).toBe(' var pivo = items.shift(), curren, left = [], right = [];') + expect(editor.lineTextForBufferRow(3)).toBe( + ' var pivo = items.shift(), curren, left = [], right = [];' + ) const [cursor1, cursor2] = editor.getCursors() expect(cursor1.getBufferPosition()).toEqual([3, 12]) @@ -3887,8 +4413,12 @@ describe('TextEditor', () => { editor.backspace() - expect(editor.lineTextForBufferRow(3)).toBe(' var pivo = items.shift(), current, left = [], right = [];') - expect(editor.lineTextForBufferRow(4)).toBe(' whileitems.length > 0) {') + expect(editor.lineTextForBufferRow(3)).toBe( + ' var pivo = items.shift(), current, left = [], right = [];' + ) + expect(editor.lineTextForBufferRow(4)).toBe( + ' whileitems.length > 0) {' + ) const [cursor1, cursor2] = editor.getCursors() expect(cursor1.getBufferPosition()).toEqual([3, 12]) @@ -3897,8 +4427,7 @@ describe('TextEditor', () => { const [selection1, selection2] = editor.getSelections() expect(selection1.isEmpty()).toBeTruthy() expect(selection2.isEmpty()).toBeTruthy() - }) - ) + })) describe('when the cursors are on the first column of their lines', () => it('removes the newlines preceding each cursor', () => { @@ -3906,16 +4435,21 @@ describe('TextEditor', () => { editor.addCursorAtScreenPosition([6, 0]) editor.backspace() - expect(editor.lineTextForBufferRow(2)).toBe(' if (items.length <= 1) return items; var pivot = items.shift(), current, left = [], right = [];') - expect(editor.lineTextForBufferRow(3)).toBe(' while(items.length > 0) {') - expect(editor.lineTextForBufferRow(4)).toBe(' current = items.shift(); current < pivot ? left.push(current) : right.push(current);') + expect(editor.lineTextForBufferRow(2)).toBe( + ' if (items.length <= 1) return items; var pivot = items.shift(), current, left = [], right = [];' + ) + expect(editor.lineTextForBufferRow(3)).toBe( + ' while(items.length > 0) {' + ) + expect(editor.lineTextForBufferRow(4)).toBe( + ' current = items.shift(); current < pivot ? left.push(current) : right.push(current);' + ) expect(editor.lineTextForBufferRow(5)).toBe(' }') const [cursor1, cursor2] = editor.getCursors() expect(cursor1.getBufferPosition()).toEqual([2, 40]) expect(cursor2.getBufferPosition()).toEqual([4, 30]) - }) - ) + })) }) }) @@ -3940,7 +4474,10 @@ describe('TextEditor', () => { describe('when there are multiple selections', () => { it('removes all selected text', () => { - editor.setSelectedBufferRanges([[[0, 4], [0, 13]], [[0, 16], [0, 24]]]) + editor.setSelectedBufferRanges([ + [[0, 4], [0, 13]], + [[0, 16], [0, 24]] + ]) editor.backspace() expect(editor.lineTextForBufferRow(0)).toBe('var = () {') }) @@ -4022,19 +4559,25 @@ describe('TextEditor', () => { editor.deleteToBeginningOfWord() expect(buffer.lineForRow(1)).toBe(' var sort = function(ems) {') - expect(buffer.lineForRow(3)).toBe(' ar pivot = items.shift(), current, left = [], right = [];') + expect(buffer.lineForRow(3)).toBe( + ' ar pivot = items.shift(), current, left = [], right = [];' + ) expect(cursor1.getBufferPosition()).toEqual([1, 22]) expect(cursor2.getBufferPosition()).toEqual([3, 4]) editor.deleteToBeginningOfWord() expect(buffer.lineForRow(1)).toBe(' var sort = functionems) {') - expect(buffer.lineForRow(2)).toBe(' if (items.length <= 1) return itemsar pivot = items.shift(), current, left = [], right = [];') + expect(buffer.lineForRow(2)).toBe( + ' if (items.length <= 1) return itemsar pivot = items.shift(), current, left = [], right = [];' + ) expect(cursor1.getBufferPosition()).toEqual([1, 21]) expect(cursor2.getBufferPosition()).toEqual([2, 39]) editor.deleteToBeginningOfWord() expect(buffer.lineForRow(1)).toBe(' var sort = ems) {') - expect(buffer.lineForRow(2)).toBe(' if (items.length <= 1) return ar pivot = items.shift(), current, left = [], right = [];') + expect(buffer.lineForRow(2)).toBe( + ' if (items.length <= 1) return ar pivot = items.shift(), current, left = [], right = [];' + ) expect(cursor1.getBufferPosition()).toEqual([1, 13]) expect(cursor2.getBufferPosition()).toEqual([2, 34]) @@ -4050,7 +4593,9 @@ describe('TextEditor', () => { editor.setSelectedBufferRanges([[[1, 24], [1, 27]], [[2, 0], [2, 4]]]) editor.deleteToBeginningOfWord() expect(buffer.lineForRow(1)).toBe(' var sort = function(it) {') - expect(buffer.lineForRow(2)).toBe('if (items.length <= 1) return items;') + expect(buffer.lineForRow(2)).toBe( + 'if (items.length <= 1) return items;' + ) }) }) }) @@ -4073,7 +4618,9 @@ describe('TextEditor', () => { it('deletes the next newline', () => { editor.setCursorBufferPosition([1, 30]) editor.deleteToEndOfLine() - expect(buffer.lineForRow(1)).toBe(' var sort = function(items) { if (items.length <= 1) return items;') + expect(buffer.lineForRow(1)).toBe( + ' var sort = function(items) { if (items.length <= 1) return items;' + ) }) }) }) @@ -4083,7 +4630,9 @@ describe('TextEditor', () => { editor.setSelectedBufferRanges([[[1, 24], [1, 27]], [[2, 0], [2, 4]]]) editor.deleteToEndOfLine() expect(buffer.lineForRow(1)).toBe(' var sort = function(it) {') - expect(buffer.lineForRow(2)).toBe('if (items.length <= 1) return items;') + expect(buffer.lineForRow(2)).toBe( + 'if (items.length <= 1) return items;' + ) }) }) }) @@ -4097,7 +4646,9 @@ describe('TextEditor', () => { editor.deleteToBeginningOfLine() expect(buffer.lineForRow(1)).toBe('ems) {') - expect(buffer.lineForRow(2)).toBe('f (items.length <= 1) return items;') + expect(buffer.lineForRow(2)).toBe( + 'f (items.length <= 1) return items;' + ) expect(cursor1.getBufferPosition()).toEqual([1, 0]) expect(cursor2.getBufferPosition()).toEqual([2, 0]) }) @@ -4106,7 +4657,9 @@ describe('TextEditor', () => { it('deletes the newline', () => { editor.setCursorBufferPosition([2]) editor.deleteToBeginningOfLine() - expect(buffer.lineForRow(1)).toBe(' var sort = function(items) { if (items.length <= 1) return items;') + expect(buffer.lineForRow(1)).toBe( + ' var sort = function(items) { if (items.length <= 1) return items;' + ) }) }) }) @@ -4116,7 +4669,9 @@ describe('TextEditor', () => { editor.setSelectedBufferRanges([[[1, 24], [1, 27]], [[2, 0], [2, 4]]]) editor.deleteToBeginningOfLine() expect(buffer.lineForRow(1)).toBe('ems) {') - expect(buffer.lineForRow(2)).toBe(' if (items.length <= 1) return items;') + expect(buffer.lineForRow(2)).toBe( + ' if (items.length <= 1) return items;' + ) }) }) }) @@ -4135,7 +4690,9 @@ describe('TextEditor', () => { it('joins the line with the following line', () => { editor.setCursorScreenPosition([1, buffer.lineForRow(1).length]) editor.delete() - expect(buffer.lineForRow(1)).toBe(' var sort = function(items) { if (items.length <= 1) return items;') + expect(buffer.lineForRow(1)).toBe( + ' var sort = function(items) { if (items.length <= 1) return items;' + ) }) }) @@ -4157,7 +4714,9 @@ describe('TextEditor', () => { expect(buffer.lineForRow(3)).toBe(' vae(items.length > 0) {') expect(buffer.lineForRow(4)).toBe(' current = items.shift();') - expect(editor.getCursorScreenPosition()).toEqual(cursorPositionBefore) + expect(editor.getCursorScreenPosition()).toEqual( + cursorPositionBefore + ) }) }) @@ -4169,7 +4728,9 @@ describe('TextEditor', () => { editor.delete() - expect(buffer.lineForRow(3)).toBe(' ar pivot = items.shift(), current, left = [], right = [];') + expect(buffer.lineForRow(3)).toBe( + ' ar pivot = items.shift(), current, left = [], right = [];' + ) expect(editor.isFoldedAtScreenRow(4)).toBe(true) expect(editor.getCursorScreenPosition()).toEqual([3, 4]) }) @@ -4182,9 +4743,15 @@ describe('TextEditor', () => { editor.delete() - expect(buffer.lineForRow(2)).toBe(' if (items.length <= 1) return items;') - expect(buffer.lineForRow(3)).toBe(' var pivot = items.shift(), current, left = [], right = [];') - expect(buffer.lineForRow(4)).toBe(' while ? left.push(current) : right.push(current);') + expect(buffer.lineForRow(2)).toBe( + ' if (items.length <= 1) return items;' + ) + expect(buffer.lineForRow(3)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) + expect(buffer.lineForRow(4)).toBe( + ' while ? left.push(current) : right.push(current);' + ) expect(buffer.lineForRow(5)).toBe(' }') expect(editor.getCursorBufferPosition()).toEqual([4, 9]) }) @@ -4199,7 +4766,9 @@ describe('TextEditor', () => { editor.delete() - expect(editor.lineTextForBufferRow(3)).toBe(' var pivot= items.shift(), current left = [], right = [];') + expect(editor.lineTextForBufferRow(3)).toBe( + ' var pivot= items.shift(), current left = [], right = [];' + ) const [cursor1, cursor2] = editor.getCursors() expect(cursor1.getBufferPosition()).toEqual([3, 13]) @@ -4219,8 +4788,12 @@ describe('TextEditor', () => { editor.delete() - expect(editor.lineTextForBufferRow(3)).toBe(' var pivot= items.shift(), current, left = [], right = [];') - expect(editor.lineTextForBufferRow(4)).toBe(' while(tems.length > 0) {') + expect(editor.lineTextForBufferRow(3)).toBe( + ' var pivot= items.shift(), current, left = [], right = [];' + ) + expect(editor.lineTextForBufferRow(4)).toBe( + ' while(tems.length > 0) {' + ) const [cursor1, cursor2] = editor.getCursors() expect(cursor1.getBufferPosition()).toEqual([3, 13]) @@ -4229,8 +4802,7 @@ describe('TextEditor', () => { const [selection1, selection2] = editor.getSelections() expect(selection1.isEmpty()).toBeTruthy() expect(selection2.isEmpty()).toBeTruthy() - }) - ) + })) describe('when the cursors are at the end of their lines', () => it('removes the newlines following each cursor', () => { @@ -4239,13 +4811,14 @@ describe('TextEditor', () => { editor.delete() - expect(editor.lineTextForBufferRow(0)).toBe('var quicksort = function () { var sort = function(items) { if (items.length <= 1) return items;') + expect(editor.lineTextForBufferRow(0)).toBe( + 'var quicksort = function () { var sort = function(items) { if (items.length <= 1) return items;' + ) const [cursor1, cursor2] = editor.getCursors() expect(cursor1.getBufferPosition()).toEqual([0, 29]) expect(cursor2.getBufferPosition()).toEqual([0, 59]) - }) - ) + })) }) }) @@ -4254,7 +4827,9 @@ describe('TextEditor', () => { editor.setSelectedBufferRanges([[[1, 24], [1, 27]], [[2, 0], [2, 4]]]) editor.delete() expect(buffer.lineForRow(1)).toBe(' var sort = function(it) {') - expect(buffer.lineForRow(2)).toBe('if (items.length <= 1) return items;') + expect(buffer.lineForRow(2)).toBe( + 'if (items.length <= 1) return items;' + ) expect(editor.getLastSelection().isEmpty()).toBeTruthy() }) }) @@ -4262,12 +4837,14 @@ describe('TextEditor', () => { describe('when there are multiple selections', () => describe('when selections are on the same line', () => { it('removes all selected text', () => { - editor.setSelectedBufferRanges([[[0, 4], [0, 13]], [[0, 16], [0, 24]]]) + editor.setSelectedBufferRanges([ + [[0, 4], [0, 13]], + [[0, 16], [0, 24]] + ]) editor.delete() expect(editor.lineTextForBufferRow(0)).toBe('var = () {') }) - }) - ) + })) }) describe('.deleteToEndOfWord()', () => { @@ -4279,13 +4856,17 @@ describe('TextEditor', () => { editor.deleteToEndOfWord() expect(buffer.lineForRow(1)).toBe(' var sort = function(it) {') - expect(buffer.lineForRow(2)).toBe(' i (items.length <= 1) return items;') + expect(buffer.lineForRow(2)).toBe( + ' i (items.length <= 1) return items;' + ) expect(cursor1.getBufferPosition()).toEqual([1, 24]) expect(cursor2.getBufferPosition()).toEqual([2, 5]) editor.deleteToEndOfWord() expect(buffer.lineForRow(1)).toBe(' var sort = function(it {') - expect(buffer.lineForRow(2)).toBe(' iitems.length <= 1) return items;') + expect(buffer.lineForRow(2)).toBe( + ' iitems.length <= 1) return items;' + ) expect(cursor1.getBufferPosition()).toEqual([1, 24]) expect(cursor2.getBufferPosition()).toEqual([2, 5]) }) @@ -4333,8 +4914,7 @@ describe('TextEditor', () => { expect(buffer.lineForRow(0)).not.toMatch(/^\t/) editor.indent() expect(buffer.lineForRow(0)).toMatch(/^\t/) - }) - ) + })) }) describe('when autoIndent is enabled', () => { @@ -4343,7 +4923,7 @@ describe('TextEditor', () => { it('moves the cursor to the end of the leading whitespace and inserts enough whitespace to bring the line to the suggested level of indentation', () => { buffer.insert([5, 0], ' \n') editor.setCursorBufferPosition([5, 0]) - editor.indent({autoIndent: true}) + editor.indent({ autoIndent: true }) expect(buffer.lineForRow(5)).toMatch(/^\s+$/) expect(buffer.lineForRow(5).length).toBe(6) expect(editor.getCursorBufferPosition()).toEqual([5, 6]) @@ -4353,14 +4933,14 @@ describe('TextEditor', () => { editor.setTabLength(4) buffer.insert([12, 2], '\n ') editor.setCursorBufferPosition([13, 1]) - editor.indent({autoIndent: true}) + editor.indent({ autoIndent: true }) expect(buffer.lineForRow(13)).toMatch(/^\s+$/) expect(buffer.lineForRow(13).length).toBe(4) expect(editor.getCursorBufferPosition()).toEqual([13, 4]) buffer.insert([13, 0], ' ') editor.setCursorBufferPosition([13, 6]) - editor.indent({autoIndent: true}) + editor.indent({ autoIndent: true }) expect(buffer.lineForRow(13).length).toBe(8) }) }) @@ -4371,7 +4951,7 @@ describe('TextEditor', () => { editor.setSoftTabs(false) buffer.insert([5, 0], '\t\n') editor.setCursorBufferPosition([5, 0]) - editor.indent({autoIndent: true}) + editor.indent({ autoIndent: true }) expect(buffer.lineForRow(5)).toMatch(/^\t\t\t$/) expect(editor.getCursorBufferPosition()).toEqual([5, 3]) }) @@ -4382,11 +4962,10 @@ describe('TextEditor', () => { buffer.setText(' \ntest') editor.setCursorBufferPosition([1, 0]) - editor.indent({autoIndent: true}) + editor.indent({ autoIndent: true }) expect(buffer.lineForRow(1)).toBe('\ttest') expect(editor.getCursorBufferPosition()).toEqual([1, 1]) - }) - ) + })) }) }) @@ -4395,12 +4974,11 @@ describe('TextEditor', () => { it("moves the cursor to the end of the leading whitespace and inserts 'tabLength' spaces into the buffer", () => { buffer.insert([7, 0], ' \n') editor.setCursorBufferPosition([7, 2]) - editor.indent({autoIndent: true}) + editor.indent({ autoIndent: true }) expect(buffer.lineForRow(7)).toMatch(/^\s+$/) expect(buffer.lineForRow(7).length).toBe(8) expect(editor.getCursorBufferPosition()).toEqual([7, 8]) - }) - ) + })) describe("when 'softTabs' is false", () => it('moves the cursor to the end of the leading whitespace and inserts \t into the buffer', () => { @@ -4408,11 +4986,10 @@ describe('TextEditor', () => { editor.setSoftTabs(false) buffer.insert([7, 0], '\t\t\t\n') editor.setCursorBufferPosition([7, 1]) - editor.indent({autoIndent: true}) + editor.indent({ autoIndent: true }) expect(buffer.lineForRow(7)).toMatch(/^\t\t\t\t$/) expect(editor.getCursorBufferPosition()).toEqual([7, 4]) - }) - ) + })) }) }) }) @@ -4434,12 +5011,18 @@ describe('TextEditor', () => { editor.indent() expect(buffer.lineForRow(0)).toMatch(/^\t/) expect(editor.getCursorBufferPosition()).toEqual([0, 1]) - expect(editor.getCursorScreenPosition()).toEqual([0, editor.getTabLength()]) + expect(editor.getCursorScreenPosition()).toEqual([ + 0, + editor.getTabLength() + ]) editor.indent() expect(buffer.lineForRow(0)).toMatch(/^\t\t/) expect(editor.getCursorBufferPosition()).toEqual([0, 2]) - expect(editor.getCursorScreenPosition()).toEqual([0, editor.getTabLength() * 2]) + expect(editor.getCursorScreenPosition()).toEqual([ + 0, + editor.getTabLength() * 2 + ]) }) }) }) @@ -4456,23 +5039,26 @@ describe('TextEditor', () => { describe('when no text is selected', () => { beforeEach(() => - editor.setSelectedBufferRanges([ - [[0, 0], [0, 0]], - [[5, 0], [5, 0]] - ]) + editor.setSelectedBufferRanges([[[0, 0], [0, 0]], [[5, 0], [5, 0]]]) ) it('cuts the lines on which there are cursors', () => { editor.cutSelectedText() expect(buffer.getLineCount()).toBe(11) - expect(buffer.lineForRow(1)).toBe(' if (items.length <= 1) return items;') - expect(buffer.lineForRow(4)).toBe(' current < pivot ? left.push(current) : right.push(current);') - expect(atom.clipboard.read()).toEqual([ - 'var quicksort = function () {', - '', - ' current = items.shift();', - '' - ].join('\n')) + expect(buffer.lineForRow(1)).toBe( + ' if (items.length <= 1) return items;' + ) + expect(buffer.lineForRow(4)).toBe( + ' current < pivot ? left.push(current) : right.push(current);' + ) + expect(atom.clipboard.read()).toEqual( + [ + 'var quicksort = function () {', + '', + ' current = items.shift();', + '' + ].join('\n') + ) }) }) @@ -4497,7 +5083,9 @@ describe('TextEditor', () => { editor.setEditorWidthInChars(25) editor.setCursorScreenPosition([2, 6]) editor.cutToEndOfLine() - expect(editor.lineTextForScreenRow(2)).toBe(' var function(items) {') + expect(editor.lineTextForScreenRow(2)).toBe( + ' var function(items) {' + ) }) }) @@ -4509,19 +5097,26 @@ describe('TextEditor', () => { editor.cutToEndOfLine() expect(buffer.lineForRow(2)).toBe(' if (items.length') expect(buffer.lineForRow(3)).toBe(' var pivot = item') - expect(atom.clipboard.read()).toBe(' <= 1) return items;\ns.shift(), current, left = [], right = [];') - }) - ) + expect(atom.clipboard.read()).toBe( + ' <= 1) return items;\ns.shift(), current, left = [], right = [];' + ) + })) describe('when text is selected', () => it('only cuts the selected text, not to the end of the line', () => { - editor.setSelectedBufferRanges([[[2, 20], [2, 30]], [[3, 20], [3, 20]]]) + editor.setSelectedBufferRanges([ + [[2, 20], [2, 30]], + [[3, 20], [3, 20]] + ]) editor.cutToEndOfLine() - expect(buffer.lineForRow(2)).toBe(' if (items.lengthurn items;') + expect(buffer.lineForRow(2)).toBe( + ' if (items.lengthurn items;' + ) expect(buffer.lineForRow(3)).toBe(' var pivot = item') - expect(atom.clipboard.read()).toBe(' <= 1) ret\ns.shift(), current, left = [], right = [];') - }) - ) + expect(atom.clipboard.read()).toBe( + ' <= 1) ret\ns.shift(), current, left = [], right = [];' + ) + })) }) }) @@ -4538,47 +5133,59 @@ describe('TextEditor', () => { editor.cutToEndOfBufferLine() expect(buffer.lineForRow(2)).toBe(' if (items.length') expect(buffer.lineForRow(3)).toBe(' var pivot = item') - expect(atom.clipboard.read()).toBe(' <= 1) return items;\ns.shift(), current, left = [], right = [];') + expect(atom.clipboard.read()).toBe( + ' <= 1) return items;\ns.shift(), current, left = [], right = [];' + ) }) }) describe('when text is selected', () => { it('only cuts the selected text, not to the end of the buffer line', () => { - editor.setSelectedBufferRanges([[[2, 20], [2, 30]], [[3, 20], [3, 20]]]) + editor.setSelectedBufferRanges([ + [[2, 20], [2, 30]], + [[3, 20], [3, 20]] + ]) editor.cutToEndOfBufferLine() expect(buffer.lineForRow(2)).toBe(' if (items.lengthurn items;') expect(buffer.lineForRow(3)).toBe(' var pivot = item') - expect(atom.clipboard.read()).toBe(' <= 1) ret\ns.shift(), current, left = [], right = [];') + expect(atom.clipboard.read()).toBe( + ' <= 1) ret\ns.shift(), current, left = [], right = [];' + ) }) }) }) describe('.copySelectedText()', () => { it('copies selected text onto the clipboard', () => { - editor.setSelectedBufferRanges([[[0, 4], [0, 13]], [[1, 6], [1, 10]], [[2, 8], [2, 13]]]) + editor.setSelectedBufferRanges([ + [[0, 4], [0, 13]], + [[1, 6], [1, 10]], + [[2, 8], [2, 13]] + ]) editor.copySelectedText() - expect(buffer.lineForRow(0)).toBe('var quicksort = function () {') + expect(buffer.lineForRow(0)).toBe('var quicksort = function () {') expect(buffer.lineForRow(1)).toBe(' var sort = function(items) {') - expect(buffer.lineForRow(2)).toBe(' if (items.length <= 1) return items;') + expect(buffer.lineForRow(2)).toBe( + ' if (items.length <= 1) return items;' + ) expect(clipboard.readText()).toBe('quicksort\nsort\nitems') expect(atom.clipboard.read()).toEqual('quicksort\nsort\nitems') }) describe('when no text is selected', () => { beforeEach(() => { - editor.setSelectedBufferRanges([ - [[1, 5], [1, 5]], - [[5, 8], [5, 8]] - ]) + editor.setSelectedBufferRanges([[[1, 5], [1, 5]], [[5, 8], [5, 8]]]) }) it('copies the lines on which there are cursors', () => { editor.copySelectedText() - expect(atom.clipboard.read()).toEqual([ - ' var sort = function(items) {\n', - ' current = items.shift();\n' - ].join('\n')) + expect(atom.clipboard.read()).toEqual( + [ + ' var sort = function(items) {\n', + ' current = items.shift();\n' + ].join('\n') + ) expect(editor.getSelectedBufferRanges()).toEqual([ [[1, 5], [1, 5]], [[5, 8], [5, 8]] @@ -4602,12 +5209,18 @@ describe('TextEditor', () => { describe('.copyOnlySelectedText()', () => { describe('when thee are multiple selections', () => { it('copies selected text onto the clipboard', () => { - editor.setSelectedBufferRanges([[[0, 4], [0, 13]], [[1, 6], [1, 10]], [[2, 8], [2, 13]]]) + editor.setSelectedBufferRanges([ + [[0, 4], [0, 13]], + [[1, 6], [1, 10]], + [[2, 8], [2, 13]] + ]) editor.copyOnlySelectedText() expect(buffer.lineForRow(0)).toBe('var quicksort = function () {') expect(buffer.lineForRow(1)).toBe(' var sort = function(items) {') - expect(buffer.lineForRow(2)).toBe(' if (items.length <= 1) return items;') + expect(buffer.lineForRow(2)).toBe( + ' if (items.length <= 1) return items;' + ) expect(clipboard.readText()).toBe('quicksort\nsort\nitems') expect(atom.clipboard.read()).toEqual(`quicksort\nsort\nitems`) }) @@ -4623,14 +5236,16 @@ describe('TextEditor', () => { }) describe('.pasteText()', () => { - const copyText = function (text, {startColumn, textEditor} = {}) { + const copyText = function (text, { startColumn, textEditor } = {}) { if (startColumn == null) startColumn = 0 if (textEditor == null) textEditor = editor textEditor.setCursorBufferPosition([0, 0]) textEditor.insertText(text) const numberOfNewlines = text.match(/\n/g).length const endColumn = text.match(/[^\n]*$/)[0].length - textEditor.getLastSelection().setBufferRange([[0, startColumn], [numberOfNewlines, endColumn]]) + textEditor + .getLastSelection() + .setBufferRange([[0, startColumn], [numberOfNewlines, endColumn]]) return textEditor.cutSelectedText() } @@ -4638,13 +5253,17 @@ describe('TextEditor', () => { editor.setSelectedBufferRanges([[[0, 4], [0, 13]], [[1, 6], [1, 10]]]) atom.clipboard.write('first') editor.pasteText() - expect(editor.lineTextForBufferRow(0)).toBe('var first = function () {') - expect(editor.lineTextForBufferRow(1)).toBe(' var first = function(items) {') + expect(editor.lineTextForBufferRow(0)).toBe( + 'var first = function () {' + ) + expect(editor.lineTextForBufferRow(1)).toBe( + ' var first = function(items) {' + ) }) it('notifies ::onWillInsertText observers', () => { const insertedStrings = [] - editor.onWillInsertText(function ({text, cancel}) { + editor.onWillInsertText(function ({ text, cancel }) { insertedStrings.push(text) cancel() }) @@ -4657,7 +5276,9 @@ describe('TextEditor', () => { it('notifies ::onDidInsertText observers', () => { const insertedStrings = [] - editor.onDidInsertText(({text, range}) => insertedStrings.push(text)) + editor.onDidInsertText(({ text, range }) => + insertedStrings.push(text) + ) atom.clipboard.write('hello') editor.pasteText() @@ -4666,11 +5287,13 @@ describe('TextEditor', () => { }) describe('when `autoIndentOnPaste` is true', () => { - beforeEach(() => editor.update({autoIndentOnPaste: true})) + beforeEach(() => editor.update({ autoIndentOnPaste: true })) describe('when pasting multiple lines before any non-whitespace characters', () => { it('auto-indents the lines spanned by the pasted text, based on the first pasted line', () => { - atom.clipboard.write('a(x);\n b(x);\n c(x);\n', {indentBasis: 0}) + atom.clipboard.write('a(x);\n b(x);\n c(x);\n', { + indentBasis: 0 + }) editor.setCursorBufferPosition([5, 0]) editor.pasteText() @@ -4680,14 +5303,18 @@ describe('TextEditor', () => { expect(editor.lineTextForBufferRow(5)).toBe(' a(x);') expect(editor.lineTextForBufferRow(6)).toBe(' b(x);') expect(editor.lineTextForBufferRow(7)).toBe(' c(x);') - expect(editor.lineTextForBufferRow(8)).toBe(' current = items.shift();') + expect(editor.lineTextForBufferRow(8)).toBe( + ' current = items.shift();' + ) }) it('auto-indents lines with a mix of hard tabs and spaces without removing spaces', () => { editor.setSoftTabs(false) expect(editor.indentationForBufferRow(5)).toBe(3) - atom.clipboard.write('/**\n\t * testing\n\t * indent\n\t **/\n', {indentBasis: 1}) + atom.clipboard.write('/**\n\t * testing\n\t * indent\n\t **/\n', { + indentBasis: 1 + }) editor.setCursorBufferPosition([5, 0]) editor.pasteText() @@ -4701,7 +5328,9 @@ describe('TextEditor', () => { describe('when pasting line(s) above a line that matches the decreaseIndentPattern', () => it('auto-indents based on the pasted line(s) only', () => { - atom.clipboard.write('a(x);\n b(x);\n c(x);\n', {indentBasis: 0}) + atom.clipboard.write('a(x);\n b(x);\n c(x);\n', { + indentBasis: 0 + }) editor.setCursorBufferPosition([7, 0]) editor.pasteText() @@ -4709,19 +5338,21 @@ describe('TextEditor', () => { expect(editor.lineTextForBufferRow(8)).toBe(' b(x);') expect(editor.lineTextForBufferRow(9)).toBe(' c(x);') expect(editor.lineTextForBufferRow(10)).toBe(' }') - }) - ) + })) describe('when pasting a line of text without line ending', () => it('does not auto-indent the text', () => { - atom.clipboard.write('a(x);', {indentBasis: 0}) + atom.clipboard.write('a(x);', { indentBasis: 0 }) editor.setCursorBufferPosition([5, 0]) editor.pasteText() - expect(editor.lineTextForBufferRow(5)).toBe('a(x); current = items.shift();') - expect(editor.lineTextForBufferRow(6)).toBe(' current < pivot ? left.push(current) : right.push(current);') - }) - ) + expect(editor.lineTextForBufferRow(5)).toBe( + 'a(x); current = items.shift();' + ) + expect(editor.lineTextForBufferRow(6)).toBe( + ' current < pivot ? left.push(current) : right.push(current);' + ) + })) describe('when pasting on a line after non-whitespace characters', () => it('does not auto-indent the affected line', () => { @@ -4739,12 +5370,11 @@ describe('TextEditor', () => { editor.pasteText() expect(editor.lineTextForBufferRow(1)).toBe(' y(); z();') expect(editor.lineTextForBufferRow(2)).toBe(' h();') - }) - ) + })) }) describe('when `autoIndentOnPaste` is false', () => { - beforeEach(() => editor.update({autoIndentOnPaste: false})) + beforeEach(() => editor.update({ autoIndentOnPaste: false })) describe('when the cursor is indented further than the original copied text', () => it('increases the indentation of the copied lines to match', () => { @@ -4754,10 +5384,13 @@ describe('TextEditor', () => { editor.setCursorBufferPosition([5, 6]) editor.pasteText() - expect(editor.lineTextForBufferRow(5)).toBe(' var sort = function(items) {') - expect(editor.lineTextForBufferRow(6)).toBe(' if (items.length <= 1) return items;') - }) - ) + expect(editor.lineTextForBufferRow(5)).toBe( + ' var sort = function(items) {' + ) + expect(editor.lineTextForBufferRow(6)).toBe( + ' if (items.length <= 1) return items;' + ) + })) describe('when the cursor is indented less far than the original copied text', () => it('decreases the indentation of the copied lines to match', () => { @@ -4767,10 +5400,11 @@ describe('TextEditor', () => { editor.setCursorBufferPosition([1, 2]) editor.pasteText() - expect(editor.lineTextForBufferRow(1)).toBe(' current < pivot ? left.push(current) : right.push(current);') + expect(editor.lineTextForBufferRow(1)).toBe( + ' current < pivot ? left.push(current) : right.push(current);' + ) expect(editor.lineTextForBufferRow(2)).toBe('}') - }) - ) + })) describe('when the first copied line has leading whitespace', () => it("preserves the line's leading whitespace", () => { @@ -4780,16 +5414,22 @@ describe('TextEditor', () => { editor.setCursorBufferPosition([0, 0]) editor.pasteText() - expect(editor.lineTextForBufferRow(0)).toBe(' while(items.length > 0) {') - expect(editor.lineTextForBufferRow(1)).toBe(' current = items.shift();') - }) - ) + expect(editor.lineTextForBufferRow(0)).toBe( + ' while(items.length > 0) {' + ) + expect(editor.lineTextForBufferRow(1)).toBe( + ' current = items.shift();' + ) + })) }) describe('when the clipboard has many selections', () => { beforeEach(() => { - editor.update({autoIndentOnPaste: false}) - editor.setSelectedBufferRanges([[[0, 4], [0, 13]], [[1, 6], [1, 10]]]) + editor.update({ autoIndentOnPaste: false }) + editor.setSelectedBufferRanges([ + [[0, 4], [0, 13]], + [[1, 6], [1, 10]] + ]) editor.copySelectedText() }) @@ -4802,17 +5442,25 @@ describe('TextEditor', () => { editor.moveRight() editor.insertText('_') editor.pasteText() - expect(editor.lineTextForBufferRow(0)).toBe('var quicksort_quicksort = function () {') - expect(editor.lineTextForBufferRow(1)).toBe(' var sort_sort = function(items) {') + expect(editor.lineTextForBufferRow(0)).toBe( + 'var quicksort_quicksort = function () {' + ) + expect(editor.lineTextForBufferRow(1)).toBe( + ' var sort_sort = function(items) {' + ) }) describe('and the selections count does not match', () => { - beforeEach(() => editor.setSelectedBufferRanges([[[0, 4], [0, 13]]])) + beforeEach(() => + editor.setSelectedBufferRanges([[[0, 4], [0, 13]]]) + ) it('pastes the whole text into the buffer', () => { editor.pasteText() expect(editor.lineTextForBufferRow(0)).toBe('var quicksort') - expect(editor.lineTextForBufferRow(1)).toBe('sort = function () {') + expect(editor.lineTextForBufferRow(1)).toBe( + 'sort = function () {' + ) }) }) }) @@ -4826,8 +5474,12 @@ describe('TextEditor', () => { it("pastes the line above the cursor and retains the cursor's column", () => { editor.pasteText() - expect(editor.lineTextForBufferRow(2)).toBe(' if (items.length <= 1) return items;') - expect(editor.lineTextForBufferRow(3)).toBe(' var pivot = items.shift(), current, left = [], right = [];') + expect(editor.lineTextForBufferRow(2)).toBe( + ' if (items.length <= 1) return items;' + ) + expect(editor.lineTextForBufferRow(3)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) expect(editor.getCursorBufferPosition()).toEqual([3, 13]) }) }) @@ -4842,35 +5494,47 @@ describe('TextEditor', () => { it('overwrites the selection as with any copied text', () => { editor.setSelectedBufferRange([[1, 2], [1, Infinity]]) editor.pasteText() - expect(editor.lineTextForBufferRow(1)).toBe(' if (items.length <= 1) return items;') + expect(editor.lineTextForBufferRow(1)).toBe( + ' if (items.length <= 1) return items;' + ) expect(editor.lineTextForBufferRow(2)).toBe('') - expect(editor.lineTextForBufferRow(3)).toBe(' if (items.length <= 1) return items;') + expect(editor.lineTextForBufferRow(3)).toBe( + ' if (items.length <= 1) return items;' + ) expect(editor.getCursorBufferPosition()).toEqual([2, 0]) - }) - ) + })) describe('when there is no selection', () => it("pastes the line above the cursor and retains the cursor's column", () => { editor.pasteText() - expect(editor.lineTextForBufferRow(2)).toBe(' if (items.length <= 1) return items;') - expect(editor.lineTextForBufferRow(3)).toBe(' if (items.length <= 1) return items;') + expect(editor.lineTextForBufferRow(2)).toBe( + ' if (items.length <= 1) return items;' + ) + expect(editor.lineTextForBufferRow(3)).toBe( + ' if (items.length <= 1) return items;' + ) expect(editor.getCursorBufferPosition()).toEqual([3, 13]) - }) - ) + })) }) it('respects options that preserve the formatting of the pasted text', () => { - editor.update({autoIndentOnPaste: true}) - atom.clipboard.write('a(x);\n b(x);\r\nc(x);\n', {indentBasis: 0}) + editor.update({ autoIndentOnPaste: true }) + atom.clipboard.write('a(x);\n b(x);\r\nc(x);\n', { indentBasis: 0 }) editor.setCursorBufferPosition([5, 0]) editor.insertText(' ') - editor.pasteText({autoIndent: false, preserveTrailingLineIndentation: true, normalizeLineEndings: false}) + editor.pasteText({ + autoIndent: false, + preserveTrailingLineIndentation: true, + normalizeLineEndings: false + }) expect(editor.lineTextForBufferRow(5)).toBe(' a(x);') expect(editor.lineTextForBufferRow(6)).toBe(' b(x);') expect(editor.buffer.lineEndingForRow(6)).toBe('\r\n') expect(editor.lineTextForBufferRow(7)).toBe('c(x);') - expect(editor.lineTextForBufferRow(8)).toBe(' current = items.shift();') + expect(editor.lineTextForBufferRow(8)).toBe( + ' current = items.shift();' + ) }) }) }) @@ -4882,7 +5546,10 @@ describe('TextEditor', () => { editor.setSelectedBufferRange([[0, 3], [0, 3]]) editor.indentSelectedRows() expect(buffer.lineForRow(0)).toBe(' var quicksort = function () {') - expect(editor.getSelectedBufferRange()).toEqual([[0, 3 + editor.getTabLength()], [0, 3 + editor.getTabLength()]]) + expect(editor.getSelectedBufferRange()).toEqual([ + [0, 3 + editor.getTabLength()], + [0, 3 + editor.getTabLength()] + ]) }) }) @@ -4893,7 +5560,10 @@ describe('TextEditor', () => { editor.setSelectedBufferRange([[0, 3], [0, 3]]) editor.indentSelectedRows() expect(buffer.lineForRow(0)).toBe('\tvar quicksort = function () {') - expect(editor.getSelectedBufferRange()).toEqual([[0, 3 + 1], [0, 3 + 1]]) + expect(editor.getSelectedBufferRange()).toEqual([ + [0, 3 + 1], + [0, 3 + 1] + ]) }) }) }) @@ -4903,8 +5573,13 @@ describe('TextEditor', () => { it('indents line and retains selection', () => { editor.setSelectedBufferRange([[0, 4], [0, 14]]) editor.indentSelectedRows() - expect(buffer.lineForRow(0)).toBe(`${editor.getTabText()}var quicksort = function () {`) - expect(editor.getSelectedBufferRange()).toEqual([[0, 4 + editor.getTabLength()], [0, 14 + editor.getTabLength()]]) + expect(buffer.lineForRow(0)).toBe( + `${editor.getTabText()}var quicksort = function () {` + ) + expect(editor.getSelectedBufferRange()).toEqual([ + [0, 4 + editor.getTabLength()], + [0, 14 + editor.getTabLength()] + ]) }) }) @@ -4915,7 +5590,10 @@ describe('TextEditor', () => { editor.setSelectedBufferRange([[0, 4], [0, 14]]) editor.indentSelectedRows() expect(buffer.lineForRow(0)).toBe('\tvar quicksort = function () {') - expect(editor.getSelectedBufferRange()).toEqual([[0, 4 + 1], [0, 14 + 1]]) + expect(editor.getSelectedBufferRange()).toEqual([ + [0, 4 + 1], + [0, 14 + 1] + ]) }) }) }) @@ -4927,8 +5605,13 @@ describe('TextEditor', () => { editor.indentSelectedRows() expect(buffer.lineForRow(9)).toBe(' };') expect(buffer.lineForRow(10)).toBe('') - expect(buffer.lineForRow(11)).toBe(' return sort(Array.apply(this, arguments));') - expect(editor.getSelectedBufferRange()).toEqual([[9, 1 + editor.getTabLength()], [11, 15 + editor.getTabLength()]]) + expect(buffer.lineForRow(11)).toBe( + ' return sort(Array.apply(this, arguments));' + ) + expect(editor.getSelectedBufferRange()).toEqual([ + [9, 1 + editor.getTabLength()], + [11, 15 + editor.getTabLength()] + ]) }) it('does not indent the last row if the selection ends at column 0', () => { @@ -4936,8 +5619,13 @@ describe('TextEditor', () => { editor.indentSelectedRows() expect(buffer.lineForRow(9)).toBe(' };') expect(buffer.lineForRow(10)).toBe('') - expect(buffer.lineForRow(11)).toBe(' return sort(Array.apply(this, arguments));') - expect(editor.getSelectedBufferRange()).toEqual([[9, 1 + editor.getTabLength()], [11, 0]]) + expect(buffer.lineForRow(11)).toBe( + ' return sort(Array.apply(this, arguments));' + ) + expect(editor.getSelectedBufferRange()).toEqual([ + [9, 1 + editor.getTabLength()], + [11, 0] + ]) }) }) @@ -4949,8 +5637,13 @@ describe('TextEditor', () => { editor.indentSelectedRows() expect(buffer.lineForRow(9)).toBe('\t\t};') expect(buffer.lineForRow(10)).toBe('') - expect(buffer.lineForRow(11)).toBe('\t\treturn sort(Array.apply(this, arguments));') - expect(editor.getSelectedBufferRange()).toEqual([[9, 1 + 1], [11, 15 + 1]]) + expect(buffer.lineForRow(11)).toBe( + '\t\treturn sort(Array.apply(this, arguments));' + ) + expect(editor.getSelectedBufferRange()).toEqual([ + [9, 1 + 1], + [11, 15 + 1] + ]) }) }) }) @@ -4962,7 +5655,10 @@ describe('TextEditor', () => { editor.setSelectedBufferRange([[1, 3], [1, 3]]) editor.outdentSelectedRows() expect(buffer.lineForRow(1)).toBe('var sort = function(items) {') - expect(editor.getSelectedBufferRange()).toEqual([[1, 3 - editor.getTabLength()], [1, 3 - editor.getTabLength()]]) + expect(editor.getSelectedBufferRange()).toEqual([ + [1, 3 - editor.getTabLength()], + [1, 3 - editor.getTabLength()] + ]) }) it('outdents when indent is less than a tab length', () => { @@ -4992,11 +5688,17 @@ describe('TextEditor', () => { it('outdents only up to the first non-space non-tab character', () => { editor.insertText(' \tfoo\t ') editor.outdentSelectedRows() - expect(buffer.lineForRow(0)).toBe('\tfoo\t var quicksort = function () {') + expect(buffer.lineForRow(0)).toBe( + '\tfoo\t var quicksort = function () {' + ) editor.outdentSelectedRows() - expect(buffer.lineForRow(0)).toBe('foo\t var quicksort = function () {') + expect(buffer.lineForRow(0)).toBe( + 'foo\t var quicksort = function () {' + ) editor.outdentSelectedRows() - expect(buffer.lineForRow(0)).toBe('foo\t var quicksort = function () {') + expect(buffer.lineForRow(0)).toBe( + 'foo\t var quicksort = function () {' + ) }) }) @@ -5005,7 +5707,10 @@ describe('TextEditor', () => { editor.setSelectedBufferRange([[1, 4], [1, 14]]) editor.outdentSelectedRows() expect(buffer.lineForRow(1)).toBe('var sort = function(items) {') - expect(editor.getSelectedBufferRange()).toEqual([[1, 4 - editor.getTabLength()], [1, 14 - editor.getTabLength()]]) + expect(editor.getSelectedBufferRange()).toEqual([ + [1, 4 - editor.getTabLength()], + [1, 14 - editor.getTabLength()] + ]) }) }) @@ -5015,9 +5720,16 @@ describe('TextEditor', () => { editor.outdentSelectedRows() expect(buffer.lineForRow(0)).toBe('var quicksort = function () {') expect(buffer.lineForRow(1)).toBe('var sort = function(items) {') - expect(buffer.lineForRow(2)).toBe(' if (items.length <= 1) return items;') - expect(buffer.lineForRow(3)).toBe(' var pivot = items.shift(), current, left = [], right = [];') - expect(editor.getSelectedBufferRange()).toEqual([[0, 1], [3, 15 - editor.getTabLength()]]) + expect(buffer.lineForRow(2)).toBe( + ' if (items.length <= 1) return items;' + ) + expect(buffer.lineForRow(3)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) + expect(editor.getSelectedBufferRange()).toEqual([ + [0, 1], + [3, 15 - editor.getTabLength()] + ]) }) it('does not outdent the last line of the selection if it ends at column 0', () => { @@ -5025,8 +5737,12 @@ describe('TextEditor', () => { editor.outdentSelectedRows() expect(buffer.lineForRow(0)).toBe('var quicksort = function () {') expect(buffer.lineForRow(1)).toBe('var sort = function(items) {') - expect(buffer.lineForRow(2)).toBe(' if (items.length <= 1) return items;') - expect(buffer.lineForRow(3)).toBe(' var pivot = items.shift(), current, left = [], right = [];') + expect(buffer.lineForRow(2)).toBe( + ' if (items.length <= 1) return items;' + ) + expect(buffer.lineForRow(3)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) expect(editor.getSelectedBufferRange()).toEqual([[0, 1], [3, 0]]) }) @@ -5079,10 +5795,7 @@ describe('TextEditor', () => { }) it('restores cursors and selections to their states before and after undone and redone changes', () => { - editor.setSelectedBufferRanges([ - [[0, 0], [0, 0]], - [[1, 0], [1, 3]] - ]) + editor.setSelectedBufferRanges([[[0, 0], [0, 0]], [[1, 0], [1, 3]]]) editor.insertText('abc') expect(editor.getSelectedBufferRanges()).toEqual([ @@ -5144,21 +5857,35 @@ describe('TextEditor', () => { const selections = editor.getSelections() expect(buffer.lineForRow(1)).toBe(' var = function( {') - expect(editor.getSelectedBufferRanges()).toEqual([[[1, 6], [1, 6]], [[1, 17], [1, 17]]]) + expect(editor.getSelectedBufferRanges()).toEqual([ + [[1, 6], [1, 6]], + [[1, 17], [1, 17]] + ]) editor.undo() - expect(editor.getSelectedBufferRanges()).toEqual([[[1, 6], [1, 6]], [[1, 18], [1, 18]]]) + expect(editor.getSelectedBufferRanges()).toEqual([ + [[1, 6], [1, 6]], + [[1, 18], [1, 18]] + ]) editor.undo() - expect(editor.getSelectedBufferRanges()).toEqual([[[1, 6], [1, 10]], [[1, 22], [1, 27]]]) + expect(editor.getSelectedBufferRanges()).toEqual([ + [[1, 6], [1, 10]], + [[1, 22], [1, 27]] + ]) editor.redo() - expect(editor.getSelectedBufferRanges()).toEqual([[[1, 6], [1, 6]], [[1, 18], [1, 18]]]) + expect(editor.getSelectedBufferRanges()).toEqual([ + [[1, 6], [1, 6]], + [[1, 18], [1, 18]] + ]) }) xit('restores folds after undo and redo', () => { editor.foldBufferRow(1) - editor.setSelectedBufferRange([[1, 0], [10, Infinity]], {preserveFolds: true}) + editor.setSelectedBufferRange([[1, 0], [10, Infinity]], { + preserveFolds: true + }) expect(editor.isFoldedAtBufferRow(1)).toBeTruthy() editor.insertText(dedent`\ @@ -5208,9 +5935,9 @@ describe('TextEditor', () => { beforeEach(async () => { editor1 = editor - editor2 = new TextEditor({buffer: editor1.buffer}) + editor2 = new TextEditor({ buffer: editor1.buffer }) - editor1.setText(dedent ` + editor1.setText(dedent` aaaaaa bbbbbb cccccc @@ -5220,12 +5947,16 @@ describe('TextEditor', () => { }) it('[editor.transact] restore selection of change-initiated-editor', () => { - editor1.setCursorBufferPosition([0, 0]); editor1.transact(() => editor1.insertText('1')) - editor2.setCursorBufferPosition([1, 0]); editor2.transact(() => editor2.insertText('2')) - editor1.setCursorBufferPosition([2, 0]); editor1.transact(() => editor1.insertText('3')) - editor2.setCursorBufferPosition([3, 0]); editor2.transact(() => editor2.insertText('4')) + editor1.setCursorBufferPosition([0, 0]) + editor1.transact(() => editor1.insertText('1')) + editor2.setCursorBufferPosition([1, 0]) + editor2.transact(() => editor2.insertText('2')) + editor1.setCursorBufferPosition([2, 0]) + editor1.transact(() => editor1.insertText('3')) + editor2.setCursorBufferPosition([3, 0]) + editor2.transact(() => editor2.insertText('4')) - expect(editor1.getText()).toBe(dedent ` + expect(editor1.getText()).toBe(dedent` 1aaaaaa 2bbbbbb 3cccccc @@ -5234,29 +5965,45 @@ describe('TextEditor', () => { `) editor2.setCursorBufferPosition([4, 0]) - editor1.undo(); expect(editor1.getCursorBufferPosition()).toEqual([3, 0]) - editor1.undo(); expect(editor1.getCursorBufferPosition()).toEqual([2, 0]) - editor1.undo(); expect(editor1.getCursorBufferPosition()).toEqual([1, 0]) - editor1.undo(); expect(editor1.getCursorBufferPosition()).toEqual([0, 0]) + editor1.undo() + expect(editor1.getCursorBufferPosition()).toEqual([3, 0]) + editor1.undo() + expect(editor1.getCursorBufferPosition()).toEqual([2, 0]) + editor1.undo() + expect(editor1.getCursorBufferPosition()).toEqual([1, 0]) + editor1.undo() + expect(editor1.getCursorBufferPosition()).toEqual([0, 0]) expect(editor2.getCursorBufferPosition()).toEqual([4, 0]) // remain unchanged - editor1.redo(); expect(editor1.getCursorBufferPosition()).toEqual([0, 1]) - editor1.redo(); expect(editor1.getCursorBufferPosition()).toEqual([1, 1]) - editor1.redo(); expect(editor1.getCursorBufferPosition()).toEqual([2, 1]) - editor1.redo(); expect(editor1.getCursorBufferPosition()).toEqual([3, 1]) + editor1.redo() + expect(editor1.getCursorBufferPosition()).toEqual([0, 1]) + editor1.redo() + expect(editor1.getCursorBufferPosition()).toEqual([1, 1]) + editor1.redo() + expect(editor1.getCursorBufferPosition()).toEqual([2, 1]) + editor1.redo() + expect(editor1.getCursorBufferPosition()).toEqual([3, 1]) expect(editor2.getCursorBufferPosition()).toEqual([4, 0]) // remain unchanged editor1.setCursorBufferPosition([4, 0]) - editor2.undo(); expect(editor2.getCursorBufferPosition()).toEqual([3, 0]) - editor2.undo(); expect(editor2.getCursorBufferPosition()).toEqual([2, 0]) - editor2.undo(); expect(editor2.getCursorBufferPosition()).toEqual([1, 0]) - editor2.undo(); expect(editor2.getCursorBufferPosition()).toEqual([0, 0]) + editor2.undo() + expect(editor2.getCursorBufferPosition()).toEqual([3, 0]) + editor2.undo() + expect(editor2.getCursorBufferPosition()).toEqual([2, 0]) + editor2.undo() + expect(editor2.getCursorBufferPosition()).toEqual([1, 0]) + editor2.undo() + expect(editor2.getCursorBufferPosition()).toEqual([0, 0]) expect(editor1.getCursorBufferPosition()).toEqual([4, 0]) // remain unchanged - editor2.redo(); expect(editor2.getCursorBufferPosition()).toEqual([0, 1]) - editor2.redo(); expect(editor2.getCursorBufferPosition()).toEqual([1, 1]) - editor2.redo(); expect(editor2.getCursorBufferPosition()).toEqual([2, 1]) - editor2.redo(); expect(editor2.getCursorBufferPosition()).toEqual([3, 1]) + editor2.redo() + expect(editor2.getCursorBufferPosition()).toEqual([0, 1]) + editor2.redo() + expect(editor2.getCursorBufferPosition()).toEqual([1, 1]) + editor2.redo() + expect(editor2.getCursorBufferPosition()).toEqual([2, 1]) + editor2.redo() + expect(editor2.getCursorBufferPosition()).toEqual([3, 1]) expect(editor1.getCursorBufferPosition()).toEqual([4, 0]) // remain unchanged }) @@ -5267,12 +6014,16 @@ describe('TextEditor', () => { editor.groupChangesSinceCheckpoint(checkpoint) } - editor1.setCursorBufferPosition([0, 0]); transact(editor1, () => editor1.insertText('1')) - editor2.setCursorBufferPosition([1, 0]); transact(editor2, () => editor2.insertText('2')) - editor1.setCursorBufferPosition([2, 0]); transact(editor1, () => editor1.insertText('3')) - editor2.setCursorBufferPosition([3, 0]); transact(editor2, () => editor2.insertText('4')) + editor1.setCursorBufferPosition([0, 0]) + transact(editor1, () => editor1.insertText('1')) + editor2.setCursorBufferPosition([1, 0]) + transact(editor2, () => editor2.insertText('2')) + editor1.setCursorBufferPosition([2, 0]) + transact(editor1, () => editor1.insertText('3')) + editor2.setCursorBufferPosition([3, 0]) + transact(editor2, () => editor2.insertText('4')) - expect(editor1.getText()).toBe(dedent ` + expect(editor1.getText()).toBe(dedent` 1aaaaaa 2bbbbbb 3cccccc @@ -5281,29 +6032,45 @@ describe('TextEditor', () => { `) editor2.setCursorBufferPosition([4, 0]) - editor1.undo(); expect(editor1.getCursorBufferPosition()).toEqual([3, 0]) - editor1.undo(); expect(editor1.getCursorBufferPosition()).toEqual([2, 0]) - editor1.undo(); expect(editor1.getCursorBufferPosition()).toEqual([1, 0]) - editor1.undo(); expect(editor1.getCursorBufferPosition()).toEqual([0, 0]) + editor1.undo() + expect(editor1.getCursorBufferPosition()).toEqual([3, 0]) + editor1.undo() + expect(editor1.getCursorBufferPosition()).toEqual([2, 0]) + editor1.undo() + expect(editor1.getCursorBufferPosition()).toEqual([1, 0]) + editor1.undo() + expect(editor1.getCursorBufferPosition()).toEqual([0, 0]) expect(editor2.getCursorBufferPosition()).toEqual([4, 0]) // remain unchanged - editor1.redo(); expect(editor1.getCursorBufferPosition()).toEqual([0, 1]) - editor1.redo(); expect(editor1.getCursorBufferPosition()).toEqual([1, 1]) - editor1.redo(); expect(editor1.getCursorBufferPosition()).toEqual([2, 1]) - editor1.redo(); expect(editor1.getCursorBufferPosition()).toEqual([3, 1]) + editor1.redo() + expect(editor1.getCursorBufferPosition()).toEqual([0, 1]) + editor1.redo() + expect(editor1.getCursorBufferPosition()).toEqual([1, 1]) + editor1.redo() + expect(editor1.getCursorBufferPosition()).toEqual([2, 1]) + editor1.redo() + expect(editor1.getCursorBufferPosition()).toEqual([3, 1]) expect(editor2.getCursorBufferPosition()).toEqual([4, 0]) // remain unchanged editor1.setCursorBufferPosition([4, 0]) - editor2.undo(); expect(editor2.getCursorBufferPosition()).toEqual([3, 0]) - editor2.undo(); expect(editor2.getCursorBufferPosition()).toEqual([2, 0]) - editor2.undo(); expect(editor2.getCursorBufferPosition()).toEqual([1, 0]) - editor2.undo(); expect(editor2.getCursorBufferPosition()).toEqual([0, 0]) + editor2.undo() + expect(editor2.getCursorBufferPosition()).toEqual([3, 0]) + editor2.undo() + expect(editor2.getCursorBufferPosition()).toEqual([2, 0]) + editor2.undo() + expect(editor2.getCursorBufferPosition()).toEqual([1, 0]) + editor2.undo() + expect(editor2.getCursorBufferPosition()).toEqual([0, 0]) expect(editor1.getCursorBufferPosition()).toEqual([4, 0]) // remain unchanged - editor2.redo(); expect(editor2.getCursorBufferPosition()).toEqual([0, 1]) - editor2.redo(); expect(editor2.getCursorBufferPosition()).toEqual([1, 1]) - editor2.redo(); expect(editor2.getCursorBufferPosition()).toEqual([2, 1]) - editor2.redo(); expect(editor2.getCursorBufferPosition()).toEqual([3, 1]) + editor2.redo() + expect(editor2.getCursorBufferPosition()).toEqual([0, 1]) + editor2.redo() + expect(editor2.getCursorBufferPosition()).toEqual([1, 1]) + editor2.redo() + expect(editor2.getCursorBufferPosition()).toEqual([2, 1]) + editor2.redo() + expect(editor2.getCursorBufferPosition()).toEqual([3, 1]) expect(editor1.getCursorBufferPosition()).toEqual([4, 0]) // remain unchanged }) }) @@ -5375,7 +6142,10 @@ describe('TextEditor', () => { expect(selections[0].getText()).toBe('quicksort') expect(selections[1].getText()).toBe('function') - expect(editor.getSelectedBufferRanges()).toEqual([[[0, 3], [0, 12]], [[0, 15], [0, 23]]]) + expect(editor.getSelectedBufferRanges()).toEqual([ + [[0, 3], [0, 12]], + [[0, 15], [0, 23]] + ]) }) it('moves multiple active selections on multiple lines one column to the left', () => { @@ -5389,7 +6159,10 @@ describe('TextEditor', () => { expect(selections[0].getText()).toBe('quicksort') expect(selections[1].getText()).toBe('sort') - expect(editor.getSelectedBufferRanges()).toEqual([[[0, 3], [0, 12]], [[1, 5], [1, 9]]]) + expect(editor.getSelectedBufferRanges()).toEqual([ + [[0, 3], [0, 12]], + [[1, 5], [1, 9]] + ]) }) describe('when a selection is at the first column of a line', () => { @@ -5405,12 +6178,18 @@ describe('TextEditor', () => { expect(selections[0].getText()).toBe('var') expect(selections[1].getText()).toBe(' v') - expect(editor.getSelectedBufferRanges()).toEqual([[[0, 0], [0, 3]], [[1, 0], [1, 3]]]) + expect(editor.getSelectedBufferRanges()).toEqual([ + [[0, 0], [0, 3]], + [[1, 0], [1, 3]] + ]) }) describe('when multiple selections are active on one line', () => { it('does not change the selection', () => { - editor.setSelectedBufferRanges([[[0, 0], [0, 3]], [[0, 4], [0, 13]]]) + editor.setSelectedBufferRanges([ + [[0, 0], [0, 3]], + [[0, 4], [0, 13]] + ]) const selections = editor.getSelections() expect(selections[0].getText()).toBe('var') @@ -5420,7 +6199,10 @@ describe('TextEditor', () => { expect(selections[0].getText()).toBe('var') expect(selections[1].getText()).toBe('quicksort') - expect(editor.getSelectedBufferRanges()).toEqual([[[0, 0], [0, 3]], [[0, 4], [0, 13]]]) + expect(editor.getSelectedBufferRanges()).toEqual([ + [[0, 0], [0, 3]], + [[0, 4], [0, 13]] + ]) }) }) }) @@ -5448,7 +6230,10 @@ describe('TextEditor', () => { expect(selections[0].getText()).toBe('quicksort') expect(selections[1].getText()).toBe('function') - expect(editor.getSelectedBufferRanges()).toEqual([[[0, 5], [0, 14]], [[0, 17], [0, 25]]]) + expect(editor.getSelectedBufferRanges()).toEqual([ + [[0, 5], [0, 14]], + [[0, 17], [0, 25]] + ]) }) it('moves multiple active selections on multiple lines one column to the right', () => { @@ -5462,12 +6247,18 @@ describe('TextEditor', () => { expect(selections[0].getText()).toBe('quicksort') expect(selections[1].getText()).toBe('sort') - expect(editor.getSelectedBufferRanges()).toEqual([[[0, 5], [0, 14]], [[1, 7], [1, 11]]]) + expect(editor.getSelectedBufferRanges()).toEqual([ + [[0, 5], [0, 14]], + [[1, 7], [1, 11]] + ]) }) describe('when a selection is at the last column of a line', () => { it('does not change the selection', () => { - editor.setSelectedBufferRanges([[[2, 34], [2, 40]], [[5, 22], [5, 30]]]) + editor.setSelectedBufferRanges([ + [[2, 34], [2, 40]], + [[5, 22], [5, 30]] + ]) const selections = editor.getSelections() expect(selections[0].getText()).toBe('items;') @@ -5478,12 +6269,18 @@ describe('TextEditor', () => { expect(selections[0].getText()).toBe('items;') expect(selections[1].getText()).toBe('shift();') - expect(editor.getSelectedBufferRanges()).toEqual([[[2, 34], [2, 40]], [[5, 22], [5, 30]]]) + expect(editor.getSelectedBufferRanges()).toEqual([ + [[2, 34], [2, 40]], + [[5, 22], [5, 30]] + ]) }) describe('when multiple selections are active on one line', () => { it('does not change the selection', () => { - editor.setSelectedBufferRanges([[[2, 27], [2, 33]], [[2, 34], [2, 40]]]) + editor.setSelectedBufferRanges([ + [[2, 27], [2, 33]], + [[2, 34], [2, 40]] + ]) const selections = editor.getSelections() expect(selections[0].getText()).toBe('return') @@ -5493,7 +6290,10 @@ describe('TextEditor', () => { expect(selections[0].getText()).toBe('return') expect(selections[1].getText()).toBe('items;') - expect(editor.getSelectedBufferRanges()).toEqual([[[2, 27], [2, 33]], [[2, 34], [2, 40]]]) + expect(editor.getSelectedBufferRanges()).toEqual([ + [[2, 27], [2, 33]], + [[2, 34], [2, 40]] + ]) }) }) }) @@ -5529,7 +6329,7 @@ describe('TextEditor', () => { { name: 'insertNewline', op: (opts = {}) => { - editor.setCursorScreenPosition({row: 1, column: 0}) + editor.setCursorScreenPosition({ row: 1, column: 0 }) editor.insertNewline(opts) } }, @@ -5550,7 +6350,7 @@ describe('TextEditor', () => { { name: 'backspace', op: (opts = {}) => { - editor.setCursorScreenPosition({row: 1, column: 7}) + editor.setCursorScreenPosition({ row: 1, column: 7 }) editor.backspace(opts) } }, @@ -5612,7 +6412,10 @@ describe('TextEditor', () => { { name: 'cutSelectedText', op: (opts = {}) => { - editor.setSelectedBufferRanges([[[0, 4], [0, 13]], [[1, 6], [1, 10]]]) + editor.setSelectedBufferRanges([ + [[0, 4], [0, 13]], + [[1, 6], [1, 10]] + ]) editor.cutSelectedText(opts) } }, @@ -5633,7 +6436,10 @@ describe('TextEditor', () => { { name: 'pasteText', op: (opts = {}) => { - editor.setSelectedBufferRanges([[[0, 4], [0, 13]], [[1, 6], [1, 10]]]) + editor.setSelectedBufferRanges([ + [[0, 4], [0, 13]], + [[1, 6], [1, 10]] + ]) atom.clipboard.write('first') editor.pasteText(opts) } @@ -5672,7 +6478,7 @@ describe('TextEditor', () => { ] describe('without bypassReadOnly', () => { - for (const {name, op} of modifications) { + for (const { name, op } of modifications) { it(`throws an error on ${name}`, () => { expect(op).toThrow() }) @@ -5680,9 +6486,9 @@ describe('TextEditor', () => { }) describe('with bypassReadOnly', () => { - for (const {name, op} of modifications) { + for (const { name, op } of modifications) { it(`permits ${name}`, () => { - op({bypassReadOnly: true}) + op({ bypassReadOnly: true }) }) } }) @@ -5692,7 +6498,9 @@ describe('TextEditor', () => { describe('reading text', () => { it('.lineTextForScreenRow(row)', () => { editor.foldBufferRow(4) - expect(editor.lineTextForScreenRow(5)).toEqual(' return sort(left).concat(pivot).concat(sort(right));') + expect(editor.lineTextForScreenRow(5)).toEqual( + ' return sort(left).concat(pivot).concat(sort(right));' + ) expect(editor.lineTextForScreenRow(9)).toEqual('};') expect(editor.lineTextForScreenRow(10)).toBeUndefined() }) @@ -5731,7 +6539,7 @@ describe('TextEditor', () => { expect(buffer.getLineCount()).toBe(count - 2) }) - it("restores cursor position for multiple cursors", () => { + it('restores cursor position for multiple cursors', () => { const line = '0123456789'.repeat(8) editor.setText((line + '\n').repeat(5)) editor.setCursorScreenPosition([0, 5]) @@ -5744,13 +6552,10 @@ describe('TextEditor', () => { expect(cursors[1].getScreenPosition()).toEqual([1, 8]) }) - it("restores cursor position for multiple selections", () => { + it('restores cursor position for multiple selections', () => { const line = '0123456789'.repeat(8) editor.setText((line + '\n').repeat(5)) - editor.setSelectedBufferRanges([ - [[0, 5], [0, 8]], - [[2, 4], [2, 15]] - ]) + editor.setSelectedBufferRanges([[[0, 5], [0, 8]], [[2, 4], [2, 15]]]) editor.deleteLine() const cursors = editor.getCursors() @@ -5762,10 +6567,7 @@ describe('TextEditor', () => { it('deletes a line only once when multiple selections are on the same line', () => { const line1 = buffer.lineForRow(1) const count = buffer.getLineCount() - editor.setSelectedBufferRanges([ - [[0, 1], [0, 2]], - [[0, 4], [0, 5]] - ]) + editor.setSelectedBufferRanges([[[0, 1], [0, 2]], [[0, 4], [0, 5]]]) expect(buffer.lineForRow(0)).not.toBe(line1) editor.deleteLine() @@ -5841,7 +6643,9 @@ describe('TextEditor', () => { expect(buffer.lineForRow(3)).toBe(' while(items.length > 0) {') editor.undo() expect(editor.isFoldedAtScreenRow(4)).toBeTruthy() - expect(buffer.lineForRow(3)).toBe(' var pivot = items.shift(), current, left = [], right = [];') + expect(buffer.lineForRow(3)).toBe( + ' var pivot = items.shift(), current, left = [], right = [];' + ) }) }) }) @@ -5853,7 +6657,7 @@ describe('TextEditor', () => { expect(buffer.lineForRow(0)).toBe('123var quicksort = function () {') editor.setCursorBufferPosition([0]) - editor.replaceSelectedText({selectWordIfEmpty: true}, () => 'var') + editor.replaceSelectedText({ selectWordIfEmpty: true }, () => 'var') expect(buffer.lineForRow(0)).toBe('var quicksort = function () {') editor.setCursorBufferPosition([10]) @@ -5941,11 +6745,15 @@ describe('TextEditor', () => { describe('.setTabLength(tabLength)', () => { it('clips atomic soft tabs to the given tab length', () => { expect(editor.getTabLength()).toBe(2) - expect(editor.clipScreenPosition([5, 1], {clipDirection: 'forward'})).toEqual([5, 2]) + expect( + editor.clipScreenPosition([5, 1], { clipDirection: 'forward' }) + ).toEqual([5, 2]) editor.setTabLength(6) expect(editor.getTabLength()).toBe(6) - expect(editor.clipScreenPosition([5, 1], {clipDirection: 'forward'})).toEqual([5, 6]) + expect( + editor.clipScreenPosition([5, 1], { clipDirection: 'forward' }) + ).toEqual([5, 6]) const changeHandler = jasmine.createSpy('changeHandler') editor.onDidChange(changeHandler) @@ -5966,7 +6774,8 @@ describe('TextEditor', () => { expect(editor.indentLevelForLine(' hello')).toBe(1.5) }) - it('returns the indent level when the line has only leading tabs', () => expect(editor.indentLevelForLine('\t\thello')).toBe(2)) + it('returns the indent level when the line has only leading tabs', () => + expect(editor.indentLevelForLine('\t\thello')).toBe(2)) it('returns the indent level based on the character starting the line when the leading whitespace contains both spaces and tabs', () => { expect(editor.indentLevelForLine('\t hello')).toBe(2) @@ -5978,7 +6787,7 @@ describe('TextEditor', () => { }) }) - describe('when the buffer\'s language mode changes', () => { + describe("when the buffer's language mode changes", () => { beforeEach(() => { atom.config.set('core.useTreeSitterParsers', false) }) @@ -5993,7 +6802,9 @@ describe('TextEditor', () => { editor.onDidTokenize(event => events.push(event)) await atom.packages.activatePackage('language-c') - expect(atom.grammars.assignLanguageMode(editor.getBuffer(), 'source.c')).toBe(true) + expect( + atom.grammars.assignLanguageMode(editor.getBuffer(), 'source.c') + ).toBe(true) advanceClock(1) expect(events.length).toBe(1) }) @@ -6003,7 +6814,9 @@ describe('TextEditor', () => { editor.onDidChangeGrammar(grammar => events.push(grammar)) await atom.packages.activatePackage('language-c') - expect(atom.grammars.assignLanguageMode(editor.getBuffer(), 'source.c')).toBe(true) + expect( + atom.grammars.assignLanguageMode(editor.getBuffer(), 'source.c') + ).toBe(true) expect(events.length).toBe(1) expect(events[0].name).toBe('C') }) @@ -6017,7 +6830,7 @@ describe('TextEditor', () => { editor.insertText('\n ') expect(editor.lineTextForBufferRow(2)).toBe(' ') - editor.update({autoIndent: false}) + editor.update({ autoIndent: false }) editor.indent() expect(editor.lineTextForBufferRow(2)).toBe(' ') }) @@ -6025,7 +6838,7 @@ describe('TextEditor', () => { }) describe('when editor.autoIndent is true', () => { - beforeEach(() => editor.update({autoIndent: true})) + beforeEach(() => editor.update({ autoIndent: true })) describe('when `indent` is triggered', () => { it('auto-indents the line', () => { @@ -6033,7 +6846,7 @@ describe('TextEditor', () => { editor.insertText('\n ') expect(editor.lineTextForBufferRow(2)).toBe(' ') - editor.update({autoIndent: true}) + editor.update({ autoIndent: true }) editor.indent() expect(editor.lineTextForBufferRow(2)).toBe(' ') }) @@ -6044,7 +6857,9 @@ describe('TextEditor', () => { it('indents the newline to one additional level of indentation beyond the preceding line', () => { editor.setCursorBufferPosition([1, Infinity]) editor.insertText('\n') - expect(editor.indentationForBufferRow(2)).toBe(editor.indentationForBufferRow(1) + 1) + expect(editor.indentationForBufferRow(2)).toBe( + editor.indentationForBufferRow(1) + 1 + ) }) }) @@ -6052,7 +6867,9 @@ describe('TextEditor', () => { it('indents the new line to the same level as the preceding line', () => { editor.setCursorBufferPosition([5, 14]) editor.insertText('\n') - expect(editor.indentationForBufferRow(6)).toBe(editor.indentationForBufferRow(5)) + expect(editor.indentationForBufferRow(6)).toBe( + editor.indentationForBufferRow(5) + ) }) }) @@ -6082,7 +6899,7 @@ describe('TextEditor', () => { editor.insertText(' var this-line-should-be-indented-more\n') expect(editor.indentationForBufferRow(1)).toBe(1) - editor.update({autoIndent: true}) + editor.update({ autoIndent: true }) editor.setCursorBufferPosition([2, Infinity]) editor.insertText('\n') expect(editor.indentationForBufferRow(1)).toBe(1) @@ -6107,9 +6924,13 @@ describe('TextEditor', () => { it('decreases the indentation to match that of the preceding line', () => { editor.setCursorBufferPosition([1, Infinity]) editor.insertText('\n') - expect(editor.indentationForBufferRow(2)).toBe(editor.indentationForBufferRow(1) + 1) + expect(editor.indentationForBufferRow(2)).toBe( + editor.indentationForBufferRow(1) + 1 + ) editor.insertText('}') - expect(editor.indentationForBufferRow(2)).toBe(editor.indentationForBufferRow(1)) + expect(editor.indentationForBufferRow(2)).toBe( + editor.indentationForBufferRow(1) + ) }) }) @@ -6117,15 +6938,21 @@ describe('TextEditor', () => { it('decreases the indentation to be one level below that of the preceding line', () => { editor.setCursorBufferPosition([3, Infinity]) editor.insertText('\n ') - expect(editor.indentationForBufferRow(4)).toBe(editor.indentationForBufferRow(3)) + expect(editor.indentationForBufferRow(4)).toBe( + editor.indentationForBufferRow(3) + ) editor.insertText('}') - expect(editor.indentationForBufferRow(4)).toBe(editor.indentationForBufferRow(3) - 1) + expect(editor.indentationForBufferRow(4)).toBe( + editor.indentationForBufferRow(3) - 1 + ) }) it("doesn't break when decreasing the indentation on a row that has no indentation", () => { editor.setCursorBufferPosition([12, Infinity]) editor.insertText('\n}; # too many closing brackets!') - expect(editor.lineTextForBufferRow(13)).toBe('}; # too many closing brackets!') + expect(editor.lineTextForBufferRow(13)).toBe( + '}; # too many closing brackets!' + ) }) }) }) @@ -6143,9 +6970,13 @@ describe('TextEditor', () => { describe('when the current line does not match a decrease indent pattern', () => { it('leaves the line unchanged', () => { editor.setCursorBufferPosition([2, 4]) - expect(editor.indentationForBufferRow(2)).toBe(editor.indentationForBufferRow(1) + 1) + expect(editor.indentationForBufferRow(2)).toBe( + editor.indentationForBufferRow(1) + 1 + ) editor.insertText('foo') - expect(editor.indentationForBufferRow(2)).toBe(editor.indentationForBufferRow(1) + 1) + expect(editor.indentationForBufferRow(2)).toBe( + editor.indentationForBufferRow(1) + 1 + ) }) }) }) @@ -6153,16 +6984,16 @@ describe('TextEditor', () => { describe('atomic soft tabs', () => { it('skips tab-length runs of leading whitespace when moving the cursor', () => { - editor.update({tabLength: 4, atomicSoftTabs: true}) + editor.update({ tabLength: 4, atomicSoftTabs: true }) editor.setCursorScreenPosition([2, 3]) expect(editor.getCursorScreenPosition()).toEqual([2, 4]) - editor.update({atomicSoftTabs: false}) + editor.update({ atomicSoftTabs: false }) editor.setCursorScreenPosition([2, 3]) expect(editor.getCursorScreenPosition()).toEqual([2, 3]) - editor.update({atomicSoftTabs: true}) + editor.update({ atomicSoftTabs: true }) editor.setCursorScreenPosition([2, 3]) expect(editor.getCursorScreenPosition()).toEqual([2, 4]) }) @@ -6181,7 +7012,7 @@ describe('TextEditor', () => { it('notifies ::onDidDestroy observers when the editor is destroyed', () => { let destroyObserverCalled = false - editor.onDidDestroy(() => destroyObserverCalled = true) + editor.onDidDestroy(() => (destroyObserverCalled = true)) editor.destroy() expect(destroyObserverCalled).toBe(true) @@ -6217,7 +7048,9 @@ describe('TextEditor', () => { editor.insertText(' ') editor.setCursorBufferPosition([0]) editor.joinLines() - expect(editor.lineTextForBufferRow(0)).toBe('var quicksort = function () { var sort = function(items) {') + expect(editor.lineTextForBufferRow(0)).toBe( + 'var quicksort = function () { var sort = function(items) {' + ) expect(editor.getCursorBufferPosition()).toEqual([0, 29]) }) }) @@ -6227,7 +7060,9 @@ describe('TextEditor', () => { editor.setCursorBufferPosition([9]) editor.joinLines() expect(editor.lineTextForBufferRow(9)).toBe(' };') - expect(editor.lineTextForBufferRow(10)).toBe(' return sort(Array.apply(this, arguments));') + expect(editor.lineTextForBufferRow(10)).toBe( + ' return sort(Array.apply(this, arguments));' + ) expect(editor.getCursorBufferPosition()).toEqual([9, 4]) }) }) @@ -6244,7 +7079,9 @@ describe('TextEditor', () => { it('joins the line below with the current line with no added space', () => { editor.setCursorBufferPosition([10]) editor.joinLines() - expect(editor.lineTextForBufferRow(10)).toBe('return sort(Array.apply(this, arguments));') + expect(editor.lineTextForBufferRow(10)).toBe( + 'return sort(Array.apply(this, arguments));' + ) expect(editor.getCursorBufferPosition()).toEqual([10, 0]) }) }) @@ -6255,7 +7092,9 @@ describe('TextEditor', () => { it('joins the line below with the current line separated by a space and retains the selected text', () => { editor.setSelectedBufferRange([[0, 1], [0, 3]]) editor.joinLines() - expect(editor.lineTextForBufferRow(0)).toBe('var quicksort = function () { var sort = function(items) {') + expect(editor.lineTextForBufferRow(0)).toBe( + 'var quicksort = function () { var sort = function(items) {' + ) expect(editor.getSelectedBufferRange()).toEqual([[0, 1], [0, 3]]) }) }) @@ -6264,7 +7103,9 @@ describe('TextEditor', () => { it('joins all selected lines separated by a space and retains the selected text', () => { editor.setSelectedBufferRange([[9, 3], [12, 1]]) editor.joinLines() - expect(editor.lineTextForBufferRow(9)).toBe(' }; return sort(Array.apply(this, arguments)); };') + expect(editor.lineTextForBufferRow(9)).toBe( + ' }; return sort(Array.apply(this, arguments)); };' + ) expect(editor.getSelectedBufferRange()).toEqual([[9, 3], [9, 49]]) }) }) @@ -6275,11 +7116,14 @@ describe('TextEditor', () => { it('for each selection, duplicates all buffer lines intersected by the selection', () => { editor.foldBufferRow(4) editor.setCursorBufferPosition([2, 5]) - editor.addSelectionForBufferRange([[3, 0], [8, 0]], {preserveFolds: true}) + editor.addSelectionForBufferRange([[3, 0], [8, 0]], { + preserveFolds: true + }) editor.duplicateLines() - expect(editor.getTextInBufferRange([[2, 0], [13, 5]])).toBe(dedent ` + expect(editor.getTextInBufferRange([[2, 0], [13, 5]])).toBe( + dedent` if (items.length <= 1) return items; if (items.length <= 1) return items; var pivot = items.shift(), current, left = [], right = []; @@ -6292,14 +7136,25 @@ describe('TextEditor', () => { current = items.shift(); current < pivot ? left.push(current) : right.push(current); }\ - `.split('\n').map(l => ` ${l}`).join('\n')) - expect(editor.getSelectedBufferRanges()).toEqual([[[3, 5], [3, 5]], [[9, 0], [14, 0]]]) + ` + .split('\n') + .map(l => ` ${l}`) + .join('\n') + ) + expect(editor.getSelectedBufferRanges()).toEqual([ + [[3, 5], [3, 5]], + [[9, 0], [14, 0]] + ]) // folds are also duplicated expect(editor.isFoldedAtScreenRow(5)).toBe(true) expect(editor.isFoldedAtScreenRow(7)).toBe(true) - expect(editor.lineTextForScreenRow(7)).toBe(` while(items.length > 0) {${editor.displayLayer.foldCharacter}}`) - expect(editor.lineTextForScreenRow(8)).toBe(' return sort(left).concat(pivot).concat(sort(right));') + expect(editor.lineTextForScreenRow(7)).toBe( + ` while(items.length > 0) {${editor.displayLayer.foldCharacter}}` + ) + expect(editor.lineTextForScreenRow(8)).toBe( + ' return sort(left).concat(pivot).concat(sort(right));' + ) }) it('duplicates all folded lines for empty selections on lines containing folds', () => { @@ -6308,7 +7163,8 @@ describe('TextEditor', () => { editor.duplicateLines() - expect(editor.getTextInBufferRange([[2, 0], [11, 5]])).toBe(dedent` + expect(editor.getTextInBufferRange([[2, 0], [11, 5]])).toBe( + dedent` if (items.length <= 1) return items; var pivot = items.shift(), current, left = [], right = []; while(items.length > 0) { @@ -6319,24 +7175,31 @@ describe('TextEditor', () => { current = items.shift(); current < pivot ? left.push(current) : right.push(current); } - `.split('\n').map(l => ` ${l}`).join('\n')) + ` + .split('\n') + .map(l => ` ${l}`) + .join('\n') + ) expect(editor.getSelectedBufferRange()).toEqual([[8, 0], [8, 0]]) }) it('can duplicate the last line of the buffer', () => { editor.setSelectedBufferRange([[11, 0], [12, 2]]) editor.duplicateLines() - expect(editor.getTextInBufferRange([[11, 0], [14, 2]])).toBe(' ' + dedent ` + expect(editor.getTextInBufferRange([[11, 0], [14, 2]])).toBe( + ' ' + + dedent` return sort(Array.apply(this, arguments)); }; return sort(Array.apply(this, arguments)); }; - `.trim()) + `.trim() + ) expect(editor.getSelectedBufferRange()).toEqual([[13, 0], [14, 2]]) }) it('only duplicates lines containing multiple selections once', () => { - editor.setText(dedent ` + editor.setText(dedent` aaaaaa bbbbbb cccccc @@ -6350,7 +7213,7 @@ describe('TextEditor', () => { [[3, 3], [3, 4]] ]) editor.duplicateLines() - expect(editor.getText()).toBe(dedent ` + expect(editor.getText()).toBe(dedent` aaaaaa aaaaaa bbbbbb @@ -6492,13 +7355,17 @@ describe('TextEditor', () => { await atom.packages.activatePackage('language-hyperlink') const grammar = atom.grammars.selectGrammar('text.js') - const {line, tags} = grammar.tokenizeLine('var i; // http://github.com') + const { line, tags } = grammar.tokenizeLine('var i; // http://github.com') const tokens = atom.grammars.decodeTokens(line, tags) expect(tokens[0].value).toBe('var') expect(tokens[0].scopes).toEqual(['source.js', 'storage.type.var.js']) expect(tokens[6].value).toBe('http://github.com') - expect(tokens[6].scopes).toEqual(['source.js', 'comment.line.double-slash.js', 'markup.underline.link.http.hyperlink']) + expect(tokens[6].scopes).toEqual([ + 'source.js', + 'comment.line.double-slash.js', + 'markup.underline.link.http.hyperlink' + ]) }) describe('when the grammar is added', () => { @@ -6507,16 +7374,49 @@ describe('TextEditor', () => { editor.setText('// http://github.com') let tokens = editor.tokensForScreenRow(0) expect(tokens).toEqual([ - {text: '//', scopes: ['syntax--source syntax--js', 'syntax--comment syntax--line syntax--double-slash syntax--js', 'syntax--punctuation syntax--definition syntax--comment syntax--js']}, - {text: ' http://github.com', scopes: ['syntax--source syntax--js', 'syntax--comment syntax--line syntax--double-slash syntax--js']} + { + text: '//', + scopes: [ + 'syntax--source syntax--js', + 'syntax--comment syntax--line syntax--double-slash syntax--js', + 'syntax--punctuation syntax--definition syntax--comment syntax--js' + ] + }, + { + text: ' http://github.com', + scopes: [ + 'syntax--source syntax--js', + 'syntax--comment syntax--line syntax--double-slash syntax--js' + ] + } ]) await atom.packages.activatePackage('language-hyperlink') tokens = editor.tokensForScreenRow(0) expect(tokens).toEqual([ - {text: '//', scopes: ['syntax--source syntax--js', 'syntax--comment syntax--line syntax--double-slash syntax--js', 'syntax--punctuation syntax--definition syntax--comment syntax--js']}, - {text: ' ', scopes: ['syntax--source syntax--js', 'syntax--comment syntax--line syntax--double-slash syntax--js']}, - {text: 'http://github.com', scopes: ['syntax--source syntax--js', 'syntax--comment syntax--line syntax--double-slash syntax--js', 'syntax--markup syntax--underline syntax--link syntax--http syntax--hyperlink']} + { + text: '//', + scopes: [ + 'syntax--source syntax--js', + 'syntax--comment syntax--line syntax--double-slash syntax--js', + 'syntax--punctuation syntax--definition syntax--comment syntax--js' + ] + }, + { + text: ' ', + scopes: [ + 'syntax--source syntax--js', + 'syntax--comment syntax--line syntax--double-slash syntax--js' + ] + }, + { + text: 'http://github.com', + scopes: [ + 'syntax--source syntax--js', + 'syntax--comment syntax--line syntax--double-slash syntax--js', + 'syntax--markup syntax--underline syntax--link syntax--http syntax--hyperlink' + ] + } ]) }) @@ -6526,28 +7426,106 @@ describe('TextEditor', () => { editor.setText('// SELECT * FROM OCTOCATS') let tokens = editor.tokensForScreenRow(0) expect(tokens).toEqual([ - {text: '//', scopes: ['syntax--source syntax--js', 'syntax--comment syntax--line syntax--double-slash syntax--js', 'syntax--punctuation syntax--definition syntax--comment syntax--js']}, - {text: ' SELECT * FROM OCTOCATS', scopes: ['syntax--source syntax--js', 'syntax--comment syntax--line syntax--double-slash syntax--js']} + { + text: '//', + scopes: [ + 'syntax--source syntax--js', + 'syntax--comment syntax--line syntax--double-slash syntax--js', + 'syntax--punctuation syntax--definition syntax--comment syntax--js' + ] + }, + { + text: ' SELECT * FROM OCTOCATS', + scopes: [ + 'syntax--source syntax--js', + 'syntax--comment syntax--line syntax--double-slash syntax--js' + ] + } ]) await atom.packages.activatePackage('package-with-injection-selector') tokens = editor.tokensForScreenRow(0) expect(tokens).toEqual([ - {text: '//', scopes: ['syntax--source syntax--js', 'syntax--comment syntax--line syntax--double-slash syntax--js', 'syntax--punctuation syntax--definition syntax--comment syntax--js']}, - {text: ' SELECT * FROM OCTOCATS', scopes: ['syntax--source syntax--js', 'syntax--comment syntax--line syntax--double-slash syntax--js']} + { + text: '//', + scopes: [ + 'syntax--source syntax--js', + 'syntax--comment syntax--line syntax--double-slash syntax--js', + 'syntax--punctuation syntax--definition syntax--comment syntax--js' + ] + }, + { + text: ' SELECT * FROM OCTOCATS', + scopes: [ + 'syntax--source syntax--js', + 'syntax--comment syntax--line syntax--double-slash syntax--js' + ] + } ]) await atom.packages.activatePackage('language-sql') tokens = editor.tokensForScreenRow(0) expect(tokens).toEqual([ - {text: '//', scopes: ['syntax--source syntax--js', 'syntax--comment syntax--line syntax--double-slash syntax--js', 'syntax--punctuation syntax--definition syntax--comment syntax--js']}, - {text: ' ', scopes: ['syntax--source syntax--js', 'syntax--comment syntax--line syntax--double-slash syntax--js']}, - {text: 'SELECT', scopes: ['syntax--source syntax--js', 'syntax--comment syntax--line syntax--double-slash syntax--js', 'syntax--keyword syntax--other syntax--DML syntax--sql']}, - {text: ' ', scopes: ['syntax--source syntax--js', 'syntax--comment syntax--line syntax--double-slash syntax--js']}, - {text: '*', scopes: ['syntax--source syntax--js', 'syntax--comment syntax--line syntax--double-slash syntax--js', 'syntax--keyword syntax--operator syntax--star syntax--sql']}, - {text: ' ', scopes: ['syntax--source syntax--js', 'syntax--comment syntax--line syntax--double-slash syntax--js']}, - {text: 'FROM', scopes: ['syntax--source syntax--js', 'syntax--comment syntax--line syntax--double-slash syntax--js', 'syntax--keyword syntax--other syntax--DML syntax--sql']}, - {text: ' OCTOCATS', scopes: ['syntax--source syntax--js', 'syntax--comment syntax--line syntax--double-slash syntax--js']} + { + text: '//', + scopes: [ + 'syntax--source syntax--js', + 'syntax--comment syntax--line syntax--double-slash syntax--js', + 'syntax--punctuation syntax--definition syntax--comment syntax--js' + ] + }, + { + text: ' ', + scopes: [ + 'syntax--source syntax--js', + 'syntax--comment syntax--line syntax--double-slash syntax--js' + ] + }, + { + text: 'SELECT', + scopes: [ + 'syntax--source syntax--js', + 'syntax--comment syntax--line syntax--double-slash syntax--js', + 'syntax--keyword syntax--other syntax--DML syntax--sql' + ] + }, + { + text: ' ', + scopes: [ + 'syntax--source syntax--js', + 'syntax--comment syntax--line syntax--double-slash syntax--js' + ] + }, + { + text: '*', + scopes: [ + 'syntax--source syntax--js', + 'syntax--comment syntax--line syntax--double-slash syntax--js', + 'syntax--keyword syntax--operator syntax--star syntax--sql' + ] + }, + { + text: ' ', + scopes: [ + 'syntax--source syntax--js', + 'syntax--comment syntax--line syntax--double-slash syntax--js' + ] + }, + { + text: 'FROM', + scopes: [ + 'syntax--source syntax--js', + 'syntax--comment syntax--line syntax--double-slash syntax--js', + 'syntax--keyword syntax--other syntax--DML syntax--sql' + ] + }, + { + text: ' OCTOCATS', + scopes: [ + 'syntax--source syntax--js', + 'syntax--comment syntax--line syntax--double-slash syntax--js' + ] + } ]) }) }) @@ -6574,10 +7552,10 @@ describe('TextEditor', () => { describe('.pageUp/Down()', () => { it('moves the cursor down one page length', () => { - editor.update({autoHeight: false}) + editor.update({ autoHeight: false }) const element = editor.getElement() jasmine.attachToDOM(element) - element.style.height = (element.component.getLineHeight() * 5) + 'px' + element.style.height = element.component.getLineHeight() * 5 + 'px' element.measureDimensions() expect(editor.getCursorBufferPosition().row).toBe(0) @@ -6598,10 +7576,10 @@ describe('TextEditor', () => { describe('.selectPageUp/Down()', () => { it('selects one screen height of text up or down', () => { - editor.update({autoHeight: false}) + editor.update({ autoHeight: false }) const element = editor.getElement() jasmine.attachToDOM(element) - element.style.height = (element.component.getLineHeight() * 5) + 'px' + element.style.height = element.component.getLineHeight() * 5 + 'px' element.measureDimensions() expect(editor.getCursorBufferPosition().row).toBe(0) @@ -6633,28 +7611,37 @@ describe('TextEditor', () => { editor.onDidRequestAutoscroll(scrollSpy) editor.scrollToScreenPosition([8, 20]) - editor.scrollToScreenPosition([8, 20], {center: true}) - editor.scrollToScreenPosition([8, 20], {center: false, reversed: true}) + editor.scrollToScreenPosition([8, 20], { center: true }) + editor.scrollToScreenPosition([8, 20], { center: false, reversed: true }) - expect(scrollSpy).toHaveBeenCalledWith({screenRange: [[8, 20], [8, 20]], options: {}}) - expect(scrollSpy).toHaveBeenCalledWith({screenRange: [[8, 20], [8, 20]], options: {center: true}}) - expect(scrollSpy).toHaveBeenCalledWith({screenRange: [[8, 20], [8, 20]], options: {center: false, reversed: true}}) + expect(scrollSpy).toHaveBeenCalledWith({ + screenRange: [[8, 20], [8, 20]], + options: {} + }) + expect(scrollSpy).toHaveBeenCalledWith({ + screenRange: [[8, 20], [8, 20]], + options: { center: true } + }) + expect(scrollSpy).toHaveBeenCalledWith({ + screenRange: [[8, 20], [8, 20]], + options: { center: false, reversed: true } + }) }) }) describe('scroll past end', () => { it('returns false by default but can be customized', () => { expect(editor.getScrollPastEnd()).toBe(false) - editor.update({scrollPastEnd: true}) + editor.update({ scrollPastEnd: true }) expect(editor.getScrollPastEnd()).toBe(true) - editor.update({scrollPastEnd: false}) + editor.update({ scrollPastEnd: false }) expect(editor.getScrollPastEnd()).toBe(false) }) it('always returns false when autoHeight is on', () => { - editor.update({autoHeight: true, scrollPastEnd: true}) + editor.update({ autoHeight: true, scrollPastEnd: true }) expect(editor.getScrollPastEnd()).toBe(false) - editor.update({autoHeight: false}) + editor.update({ autoHeight: false }) expect(editor.getScrollPastEnd()).toBe(true) }) }) @@ -6663,9 +7650,9 @@ describe('TextEditor', () => { it('returns true by default but can be customized', () => { editor = new TextEditor() expect(editor.getAutoHeight()).toBe(true) - editor.update({autoHeight: false}) + editor.update({ autoHeight: false }) expect(editor.getAutoHeight()).toBe(false) - editor.update({autoHeight: true}) + editor.update({ autoHeight: true }) expect(editor.getAutoHeight()).toBe(true) editor.destroy() }) @@ -6674,9 +7661,9 @@ describe('TextEditor', () => { describe('auto width', () => { it('returns false by default but can be customized', () => { expect(editor.getAutoWidth()).toBe(false) - editor.update({autoWidth: true}) + editor.update({ autoWidth: true }) expect(editor.getAutoWidth()).toBe(true) - editor.update({autoWidth: false}) + editor.update({ autoWidth: false }) expect(editor.getAutoWidth()).toBe(false) }) }) @@ -6692,7 +7679,7 @@ describe('TextEditor', () => { it('models placeholderText and emits an event when changed', () => { let handler - editor.onDidChangePlaceholderText(handler = jasmine.createSpy()) + editor.onDidChangePlaceholderText((handler = jasmine.createSpy())) expect(editor.getPlaceholderText()).toBeUndefined() @@ -6738,17 +7725,22 @@ describe('TextEditor', () => { expect(gutter.type).toBe('line-number') }) - it("does not allow a custom gutter with the 'line-number' name.", () => expect(editor.addGutter.bind(editor, {name: 'line-number'})).toThrow()) + it("does not allow a custom gutter with the 'line-number' name.", () => + expect( + editor.addGutter.bind(editor, { name: 'line-number' }) + ).toThrow()) }) describe('::decorateMarker', () => { let marker - beforeEach(() => marker = editor.markBufferRange([[1, 0], [1, 0]])) + beforeEach(() => (marker = editor.markBufferRange([[1, 0], [1, 0]]))) it('reflects an added decoration when one of its custom gutters is decorated.', () => { - const gutter = editor.addGutter({'name': 'custom-gutter'}) - const decoration = gutter.decorateMarker(marker, {class: 'custom-class'}) + const gutter = editor.addGutter({ name: 'custom-gutter' }) + const decoration = gutter.decorateMarker(marker, { + class: 'custom-class' + }) const gutterDecorations = editor.getDecorations({ type: 'gutter', gutterName: 'custom-gutter', @@ -6759,7 +7751,9 @@ describe('TextEditor', () => { }) it('reflects an added decoration when its line-number gutter is decorated.', () => { - const decoration = editor.gutterWithName('line-number').decorateMarker(marker, {class: 'test-class'}) + const decoration = editor + .gutterWithName('line-number') + .decorateMarker(marker, { class: 'test-class' }) const gutterDecorations = editor.getDecorations({ type: 'line-number', gutterName: 'line-number', @@ -6782,14 +7776,14 @@ describe('TextEditor', () => { const lineNumberGutter = editor.gutterWithName('line-number') editor.observeGutters(callback) expect(payloads).toEqual([lineNumberGutter]) - const gutter1 = editor.addGutter({name: 'test-gutter-1'}) + const gutter1 = editor.addGutter({ name: 'test-gutter-1' }) expect(payloads).toEqual([lineNumberGutter, gutter1]) - const gutter2 = editor.addGutter({name: 'test-gutter-2'}) + const gutter2 = editor.addGutter({ name: 'test-gutter-2' }) expect(payloads).toEqual([lineNumberGutter, gutter1, gutter2]) }) it('does not call the callback when a gutter is removed.', () => { - const gutter = editor.addGutter({name: 'test-gutter'}) + const gutter = editor.addGutter({ name: 'test-gutter' }) editor.observeGutters(callback) payloads = [] gutter.destroy() @@ -6800,7 +7794,7 @@ describe('TextEditor', () => { const subscription = editor.observeGutters(callback) payloads = [] subscription.dispose() - editor.addGutter({name: 'test-gutter'}) + editor.addGutter({ name: 'test-gutter' }) expect(payloads).toEqual([]) }) }) @@ -6816,7 +7810,7 @@ describe('TextEditor', () => { it('calls the callback with each newly-added gutter, but not with existing gutters.', () => { editor.onDidAddGutter(callback) expect(payloads).toEqual([]) - const gutter = editor.addGutter({name: 'test-gutter'}) + const gutter = editor.addGutter({ name: 'test-gutter' }) expect(payloads).toEqual([gutter]) }) @@ -6824,7 +7818,7 @@ describe('TextEditor', () => { const subscription = editor.onDidAddGutter(callback) payloads = [] subscription.dispose() - editor.addGutter({name: 'test-gutter'}) + editor.addGutter({ name: 'test-gutter' }) expect(payloads).toEqual([]) }) }) @@ -6838,7 +7832,7 @@ describe('TextEditor', () => { }) it('calls the callback when a gutter is removed.', () => { - const gutter = editor.addGutter({name: 'test-gutter'}) + const gutter = editor.addGutter({ name: 'test-gutter' }) editor.onDidRemoveGutter(callback) expect(payloads).toEqual([]) gutter.destroy() @@ -6846,7 +7840,7 @@ describe('TextEditor', () => { }) it('does not call the callback after the subscription has been disposed.', () => { - const gutter = editor.addGutter({name: 'test-gutter'}) + const gutter = editor.addGutter({ name: 'test-gutter' }) const subscription = editor.onDidRemoveGutter(callback) subscription.dispose() gutter.destroy() @@ -6859,9 +7853,19 @@ describe('TextEditor', () => { describe('::decorateMarker', () => { it('includes the decoration in the object returned from ::decorationsStateForScreenRowRange', () => { const marker = editor.markBufferRange([[2, 4], [6, 8]]) - const decoration = editor.decorateMarker(marker, {type: 'highlight', class: 'foo'}) - expect(editor.decorationsStateForScreenRowRange(0, 5)[decoration.id]).toEqual({ - properties: {id: decoration.id, order: Infinity, type: 'highlight', class: 'foo'}, + const decoration = editor.decorateMarker(marker, { + type: 'highlight', + class: 'foo' + }) + expect( + editor.decorationsStateForScreenRowRange(0, 5)[decoration.id] + ).toEqual({ + properties: { + id: decoration.id, + order: Infinity, + type: 'highlight', + class: 'foo' + }, screenRange: marker.getScreenRange(), bufferRange: marker.getBufferRange(), rangeIsReversed: false @@ -6871,7 +7875,10 @@ describe('TextEditor', () => { it("does not throw errors after the marker's containing layer is destroyed", () => { const layer = editor.addMarkerLayer() const marker = layer.markBufferRange([[2, 4], [6, 8]]) - const decoration = editor.decorateMarker(marker, {type: 'highlight', class: 'foo'}) + const decoration = editor.decorateMarker(marker, { + type: 'highlight', + class: 'foo' + }) layer.destroy() editor.decorationsStateForScreenRowRange(0, 5) }) @@ -6885,71 +7892,105 @@ describe('TextEditor', () => { const layer2 = editor.getBuffer().addMarkerLayer() const marker3 = layer2.markRange([[8, 0], [9, 0]]) - const layer1Decoration1 = editor.decorateMarkerLayer(layer1, {type: 'highlight', class: 'foo'}) - const layer1Decoration2 = editor.decorateMarkerLayer(layer1, {type: 'highlight', class: 'bar'}) - const layer2Decoration = editor.decorateMarkerLayer(layer2, {type: 'highlight', class: 'baz'}) + const layer1Decoration1 = editor.decorateMarkerLayer(layer1, { + type: 'highlight', + class: 'foo' + }) + const layer1Decoration2 = editor.decorateMarkerLayer(layer1, { + type: 'highlight', + class: 'bar' + }) + const layer2Decoration = editor.decorateMarkerLayer(layer2, { + type: 'highlight', + class: 'baz' + }) let decorationState = editor.decorationsStateForScreenRowRange(0, 13) - expect(decorationState[`${layer1Decoration1.id}-${marker1.id}`]).toEqual({ - properties: {type: 'highlight', class: 'foo'}, + expect( + decorationState[`${layer1Decoration1.id}-${marker1.id}`] + ).toEqual({ + properties: { type: 'highlight', class: 'foo' }, screenRange: marker1.getRange(), bufferRange: marker1.getRange(), rangeIsReversed: false }) - expect(decorationState[`${layer1Decoration1.id}-${marker2.id}`]).toEqual({ - properties: {type: 'highlight', class: 'foo'}, + expect( + decorationState[`${layer1Decoration1.id}-${marker2.id}`] + ).toEqual({ + properties: { type: 'highlight', class: 'foo' }, screenRange: marker2.getRange(), bufferRange: marker2.getRange(), rangeIsReversed: false }) - expect(decorationState[`${layer1Decoration2.id}-${marker1.id}`]).toEqual({ - properties: {type: 'highlight', class: 'bar'}, + expect( + decorationState[`${layer1Decoration2.id}-${marker1.id}`] + ).toEqual({ + properties: { type: 'highlight', class: 'bar' }, screenRange: marker1.getRange(), bufferRange: marker1.getRange(), rangeIsReversed: false }) - expect(decorationState[`${layer1Decoration2.id}-${marker2.id}`]).toEqual({ - properties: {type: 'highlight', class: 'bar'}, + expect( + decorationState[`${layer1Decoration2.id}-${marker2.id}`] + ).toEqual({ + properties: { type: 'highlight', class: 'bar' }, screenRange: marker2.getRange(), bufferRange: marker2.getRange(), rangeIsReversed: false }) - expect(decorationState[`${layer2Decoration.id}-${marker3.id}`]).toEqual({ - properties: {type: 'highlight', class: 'baz'}, - screenRange: marker3.getRange(), - bufferRange: marker3.getRange(), - rangeIsReversed: false - }) + expect(decorationState[`${layer2Decoration.id}-${marker3.id}`]).toEqual( + { + properties: { type: 'highlight', class: 'baz' }, + screenRange: marker3.getRange(), + bufferRange: marker3.getRange(), + rangeIsReversed: false + } + ) layer1Decoration1.destroy() decorationState = editor.decorationsStateForScreenRowRange(0, 12) - expect(decorationState[`${layer1Decoration1.id}-${marker1.id}`]).toBeUndefined() - expect(decorationState[`${layer1Decoration1.id}-${marker2.id}`]).toBeUndefined() - expect(decorationState[`${layer1Decoration2.id}-${marker1.id}`]).toEqual({ - properties: {type: 'highlight', class: 'bar'}, + expect( + decorationState[`${layer1Decoration1.id}-${marker1.id}`] + ).toBeUndefined() + expect( + decorationState[`${layer1Decoration1.id}-${marker2.id}`] + ).toBeUndefined() + expect( + decorationState[`${layer1Decoration2.id}-${marker1.id}`] + ).toEqual({ + properties: { type: 'highlight', class: 'bar' }, screenRange: marker1.getRange(), bufferRange: marker1.getRange(), rangeIsReversed: false }) - expect(decorationState[`${layer1Decoration2.id}-${marker2.id}`]).toEqual({ - properties: {type: 'highlight', class: 'bar'}, + expect( + decorationState[`${layer1Decoration2.id}-${marker2.id}`] + ).toEqual({ + properties: { type: 'highlight', class: 'bar' }, screenRange: marker2.getRange(), bufferRange: marker2.getRange(), rangeIsReversed: false }) - expect(decorationState[`${layer2Decoration.id}-${marker3.id}`]).toEqual({ - properties: {type: 'highlight', class: 'baz'}, - screenRange: marker3.getRange(), - bufferRange: marker3.getRange(), - rangeIsReversed: false - }) + expect(decorationState[`${layer2Decoration.id}-${marker3.id}`]).toEqual( + { + properties: { type: 'highlight', class: 'baz' }, + screenRange: marker3.getRange(), + bufferRange: marker3.getRange(), + rangeIsReversed: false + } + ) - layer1Decoration2.setPropertiesForMarker(marker1, {type: 'highlight', class: 'quux'}) + layer1Decoration2.setPropertiesForMarker(marker1, { + type: 'highlight', + class: 'quux' + }) decorationState = editor.decorationsStateForScreenRowRange(0, 12) - expect(decorationState[`${layer1Decoration2.id}-${marker1.id}`]).toEqual({ - properties: {type: 'highlight', class: 'quux'}, + expect( + decorationState[`${layer1Decoration2.id}-${marker1.id}`] + ).toEqual({ + properties: { type: 'highlight', class: 'quux' }, screenRange: marker1.getRange(), bufferRange: marker1.getRange(), rangeIsReversed: false @@ -6957,8 +7998,10 @@ describe('TextEditor', () => { layer1Decoration2.setPropertiesForMarker(marker1, null) decorationState = editor.decorationsStateForScreenRowRange(0, 12) - expect(decorationState[`${layer1Decoration2.id}-${marker1.id}`]).toEqual({ - properties: {type: 'highlight', class: 'bar'}, + expect( + decorationState[`${layer1Decoration2.id}-${marker1.id}`] + ).toEqual({ + properties: { type: 'highlight', class: 'bar' }, screenRange: marker1.getRange(), bufferRange: marker1.getRange(), rangeIsReversed: false @@ -6969,47 +8012,68 @@ describe('TextEditor', () => { describe('invisibles', () => { beforeEach(() => { - editor.update({showInvisibles: true}) + editor.update({ showInvisibles: true }) }) it('substitutes invisible characters according to the given rules', () => { const previousLineText = editor.lineTextForScreenRow(0) - editor.update({invisibles: {eol: '?'}}) + editor.update({ invisibles: { eol: '?' } }) expect(editor.lineTextForScreenRow(0)).not.toBe(previousLineText) expect(editor.lineTextForScreenRow(0).endsWith('?')).toBe(true) - expect(editor.getInvisibles()).toEqual({eol: '?'}) + expect(editor.getInvisibles()).toEqual({ eol: '?' }) }) it('does not use invisibles if showInvisibles is set to false', () => { - editor.update({invisibles: {eol: '?'}}) + editor.update({ invisibles: { eol: '?' } }) expect(editor.lineTextForScreenRow(0).endsWith('?')).toBe(true) - editor.update({showInvisibles: false}) + editor.update({ showInvisibles: false }) expect(editor.lineTextForScreenRow(0).endsWith('?')).toBe(false) }) }) describe('indent guides', () => { it('shows indent guides when `editor.showIndentGuide` is set to true and the editor is not mini', () => { - editor.update({showIndentGuide: false}) + editor.update({ showIndentGuide: false }) expect(editor.tokensForScreenRow(1).slice(0, 3)).toEqual([ - {text: ' ', scopes: ['syntax--source syntax--js', 'leading-whitespace']}, - {text: 'var', scopes: ['syntax--source syntax--js', 'syntax--storage syntax--type']}, - {text: ' sort ', scopes: ['syntax--source syntax--js']} + { + text: ' ', + scopes: ['syntax--source syntax--js', 'leading-whitespace'] + }, + { + text: 'var', + scopes: ['syntax--source syntax--js', 'syntax--storage syntax--type'] + }, + { text: ' sort ', scopes: ['syntax--source syntax--js'] } ]) - editor.update({showIndentGuide: true}) + editor.update({ showIndentGuide: true }) expect(editor.tokensForScreenRow(1).slice(0, 3)).toEqual([ - {text: ' ', scopes: ['syntax--source syntax--js', 'leading-whitespace indent-guide']}, - {text: 'var', scopes: ['syntax--source syntax--js', 'syntax--storage syntax--type']}, - {text: ' sort ', scopes: ['syntax--source syntax--js']} + { + text: ' ', + scopes: [ + 'syntax--source syntax--js', + 'leading-whitespace indent-guide' + ] + }, + { + text: 'var', + scopes: ['syntax--source syntax--js', 'syntax--storage syntax--type'] + }, + { text: ' sort ', scopes: ['syntax--source syntax--js'] } ]) editor.setMini(true) expect(editor.tokensForScreenRow(1).slice(0, 3)).toEqual([ - {text: ' ', scopes: ['syntax--source syntax--js', 'leading-whitespace']}, - {text: 'var', scopes: ['syntax--source syntax--js', 'syntax--storage syntax--type']}, - {text: ' sort ', scopes: ['syntax--source syntax--js']} + { + text: ' ', + scopes: ['syntax--source syntax--js', 'leading-whitespace'] + }, + { + text: 'var', + scopes: ['syntax--source syntax--js', 'syntax--storage syntax--type'] + }, + { text: ' sort ', scopes: ['syntax--source syntax--js'] } ]) }) }) @@ -7025,11 +8089,13 @@ describe('TextEditor', () => { expect(editor.lineTextForScreenRow(0)).toBe('var quicksort = ') - editor.update({editorWidthInChars: 10}) + editor.update({ editorWidthInChars: 10 }) expect(editor.lineTextForScreenRow(0)).toBe('var ') - editor.update({mini: true}) - expect(editor.lineTextForScreenRow(0)).toBe('var quicksort = function () {') + editor.update({ mini: true }) + expect(editor.lineTextForScreenRow(0)).toBe( + 'var quicksort = function () {' + ) }) }) @@ -7043,13 +8109,14 @@ describe('TextEditor', () => { }) expect(editor.lineTextForScreenRow(1)).toEqual(' 9') - editor.update({softWrapHangingIndentLength: 4}) + editor.update({ softWrapHangingIndentLength: 4 }) expect(editor.lineTextForScreenRow(1)).toEqual(' 9') }) }) describe('::getElement', () => { - it('returns an element', () => expect(editor.getElement() instanceof HTMLElement).toBe(true)) + it('returns an element', () => + expect(editor.getElement() instanceof HTMLElement).toBe(true)) }) describe('setMaxScreenLineLength', () => { @@ -7072,7 +8139,7 @@ describe('TextEditor', () => { describe('.scopeDescriptorForBufferPosition(position)', () => { it('returns a default scope descriptor when no language mode is assigned', () => { - editor = new TextEditor({buffer: new TextBuffer()}) + editor = new TextEditor({ buffer: new TextBuffer() }) const scopeDescriptor = editor.scopeDescriptorForBufferPosition([0, 0]) expect(scopeDescriptor.getScopesArray()).toEqual(['text']) }) @@ -7081,7 +8148,7 @@ describe('TextEditor', () => { describe('.syntaxTreeScopeDescriptorForBufferPosition(position)', () => { it('returns the result of scopeDescriptorForBufferPosition() when textmate language mode is used', async () => { atom.config.set('core.useTreeSitterParsers', false) - editor = await atom.workspace.open('sample.js', {autoIndent: false}) + editor = await atom.workspace.open('sample.js', { autoIndent: false }) await atom.packages.activatePackage('language-javascript') let buffer = editor.getBuffer() @@ -7098,7 +8165,9 @@ describe('TextEditor', () => { advanceClock() } - const syntaxTreeeScopeDescriptor = editor.syntaxTreeScopeDescriptorForBufferPosition([4, 17]) + const syntaxTreeeScopeDescriptor = editor.syntaxTreeScopeDescriptorForBufferPosition( + [4, 17] + ) expect(syntaxTreeeScopeDescriptor.getScopesArray()).toEqual([ 'source.js', 'support.variable.property.js' @@ -7106,17 +8175,21 @@ describe('TextEditor', () => { }) it('returns the result of syntaxTreeScopeDescriptorForBufferPosition() when tree-sitter language mode is used', async () => { - editor = await atom.workspace.open('sample.js', {autoIndent: false}) + editor = await atom.workspace.open('sample.js', { autoIndent: false }) await atom.packages.activatePackage('language-javascript') let buffer = editor.getBuffer() - buffer.setLanguageMode(new TreeSitterLanguageMode({ - buffer, - grammar: atom.grammars.grammarForScopeName('source.js') - })) + buffer.setLanguageMode( + new TreeSitterLanguageMode({ + buffer, + grammar: atom.grammars.grammarForScopeName('source.js') + }) + ) - const syntaxTreeeScopeDescriptor = editor.syntaxTreeScopeDescriptorForBufferPosition([4, 17]) + const syntaxTreeeScopeDescriptor = editor.syntaxTreeScopeDescriptorForBufferPosition( + [4, 17] + ) expect(syntaxTreeeScopeDescriptor.getScopesArray()).toEqual([ 'source.js', 'program', @@ -7154,7 +8227,9 @@ describe('TextEditor', () => { editor.setText('changed') atom.workspace.getActivePane().splitRight() - const editor2 = await atom.workspace.open('sample.js', {autoIndent: false}) + const editor2 = await atom.workspace.open('sample.js', { + autoIndent: false + }) expect(editor.shouldPromptToSave()).toBeFalsy() editor2.destroy() @@ -7169,20 +8244,40 @@ describe('TextEditor', () => { editor.setText('other stuff') fs.writeFileSync(editor.getPath(), 'new stuff') - expect(editor.shouldPromptToSave({windowCloseRequested: true, projectHasPaths: true})).toBeFalsy() + expect( + editor.shouldPromptToSave({ + windowCloseRequested: true, + projectHasPaths: true + }) + ).toBeFalsy() await new Promise(resolve => editor.onDidConflict(resolve)) - expect(editor.shouldPromptToSave({windowCloseRequested: true, projectHasPaths: true})).toBeTruthy() + expect( + editor.shouldPromptToSave({ + windowCloseRequested: true, + projectHasPaths: true + }) + ).toBeTruthy() }) it('returns false when the window is closing and the project has one or more directory paths', () => { editor.setText('changed') - expect(editor.shouldPromptToSave({windowCloseRequested: true, projectHasPaths: true})).toBeFalsy() + expect( + editor.shouldPromptToSave({ + windowCloseRequested: true, + projectHasPaths: true + }) + ).toBeFalsy() }) it('returns false when the window is closing and the project has no directory paths', () => { editor.setText('changed') - expect(editor.shouldPromptToSave({windowCloseRequested: true, projectHasPaths: false})).toBeTruthy() + expect( + editor.shouldPromptToSave({ + windowCloseRequested: true, + projectHasPaths: false + }) + ).toBeTruthy() }) }) @@ -7196,63 +8291,105 @@ describe('TextEditor', () => { editor.setSelectedBufferRange([[4, 5], [7, 5]]) editor.toggleLineCommentsInSelection() - expect(editor.lineTextForBufferRow(4)).toBe(' // while(items.length > 0) {') - expect(editor.lineTextForBufferRow(5)).toBe(' // current = items.shift();') - expect(editor.lineTextForBufferRow(6)).toBe(' // current < pivot ? left.push(current) : right.push(current);') + expect(editor.lineTextForBufferRow(4)).toBe( + ' // while(items.length > 0) {' + ) + expect(editor.lineTextForBufferRow(5)).toBe( + ' // current = items.shift();' + ) + expect(editor.lineTextForBufferRow(6)).toBe( + ' // current < pivot ? left.push(current) : right.push(current);' + ) expect(editor.lineTextForBufferRow(7)).toBe(' // }') expect(editor.getSelectedBufferRange()).toEqual([[4, 8], [7, 8]]) editor.toggleLineCommentsInSelection() - expect(editor.lineTextForBufferRow(4)).toBe(' while(items.length > 0) {') - expect(editor.lineTextForBufferRow(5)).toBe(' current = items.shift();') - expect(editor.lineTextForBufferRow(6)).toBe(' current < pivot ? left.push(current) : right.push(current);') + expect(editor.lineTextForBufferRow(4)).toBe( + ' while(items.length > 0) {' + ) + expect(editor.lineTextForBufferRow(5)).toBe( + ' current = items.shift();' + ) + expect(editor.lineTextForBufferRow(6)).toBe( + ' current < pivot ? left.push(current) : right.push(current);' + ) expect(editor.lineTextForBufferRow(7)).toBe(' }') }) it('does not comment the last line of a non-empty selection if it ends at column 0', () => { editor.setSelectedBufferRange([[4, 5], [7, 0]]) editor.toggleLineCommentsInSelection() - expect(editor.lineTextForBufferRow(4)).toBe(' // while(items.length > 0) {') - expect(editor.lineTextForBufferRow(5)).toBe(' // current = items.shift();') - expect(editor.lineTextForBufferRow(6)).toBe(' // current < pivot ? left.push(current) : right.push(current);') + expect(editor.lineTextForBufferRow(4)).toBe( + ' // while(items.length > 0) {' + ) + expect(editor.lineTextForBufferRow(5)).toBe( + ' // current = items.shift();' + ) + expect(editor.lineTextForBufferRow(6)).toBe( + ' // current < pivot ? left.push(current) : right.push(current);' + ) expect(editor.lineTextForBufferRow(7)).toBe(' }') }) it('uncomments lines if all lines match the comment regex', () => { editor.setSelectedBufferRange([[0, 0], [0, 1]]) editor.toggleLineCommentsInSelection() - expect(editor.lineTextForBufferRow(0)).toBe('// var quicksort = function () {') + expect(editor.lineTextForBufferRow(0)).toBe( + '// var quicksort = function () {' + ) editor.setSelectedBufferRange([[0, 0], [2, Infinity]]) editor.toggleLineCommentsInSelection() - expect(editor.lineTextForBufferRow(0)).toBe('// // var quicksort = function () {') - expect(editor.lineTextForBufferRow(1)).toBe('// var sort = function(items) {') - expect(editor.lineTextForBufferRow(2)).toBe('// if (items.length <= 1) return items;') + expect(editor.lineTextForBufferRow(0)).toBe( + '// // var quicksort = function () {' + ) + expect(editor.lineTextForBufferRow(1)).toBe( + '// var sort = function(items) {' + ) + expect(editor.lineTextForBufferRow(2)).toBe( + '// if (items.length <= 1) return items;' + ) editor.setSelectedBufferRange([[0, 0], [2, Infinity]]) editor.toggleLineCommentsInSelection() - expect(editor.lineTextForBufferRow(0)).toBe('// var quicksort = function () {') - expect(editor.lineTextForBufferRow(1)).toBe(' var sort = function(items) {') - expect(editor.lineTextForBufferRow(2)).toBe(' if (items.length <= 1) return items;') + expect(editor.lineTextForBufferRow(0)).toBe( + '// var quicksort = function () {' + ) + expect(editor.lineTextForBufferRow(1)).toBe( + ' var sort = function(items) {' + ) + expect(editor.lineTextForBufferRow(2)).toBe( + ' if (items.length <= 1) return items;' + ) editor.setSelectedBufferRange([[0, 0], [0, Infinity]]) editor.toggleLineCommentsInSelection() - expect(editor.lineTextForBufferRow(0)).toBe('var quicksort = function () {') + expect(editor.lineTextForBufferRow(0)).toBe( + 'var quicksort = function () {' + ) }) it('uncomments commented lines separated by an empty line', () => { editor.setSelectedBufferRange([[0, 0], [1, Infinity]]) editor.toggleLineCommentsInSelection() - expect(editor.lineTextForBufferRow(0)).toBe('// var quicksort = function () {') - expect(editor.lineTextForBufferRow(1)).toBe('// var sort = function(items) {') + expect(editor.lineTextForBufferRow(0)).toBe( + '// var quicksort = function () {' + ) + expect(editor.lineTextForBufferRow(1)).toBe( + '// var sort = function(items) {' + ) editor.getBuffer().insert([0, Infinity], '\n') editor.setSelectedBufferRange([[0, 0], [2, Infinity]]) editor.toggleLineCommentsInSelection() - expect(editor.lineTextForBufferRow(0)).toBe('var quicksort = function () {') + expect(editor.lineTextForBufferRow(0)).toBe( + 'var quicksort = function () {' + ) expect(editor.lineTextForBufferRow(1)).toBe('') - expect(editor.lineTextForBufferRow(2)).toBe(' var sort = function(items) {') + expect(editor.lineTextForBufferRow(2)).toBe( + ' var sort = function(items) {' + ) }) it('preserves selection emptiness', () => { @@ -7262,7 +8399,9 @@ describe('TextEditor', () => { }) it('does not explode if the current language mode has no comment regex', () => { - const editor = new TextEditor({buffer: new TextBuffer({text: 'hello'})}) + const editor = new TextEditor({ + buffer: new TextBuffer({ text: 'hello' }) + }) editor.setSelectedBufferRange([[0, 0], [0, 5]]) editor.toggleLineCommentsInSelection() expect(editor.lineTextForBufferRow(0)).toBe('hello') @@ -7340,35 +8479,50 @@ describe('TextEditor', () => { expect(editor.lineTextForBufferRow(0)).toBe('/* body {') expect(editor.lineTextForBufferRow(1)).toBe(' font-size: 1234px; */') expect(editor.lineTextForBufferRow(2)).toBe(' width: 110%;') - expect(editor.lineTextForBufferRow(3)).toBe(' font-weight: bold !important;') + expect(editor.lineTextForBufferRow(3)).toBe( + ' font-weight: bold !important;' + ) editor.toggleLineCommentsForBufferRows(2, 2) expect(editor.lineTextForBufferRow(0)).toBe('/* body {') expect(editor.lineTextForBufferRow(1)).toBe(' font-size: 1234px; */') expect(editor.lineTextForBufferRow(2)).toBe(' /* width: 110%; */') - expect(editor.lineTextForBufferRow(3)).toBe(' font-weight: bold !important;') + expect(editor.lineTextForBufferRow(3)).toBe( + ' font-weight: bold !important;' + ) editor.toggleLineCommentsForBufferRows(0, 1) expect(editor.lineTextForBufferRow(0)).toBe('body {') expect(editor.lineTextForBufferRow(1)).toBe(' font-size: 1234px;') expect(editor.lineTextForBufferRow(2)).toBe(' /* width: 110%; */') - expect(editor.lineTextForBufferRow(3)).toBe(' font-weight: bold !important;') + expect(editor.lineTextForBufferRow(3)).toBe( + ' font-weight: bold !important;' + ) }) it('uncomments lines with leading whitespace', () => { - editor.setTextInBufferRange([[2, 0], [2, Infinity]], ' /* width: 110%; */') + editor.setTextInBufferRange( + [[2, 0], [2, Infinity]], + ' /* width: 110%; */' + ) editor.toggleLineCommentsForBufferRows(2, 2) expect(editor.lineTextForBufferRow(2)).toBe(' width: 110%;') }) it('uncomments lines with trailing whitespace', () => { - editor.setTextInBufferRange([[2, 0], [2, Infinity]], '/* width: 110%; */ ') + editor.setTextInBufferRange( + [[2, 0], [2, Infinity]], + '/* width: 110%; */ ' + ) editor.toggleLineCommentsForBufferRows(2, 2) expect(editor.lineTextForBufferRow(2)).toBe('width: 110%; ') }) it('uncomments lines with leading and trailing whitespace', () => { - editor.setTextInBufferRange([[2, 0], [2, Infinity]], ' /* width: 110%; */ ') + editor.setTextInBufferRange( + [[2, 0], [2, Infinity]], + ' /* width: 110%; */ ' + ) editor.toggleLineCommentsForBufferRows(2, 2) expect(editor.lineTextForBufferRow(2)).toBe(' width: 110%; ') }) @@ -7382,7 +8536,9 @@ describe('TextEditor', () => { it('comments/uncomments lines in the given range', () => { editor.toggleLineCommentsForBufferRows(4, 6) - expect(editor.lineTextForBufferRow(4)).toBe(' # pivot = items.shift()') + expect(editor.lineTextForBufferRow(4)).toBe( + ' # pivot = items.shift()' + ) expect(editor.lineTextForBufferRow(5)).toBe(' # left = []') expect(editor.lineTextForBufferRow(6)).toBe(' # right = []') @@ -7394,7 +8550,9 @@ describe('TextEditor', () => { it('comments/uncomments empty lines', () => { editor.toggleLineCommentsForBufferRows(4, 7) - expect(editor.lineTextForBufferRow(4)).toBe(' # pivot = items.shift()') + expect(editor.lineTextForBufferRow(4)).toBe( + ' # pivot = items.shift()' + ) expect(editor.lineTextForBufferRow(5)).toBe(' # left = []') expect(editor.lineTextForBufferRow(6)).toBe(' # right = []') expect(editor.lineTextForBufferRow(7)).toBe(' # ') @@ -7415,15 +8573,27 @@ describe('TextEditor', () => { it('comments/uncomments lines in the given range', () => { editor.toggleLineCommentsForBufferRows(4, 7) - expect(editor.lineTextForBufferRow(4)).toBe(' // while(items.length > 0) {') - expect(editor.lineTextForBufferRow(5)).toBe(' // current = items.shift();') - expect(editor.lineTextForBufferRow(6)).toBe(' // current < pivot ? left.push(current) : right.push(current);') + expect(editor.lineTextForBufferRow(4)).toBe( + ' // while(items.length > 0) {' + ) + expect(editor.lineTextForBufferRow(5)).toBe( + ' // current = items.shift();' + ) + expect(editor.lineTextForBufferRow(6)).toBe( + ' // current < pivot ? left.push(current) : right.push(current);' + ) expect(editor.lineTextForBufferRow(7)).toBe(' // }') editor.toggleLineCommentsForBufferRows(4, 5) - expect(editor.lineTextForBufferRow(4)).toBe(' while(items.length > 0) {') - expect(editor.lineTextForBufferRow(5)).toBe(' current = items.shift();') - expect(editor.lineTextForBufferRow(6)).toBe(' // current < pivot ? left.push(current) : right.push(current);') + expect(editor.lineTextForBufferRow(4)).toBe( + ' while(items.length > 0) {' + ) + expect(editor.lineTextForBufferRow(5)).toBe( + ' current = items.shift();' + ) + expect(editor.lineTextForBufferRow(6)).toBe( + ' // current < pivot ? left.push(current) : right.push(current);' + ) expect(editor.lineTextForBufferRow(7)).toBe(' // }') editor.setText('\tvar i;') @@ -7462,7 +8632,7 @@ describe('TextEditor', () => { }) it('maintains cursor buffer position when a folding/unfolding', async () => { - editor = await atom.workspace.open('sample.js', {autoIndent: false}) + editor = await atom.workspace.open('sample.js', { autoIndent: false }) editor.setCursorBufferPosition([5, 5]) editor.foldAll() expect(editor.getCursorBufferPosition()).toEqual([5, 5]) @@ -7470,7 +8640,7 @@ describe('TextEditor', () => { describe('.unfoldAll()', () => { it('unfolds every folded line', async () => { - editor = await atom.workspace.open('sample.js', {autoIndent: false}) + editor = await atom.workspace.open('sample.js', { autoIndent: false }) const initialScreenLineCount = editor.getScreenLineCount() editor.foldBufferRow(0) @@ -7481,7 +8651,9 @@ describe('TextEditor', () => { }) it('unfolds every folded line with comments', async () => { - editor = await atom.workspace.open('sample-with-comments.js', {autoIndent: false}) + editor = await atom.workspace.open('sample-with-comments.js', { + autoIndent: false + }) const initialScreenLineCount = editor.getScreenLineCount() editor.foldBufferRow(0) @@ -7494,7 +8666,7 @@ describe('TextEditor', () => { describe('.foldAll()', () => { it('folds every foldable line', async () => { - editor = await atom.workspace.open('sample.js', {autoIndent: false}) + editor = await atom.workspace.open('sample.js', { autoIndent: false }) editor.foldAll() const [fold1, fold2, fold3] = editor.unfoldAll() @@ -7568,26 +8740,40 @@ describe('TextEditor', () => { describe('.foldAllAtIndentLevel(indentLevel)', () => { it('folds blocks of text at the given indentation level', async () => { - editor = await atom.workspace.open('sample.js', {autoIndent: false}) + editor = await atom.workspace.open('sample.js', { autoIndent: false }) editor.foldAllAtIndentLevel(0) - expect(editor.lineTextForScreenRow(0)).toBe(`var quicksort = function () {${editor.displayLayer.foldCharacter}};`) + expect(editor.lineTextForScreenRow(0)).toBe( + `var quicksort = function () {${editor.displayLayer.foldCharacter}};` + ) expect(editor.getLastScreenRow()).toBe(0) editor.foldAllAtIndentLevel(1) - expect(editor.lineTextForScreenRow(0)).toBe('var quicksort = function () {') - expect(editor.lineTextForScreenRow(1)).toBe(` var sort = function(items) {${editor.displayLayer.foldCharacter}};`) + expect(editor.lineTextForScreenRow(0)).toBe( + 'var quicksort = function () {' + ) + expect(editor.lineTextForScreenRow(1)).toBe( + ` var sort = function(items) {${editor.displayLayer.foldCharacter}};` + ) expect(editor.getLastScreenRow()).toBe(4) editor.foldAllAtIndentLevel(2) - expect(editor.lineTextForScreenRow(0)).toBe('var quicksort = function () {') - expect(editor.lineTextForScreenRow(1)).toBe(' var sort = function(items) {') - expect(editor.lineTextForScreenRow(2)).toBe(' if (items.length <= 1) return items;') + expect(editor.lineTextForScreenRow(0)).toBe( + 'var quicksort = function () {' + ) + expect(editor.lineTextForScreenRow(1)).toBe( + ' var sort = function(items) {' + ) + expect(editor.lineTextForScreenRow(2)).toBe( + ' if (items.length <= 1) return items;' + ) expect(editor.getLastScreenRow()).toBe(9) }) it('does not fold anything but the indentLevel', async () => { - editor = await atom.workspace.open('sample-with-comments.js', {autoIndent: false}) + editor = await atom.workspace.open('sample-with-comments.js', { + autoIndent: false + }) editor.foldAllAtIndentLevel(0) const folds = editor.unfoldAll() diff --git a/spec/text-mate-language-mode-spec.js b/spec/text-mate-language-mode-spec.js index 47b79af2d..3b1aae9b5 100644 --- a/spec/text-mate-language-mode-spec.js +++ b/spec/text-mate-language-mode-spec.js @@ -1,10 +1,17 @@ const NullGrammar = require('../src/null-grammar') const TextMateLanguageMode = require('../src/text-mate-language-mode') const TextBuffer = require('text-buffer') -const {Point, Range} = TextBuffer +const { Point, Range } = TextBuffer const _ = require('underscore-plus') const dedent = require('dedent') -const {it, fit, ffit, fffit, beforeEach, afterEach} = require('./async-spec-helpers') +const { + it, + fit, + ffit, + fffit, + beforeEach, + afterEach +} = require('./async-spec-helpers') describe('TextMateLanguageMode', () => { let languageMode, buffer, config @@ -40,15 +47,15 @@ describe('TextMateLanguageMode', () => { // It treats the entire line as one big token let iterator = languageMode.buildHighlightIterator() - iterator.seek({row: 0, column: 0}) + iterator.seek({ row: 0, column: 0 }) iterator.moveToSuccessor() - expect(iterator.getPosition()).toEqual({row: 0, column: 7}) + expect(iterator.getPosition()).toEqual({ row: 0, column: 7 }) buffer.insert([0, 0], 'hey"') iterator = languageMode.buildHighlightIterator() - iterator.seek({row: 0, column: 0}) + iterator.seek({ row: 0, column: 0 }) iterator.moveToSuccessor() - expect(iterator.getPosition()).toEqual({row: 0, column: 11}) + expect(iterator.getPosition()).toEqual({ row: 0, column: 11 }) }) }) @@ -56,7 +63,12 @@ describe('TextMateLanguageMode', () => { describe('when the buffer is destroyed', () => { beforeEach(() => { buffer = atom.project.bufferForPathSync('sample.js') - languageMode = new TextMateLanguageMode({buffer, config, config, grammar: atom.grammars.grammarForScopeName('source.js')}) + languageMode = new TextMateLanguageMode({ + buffer, + config, + config, + grammar: atom.grammars.grammarForScopeName('source.js') + }) languageMode.startTokenizing() }) @@ -71,7 +83,11 @@ describe('TextMateLanguageMode', () => { describe('when the buffer contains soft-tabs', () => { beforeEach(() => { buffer = atom.project.bufferForPathSync('sample.js') - languageMode = new TextMateLanguageMode({buffer, config, grammar: atom.grammars.grammarForScopeName('source.js')}) + languageMode = new TextMateLanguageMode({ + buffer, + config, + grammar: atom.grammars.grammarForScopeName('source.js') + }) buffer.setLanguageMode(languageMode) languageMode.startTokenizing() }) @@ -105,8 +121,7 @@ describe('TextMateLanguageMode', () => { advanceClock() expect(languageMode.tokenizedLines[10].ruleStack != null).toBeTruthy() expect(languageMode.tokenizedLines[12].ruleStack != null).toBeTruthy() - }) - ) + })) describe('when the buffer is partially tokenized', () => { beforeEach(() => { @@ -168,22 +183,44 @@ describe('TextMateLanguageMode', () => { it('updates tokens to reflect the change', () => { buffer.setTextInRange([[0, 0], [2, 0]], 'foo()\n7\n') - expect(languageMode.tokenizedLines[0].tokens[1]).toEqual({value: '(', scopes: ['source.js', 'meta.function-call.js', 'meta.arguments.js', 'punctuation.definition.arguments.begin.bracket.round.js']}) - expect(languageMode.tokenizedLines[1].tokens[0]).toEqual({value: '7', scopes: ['source.js', 'constant.numeric.decimal.js']}) + expect(languageMode.tokenizedLines[0].tokens[1]).toEqual({ + value: '(', + scopes: [ + 'source.js', + 'meta.function-call.js', + 'meta.arguments.js', + 'punctuation.definition.arguments.begin.bracket.round.js' + ] + }) + expect(languageMode.tokenizedLines[1].tokens[0]).toEqual({ + value: '7', + scopes: ['source.js', 'constant.numeric.decimal.js'] + }) // line 2 is unchanged - expect(languageMode.tokenizedLines[2].tokens[1]).toEqual({value: 'if', scopes: ['source.js', 'keyword.control.js']}) + expect(languageMode.tokenizedLines[2].tokens[1]).toEqual({ + value: 'if', + scopes: ['source.js', 'keyword.control.js'] + }) }) describe('when the change invalidates the tokenization of subsequent lines', () => { it('schedules the invalidated lines to be tokenized in the background', () => { buffer.insert([5, 30], '/* */') buffer.insert([2, 0], '/*') - expect(languageMode.tokenizedLines[3].tokens[0].scopes).toEqual(['source.js']) + expect(languageMode.tokenizedLines[3].tokens[0].scopes).toEqual( + ['source.js'] + ) advanceClock() - expect(languageMode.tokenizedLines[3].tokens[0].scopes).toEqual(['source.js', 'comment.block.js']) - expect(languageMode.tokenizedLines[4].tokens[0].scopes).toEqual(['source.js', 'comment.block.js']) - expect(languageMode.tokenizedLines[5].tokens[0].scopes).toEqual(['source.js', 'comment.block.js']) + expect(languageMode.tokenizedLines[3].tokens[0].scopes).toEqual( + ['source.js', 'comment.block.js'] + ) + expect(languageMode.tokenizedLines[4].tokens[0].scopes).toEqual( + ['source.js', 'comment.block.js'] + ) + expect(languageMode.tokenizedLines[5].tokens[0].scopes).toEqual( + ['source.js', 'comment.block.js'] + ) }) }) @@ -192,7 +229,10 @@ describe('TextMateLanguageMode', () => { buffer.insert([5, 0], '*/') buffer.insert([1, 0], 'var ') - expect(languageMode.tokenizedLines[1].tokens[0].scopes).toEqual(['source.js', 'comment.block.js']) + expect(languageMode.tokenizedLines[1].tokens[0].scopes).toEqual([ + 'source.js', + 'comment.block.js' + ]) }) }) @@ -201,16 +241,38 @@ describe('TextMateLanguageMode', () => { buffer.setTextInRange([[1, 0], [3, 0]], 'foo()') // previous line 0 remains - expect(languageMode.tokenizedLines[0].tokens[0]).toEqual({value: 'var', scopes: ['source.js', 'storage.type.var.js']}) + expect(languageMode.tokenizedLines[0].tokens[0]).toEqual({ + value: 'var', + scopes: ['source.js', 'storage.type.var.js'] + }) // previous line 3 should be combined with input to form line 1 - expect(languageMode.tokenizedLines[1].tokens[0]).toEqual({value: 'foo', scopes: ['source.js', 'meta.function-call.js', 'entity.name.function.js']}) - expect(languageMode.tokenizedLines[1].tokens[6]).toEqual({value: '=', scopes: ['source.js', 'keyword.operator.assignment.js']}) + expect(languageMode.tokenizedLines[1].tokens[0]).toEqual({ + value: 'foo', + scopes: [ + 'source.js', + 'meta.function-call.js', + 'entity.name.function.js' + ] + }) + expect(languageMode.tokenizedLines[1].tokens[6]).toEqual({ + value: '=', + scopes: ['source.js', 'keyword.operator.assignment.js'] + }) // lines below deleted regions should be shifted upward - expect(languageMode.tokenizedLines[2].tokens[1]).toEqual({value: 'while', scopes: ['source.js', 'keyword.control.js']}) - expect(languageMode.tokenizedLines[3].tokens[1]).toEqual({value: '=', scopes: ['source.js', 'keyword.operator.assignment.js']}) - expect(languageMode.tokenizedLines[4].tokens[1]).toEqual({value: '<', scopes: ['source.js', 'keyword.operator.comparison.js']}) + expect(languageMode.tokenizedLines[2].tokens[1]).toEqual({ + value: 'while', + scopes: ['source.js', 'keyword.control.js'] + }) + expect(languageMode.tokenizedLines[3].tokens[1]).toEqual({ + value: '=', + scopes: ['source.js', 'keyword.operator.assignment.js'] + }) + expect(languageMode.tokenizedLines[4].tokens[1]).toEqual({ + value: '<', + scopes: ['source.js', 'keyword.operator.comparison.js'] + }) }) }) @@ -218,33 +280,85 @@ describe('TextMateLanguageMode', () => { it('schedules the invalidated lines to be tokenized in the background', () => { buffer.insert([5, 30], '/* */') buffer.setTextInRange([[2, 0], [3, 0]], '/*') - expect(languageMode.tokenizedLines[2].tokens[0].scopes).toEqual(['source.js', 'comment.block.js', 'punctuation.definition.comment.begin.js']) - expect(languageMode.tokenizedLines[3].tokens[0].scopes).toEqual(['source.js']) + expect(languageMode.tokenizedLines[2].tokens[0].scopes).toEqual([ + 'source.js', + 'comment.block.js', + 'punctuation.definition.comment.begin.js' + ]) + expect(languageMode.tokenizedLines[3].tokens[0].scopes).toEqual([ + 'source.js' + ]) advanceClock() - expect(languageMode.tokenizedLines[3].tokens[0].scopes).toEqual(['source.js', 'comment.block.js']) - expect(languageMode.tokenizedLines[4].tokens[0].scopes).toEqual(['source.js', 'comment.block.js']) + expect(languageMode.tokenizedLines[3].tokens[0].scopes).toEqual([ + 'source.js', + 'comment.block.js' + ]) + expect(languageMode.tokenizedLines[4].tokens[0].scopes).toEqual([ + 'source.js', + 'comment.block.js' + ]) }) }) describe('when lines are both updated and inserted', () => { it('updates tokens to reflect the change', () => { - buffer.setTextInRange([[1, 0], [2, 0]], 'foo()\nbar()\nbaz()\nquux()') + buffer.setTextInRange( + [[1, 0], [2, 0]], + 'foo()\nbar()\nbaz()\nquux()' + ) // previous line 0 remains - expect(languageMode.tokenizedLines[0].tokens[0]).toEqual({ value: 'var', scopes: ['source.js', 'storage.type.var.js']}) + expect(languageMode.tokenizedLines[0].tokens[0]).toEqual({ + value: 'var', + scopes: ['source.js', 'storage.type.var.js'] + }) // 3 new lines inserted - expect(languageMode.tokenizedLines[1].tokens[0]).toEqual({value: 'foo', scopes: ['source.js', 'meta.function-call.js', 'entity.name.function.js']}) - expect(languageMode.tokenizedLines[2].tokens[0]).toEqual({value: 'bar', scopes: ['source.js', 'meta.function-call.js', 'entity.name.function.js']}) - expect(languageMode.tokenizedLines[3].tokens[0]).toEqual({value: 'baz', scopes: ['source.js', 'meta.function-call.js', 'entity.name.function.js']}) + expect(languageMode.tokenizedLines[1].tokens[0]).toEqual({ + value: 'foo', + scopes: [ + 'source.js', + 'meta.function-call.js', + 'entity.name.function.js' + ] + }) + expect(languageMode.tokenizedLines[2].tokens[0]).toEqual({ + value: 'bar', + scopes: [ + 'source.js', + 'meta.function-call.js', + 'entity.name.function.js' + ] + }) + expect(languageMode.tokenizedLines[3].tokens[0]).toEqual({ + value: 'baz', + scopes: [ + 'source.js', + 'meta.function-call.js', + 'entity.name.function.js' + ] + }) // previous line 2 is joined with quux() on line 4 - expect(languageMode.tokenizedLines[4].tokens[0]).toEqual({value: 'quux', scopes: ['source.js', 'meta.function-call.js', 'entity.name.function.js']}) - expect(languageMode.tokenizedLines[4].tokens[4]).toEqual({value: 'if', scopes: ['source.js', 'keyword.control.js']}) + expect(languageMode.tokenizedLines[4].tokens[0]).toEqual({ + value: 'quux', + scopes: [ + 'source.js', + 'meta.function-call.js', + 'entity.name.function.js' + ] + }) + expect(languageMode.tokenizedLines[4].tokens[4]).toEqual({ + value: 'if', + scopes: ['source.js', 'keyword.control.js'] + }) // previous line 3 is pushed down to become line 5 - expect(languageMode.tokenizedLines[5].tokens[3]).toEqual({value: '=', scopes: ['source.js', 'keyword.operator.assignment.js']}) + expect(languageMode.tokenizedLines[5].tokens[3]).toEqual({ + value: '=', + scopes: ['source.js', 'keyword.operator.assignment.js'] + }) }) }) @@ -252,31 +366,66 @@ describe('TextMateLanguageMode', () => { it('schedules the invalidated lines to be tokenized in the background', () => { buffer.insert([5, 30], '/* */') buffer.insert([2, 0], '/*\nabcde\nabcder') - expect(languageMode.tokenizedLines[2].tokens[0].scopes).toEqual(['source.js', 'comment.block.js', 'punctuation.definition.comment.begin.js']) - expect(languageMode.tokenizedLines[3].tokens[0].scopes).toEqual(['source.js', 'comment.block.js']) - expect(languageMode.tokenizedLines[4].tokens[0].scopes).toEqual(['source.js', 'comment.block.js']) - expect(languageMode.tokenizedLines[5].tokens[0].scopes).toEqual(['source.js']) + expect(languageMode.tokenizedLines[2].tokens[0].scopes).toEqual([ + 'source.js', + 'comment.block.js', + 'punctuation.definition.comment.begin.js' + ]) + expect(languageMode.tokenizedLines[3].tokens[0].scopes).toEqual([ + 'source.js', + 'comment.block.js' + ]) + expect(languageMode.tokenizedLines[4].tokens[0].scopes).toEqual([ + 'source.js', + 'comment.block.js' + ]) + expect(languageMode.tokenizedLines[5].tokens[0].scopes).toEqual([ + 'source.js' + ]) advanceClock() // tokenize invalidated lines in background - expect(languageMode.tokenizedLines[5].tokens[0].scopes).toEqual(['source.js', 'comment.block.js']) - expect(languageMode.tokenizedLines[6].tokens[0].scopes).toEqual(['source.js', 'comment.block.js']) - expect(languageMode.tokenizedLines[7].tokens[0].scopes).toEqual(['source.js', 'comment.block.js']) - expect(languageMode.tokenizedLines[8].tokens[0].scopes).not.toBe(['source.js', 'comment.block.js']) + expect(languageMode.tokenizedLines[5].tokens[0].scopes).toEqual([ + 'source.js', + 'comment.block.js' + ]) + expect(languageMode.tokenizedLines[6].tokens[0].scopes).toEqual([ + 'source.js', + 'comment.block.js' + ]) + expect(languageMode.tokenizedLines[7].tokens[0].scopes).toEqual([ + 'source.js', + 'comment.block.js' + ]) + expect(languageMode.tokenizedLines[8].tokens[0].scopes).not.toBe([ + 'source.js', + 'comment.block.js' + ]) }) }) }) describe('when there is an insertion that is larger than the chunk size', () => { it('tokenizes the initial chunk synchronously, then tokenizes the remaining lines in the background', () => { - const commentBlock = _.multiplyString('// a comment\n', languageMode.chunkSize + 2) + const commentBlock = _.multiplyString( + '// a comment\n', + languageMode.chunkSize + 2 + ) buffer.insert([0, 0], commentBlock) - expect(languageMode.tokenizedLines[0].ruleStack != null).toBeTruthy() - expect(languageMode.tokenizedLines[4].ruleStack != null).toBeTruthy() + expect( + languageMode.tokenizedLines[0].ruleStack != null + ).toBeTruthy() + expect( + languageMode.tokenizedLines[4].ruleStack != null + ).toBeTruthy() expect(languageMode.tokenizedLines[5]).toBeUndefined() advanceClock() - expect(languageMode.tokenizedLines[5].ruleStack != null).toBeTruthy() - expect(languageMode.tokenizedLines[6].ruleStack != null).toBeTruthy() + expect( + languageMode.tokenizedLines[5].ruleStack != null + ).toBeTruthy() + expect( + languageMode.tokenizedLines[6].ruleStack != null + ).toBeTruthy() }) }) }) @@ -287,7 +436,11 @@ describe('TextMateLanguageMode', () => { atom.packages.activatePackage('language-coffee-script') buffer = atom.project.bufferForPathSync('sample-with-tabs.coffee') - languageMode = new TextMateLanguageMode({buffer, config, grammar: atom.grammars.grammarForScopeName('source.coffee')}) + languageMode = new TextMateLanguageMode({ + buffer, + config, + grammar: atom.grammars.grammarForScopeName('source.coffee') + }) languageMode.startTokenizing() }) @@ -328,7 +481,9 @@ describe('TextMateLanguageMode', () => { let tokenizationCount = 0 const editor = await atom.workspace.open('coffee.coffee') - editor.onDidTokenize(() => { tokenizationCount++ }) + editor.onDidTokenize(() => { + tokenizationCount++ + }) fullyTokenize(editor.getBuffer().getLanguageMode()) tokenizationCount = 0 @@ -344,7 +499,11 @@ describe('TextMateLanguageMode', () => { buffer = atom.project.bufferForPathSync() buffer.setText("
    <%= User.find(2).full_name %>
    ") - languageMode = new TextMateLanguageMode({buffer, config, grammar: atom.grammars.selectGrammar('test.erb')}) + languageMode = new TextMateLanguageMode({ + buffer, + config, + grammar: atom.grammars.selectGrammar('test.erb') + }) fullyTokenize(languageMode) expect(languageMode.tokenizedLines[0].tokens[0]).toEqual({ value: "
    ", @@ -355,7 +514,11 @@ describe('TextMateLanguageMode', () => { fullyTokenize(languageMode) expect(languageMode.tokenizedLines[0].tokens[0]).toEqual({ value: '<', - scopes: ['text.html.ruby', 'meta.tag.block.div.html', 'punctuation.definition.tag.begin.html'] + scopes: [ + 'text.html.ruby', + 'meta.tag.block.div.html', + 'punctuation.definition.tag.begin.html' + ] }) }) }) @@ -363,9 +526,11 @@ describe('TextMateLanguageMode', () => { describe('when the buffer is configured with the null grammar', () => { it('does not actually tokenize using the grammar', () => { spyOn(NullGrammar, 'tokenizeLine').andCallThrough() - buffer = atom.project.bufferForPathSync('sample.will-use-the-null-grammar') + buffer = atom.project.bufferForPathSync( + 'sample.will-use-the-null-grammar' + ) buffer.setText('a\nb\nc') - languageMode = new TextMateLanguageMode({buffer, config}) + languageMode = new TextMateLanguageMode({ buffer, config }) const tokenizeCallback = jasmine.createSpy('onDidTokenize') languageMode.onDidTokenize(tokenizeCallback) @@ -393,35 +558,64 @@ describe('TextMateLanguageMode', () => { it('returns the correct token (regression)', () => { buffer = atom.project.bufferForPathSync('sample.js') - languageMode = new TextMateLanguageMode({buffer, config, grammar: atom.grammars.grammarForScopeName('source.js')}) + languageMode = new TextMateLanguageMode({ + buffer, + config, + grammar: atom.grammars.grammarForScopeName('source.js') + }) fullyTokenize(languageMode) - expect(languageMode.tokenForPosition([1, 0]).scopes).toEqual(['source.js']) - expect(languageMode.tokenForPosition([1, 1]).scopes).toEqual(['source.js']) - expect(languageMode.tokenForPosition([1, 2]).scopes).toEqual(['source.js', 'storage.type.var.js']) + expect(languageMode.tokenForPosition([1, 0]).scopes).toEqual([ + 'source.js' + ]) + expect(languageMode.tokenForPosition([1, 1]).scopes).toEqual([ + 'source.js' + ]) + expect(languageMode.tokenForPosition([1, 2]).scopes).toEqual([ + 'source.js', + 'storage.type.var.js' + ]) }) }) describe('.bufferRangeForScopeAtPosition(selector, position)', () => { beforeEach(() => { buffer = atom.project.bufferForPathSync('sample.js') - languageMode = new TextMateLanguageMode({buffer, config, grammar: atom.grammars.grammarForScopeName('source.js')}) + languageMode = new TextMateLanguageMode({ + buffer, + config, + grammar: atom.grammars.grammarForScopeName('source.js') + }) fullyTokenize(languageMode) }) describe('when the selector does not match the token at the position', () => - it('returns a falsy value', () => expect(languageMode.bufferRangeForScopeAtPosition('.bogus', [0, 1])).toBeUndefined()) - ) + it('returns a falsy value', () => + expect( + languageMode.bufferRangeForScopeAtPosition('.bogus', [0, 1]) + ).toBeUndefined())) describe('when the selector matches a single token at the position', () => { it('returns the range covered by the token', () => { - expect(languageMode.bufferRangeForScopeAtPosition('.storage.type.var.js', [0, 1])).toEqual([[0, 0], [0, 3]]) - expect(languageMode.bufferRangeForScopeAtPosition('.storage.type.var.js', [0, 3])).toEqual([[0, 0], [0, 3]]) + expect( + languageMode.bufferRangeForScopeAtPosition('.storage.type.var.js', [ + 0, + 1 + ]) + ).toEqual([[0, 0], [0, 3]]) + expect( + languageMode.bufferRangeForScopeAtPosition('.storage.type.var.js', [ + 0, + 3 + ]) + ).toEqual([[0, 0], [0, 3]]) }) }) describe('when the selector matches a run of multiple tokens at the position', () => { it('returns the range covered by all contiguous tokens (within a single line)', () => { - expect(languageMode.bufferRangeForScopeAtPosition('.function', [1, 18])).toEqual([[1, 6], [1, 28]]) + expect( + languageMode.bufferRangeForScopeAtPosition('.function', [1, 18]) + ).toEqual([[1, 6], [1, 28]]) }) }) }) @@ -430,7 +624,7 @@ describe('TextMateLanguageMode', () => { it("returns the tokenized line for a row, or a placeholder line if it hasn't been tokenized yet", () => { buffer = atom.project.bufferForPathSync('sample.js') const grammar = atom.grammars.grammarForScopeName('source.js') - languageMode = new TextMateLanguageMode({buffer, config, grammar}) + languageMode = new TextMateLanguageMode({ buffer, config, grammar }) const line0 = buffer.lineForRow(0) const jsScopeStartId = grammar.startIdForScope(grammar.scopeName) @@ -438,93 +632,220 @@ describe('TextMateLanguageMode', () => { languageMode.startTokenizing() expect(languageMode.tokenizedLines[0]).toBeUndefined() expect(languageMode.tokenizedLineForRow(0).text).toBe(line0) - expect(languageMode.tokenizedLineForRow(0).tags).toEqual([jsScopeStartId, line0.length, jsScopeEndId]) + expect(languageMode.tokenizedLineForRow(0).tags).toEqual([ + jsScopeStartId, + line0.length, + jsScopeEndId + ]) advanceClock(1) expect(languageMode.tokenizedLines[0]).not.toBeUndefined() expect(languageMode.tokenizedLineForRow(0).text).toBe(line0) - expect(languageMode.tokenizedLineForRow(0).tags).not.toEqual([jsScopeStartId, line0.length, jsScopeEndId]) + expect(languageMode.tokenizedLineForRow(0).tags).not.toEqual([ + jsScopeStartId, + line0.length, + jsScopeEndId + ]) }) it('returns undefined if the requested row is outside the buffer range', () => { buffer = atom.project.bufferForPathSync('sample.js') const grammar = atom.grammars.grammarForScopeName('source.js') - languageMode = new TextMateLanguageMode({buffer, config, grammar}) + languageMode = new TextMateLanguageMode({ buffer, config, grammar }) fullyTokenize(languageMode) expect(languageMode.tokenizedLineForRow(999)).toBeUndefined() }) }) describe('.buildHighlightIterator', () => { - const {TextMateHighlightIterator} = TextMateLanguageMode + const { TextMateHighlightIterator } = TextMateLanguageMode it('iterates over the syntactic scope boundaries', () => { - buffer = new TextBuffer({text: 'var foo = 1 /*\nhello*/var bar = 2\n'}) - languageMode = new TextMateLanguageMode({buffer, config, grammar: atom.grammars.grammarForScopeName('source.js')}) + buffer = new TextBuffer({ text: 'var foo = 1 /*\nhello*/var bar = 2\n' }) + languageMode = new TextMateLanguageMode({ + buffer, + config, + grammar: atom.grammars.grammarForScopeName('source.js') + }) fullyTokenize(languageMode) const iterator = languageMode.buildHighlightIterator() iterator.seek(Point(0, 0)) const expectedBoundaries = [ - {position: Point(0, 0), closeTags: [], openTags: ['syntax--source syntax--js', 'syntax--storage syntax--type syntax--var syntax--js']}, - {position: Point(0, 3), closeTags: ['syntax--storage syntax--type syntax--var syntax--js'], openTags: []}, - {position: Point(0, 8), closeTags: [], openTags: ['syntax--keyword syntax--operator syntax--assignment syntax--js']}, - {position: Point(0, 9), closeTags: ['syntax--keyword syntax--operator syntax--assignment syntax--js'], openTags: []}, - {position: Point(0, 10), closeTags: [], openTags: ['syntax--constant syntax--numeric syntax--decimal syntax--js']}, - {position: Point(0, 11), closeTags: ['syntax--constant syntax--numeric syntax--decimal syntax--js'], openTags: []}, - {position: Point(0, 12), closeTags: [], openTags: ['syntax--comment syntax--block syntax--js', 'syntax--punctuation syntax--definition syntax--comment syntax--begin syntax--js']}, - {position: Point(0, 14), closeTags: ['syntax--punctuation syntax--definition syntax--comment syntax--begin syntax--js'], openTags: []}, - {position: Point(1, 5), closeTags: [], openTags: ['syntax--punctuation syntax--definition syntax--comment syntax--end syntax--js']}, - {position: Point(1, 7), closeTags: ['syntax--punctuation syntax--definition syntax--comment syntax--end syntax--js', 'syntax--comment syntax--block syntax--js'], openTags: ['syntax--storage syntax--type syntax--var syntax--js']}, - {position: Point(1, 10), closeTags: ['syntax--storage syntax--type syntax--var syntax--js'], openTags: []}, - {position: Point(1, 15), closeTags: [], openTags: ['syntax--keyword syntax--operator syntax--assignment syntax--js']}, - {position: Point(1, 16), closeTags: ['syntax--keyword syntax--operator syntax--assignment syntax--js'], openTags: []}, - {position: Point(1, 17), closeTags: [], openTags: ['syntax--constant syntax--numeric syntax--decimal syntax--js']}, - {position: Point(1, 18), closeTags: ['syntax--constant syntax--numeric syntax--decimal syntax--js'], openTags: []} + { + position: Point(0, 0), + closeTags: [], + openTags: [ + 'syntax--source syntax--js', + 'syntax--storage syntax--type syntax--var syntax--js' + ] + }, + { + position: Point(0, 3), + closeTags: ['syntax--storage syntax--type syntax--var syntax--js'], + openTags: [] + }, + { + position: Point(0, 8), + closeTags: [], + openTags: [ + 'syntax--keyword syntax--operator syntax--assignment syntax--js' + ] + }, + { + position: Point(0, 9), + closeTags: [ + 'syntax--keyword syntax--operator syntax--assignment syntax--js' + ], + openTags: [] + }, + { + position: Point(0, 10), + closeTags: [], + openTags: [ + 'syntax--constant syntax--numeric syntax--decimal syntax--js' + ] + }, + { + position: Point(0, 11), + closeTags: [ + 'syntax--constant syntax--numeric syntax--decimal syntax--js' + ], + openTags: [] + }, + { + position: Point(0, 12), + closeTags: [], + openTags: [ + 'syntax--comment syntax--block syntax--js', + 'syntax--punctuation syntax--definition syntax--comment syntax--begin syntax--js' + ] + }, + { + position: Point(0, 14), + closeTags: [ + 'syntax--punctuation syntax--definition syntax--comment syntax--begin syntax--js' + ], + openTags: [] + }, + { + position: Point(1, 5), + closeTags: [], + openTags: [ + 'syntax--punctuation syntax--definition syntax--comment syntax--end syntax--js' + ] + }, + { + position: Point(1, 7), + closeTags: [ + 'syntax--punctuation syntax--definition syntax--comment syntax--end syntax--js', + 'syntax--comment syntax--block syntax--js' + ], + openTags: ['syntax--storage syntax--type syntax--var syntax--js'] + }, + { + position: Point(1, 10), + closeTags: ['syntax--storage syntax--type syntax--var syntax--js'], + openTags: [] + }, + { + position: Point(1, 15), + closeTags: [], + openTags: [ + 'syntax--keyword syntax--operator syntax--assignment syntax--js' + ] + }, + { + position: Point(1, 16), + closeTags: [ + 'syntax--keyword syntax--operator syntax--assignment syntax--js' + ], + openTags: [] + }, + { + position: Point(1, 17), + closeTags: [], + openTags: [ + 'syntax--constant syntax--numeric syntax--decimal syntax--js' + ] + }, + { + position: Point(1, 18), + closeTags: [ + 'syntax--constant syntax--numeric syntax--decimal syntax--js' + ], + openTags: [] + } ] while (true) { const boundary = { position: iterator.getPosition(), - closeTags: iterator.getCloseScopeIds().map(scopeId => languageMode.classNameForScopeId(scopeId)), - openTags: iterator.getOpenScopeIds().map(scopeId => languageMode.classNameForScopeId(scopeId)) + closeTags: iterator + .getCloseScopeIds() + .map(scopeId => languageMode.classNameForScopeId(scopeId)), + openTags: iterator + .getOpenScopeIds() + .map(scopeId => languageMode.classNameForScopeId(scopeId)) } expect(boundary).toEqual(expectedBoundaries.shift()) - if (!iterator.moveToSuccessor()) { break } + if (!iterator.moveToSuccessor()) { + break + } } - expect(iterator.seek(Point(0, 1)).map(scopeId => languageMode.classNameForScopeId(scopeId))).toEqual([ + expect( + iterator + .seek(Point(0, 1)) + .map(scopeId => languageMode.classNameForScopeId(scopeId)) + ).toEqual([ 'syntax--source syntax--js', 'syntax--storage syntax--type syntax--var syntax--js' ]) expect(iterator.getPosition()).toEqual(Point(0, 3)) - expect(iterator.seek(Point(0, 8)).map(scopeId => languageMode.classNameForScopeId(scopeId))).toEqual([ - 'syntax--source syntax--js' - ]) + expect( + iterator + .seek(Point(0, 8)) + .map(scopeId => languageMode.classNameForScopeId(scopeId)) + ).toEqual(['syntax--source syntax--js']) expect(iterator.getPosition()).toEqual(Point(0, 8)) - expect(iterator.seek(Point(1, 0)).map(scopeId => languageMode.classNameForScopeId(scopeId))).toEqual([ + expect( + iterator + .seek(Point(1, 0)) + .map(scopeId => languageMode.classNameForScopeId(scopeId)) + ).toEqual([ 'syntax--source syntax--js', 'syntax--comment syntax--block syntax--js' ]) expect(iterator.getPosition()).toEqual(Point(1, 0)) - expect(iterator.seek(Point(1, 18)).map(scopeId => languageMode.classNameForScopeId(scopeId))).toEqual([ + expect( + iterator + .seek(Point(1, 18)) + .map(scopeId => languageMode.classNameForScopeId(scopeId)) + ).toEqual([ 'syntax--source syntax--js', 'syntax--constant syntax--numeric syntax--decimal syntax--js' ]) expect(iterator.getPosition()).toEqual(Point(1, 18)) - expect(iterator.seek(Point(2, 0)).map(scopeId => languageMode.classNameForScopeId(scopeId))).toEqual([ - 'syntax--source syntax--js' - ]) + expect( + iterator + .seek(Point(2, 0)) + .map(scopeId => languageMode.classNameForScopeId(scopeId)) + ).toEqual(['syntax--source syntax--js']) iterator.moveToSuccessor() }) // ensure we don't infinitely loop (regression test) it('does not report columns beyond the length of the line', async () => { await atom.packages.activatePackage('language-coffee-script') - buffer = new TextBuffer({text: '# hello\n# world'}) - languageMode = new TextMateLanguageMode({buffer, config, grammar: atom.grammars.grammarForScopeName('source.coffee')}) + buffer = new TextBuffer({ text: '# hello\n# world' }) + languageMode = new TextMateLanguageMode({ + buffer, + config, + grammar: atom.grammars.grammarForScopeName('source.coffee') + }) fullyTokenize(languageMode) const iterator = languageMode.buildHighlightIterator() @@ -545,24 +866,32 @@ describe('TextMateLanguageMode', () => { it('correctly terminates scopes at the beginning of the line (regression)', () => { const grammar = atom.grammars.createGrammar('test', { - 'scopeName': 'text.broken', - 'name': 'Broken grammar', - 'patterns': [ - {'begin': 'start', 'end': '(?=end)', 'name': 'blue.broken'}, - {'match': '.', 'name': 'yellow.broken'} + scopeName: 'text.broken', + name: 'Broken grammar', + patterns: [ + { begin: 'start', end: '(?=end)', name: 'blue.broken' }, + { match: '.', name: 'yellow.broken' } ] }) - buffer = new TextBuffer({text: 'start x\nend x\nx'}) - languageMode = new TextMateLanguageMode({buffer, config, grammar}) + buffer = new TextBuffer({ text: 'start x\nend x\nx' }) + languageMode = new TextMateLanguageMode({ buffer, config, grammar }) fullyTokenize(languageMode) const iterator = languageMode.buildHighlightIterator() iterator.seek(Point(1, 0)) expect(iterator.getPosition()).toEqual([1, 0]) - expect(iterator.getCloseScopeIds().map(scopeId => languageMode.classNameForScopeId(scopeId))).toEqual(['syntax--blue syntax--broken']) - expect(iterator.getOpenScopeIds().map(scopeId => languageMode.classNameForScopeId(scopeId))).toEqual(['syntax--yellow syntax--broken']) + expect( + iterator + .getCloseScopeIds() + .map(scopeId => languageMode.classNameForScopeId(scopeId)) + ).toEqual(['syntax--blue syntax--broken']) + expect( + iterator + .getOpenScopeIds() + .map(scopeId => languageMode.classNameForScopeId(scopeId)) + ).toEqual(['syntax--yellow syntax--broken']) }) describe('TextMateHighlightIterator.seek(position)', function () { @@ -675,7 +1004,7 @@ describe('TextMateLanguageMode', () => { describe('javascript', () => { beforeEach(async () => { - editor = await atom.workspace.open('sample.js', {autoIndent: false}) + editor = await atom.workspace.open('sample.js', { autoIndent: false }) await atom.packages.activatePackage('language-javascript') }) @@ -690,7 +1019,7 @@ describe('TextMateLanguageMode', () => { }) it('does not take invisibles into account', () => { - editor.update({showInvisibles: true}) + editor.update({ showInvisibles: true }) expect(editor.suggestedIndentForBufferRow(0)).toBe(0) expect(editor.suggestedIndentForBufferRow(1)).toBe(1) expect(editor.suggestedIndentForBufferRow(2)).toBe(2) @@ -703,7 +1032,7 @@ describe('TextMateLanguageMode', () => { describe('css', () => { beforeEach(async () => { - editor = await atom.workspace.open('css.css', {autoIndent: true}) + editor = await atom.workspace.open('css.css', { autoIndent: true }) await atom.packages.activatePackage('language-source') await atom.packages.activatePackage('language-css') }) @@ -720,7 +1049,11 @@ describe('TextMateLanguageMode', () => { buffer = atom.project.bufferForPathSync('sample.js') buffer.insert([10, 0], ' // multi-line\n // comment\n // block\n') buffer.insert([0, 0], '// multi-line\n// comment\n// block\n') - languageMode = new TextMateLanguageMode({buffer, config, grammar: atom.grammars.grammarForScopeName('source.js')}) + languageMode = new TextMateLanguageMode({ + buffer, + config, + grammar: atom.grammars.grammarForScopeName('source.js') + }) buffer.setLanguageMode(languageMode) fullyTokenize(languageMode) }) @@ -820,7 +1153,7 @@ describe('TextMateLanguageMode', () => { describe('.getFoldableRangesAtIndentLevel', () => { it('returns the ranges that can be folded at the given indent level', () => { - buffer = new TextBuffer(dedent ` + buffer = new TextBuffer(dedent` if (a) { b(); if (c) { @@ -838,9 +1171,10 @@ describe('TextMateLanguageMode', () => { } `) - languageMode = new TextMateLanguageMode({buffer, config}) + languageMode = new TextMateLanguageMode({ buffer, config }) - expect(simulateFold(languageMode.getFoldableRangesAtIndentLevel(0, 2))).toBe(dedent ` + expect(simulateFold(languageMode.getFoldableRangesAtIndentLevel(0, 2))) + .toBe(dedent` if (a) {⋯ } i() @@ -848,7 +1182,8 @@ describe('TextMateLanguageMode', () => { } `) - expect(simulateFold(languageMode.getFoldableRangesAtIndentLevel(1, 2))).toBe(dedent ` + expect(simulateFold(languageMode.getFoldableRangesAtIndentLevel(1, 2))) + .toBe(dedent` if (a) { b(); if (c) {⋯ @@ -861,7 +1196,8 @@ describe('TextMateLanguageMode', () => { } `) - expect(simulateFold(languageMode.getFoldableRangesAtIndentLevel(2, 2))).toBe(dedent ` + expect(simulateFold(languageMode.getFoldableRangesAtIndentLevel(2, 2))) + .toBe(dedent` if (a) { b(); if (c) { @@ -896,7 +1232,7 @@ describe('TextMateLanguageMode', () => { describe('.getFoldableRanges', () => { it('returns the ranges that can be folded', () => { - buffer = new TextBuffer(dedent ` + buffer = new TextBuffer(dedent` if (a) { b(); if (c) { @@ -914,18 +1250,24 @@ describe('TextMateLanguageMode', () => { } `) - languageMode = new TextMateLanguageMode({buffer, config}) + languageMode = new TextMateLanguageMode({ buffer, config }) - expect(languageMode.getFoldableRanges(2).map(r => r.toString())).toEqual([ - ...languageMode.getFoldableRangesAtIndentLevel(0, 2), - ...languageMode.getFoldableRangesAtIndentLevel(1, 2), - ...languageMode.getFoldableRangesAtIndentLevel(2, 2), - ].sort((a, b) => (a.start.row - b.start.row) || (a.end.row - b.end.row)).map(r => r.toString())) + expect(languageMode.getFoldableRanges(2).map(r => r.toString())).toEqual( + [ + ...languageMode.getFoldableRangesAtIndentLevel(0, 2), + ...languageMode.getFoldableRangesAtIndentLevel(1, 2), + ...languageMode.getFoldableRangesAtIndentLevel(2, 2) + ] + .sort((a, b) => a.start.row - b.start.row || a.end.row - b.end.row) + .map(r => r.toString()) + ) }) it('works with multi-line comments', async () => { await atom.packages.activatePackage('language-javascript') - editor = await atom.workspace.open('sample-with-comments.js', {autoIndent: false}) + editor = await atom.workspace.open('sample-with-comments.js', { + autoIndent: false + }) fullyTokenize(editor.getBuffer().getLanguageMode()) editor.foldAll() @@ -944,7 +1286,7 @@ describe('TextMateLanguageMode', () => { describe('.getFoldableRangeContainingPoint', () => { it('returns the range for the smallest fold that contains the given range', () => { - buffer = new TextBuffer(dedent ` + buffer = new TextBuffer(dedent` if (a) { b(); if (c) { @@ -962,12 +1304,14 @@ describe('TextMateLanguageMode', () => { } `) - languageMode = new TextMateLanguageMode({buffer, config}) + languageMode = new TextMateLanguageMode({ buffer, config }) - expect(languageMode.getFoldableRangeContainingPoint(Point(0, 5), 2)).toBeNull() + expect( + languageMode.getFoldableRangeContainingPoint(Point(0, 5), 2) + ).toBeNull() let range = languageMode.getFoldableRangeContainingPoint(Point(0, 10), 2) - expect(simulateFold([range])).toBe(dedent ` + expect(simulateFold([range])).toBe(dedent` if (a) {⋯ } i() @@ -977,7 +1321,7 @@ describe('TextMateLanguageMode', () => { `) range = languageMode.getFoldableRangeContainingPoint(Point(7, 0), 2) - expect(simulateFold([range])).toBe(dedent ` + expect(simulateFold([range])).toBe(dedent` if (a) { b(); if (c) {⋯ @@ -990,8 +1334,11 @@ describe('TextMateLanguageMode', () => { } `) - range = languageMode.getFoldableRangeContainingPoint(Point(1, Infinity), 2) - expect(simulateFold([range])).toBe(dedent ` + range = languageMode.getFoldableRangeContainingPoint( + Point(1, Infinity), + 2 + ) + expect(simulateFold([range])).toBe(dedent` if (a) {⋯ } i() @@ -1001,7 +1348,7 @@ describe('TextMateLanguageMode', () => { `) range = languageMode.getFoldableRangeContainingPoint(Point(2, 20), 2) - expect(simulateFold([range])).toBe(dedent ` + expect(simulateFold([range])).toBe(dedent` if (a) { b(); if (c) {⋯ @@ -1021,10 +1368,18 @@ describe('TextMateLanguageMode', () => { buffer = editor.buffer languageMode = editor.languageMode - expect(languageMode.getFoldableRangeContainingPoint(Point(0, Infinity), 2)).toEqual([[0, Infinity], [20, Infinity]]) - expect(languageMode.getFoldableRangeContainingPoint(Point(1, Infinity), 2)).toEqual([[1, Infinity], [17, Infinity]]) - expect(languageMode.getFoldableRangeContainingPoint(Point(2, Infinity), 2)).toEqual([[1, Infinity], [17, Infinity]]) - expect(languageMode.getFoldableRangeContainingPoint(Point(19, Infinity), 2)).toEqual([[19, Infinity], [20, Infinity]]) + expect( + languageMode.getFoldableRangeContainingPoint(Point(0, Infinity), 2) + ).toEqual([[0, Infinity], [20, Infinity]]) + expect( + languageMode.getFoldableRangeContainingPoint(Point(1, Infinity), 2) + ).toEqual([[1, Infinity], [17, Infinity]]) + expect( + languageMode.getFoldableRangeContainingPoint(Point(2, Infinity), 2) + ).toEqual([[1, Infinity], [17, Infinity]]) + expect( + languageMode.getFoldableRangeContainingPoint(Point(19, Infinity), 2) + ).toEqual([[19, Infinity], [20, Infinity]]) }) it('works for javascript', async () => { @@ -1033,16 +1388,39 @@ describe('TextMateLanguageMode', () => { buffer = editor.buffer languageMode = editor.languageMode - expect(editor.languageMode.getFoldableRangeContainingPoint(Point(0, Infinity), 2)).toEqual([[0, Infinity], [12, Infinity]]) - expect(editor.languageMode.getFoldableRangeContainingPoint(Point(1, Infinity), 2)).toEqual([[1, Infinity], [9, Infinity]]) - expect(editor.languageMode.getFoldableRangeContainingPoint(Point(2, Infinity), 2)).toEqual([[1, Infinity], [9, Infinity]]) - expect(editor.languageMode.getFoldableRangeContainingPoint(Point(4, Infinity), 2)).toEqual([[4, Infinity], [7, Infinity]]) + expect( + editor.languageMode.getFoldableRangeContainingPoint( + Point(0, Infinity), + 2 + ) + ).toEqual([[0, Infinity], [12, Infinity]]) + expect( + editor.languageMode.getFoldableRangeContainingPoint( + Point(1, Infinity), + 2 + ) + ).toEqual([[1, Infinity], [9, Infinity]]) + expect( + editor.languageMode.getFoldableRangeContainingPoint( + Point(2, Infinity), + 2 + ) + ).toEqual([[1, Infinity], [9, Infinity]]) + expect( + editor.languageMode.getFoldableRangeContainingPoint( + Point(4, Infinity), + 2 + ) + ).toEqual([[4, Infinity], [7, Infinity]]) }) it('searches upward and downward for surrounding comment lines and folds them as a single fold', async () => { await atom.packages.activatePackage('language-javascript') editor = await atom.workspace.open('sample-with-comments.js') - editor.buffer.insert([1, 0], ' //this is a comment\n // and\n //more docs\n\n//second comment') + editor.buffer.insert( + [1, 0], + ' //this is a comment\n // and\n //more docs\n\n//second comment' + ) fullyTokenize(editor.getBuffer().getLanguageMode()) editor.foldBufferRow(1) const [fold] = editor.unfoldAll() @@ -1053,26 +1431,28 @@ describe('TextMateLanguageMode', () => { describe('TokenIterator', () => it('correctly terminates scopes at the beginning of the line (regression)', () => { const grammar = atom.grammars.createGrammar('test', { - 'scopeName': 'text.broken', - 'name': 'Broken grammar', - 'patterns': [ + scopeName: 'text.broken', + name: 'Broken grammar', + patterns: [ { - 'begin': 'start', - 'end': '(?=end)', - 'name': 'blue.broken' + begin: 'start', + end: '(?=end)', + name: 'blue.broken' }, { - 'match': '.', - 'name': 'yellow.broken' + match: '.', + name: 'yellow.broken' } ] }) - const buffer = new TextBuffer({text: dedent` + const buffer = new TextBuffer({ + text: dedent` start x end x x - `}) + ` + }) const languageMode = new TextMateLanguageMode({ buffer, @@ -1085,14 +1465,18 @@ describe('TextMateLanguageMode', () => { fullyTokenize(languageMode) - const tokenIterator = languageMode.tokenizedLineForRow(1).getTokenIterator() + const tokenIterator = languageMode + .tokenizedLineForRow(1) + .getTokenIterator() tokenIterator.next() expect(tokenIterator.getBufferStart()).toBe(0) expect(tokenIterator.getScopeEnds()).toEqual([]) - expect(tokenIterator.getScopeStarts()).toEqual(['text.broken', 'yellow.broken']) - }) - ) + expect(tokenIterator.getScopeStarts()).toEqual([ + 'text.broken', + 'yellow.broken' + ]) + })) function simulateFold (ranges) { buffer.transact(() => { diff --git a/spec/text-utils-spec.js b/spec/text-utils-spec.js index 3a4b29866..ca0e2a6d7 100644 --- a/spec/text-utils-spec.js +++ b/spec/text-utils-spec.js @@ -4,7 +4,9 @@ describe('text utilities', () => { describe('.hasPairedCharacter(string)', () => it('returns true when the string contains a surrogate pair, variation sequence, or combined character', () => { expect(textUtils.hasPairedCharacter('abc')).toBe(false) - expect(textUtils.hasPairedCharacter('a\uD835\uDF97b\uD835\uDF97c')).toBe(true) + expect(textUtils.hasPairedCharacter('a\uD835\uDF97b\uD835\uDF97c')).toBe( + true + ) expect(textUtils.hasPairedCharacter('\uD835\uDF97')).toBe(true) expect(textUtils.hasPairedCharacter('\u2714\uFE0E')).toBe(true) expect(textUtils.hasPairedCharacter('e\u0301')).toBe(true) @@ -16,18 +18,31 @@ describe('text utilities', () => { expect(textUtils.hasPairedCharacter('\uFE0E\uFE0E')).toBe(false) expect(textUtils.hasPairedCharacter('\u0301\u0301')).toBe(false) - }) - ) + })) describe('.isPairedCharacter(string, index)', () => it('returns true when the index is the start of a high/low surrogate pair, variation sequence, or combined character', () => { - expect(textUtils.isPairedCharacter('a\uD835\uDF97b\uD835\uDF97c', 0)).toBe(false) - expect(textUtils.isPairedCharacter('a\uD835\uDF97b\uD835\uDF97c', 1)).toBe(true) - expect(textUtils.isPairedCharacter('a\uD835\uDF97b\uD835\uDF97c', 2)).toBe(false) - expect(textUtils.isPairedCharacter('a\uD835\uDF97b\uD835\uDF97c', 3)).toBe(false) - expect(textUtils.isPairedCharacter('a\uD835\uDF97b\uD835\uDF97c', 4)).toBe(true) - expect(textUtils.isPairedCharacter('a\uD835\uDF97b\uD835\uDF97c', 5)).toBe(false) - expect(textUtils.isPairedCharacter('a\uD835\uDF97b\uD835\uDF97c', 6)).toBe(false) + expect( + textUtils.isPairedCharacter('a\uD835\uDF97b\uD835\uDF97c', 0) + ).toBe(false) + expect( + textUtils.isPairedCharacter('a\uD835\uDF97b\uD835\uDF97c', 1) + ).toBe(true) + expect( + textUtils.isPairedCharacter('a\uD835\uDF97b\uD835\uDF97c', 2) + ).toBe(false) + expect( + textUtils.isPairedCharacter('a\uD835\uDF97b\uD835\uDF97c', 3) + ).toBe(false) + expect( + textUtils.isPairedCharacter('a\uD835\uDF97b\uD835\uDF97c', 4) + ).toBe(true) + expect( + textUtils.isPairedCharacter('a\uD835\uDF97b\uD835\uDF97c', 5) + ).toBe(false) + expect( + textUtils.isPairedCharacter('a\uD835\uDF97b\uD835\uDF97c', 6) + ).toBe(false) expect(textUtils.isPairedCharacter('a\u2714\uFE0E', 0)).toBe(false) expect(textUtils.isPairedCharacter('a\u2714\uFE0E', 1)).toBe(true) @@ -46,8 +61,7 @@ describe('text utilities', () => { expect(textUtils.isPairedCharacter('ae\u0301c', 2)).toBe(false) expect(textUtils.isPairedCharacter('ae\u0301c', 3)).toBe(false) expect(textUtils.isPairedCharacter('ae\u0301c', 4)).toBe(false) - }) - ) + })) describe('.isDoubleWidthCharacter(character)', () => it('returns true when the character is either japanese, chinese or a full width form', () => { @@ -60,8 +74,7 @@ describe('text utilities', () => { expect(textUtils.isDoubleWidthCharacter('¢')).toBe(true) expect(textUtils.isDoubleWidthCharacter('a')).toBe(false) - }) - ) + })) describe('.isHalfWidthCharacter(character)', () => it('returns true when the character is an half width form', () => { @@ -71,8 +84,7 @@ describe('text utilities', () => { expect(textUtils.isHalfWidthCharacter('■')).toBe(true) expect(textUtils.isHalfWidthCharacter('B')).toBe(false) - }) - ) + })) describe('.isKoreanCharacter(character)', () => it('returns true when the character is a korean character', () => { @@ -82,8 +94,7 @@ describe('text utilities', () => { expect(textUtils.isKoreanCharacter('ㄼ')).toBe(true) expect(textUtils.isKoreanCharacter('O')).toBe(false) - }) - ) + })) describe('.isWrapBoundary(previousCharacter, character)', () => it('returns true when the character is CJK or when the previous character is a space/tab', () => { @@ -105,6 +116,5 @@ describe('text utilities', () => { expect(textUtils.isWrapBoundary(' ', 'h')).toBe(true) expect(textUtils.isWrapBoundary('\t', 'h')).toBe(true) expect(textUtils.isWrapBoundary('a', 'h')).toBe(false) - }) - ) + })) }) diff --git a/spec/theme-manager-spec.js b/spec/theme-manager-spec.js index 9d1d3a3cc..2de214921 100644 --- a/spec/theme-manager-spec.js +++ b/spec/theme-manager-spec.js @@ -29,8 +29,7 @@ describe('atom.themes', function () { it('gets all the loaded themes', function () { const themes = atom.themes.getLoadedThemes() expect(themes.length).toBeGreaterThan(2) - }) - ) + })) describe('getActiveThemes', () => it('gets all the active themes', function () { @@ -42,8 +41,7 @@ describe('atom.themes', function () { const themes = atom.themes.getActiveThemes() expect(themes).toHaveLength(names.length) }) - }) - ) + })) }) describe('when the core.themes config value contains invalid entry', () => @@ -60,13 +58,19 @@ describe('atom.themes', function () { 'atom-dark-ui' ]) - expect(atom.themes.getEnabledThemeNames()).toEqual(['atom-dark-ui', 'atom-light-ui']) - }) -) + expect(atom.themes.getEnabledThemeNames()).toEqual([ + 'atom-dark-ui', + 'atom-light-ui' + ]) + })) describe('::getImportPaths()', function () { it('returns the theme directories before the themes are loaded', function () { - atom.config.set('core.themes', ['theme-with-index-less', 'atom-dark-ui', 'atom-light-ui']) + atom.config.set('core.themes', [ + 'theme-with-index-less', + 'atom-dark-ui', + 'atom-light-ui' + ]) const paths = atom.themes.getImportPaths() @@ -85,7 +89,9 @@ describe('atom.themes', function () { describe('when the core.themes config value changes', function () { it('add/removes stylesheets to reflect the new config value', function () { let didChangeActiveThemesHandler - atom.themes.onDidChangeActiveThemes(didChangeActiveThemesHandler = jasmine.createSpy()) + atom.themes.onDidChangeActiveThemes( + (didChangeActiveThemesHandler = jasmine.createSpy()) + ) spyOn(atom.styles, 'getUserStyleSheetPath').andCallFake(() => null) waitsForPromise(() => atom.themes.activateThemes()) @@ -108,7 +114,11 @@ describe('atom.themes', function () { runs(function () { didChangeActiveThemesHandler.reset() expect(document.querySelectorAll('style[priority="1"]')).toHaveLength(2) - expect(document.querySelector('style[priority="1"]').getAttribute('source-path')).toMatch(/atom-dark-ui/) + expect( + document + .querySelector('style[priority="1"]') + .getAttribute('source-path') + ).toMatch(/atom-dark-ui/) atom.config.set('core.themes', ['atom-light-ui', 'atom-dark-ui']) }) @@ -117,8 +127,16 @@ describe('atom.themes', function () { runs(function () { didChangeActiveThemesHandler.reset() expect(document.querySelectorAll('style[priority="1"]')).toHaveLength(2) - expect(document.querySelectorAll('style[priority="1"]')[0].getAttribute('source-path')).toMatch(/atom-dark-ui/) - expect(document.querySelectorAll('style[priority="1"]')[1].getAttribute('source-path')).toMatch(/atom-light-ui/) + expect( + document + .querySelectorAll('style[priority="1"]')[0] + .getAttribute('source-path') + ).toMatch(/atom-dark-ui/) + expect( + document + .querySelectorAll('style[priority="1"]')[1] + .getAttribute('source-path') + ).toMatch(/atom-light-ui/) atom.config.set('core.themes', []) }) @@ -128,7 +146,10 @@ describe('atom.themes', function () { didChangeActiveThemesHandler.reset() expect(document.querySelectorAll('style[priority="1"]')).toHaveLength(2) // atom-dark-ui has a directory path, the syntax one doesn't - atom.config.set('core.themes', ['theme-with-index-less', 'atom-dark-ui']) + atom.config.set('core.themes', [ + 'theme-with-index-less', + 'atom-dark-ui' + ]) }) waitsFor(() => didChangeActiveThemesHandler.callCount === 1) @@ -145,15 +166,22 @@ describe('atom.themes', function () { atom.config.set('core.themes', ['atom-dark-ui', 'atom-dark-syntax']) let didChangeActiveThemesHandler - atom.themes.onDidChangeActiveThemes(didChangeActiveThemesHandler = jasmine.createSpy()) + atom.themes.onDidChangeActiveThemes( + (didChangeActiveThemesHandler = jasmine.createSpy()) + ) waitsForPromise(() => atom.themes.activateThemes()) const workspaceElement = atom.workspace.getElement() runs(function () { expect(workspaceElement).toHaveClass('theme-atom-dark-ui') - atom.themes.onDidChangeActiveThemes(didChangeActiveThemesHandler = jasmine.createSpy()) - atom.config.set('core.themes', ['theme-with-ui-variables', 'theme-with-syntax-variables']) + atom.themes.onDidChangeActiveThemes( + (didChangeActiveThemesHandler = jasmine.createSpy()) + ) + atom.config.set('core.themes', [ + 'theme-with-ui-variables', + 'theme-with-syntax-variables' + ]) }) waitsFor(() => didChangeActiveThemesHandler.callCount > 0) @@ -161,7 +189,9 @@ describe('atom.themes', function () { runs(function () { // `theme-` twice as it prefixes the name with `theme-` expect(workspaceElement).toHaveClass('theme-theme-with-ui-variables') - expect(workspaceElement).toHaveClass('theme-theme-with-syntax-variables') + expect(workspaceElement).toHaveClass( + 'theme-theme-with-syntax-variables' + ) expect(workspaceElement).not.toHaveClass('theme-atom-dark-ui') expect(workspaceElement).not.toHaveClass('theme-atom-dark-syntax') }) @@ -171,11 +201,14 @@ describe('atom.themes', function () { describe('when a theme fails to load', () => it('logs a warning', function () { console.warn.reset() - atom.packages.activatePackage('a-theme-that-will-not-be-found').then(function () {}, function () {}) + atom.packages + .activatePackage('a-theme-that-will-not-be-found') + .then(function () {}, function () {}) expect(console.warn.callCount).toBe(1) - expect(console.warn.argsForCall[0][0]).toContain("Could not resolve 'a-theme-that-will-not-be-found'") - }) - ) + expect(console.warn.argsForCall[0][0]).toContain( + "Could not resolve 'a-theme-that-will-not-be-found'" + ) + })) describe('::requireStylesheet(path)', function () { beforeEach(() => jasmine.snapshotDeprecations()) @@ -184,38 +217,60 @@ describe('atom.themes', function () { it('synchronously loads css at the given path and installs a style tag for it in the head', function () { let styleElementAddedHandler - atom.styles.onDidAddStyleElement(styleElementAddedHandler = jasmine.createSpy('styleElementAddedHandler')) + atom.styles.onDidAddStyleElement( + (styleElementAddedHandler = jasmine.createSpy( + 'styleElementAddedHandler' + )) + ) - const cssPath = getAbsolutePath(atom.project.getDirectories()[0], 'css.css') + const cssPath = getAbsolutePath( + atom.project.getDirectories()[0], + 'css.css' + ) const lengthBefore = document.querySelectorAll('head style').length atom.themes.requireStylesheet(cssPath) - expect(document.querySelectorAll('head style').length).toBe(lengthBefore + 1) + expect(document.querySelectorAll('head style').length).toBe( + lengthBefore + 1 + ) expect(styleElementAddedHandler).toHaveBeenCalled() - const element = document.querySelector('head style[source-path*="css.css"]') + const element = document.querySelector( + 'head style[source-path*="css.css"]' + ) expect(element.getAttribute('source-path')).toEqualPath(cssPath) expect(element.textContent).toBe(fs.readFileSync(cssPath, 'utf8')) // doesn't append twice styleElementAddedHandler.reset() atom.themes.requireStylesheet(cssPath) - expect(document.querySelectorAll('head style').length).toBe(lengthBefore + 1) + expect(document.querySelectorAll('head style').length).toBe( + lengthBefore + 1 + ) expect(styleElementAddedHandler).not.toHaveBeenCalled() - document.querySelectorAll('head style[id*="css.css"]').forEach((styleElement) => { - styleElement.remove() - }) + document + .querySelectorAll('head style[id*="css.css"]') + .forEach(styleElement => { + styleElement.remove() + }) }) it('synchronously loads and parses less files at the given path and installs a style tag for it in the head', function () { - const lessPath = getAbsolutePath(atom.project.getDirectories()[0], 'sample.less') + const lessPath = getAbsolutePath( + atom.project.getDirectories()[0], + 'sample.less' + ) const lengthBefore = document.querySelectorAll('head style').length atom.themes.requireStylesheet(lessPath) - expect(document.querySelectorAll('head style').length).toBe(lengthBefore + 1) + expect(document.querySelectorAll('head style').length).toBe( + lengthBefore + 1 + ) - const element = document.querySelector('head style[source-path*="sample.less"]') + const element = document.querySelector( + 'head style[source-path*="sample.less"]' + ) expect(element.getAttribute('source-path')).toEqualPath(lessPath) expect(element.textContent.toLowerCase()).toBe(`\ #header { @@ -225,24 +280,37 @@ h2 { color: #4d926f; } \ -` - ) +`) // doesn't append twice atom.themes.requireStylesheet(lessPath) - expect(document.querySelectorAll('head style').length).toBe(lengthBefore + 1) - document.querySelectorAll('head style[id*="sample.less"]').forEach((styleElement) => { - styleElement.remove() - }) + expect(document.querySelectorAll('head style').length).toBe( + lengthBefore + 1 + ) + document + .querySelectorAll('head style[id*="sample.less"]') + .forEach(styleElement => { + styleElement.remove() + }) }) it('supports requiring css and less stylesheets without an explicit extension', function () { atom.themes.requireStylesheet(path.join(__dirname, 'fixtures', 'css')) - expect(document.querySelector('head style[source-path*="css.css"]').getAttribute('source-path')) - .toEqualPath(getAbsolutePath(atom.project.getDirectories()[0], 'css.css')) + expect( + document + .querySelector('head style[source-path*="css.css"]') + .getAttribute('source-path') + ).toEqualPath( + getAbsolutePath(atom.project.getDirectories()[0], 'css.css') + ) atom.themes.requireStylesheet(path.join(__dirname, 'fixtures', 'sample')) - expect(document.querySelector('head style[source-path*="sample.less"]').getAttribute('source-path')) - .toEqualPath(getAbsolutePath(atom.project.getDirectories()[0], 'sample.less')) + expect( + document + .querySelector('head style[source-path*="sample.less"]') + .getAttribute('source-path') + ).toEqualPath( + getAbsolutePath(atom.project.getDirectories()[0], 'sample.less') + ) document.querySelector('head style[source-path*="css.css"]').remove() document.querySelector('head style[source-path*="sample.less"]').remove() @@ -256,7 +324,11 @@ h2 { expect(getComputedStyle(document.body).fontWeight).toBe('bold') let styleElementRemovedHandler - atom.styles.onDidRemoveStyleElement(styleElementRemovedHandler = jasmine.createSpy('styleElementRemovedHandler')) + atom.styles.onDidRemoveStyleElement( + (styleElementRemovedHandler = jasmine.createSpy( + 'styleElementRemovedHandler' + )) + ) disposable.dispose() @@ -277,46 +349,74 @@ h2 { it("loads the correct values from the theme's ui-variables file", function () { let didChangeActiveThemesHandler - atom.themes.onDidChangeActiveThemes(didChangeActiveThemesHandler = jasmine.createSpy()) - atom.config.set('core.themes', ['theme-with-ui-variables', 'theme-with-syntax-variables']) + atom.themes.onDidChangeActiveThemes( + (didChangeActiveThemesHandler = jasmine.createSpy()) + ) + atom.config.set('core.themes', [ + 'theme-with-ui-variables', + 'theme-with-syntax-variables' + ]) waitsFor(() => didChangeActiveThemesHandler.callCount > 0) runs(function () { // an override loaded in the base css - expect(getComputedStyle(atom.workspace.getElement())['background-color']).toBe('rgb(0, 0, 255)') + expect( + getComputedStyle(atom.workspace.getElement())['background-color'] + ).toBe('rgb(0, 0, 255)') // from within the theme itself - expect(getComputedStyle(document.querySelector('atom-text-editor')).paddingTop).toBe('150px') - expect(getComputedStyle(document.querySelector('atom-text-editor')).paddingRight).toBe('150px') - expect(getComputedStyle(document.querySelector('atom-text-editor')).paddingBottom).toBe('150px') + expect( + getComputedStyle(document.querySelector('atom-text-editor')) + .paddingTop + ).toBe('150px') + expect( + getComputedStyle(document.querySelector('atom-text-editor')) + .paddingRight + ).toBe('150px') + expect( + getComputedStyle(document.querySelector('atom-text-editor')) + .paddingBottom + ).toBe('150px') }) }) describe('when there is a theme with incomplete variables', () => it('loads the correct values from the fallback ui-variables', function () { let didChangeActiveThemesHandler - atom.themes.onDidChangeActiveThemes(didChangeActiveThemesHandler = jasmine.createSpy()) - atom.config.set('core.themes', ['theme-with-incomplete-ui-variables', 'theme-with-syntax-variables']) + atom.themes.onDidChangeActiveThemes( + (didChangeActiveThemesHandler = jasmine.createSpy()) + ) + atom.config.set('core.themes', [ + 'theme-with-incomplete-ui-variables', + 'theme-with-syntax-variables' + ]) waitsFor(() => didChangeActiveThemesHandler.callCount > 0) runs(function () { // an override loaded in the base css - expect(getComputedStyle(atom.workspace.getElement())['background-color']).toBe('rgb(0, 0, 255)') + expect( + getComputedStyle(atom.workspace.getElement())['background-color'] + ).toBe('rgb(0, 0, 255)') // from within the theme itself - expect(getComputedStyle(document.querySelector('atom-text-editor')).backgroundColor).toBe('rgb(0, 152, 255)') + expect( + getComputedStyle(document.querySelector('atom-text-editor')) + .backgroundColor + ).toBe('rgb(0, 152, 255)') }) - }) - ) + })) }) describe('user stylesheet', function () { let userStylesheetPath beforeEach(function () { userStylesheetPath = path.join(temp.mkdirSync('atom'), 'styles.less') - fs.writeFileSync(userStylesheetPath, 'body {border-style: dotted !important;}') + fs.writeFileSync( + userStylesheetPath, + 'body {border-style: dotted !important;}' + ) spyOn(atom.styles, 'getUserStyleSheetPath').andReturn(userStylesheetPath) }) @@ -331,8 +431,16 @@ h2 { waitsForPromise(() => atom.themes.activateThemes()) runs(function () { - atom.styles.onDidRemoveStyleElement(styleElementRemovedHandler = jasmine.createSpy('styleElementRemovedHandler')) - atom.styles.onDidAddStyleElement(styleElementAddedHandler = jasmine.createSpy('styleElementAddedHandler')) + atom.styles.onDidRemoveStyleElement( + (styleElementRemovedHandler = jasmine.createSpy( + 'styleElementRemovedHandler' + )) + ) + atom.styles.onDidAddStyleElement( + (styleElementAddedHandler = jasmine.createSpy( + 'styleElementAddedHandler' + )) + ) spyOn(atom.themes, 'loadUserStylesheet').andCallThrough() @@ -346,10 +454,14 @@ h2 { expect(getComputedStyle(document.body).borderStyle).toBe('dashed') expect(styleElementRemovedHandler).toHaveBeenCalled() - expect(styleElementRemovedHandler.argsForCall[0][0].textContent).toContain('dotted') + expect( + styleElementRemovedHandler.argsForCall[0][0].textContent + ).toContain('dotted') expect(styleElementAddedHandler).toHaveBeenCalled() - expect(styleElementAddedHandler.argsForCall[0][0].textContent).toContain('dashed') + expect( + styleElementAddedHandler.argsForCall[0][0].textContent + ).toContain('dashed') styleElementRemovedHandler.reset() fs.removeSync(userStylesheetPath) @@ -359,7 +471,9 @@ h2 { runs(function () { expect(styleElementRemovedHandler).toHaveBeenCalled() - expect(styleElementRemovedHandler.argsForCall[0][0].textContent).toContain('dashed') + expect( + styleElementRemovedHandler.argsForCall[0][0].textContent + ).toContain('dashed') expect(getComputedStyle(document.body).borderStyle).toBe('none') }) }) @@ -372,7 +486,9 @@ h2 { spyOn(atom.themes.lessCache, 'cssForFile').andCallFake(function () { throw new Error('EACCES permission denied "styles.less"') }) - atom.notifications.onDidAddNotification(addErrorHandler = jasmine.createSpy()) + atom.notifications.onDidAddNotification( + (addErrorHandler = jasmine.createSpy()) + ) }) it('creates an error notification and does not add the stylesheet', function () { @@ -381,21 +497,27 @@ h2 { const note = addErrorHandler.mostRecentCall.args[0] expect(note.getType()).toBe('error') expect(note.getMessage()).toContain('Error loading') - expect(atom.styles.styleElementsBySourcePath[atom.styles.getUserStyleSheetPath()]).toBeUndefined() + expect( + atom.styles.styleElementsBySourcePath[ + atom.styles.getUserStyleSheetPath() + ] + ).toBeUndefined() }) }) describe('when there is an error watching the user stylesheet', function () { let addErrorHandler = null beforeEach(function () { - const {File} = require('pathwatcher') + const { File } = require('pathwatcher') spyOn(File.prototype, 'on').andCallFake(function (event) { if (event.indexOf('contents-changed') > -1) { throw new Error('Unable to watch path') } }) spyOn(atom.themes, 'loadStylesheet').andReturn('') - atom.notifications.onDidAddNotification(addErrorHandler = jasmine.createSpy()) + atom.notifications.onDidAddNotification( + (addErrorHandler = jasmine.createSpy()) + ) }) it('creates an error notification', function () { @@ -410,16 +532,25 @@ h2 { it("adds a notification when a theme's stylesheet is invalid", function () { const addErrorHandler = jasmine.createSpy() atom.notifications.onDidAddNotification(addErrorHandler) - expect(() => atom.packages.activatePackage('theme-with-invalid-styles').then(function () {}, function () {})).not.toThrow() + expect(() => + atom.packages + .activatePackage('theme-with-invalid-styles') + .then(function () {}, function () {}) + ).not.toThrow() expect(addErrorHandler.callCount).toBe(2) - expect(addErrorHandler.argsForCall[1][0].message).toContain('Failed to activate the theme-with-invalid-styles theme') + expect(addErrorHandler.argsForCall[1][0].message).toContain( + 'Failed to activate the theme-with-invalid-styles theme' + ) }) }) describe('when a non-existent theme is present in the config', function () { beforeEach(function () { console.warn.reset() - atom.config.set('core.themes', ['non-existent-dark-ui', 'non-existent-dark-syntax']) + atom.config.set('core.themes', [ + 'non-existent-dark-ui', + 'non-existent-dark-syntax' + ]) waitsForPromise(() => atom.themes.activateThemes()) }) @@ -451,7 +582,10 @@ h2 { describe('when the enabled UI and syntax themes are not bundled with Atom', function () { beforeEach(function () { - atom.config.set('core.themes', ['installed-dark-ui', 'installed-dark-syntax']) + atom.config.set('core.themes', [ + 'installed-dark-ui', + 'installed-dark-syntax' + ]) waitsForPromise(() => atom.themes.activateThemes()) }) @@ -466,7 +600,10 @@ h2 { describe('when the enabled UI theme is not bundled with Atom', function () { beforeEach(function () { - atom.config.set('core.themes', ['installed-dark-ui', 'atom-light-syntax']) + atom.config.set('core.themes', [ + 'installed-dark-ui', + 'atom-light-syntax' + ]) waitsForPromise(() => atom.themes.activateThemes()) }) @@ -481,7 +618,10 @@ h2 { describe('when the enabled syntax theme is not bundled with Atom', function () { beforeEach(function () { - atom.config.set('core.themes', ['atom-light-ui', 'installed-dark-syntax']) + atom.config.set('core.themes', [ + 'atom-light-ui', + 'installed-dark-syntax' + ]) waitsForPromise(() => atom.themes.activateThemes()) }) diff --git a/spec/title-bar-spec.js b/spec/title-bar-spec.js index b219a5819..c5d98ed03 100644 --- a/spec/title-bar-spec.js +++ b/spec/title-bar-spec.js @@ -8,20 +8,28 @@ describe('TitleBar', () => { themes: atom.themes, applicationDelegate: atom.applicationDelegate }) - expect(titleBar.element.querySelector('.title').textContent).toBe(document.title) + expect(titleBar.element.querySelector('.title').textContent).toBe( + document.title + ) const paneItem = new FakePaneItem('Title 1') atom.workspace.getActivePane().activateItem(paneItem) expect(document.title).toMatch('Title 1') - expect(titleBar.element.querySelector('.title').textContent).toBe(document.title) + expect(titleBar.element.querySelector('.title').textContent).toBe( + document.title + ) paneItem.setTitle('Title 2') expect(document.title).toMatch('Title 2') - expect(titleBar.element.querySelector('.title').textContent).toBe(document.title) + expect(titleBar.element.querySelector('.title').textContent).toBe( + document.title + ) atom.project.setPaths([temp.mkdirSync('project-1')]) expect(document.title).toMatch('project-1') - expect(titleBar.element.querySelector('.title').textContent).toBe(document.title) + expect(titleBar.element.querySelector('.title').textContent).toBe( + document.title + ) }) it('can update the sheet offset for the current window based on its height', () => { @@ -46,7 +54,9 @@ class FakePaneItem { onDidChangeTitle (callback) { this.didChangeTitleCallback = callback return { - dispose: () => { this.didChangeTitleCallback = null } + dispose: () => { + this.didChangeTitleCallback = null + } } } diff --git a/spec/tooltip-manager-spec.js b/spec/tooltip-manager-spec.js index e6ca01de2..183439a3c 100644 --- a/spec/tooltip-manager-spec.js +++ b/spec/tooltip-manager-spec.js @@ -1,4 +1,4 @@ -const {CompositeDisposable} = require('atom') +const { CompositeDisposable } = require('atom') const TooltipManager = require('../src/tooltip-manager') const Tooltip = require('../src/tooltip') const _ = require('underscore-plus') @@ -18,25 +18,30 @@ describe('TooltipManager', () => { } beforeEach(function () { - manager = new TooltipManager({keymapManager: atom.keymaps, viewRegistry: atom.views}) + manager = new TooltipManager({ + keymapManager: atom.keymaps, + viewRegistry: atom.views + }) element = createElement('foo') }) describe('::add(target, options)', () => { describe("when the trigger is 'hover' (the default)", () => { it('creates a tooltip when hovering over the target element', () => { - manager.add(element, {title: 'Title'}) - hover(element, () => expect(document.body.querySelector('.tooltip')).toHaveText('Title')) + manager.add(element, { title: 'Title' }) + hover(element, () => + expect(document.body.querySelector('.tooltip')).toHaveText('Title') + ) }) it('displays tooltips immediately when hovering over new elements once a tooltip has been displayed once', () => { const disposables = new CompositeDisposable() const element1 = createElement('foo') - disposables.add(manager.add(element1, {title: 'Title'})) + disposables.add(manager.add(element1, { title: 'Title' })) const element2 = createElement('bar') - disposables.add(manager.add(element2, {title: 'Title'})) + disposables.add(manager.add(element2, { title: 'Title' })) const element3 = createElement('baz') - disposables.add(manager.add(element3, {title: 'Title'})) + disposables.add(manager.add(element3, { title: 'Title' })) hover(element1, () => {}) expect(document.body.querySelector('.tooltip')).toBeNull() @@ -57,12 +62,17 @@ describe('TooltipManager', () => { }) it('hides the tooltip on keydown events', () => { - const disposable = manager.add(element, { title: 'Title', trigger: 'hover' }) + const disposable = manager.add(element, { + title: 'Title', + trigger: 'hover' + }) hover(element, function () { expect(document.body.querySelector('.tooltip')).not.toBeNull() - window.dispatchEvent(new CustomEvent('keydown', { - bubbles: true - })) + window.dispatchEvent( + new CustomEvent('keydown', { + bubbles: true + }) + ) expect(document.body.querySelector('.tooltip')).toBeNull() disposable.dispose() }) @@ -71,16 +81,18 @@ describe('TooltipManager', () => { describe("when the trigger is 'manual'", () => it('creates a tooltip immediately and only hides it on dispose', () => { - const disposable = manager.add(element, {title: 'Title', trigger: 'manual'}) + const disposable = manager.add(element, { + title: 'Title', + trigger: 'manual' + }) expect(document.body.querySelector('.tooltip')).toHaveText('Title') disposable.dispose() expect(document.body.querySelector('.tooltip')).toBeNull() - }) - ) + })) describe("when the trigger is 'click'", () => it('shows and hides the tooltip when the target element is clicked', () => { - manager.add(element, {title: 'Title', trigger: 'click'}) + manager.add(element, { title: 'Title', trigger: 'click' }) expect(document.body.querySelector('.tooltip')).toBeNull() element.click() expect(document.body.querySelector('.tooltip')).not.toBeNull() @@ -102,16 +114,17 @@ describe('TooltipManager', () => { expect(document.body.querySelector('.tooltip')).not.toBeNull() element.click() expect(document.body.querySelector('.tooltip')).toBeNull() - }) - ) + })) it('does not hide the tooltip on keyboard input', () => { - manager.add(element, {title: 'Title', trigger: 'click'}) + manager.add(element, { title: 'Title', trigger: 'click' }) element.click() expect(document.body.querySelector('.tooltip')).not.toBeNull() - window.dispatchEvent(new CustomEvent('keydown', { - bubbles: true - })) + window.dispatchEvent( + new CustomEvent('keydown', { + bubbles: true + }) + ) expect(document.body.querySelector('.tooltip')).not.toBeNull() // click again to hide the tooltip because otherwise state leaks // into other tests. @@ -120,13 +133,21 @@ describe('TooltipManager', () => { it('allows a custom item to be specified for the content of the tooltip', () => { const tooltipElement = document.createElement('div') - manager.add(element, {item: {element: tooltipElement}}) - hover(element, () => expect(tooltipElement.closest('.tooltip')).not.toBeNull()) + manager.add(element, { item: { element: tooltipElement } }) + hover(element, () => + expect(tooltipElement.closest('.tooltip')).not.toBeNull() + ) }) it('allows a custom class to be specified for the tooltip', () => { - manager.add(element, {title: 'Title', class: 'custom-tooltip-class'}) - hover(element, () => expect(document.body.querySelector('.tooltip').classList.contains('custom-tooltip-class')).toBe(true)) + manager.add(element, { title: 'Title', class: 'custom-tooltip-class' }) + hover(element, () => + expect( + document.body + .querySelector('.tooltip') + .classList.contains('custom-tooltip-class') + ).toBe(true) + ) }) it('allows jQuery elements to be passed as the target', () => { @@ -139,63 +160,71 @@ describe('TooltipManager', () => { length: 2, jquery: 'any-version' } - const disposable = manager.add(fakeJqueryWrapper, {title: 'Title'}) + const disposable = manager.add(fakeJqueryWrapper, { title: 'Title' }) - hover(element, () => expect(document.body.querySelector('.tooltip')).toHaveText('Title')) + hover(element, () => + expect(document.body.querySelector('.tooltip')).toHaveText('Title') + ) expect(document.body.querySelector('.tooltip')).toBeNull() - hover(element2, () => expect(document.body.querySelector('.tooltip')).toHaveText('Title')) + hover(element2, () => + expect(document.body.querySelector('.tooltip')).toHaveText('Title') + ) expect(document.body.querySelector('.tooltip')).toBeNull() disposable.dispose() - hover(element, () => expect(document.body.querySelector('.tooltip')).toBeNull()) - hover(element2, () => expect(document.body.querySelector('.tooltip')).toBeNull()) + hover(element, () => + expect(document.body.querySelector('.tooltip')).toBeNull() + ) + hover(element2, () => + expect(document.body.querySelector('.tooltip')).toBeNull() + ) }) describe('when a keyBindingCommand is specified', () => { describe('when a title is specified', () => it('appends the key binding corresponding to the command to the title', () => { atom.keymaps.add('test', { - '.foo': { 'ctrl-x ctrl-y': 'test-command' - }, - '.bar': { 'ctrl-x ctrl-z': 'test-command' - } - } - ) + '.foo': { 'ctrl-x ctrl-y': 'test-command' }, + '.bar': { 'ctrl-x ctrl-z': 'test-command' } + }) - manager.add(element, {title: 'Title', keyBindingCommand: 'test-command'}) + manager.add(element, { + title: 'Title', + keyBindingCommand: 'test-command' + }) hover(element, function () { const tooltipElement = document.body.querySelector('.tooltip') expect(tooltipElement).toHaveText(`Title ${ctrlX} ${ctrlY}`) }) - }) - ) + })) describe('when no title is specified', () => it('shows the key binding corresponding to the command alone', () => { - atom.keymaps.add('test', {'.foo': {'ctrl-x ctrl-y': 'test-command'}}) + atom.keymaps.add('test', { + '.foo': { 'ctrl-x ctrl-y': 'test-command' } + }) - manager.add(element, {keyBindingCommand: 'test-command'}) + manager.add(element, { keyBindingCommand: 'test-command' }) hover(element, function () { const tooltipElement = document.body.querySelector('.tooltip') expect(tooltipElement).toHaveText(`${ctrlX} ${ctrlY}`) }) - }) - ) + })) describe('when a keyBindingTarget is specified', () => { it('looks up the key binding relative to the target', () => { atom.keymaps.add('test', { - '.bar': { 'ctrl-x ctrl-z': 'test-command' - }, - '.foo': { 'ctrl-x ctrl-y': 'test-command' - } - } - ) + '.bar': { 'ctrl-x ctrl-z': 'test-command' }, + '.foo': { 'ctrl-x ctrl-y': 'test-command' } + }) - manager.add(element, {keyBindingCommand: 'test-command', keyBindingTarget: element}) + manager.add(element, { + keyBindingCommand: 'test-command', + keyBindingTarget: element + }) hover(element, function () { const tooltipElement = document.body.querySelector('.tooltip') @@ -204,7 +233,11 @@ describe('TooltipManager', () => { }) it('does not display the keybinding if there is nothing mapped to the specified keyBindingCommand', () => { - manager.add(element, {title: 'A Title', keyBindingCommand: 'test-command', keyBindingTarget: element}) + manager.add(element, { + title: 'A Title', + keyBindingCommand: 'test-command', + keyBindingTarget: element + }) hover(element, function () { const tooltipElement = document.body.querySelector('.tooltip') @@ -216,34 +249,36 @@ describe('TooltipManager', () => { describe('when .dispose() is called on the returned disposable', () => it('no longer displays the tooltip on hover', () => { - const disposable = manager.add(element, {title: 'Title'}) + const disposable = manager.add(element, { title: 'Title' }) - hover(element, () => expect(document.body.querySelector('.tooltip')).toHaveText('Title')) + hover(element, () => + expect(document.body.querySelector('.tooltip')).toHaveText('Title') + ) disposable.dispose() - hover(element, () => expect(document.body.querySelector('.tooltip')).toBeNull()) - }) - ) + hover(element, () => + expect(document.body.querySelector('.tooltip')).toBeNull() + ) + })) describe('when the window is resized', () => it('hides the tooltips', () => { - const disposable = manager.add(element, {title: 'Title'}) + const disposable = manager.add(element, { title: 'Title' }) hover(element, function () { expect(document.body.querySelector('.tooltip')).not.toBeNull() window.dispatchEvent(new CustomEvent('resize')) expect(document.body.querySelector('.tooltip')).toBeNull() disposable.dispose() }) - }) - ) + })) describe('findTooltips', () => { it('adds and remove tooltips correctly', () => { expect(manager.findTooltips(element).length).toBe(0) - const disposable1 = manager.add(element, {title: 'elem1'}) + const disposable1 = manager.add(element, { title: 'elem1' }) expect(manager.findTooltips(element).length).toBe(1) - const disposable2 = manager.add(element, {title: 'elem2'}) + const disposable2 = manager.add(element, { title: 'elem2' }) expect(manager.findTooltips(element).length).toBe(2) disposable1.dispose() expect(manager.findTooltips(element).length).toBe(1) @@ -252,7 +287,7 @@ describe('TooltipManager', () => { }) it('lets us hide tooltips programmatically', () => { - const disposable = manager.add(element, {title: 'Title'}) + const disposable = manager.add(element, { title: 'Title' }) hover(element, function () { expect(document.body.querySelector('.tooltip')).not.toBeNull() manager.findTooltips(element)[0].hide() @@ -272,11 +307,11 @@ function createElement (className) { } function mouseEnter (element) { - element.dispatchEvent(new CustomEvent('mouseenter', {bubbles: false})) - element.dispatchEvent(new CustomEvent('mouseover', {bubbles: true})) + element.dispatchEvent(new CustomEvent('mouseenter', { bubbles: false })) + element.dispatchEvent(new CustomEvent('mouseover', { bubbles: true })) } function mouseLeave (element) { - element.dispatchEvent(new CustomEvent('mouseleave', {bubbles: false})) - element.dispatchEvent(new CustomEvent('mouseout', {bubbles: true})) + element.dispatchEvent(new CustomEvent('mouseleave', { bubbles: false })) + element.dispatchEvent(new CustomEvent('mouseout', { bubbles: true })) } diff --git a/spec/tree-sitter-language-mode-spec.js b/spec/tree-sitter-language-mode-spec.js index 7b8344d9c..e4b41b994 100644 --- a/spec/tree-sitter-language-mode-spec.js +++ b/spec/tree-sitter-language-mode-spec.js @@ -1,22 +1,39 @@ -const {it, fit, ffit, fffit, beforeEach, afterEach} = require('./async-spec-helpers') +const { + it, + fit, + ffit, + fffit, + beforeEach, + afterEach +} = require('./async-spec-helpers') const fs = require('fs') const path = require('path') const dedent = require('dedent') const TextBuffer = require('text-buffer') -const {Point} = TextBuffer +const { Point } = TextBuffer const TextEditor = require('../src/text-editor') const TreeSitterGrammar = require('../src/tree-sitter-grammar') const TreeSitterLanguageMode = require('../src/tree-sitter-language-mode') const Random = require('../script/node_modules/random-seed') -const {getRandomBufferRange, buildRandomLines} = require('./helpers/random') +const { getRandomBufferRange, buildRandomLines } = require('./helpers/random') const cGrammarPath = require.resolve('language-c/grammars/tree-sitter-c.cson') -const pythonGrammarPath = require.resolve('language-python/grammars/tree-sitter-python.cson') -const jsGrammarPath = require.resolve('language-javascript/grammars/tree-sitter-javascript.cson') -const htmlGrammarPath = require.resolve('language-html/grammars/tree-sitter-html.cson') -const ejsGrammarPath = require.resolve('language-html/grammars/tree-sitter-ejs.cson') -const rubyGrammarPath = require.resolve('language-ruby/grammars/tree-sitter-ruby.cson') +const pythonGrammarPath = require.resolve( + 'language-python/grammars/tree-sitter-python.cson' +) +const jsGrammarPath = require.resolve( + 'language-javascript/grammars/tree-sitter-javascript.cson' +) +const htmlGrammarPath = require.resolve( + 'language-html/grammars/tree-sitter-html.cson' +) +const ejsGrammarPath = require.resolve( + 'language-html/grammars/tree-sitter-ejs.cson' +) +const rubyGrammarPath = require.resolve( + 'language-ruby/grammars/tree-sitter-ruby.cson' +) describe('TreeSitterLanguageMode', () => { let editor, buffer @@ -24,7 +41,7 @@ describe('TreeSitterLanguageMode', () => { beforeEach(async () => { editor = await atom.workspace.open('') buffer = editor.getBuffer() - editor.displayLayer.reset({foldCharacter: '…'}) + editor.displayLayer.reset({ foldCharacter: '…' }) }) describe('highlighting', () => { @@ -32,82 +49,85 @@ describe('TreeSitterLanguageMode', () => { const grammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, { parser: 'tree-sitter-javascript', scopes: { - 'program': 'source', + program: 'source', 'call_expression > identifier': 'function', - 'property_identifier': 'property', + property_identifier: 'property', 'call_expression > member_expression > property_identifier': 'method' } }) buffer.setText('aa.bbb = cc(d.eee());') - const languageMode = new TreeSitterLanguageMode({buffer, grammar}) + const languageMode = new TreeSitterLanguageMode({ buffer, grammar }) buffer.setLanguageMode(languageMode) - expectTokensToEqual(editor, [[ - {text: 'aa.', scopes: ['source']}, - {text: 'bbb', scopes: ['source', 'property']}, - {text: ' = ', scopes: ['source']}, - {text: 'cc', scopes: ['source', 'function']}, - {text: '(d.', scopes: ['source']}, - {text: 'eee', scopes: ['source', 'method']}, - {text: '());', scopes: ['source']} - ]]) + expectTokensToEqual(editor, [ + [ + { text: 'aa.', scopes: ['source'] }, + { text: 'bbb', scopes: ['source', 'property'] }, + { text: ' = ', scopes: ['source'] }, + { text: 'cc', scopes: ['source', 'function'] }, + { text: '(d.', scopes: ['source'] }, + { text: 'eee', scopes: ['source', 'method'] }, + { text: '());', scopes: ['source'] } + ] + ]) }) it('can start or end multiple scopes at the same position', async () => { const grammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, { parser: 'tree-sitter-javascript', scopes: { - 'program': 'source', - 'call_expression': 'call', - 'member_expression': 'member', - 'identifier': 'variable', + program: 'source', + call_expression: 'call', + member_expression: 'member', + identifier: 'variable', '"("': 'open-paren', - '")"': 'close-paren', + '")"': 'close-paren' } }) buffer.setText('a = bb.ccc();') - const languageMode = new TreeSitterLanguageMode({buffer, grammar}) + const languageMode = new TreeSitterLanguageMode({ buffer, grammar }) buffer.setLanguageMode(languageMode) - expectTokensToEqual(editor, [[ - {text: 'a', scopes: ['source', 'variable']}, - {text: ' = ', scopes: ['source']}, - {text: 'bb', scopes: ['source', 'call', 'member', 'variable']}, - {text: '.ccc', scopes: ['source', 'call', 'member']}, - {text: '(', scopes: ['source', 'call', 'open-paren']}, - {text: ')', scopes: ['source', 'call', 'close-paren']}, - {text: ';', scopes: ['source']} - ]]) + expectTokensToEqual(editor, [ + [ + { text: 'a', scopes: ['source', 'variable'] }, + { text: ' = ', scopes: ['source'] }, + { text: 'bb', scopes: ['source', 'call', 'member', 'variable'] }, + { text: '.ccc', scopes: ['source', 'call', 'member'] }, + { text: '(', scopes: ['source', 'call', 'open-paren'] }, + { text: ')', scopes: ['source', 'call', 'close-paren'] }, + { text: ';', scopes: ['source'] } + ] + ]) }) it('can resume highlighting on a line that starts with whitespace', async () => { const grammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, { parser: 'tree-sitter-javascript', scopes: { - 'call_expression > member_expression > property_identifier': 'function', - 'property_identifier': 'member', - 'identifier': 'variable' + 'call_expression > member_expression > property_identifier': + 'function', + property_identifier: 'member', + identifier: 'variable' } }) buffer.setText('a\n .b();') - const languageMode = new TreeSitterLanguageMode({buffer, grammar}) + const languageMode = new TreeSitterLanguageMode({ buffer, grammar }) buffer.setLanguageMode(languageMode) expectTokensToEqual(editor, [ + [{ text: 'a', scopes: ['variable'] }], [ - {text: 'a', scopes: ['variable']}, - ], - [ - {text: ' ', scopes: ['leading-whitespace']}, - {text: '.', scopes: []}, - {text: 'b', scopes: ['function']}, - {text: '();', scopes: []} + { text: ' ', scopes: ['leading-whitespace'] }, + { text: '.', scopes: [] }, + { text: 'b', scopes: ['function'] }, + { text: '();', scopes: [] } ] ]) }) @@ -116,77 +136,74 @@ describe('TreeSitterLanguageMode', () => { const grammar = new TreeSitterGrammar(atom.grammars, cGrammarPath, { parser: 'tree-sitter-c', scopes: { - 'primitive_type': 'type', - 'identifier': 'variable', + primitive_type: 'type', + identifier: 'variable' } }) - buffer.setText('int main() {\n int a\n int b;\n}'); + buffer.setText('int main() {\n int a\n int b;\n}') - const languageMode = new TreeSitterLanguageMode({buffer, grammar}) + const languageMode = new TreeSitterLanguageMode({ buffer, grammar }) buffer.setLanguageMode(languageMode) expect( - languageMode.tree.rootNode.descendantForPosition(Point(1, 2), Point(1, 6)).toString() + languageMode.tree.rootNode + .descendantForPosition(Point(1, 2), Point(1, 6)) + .toString() ).toBe('(declaration (primitive_type) (identifier) (MISSING))') expectTokensToEqual(editor, [ [ - {text: 'int', scopes: ['type']}, - {text: ' ', scopes: []}, - {text: 'main', scopes: ['variable']}, - {text: '() {', scopes: []} + { text: 'int', scopes: ['type'] }, + { text: ' ', scopes: [] }, + { text: 'main', scopes: ['variable'] }, + { text: '() {', scopes: [] } ], [ - {text: ' ', scopes: ['leading-whitespace']}, - {text: 'int', scopes: ['type']}, - {text: ' ', scopes: []}, - {text: 'a', scopes: ['variable']} + { text: ' ', scopes: ['leading-whitespace'] }, + { text: 'int', scopes: ['type'] }, + { text: ' ', scopes: [] }, + { text: 'a', scopes: ['variable'] } ], [ - {text: ' ', scopes: ['leading-whitespace']}, - {text: 'int', scopes: ['type']}, - {text: ' ', scopes: []}, - {text: 'b', scopes: ['variable']}, - {text: ';', scopes: []} + { text: ' ', scopes: ['leading-whitespace'] }, + { text: 'int', scopes: ['type'] }, + { text: ' ', scopes: [] }, + { text: 'b', scopes: ['variable'] }, + { text: ';', scopes: [] } ], - [ - {text: '}', scopes: []} - ] + [{ text: '}', scopes: [] }] ]) }) - it('updates lines\' highlighting when they are affected by distant changes', async () => { + it("updates lines' highlighting when they are affected by distant changes", async () => { const grammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, { parser: 'tree-sitter-javascript', scopes: { 'call_expression > identifier': 'function', - 'property_identifier': 'member' + property_identifier: 'member' } }) buffer.setText('a(\nb,\nc\n') - const languageMode = new TreeSitterLanguageMode({buffer, grammar}) + const languageMode = new TreeSitterLanguageMode({ buffer, grammar }) buffer.setLanguageMode(languageMode) // missing closing paren expectTokensToEqual(editor, [ - [{text: 'a(', scopes: []}], - [{text: 'b,', scopes: []}], - [{text: 'c', scopes: []}], - [{text: '', scopes: []}] + [{ text: 'a(', scopes: [] }], + [{ text: 'b,', scopes: [] }], + [{ text: 'c', scopes: [] }], + [{ text: '', scopes: [] }] ]) buffer.append(')') expectTokensToEqual(editor, [ - [ - {text: 'a', scopes: ['function']}, - {text: '(', scopes: []} - ], - [{text: 'b,', scopes: []}], - [{text: 'c', scopes: []}], - [{text: ')', scopes: []}] + [{ text: 'a', scopes: ['function'] }, { text: '(', scopes: [] }], + [{ text: 'b,', scopes: [] }], + [{ text: 'c', scopes: [] }], + [{ text: ')', scopes: [] }] ]) }) @@ -195,7 +212,7 @@ describe('TreeSitterLanguageMode', () => { parser: 'tree-sitter-javascript', scopes: { 'identifier, call_expression > identifier': [ - {match: '^[A-Z]', scopes: 'constructor'} + { match: '^[A-Z]', scopes: 'constructor' } ], 'call_expression > identifier': 'function' @@ -204,17 +221,17 @@ describe('TreeSitterLanguageMode', () => { buffer.setText(`a(B(new C))`) - const languageMode = new TreeSitterLanguageMode({buffer, grammar}) + const languageMode = new TreeSitterLanguageMode({ buffer, grammar }) buffer.setLanguageMode(languageMode) expectTokensToEqual(editor, [ [ - {text: 'a', scopes: ['function']}, - {text: '(', scopes: []}, - {text: 'B', scopes: ['constructor']}, - {text: '(new ', scopes: []}, - {text: 'C', scopes: ['constructor']}, - {text: '))', scopes: []}, + { text: 'a', scopes: ['function'] }, + { text: '(', scopes: [] }, + { text: 'B', scopes: ['constructor'] }, + { text: '(new ', scopes: [] }, + { text: 'C', scopes: ['constructor'] }, + { text: '))', scopes: [] } ] ]) }) @@ -223,42 +240,38 @@ describe('TreeSitterLanguageMode', () => { const grammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, { parser: 'tree-sitter-javascript', scopes: { - 'comment': 'comment', - 'string': 'string', - 'property_identifier': 'property', + comment: 'comment', + string: 'string', + property_identifier: 'property' } }) - buffer.setText([ - '// abc', - '', - 'a("b").c' - ].join('\r\n')) + buffer.setText(['// abc', '', 'a("b").c'].join('\r\n')) - const languageMode = new TreeSitterLanguageMode({buffer, grammar}) + const languageMode = new TreeSitterLanguageMode({ buffer, grammar }) buffer.setLanguageMode(languageMode) expectTokensToEqual(editor, [ - [{text: '// abc', scopes: ['comment']}], - [{text: '', scopes: []}], + [{ text: '// abc', scopes: ['comment'] }], + [{ text: '', scopes: [] }], [ - {text: 'a(', scopes: []}, - {text: '"b"', scopes: ['string']}, - {text: ').', scopes: []}, - {text: 'c', scopes: ['property']} + { text: 'a(', scopes: [] }, + { text: '"b"', scopes: ['string'] }, + { text: ').', scopes: [] }, + { text: 'c', scopes: ['property'] } ] ]) buffer.insert([2, 0], ' ') expectTokensToEqual(editor, [ - [{text: '// abc', scopes: ['comment']}], - [{text: '', scopes: []}], + [{ text: '// abc', scopes: ['comment'] }], + [{ text: '', scopes: [] }], [ - {text: ' ', scopes: ['leading-whitespace']}, - {text: 'a(', scopes: []}, - {text: '"b"', scopes: ['string']}, - {text: ').', scopes: []}, - {text: 'c', scopes: ['property']} + { text: ' ', scopes: ['leading-whitespace'] }, + { text: 'a(', scopes: [] }, + { text: '"b"', scopes: ['string'] }, + { text: ').', scopes: [] }, + { text: 'c', scopes: ['property'] } ] ]) }) @@ -267,35 +280,32 @@ describe('TreeSitterLanguageMode', () => { const grammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, { parser: 'tree-sitter-javascript', scopes: { - 'template_string': 'string', + template_string: 'string', '"${"': 'interpolation', '"}"': 'interpolation' } - }); + }) buffer.setText('`\na${1}\nb${2}\n`;') - const languageMode = new TreeSitterLanguageMode({buffer, grammar}) + const languageMode = new TreeSitterLanguageMode({ buffer, grammar }) buffer.setLanguageMode(languageMode) expectTokensToEqual(editor, [ + [{ text: '`', scopes: ['string'] }], [ - {text: '`', scopes: ['string']} - ], [ - {text: 'a', scopes: ['string']}, - {text: '${', scopes: ['string', 'interpolation']}, - {text: '1', scopes: ['string']}, - {text: '}', scopes: ['string', 'interpolation']} - ], [ - {text: 'b', scopes: ['string']}, - {text: '${', scopes: ['string', 'interpolation']}, - {text: '2', scopes: ['string']}, - {text: '}', scopes: ['string', 'interpolation']} + { text: 'a', scopes: ['string'] }, + { text: '${', scopes: ['string', 'interpolation'] }, + { text: '1', scopes: ['string'] }, + { text: '}', scopes: ['string', 'interpolation'] } ], [ - {text: '`', scopes: ['string']}, - {text: ';', scopes: []} - ] + { text: 'b', scopes: ['string'] }, + { text: '${', scopes: ['string', 'interpolation'] }, + { text: '2', scopes: ['string'] }, + { text: '}', scopes: ['string', 'interpolation'] } + ], + [{ text: '`', scopes: ['string'] }, { text: ';', scopes: [] }] ]) }) @@ -303,12 +313,12 @@ describe('TreeSitterLanguageMode', () => { const grammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, { parser: 'tree-sitter-javascript', scopes: { - 'comment': 'comment', - 'call_expression > identifier': 'function', + comment: 'comment', + 'call_expression > identifier': 'function' } }) - buffer.setText(dedent ` + buffer.setText(dedent` /* * Hello */ @@ -316,24 +326,19 @@ describe('TreeSitterLanguageMode', () => { hello(); `) - const languageMode = new TreeSitterLanguageMode({buffer, grammar}) + const languageMode = new TreeSitterLanguageMode({ buffer, grammar }) buffer.setLanguageMode(languageMode) editor.foldBufferRange([[0, 2], [2, 0]]) expectTokensToEqual(editor, [ [ - {text: '/*', scopes: ['comment']}, - {text: '…', scopes: ['fold-marker']}, - {text: ' */', scopes: ['comment']} + { text: '/*', scopes: ['comment'] }, + { text: '…', scopes: ['fold-marker'] }, + { text: ' */', scopes: ['comment'] } ], - [ - {text: '', scopes: []} - ], - [ - {text: 'hello', scopes: ['function']}, - {text: '();', scopes: []}, - ] + [{ text: '', scopes: [] }], + [{ text: 'hello', scopes: ['function'] }, { text: '();', scopes: [] }] ]) }) @@ -341,30 +346,30 @@ describe('TreeSitterLanguageMode', () => { const grammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, { parser: 'tree-sitter-javascript', scopes: { - 'identifier': [ - {match: '^(exports|document|window|global)$', scopes: 'global'}, - {match: '^[A-Z_]+$', scopes: 'constant'}, - {match: '^[A-Z]', scopes: 'constructor'}, + identifier: [ + { match: '^(exports|document|window|global)$', scopes: 'global' }, + { match: '^[A-Z_]+$', scopes: 'constant' }, + { match: '^[A-Z]', scopes: 'constructor' }, 'variable' - ], + ] } }) buffer.setText(`exports.object = Class(SOME_CONSTANT, x)`) - const languageMode = new TreeSitterLanguageMode({buffer, grammar}) + const languageMode = new TreeSitterLanguageMode({ buffer, grammar }) buffer.setLanguageMode(languageMode) expectTokensToEqual(editor, [ [ - {text: 'exports', scopes: ['global']}, - {text: '.object = ', scopes: []}, - {text: 'Class', scopes: ['constructor']}, - {text: '(', scopes: []}, - {text: 'SOME_CONSTANT', scopes: ['constant']}, - {text: ', ', scopes: []}, - {text: 'x', scopes: ['variable']}, - {text: ')', scopes: []}, + { text: 'exports', scopes: ['global'] }, + { text: '.object = ', scopes: [] }, + { text: 'Class', scopes: ['constructor'] }, + { text: '(', scopes: [] }, + { text: 'SOME_CONSTANT', scopes: ['constant'] }, + { text: ', ', scopes: [] }, + { text: 'x', scopes: ['variable'] }, + { text: ')', scopes: [] } ] ]) }) @@ -373,10 +378,10 @@ describe('TreeSitterLanguageMode', () => { const grammar = new TreeSitterGrammar(atom.grammars, rubyGrammarPath, { parser: 'tree-sitter-ruby', scopes: { - 'bare_string': 'string', - 'interpolation': 'embedded', + bare_string: 'string', + interpolation: 'embedded', '"#{"': 'punctuation', - '"}"': 'punctuation', + '"}"': 'punctuation' } }) @@ -384,18 +389,18 @@ describe('TreeSitterLanguageMode', () => { // starts later and ends earlier than the bare string. buffer.setText('a = %W( bc#{d}ef )') - const languageMode = new TreeSitterLanguageMode({buffer, grammar}) + const languageMode = new TreeSitterLanguageMode({ buffer, grammar }) buffer.setLanguageMode(languageMode) expectTokensToEqual(editor, [ [ - {text: 'a = %W( ', scopes: []}, - {text: 'bc', scopes: ['string']}, - {text: '#{', scopes: ['string', 'embedded', 'punctuation']}, - {text: 'd', scopes: ['string', 'embedded']}, - {text: '}', scopes: ['string', 'embedded', 'punctuation']}, - {text: 'ef', scopes: ['string']}, - {text: ' )', scopes: []}, + { text: 'a = %W( ', scopes: [] }, + { text: 'bc', scopes: ['string'] }, + { text: '#{', scopes: ['string', 'embedded', 'punctuation'] }, + { text: 'd', scopes: ['string', 'embedded'] }, + { text: '}', scopes: ['string', 'embedded', 'punctuation'] }, + { text: 'ef', scopes: ['string'] }, + { text: ' )', scopes: [] } ] ]) }) @@ -405,59 +410,57 @@ describe('TreeSitterLanguageMode', () => { const grammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, { parser: 'tree-sitter-javascript', scopes: { - 'identifier': 'variable', + identifier: 'variable', 'call_expression > identifier': 'function', 'new_expression > identifier': 'constructor' } }) - buffer.setText('abc;'); + buffer.setText('abc;') - const languageMode = new TreeSitterLanguageMode({buffer, grammar, syncOperationLimit: 0}) + const languageMode = new TreeSitterLanguageMode({ + buffer, + grammar, + syncOperationLimit: 0 + }) buffer.setLanguageMode(languageMode) await nextHighlightingUpdate(languageMode) await new Promise(process.nextTick) expectTokensToEqual(editor, [ - [ - {text: 'abc', scopes: ['variable']}, - {text: ';', scopes: []} - ], + [{ text: 'abc', scopes: ['variable'] }, { text: ';', scopes: [] }] ]) - buffer.setTextInRange([[0, 3], [0, 3]], '()'); + buffer.setTextInRange([[0, 3], [0, 3]], '()') expectTokensToEqual(editor, [ - [ - {text: 'abc()', scopes: ['variable']}, - {text: ';', scopes: []} - ], + [{ text: 'abc()', scopes: ['variable'] }, { text: ';', scopes: [] }] ]) - buffer.setTextInRange([[0, 0], [0, 0]], 'new '); + buffer.setTextInRange([[0, 0], [0, 0]], 'new ') expectTokensToEqual(editor, [ [ - {text: 'new ', scopes: []}, - {text: 'abc()', scopes: ['variable']}, - {text: ';', scopes: []} - ], + { text: 'new ', scopes: [] }, + { text: 'abc()', scopes: ['variable'] }, + { text: ';', scopes: [] } + ] ]) await nextHighlightingUpdate(languageMode) expectTokensToEqual(editor, [ [ - {text: 'new ', scopes: []}, - {text: 'abc', scopes: ['function']}, - {text: '();', scopes: []} - ], + { text: 'new ', scopes: [] }, + { text: 'abc', scopes: ['function'] }, + { text: '();', scopes: [] } + ] ]) await nextHighlightingUpdate(languageMode) expectTokensToEqual(editor, [ [ - {text: 'new ', scopes: []}, - {text: 'abc', scopes: ['constructor']}, - {text: '();', scopes: []} - ], + { text: 'new ', scopes: [] }, + { text: 'abc', scopes: ['constructor'] }, + { text: '();', scopes: [] } + ] ]) }) }) @@ -467,42 +470,39 @@ describe('TreeSitterLanguageMode', () => { const grammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, { parser: 'tree-sitter-javascript', scopes: { - 'property_identifier': 'property', + property_identifier: 'property', 'call_expression > identifier': 'function', - 'call_expression > member_expression > property_identifier': 'method', + 'call_expression > member_expression > property_identifier': + 'method' } }) - const languageMode = new TreeSitterLanguageMode({buffer, grammar}) + const languageMode = new TreeSitterLanguageMode({ buffer, grammar }) buffer.setLanguageMode(languageMode) - buffer.setText('a'); - expectTokensToEqual(editor, [[ - {text: 'a', scopes: []}, - ]]) + buffer.setText('a') + expectTokensToEqual(editor, [[{ text: 'a', scopes: [] }]]) buffer.append('.') - expectTokensToEqual(editor, [[ - {text: 'a.', scopes: []}, - ]]) + expectTokensToEqual(editor, [[{ text: 'a.', scopes: [] }]]) buffer.append('b') - expectTokensToEqual(editor, [[ - {text: 'a.', scopes: []}, - {text: 'b', scopes: ['property']}, - ]]) + expectTokensToEqual(editor, [ + [{ text: 'a.', scopes: [] }, { text: 'b', scopes: ['property'] }] + ]) buffer.append('()') - expectTokensToEqual(editor, [[ - {text: 'a.', scopes: []}, - {text: 'b', scopes: ['method']}, - {text: '()', scopes: []}, - ]]) + expectTokensToEqual(editor, [ + [ + { text: 'a.', scopes: [] }, + { text: 'b', scopes: ['method'] }, + { text: '()', scopes: [] } + ] + ]) buffer.delete([[0, 1], [0, 2]]) - expectTokensToEqual(editor, [[ - {text: 'ab', scopes: ['function']}, - {text: '()', scopes: []}, - ]]) + expectTokensToEqual(editor, [ + [{ text: 'ab', scopes: ['function'] }, { text: '()', scopes: [] }] + ]) }) }) @@ -514,9 +514,9 @@ describe('TreeSitterLanguageMode', () => { scopeName: 'javascript', parser: 'tree-sitter-javascript', scopes: { - 'property_identifier': 'property', + property_identifier: 'property', 'call_expression > identifier': 'function', - 'template_string': 'string', + template_string: 'string', 'template_substitution > "${"': 'interpolation', 'template_substitution > "}"': 'interpolation' }, @@ -542,32 +542,35 @@ describe('TreeSitterLanguageMode', () => { atom.grammars.addGrammar(htmlGrammar) buffer.setText('node.innerHTML = html `\na ${b}\n`;') - const languageMode = new TreeSitterLanguageMode({buffer, grammar: jsGrammar, grammars: atom.grammars}) + const languageMode = new TreeSitterLanguageMode({ + buffer, + grammar: jsGrammar, + grammars: atom.grammars + }) buffer.setLanguageMode(languageMode) expectTokensToEqual(editor, [ [ - {text: 'node.', scopes: []}, - {text: 'innerHTML', scopes: ['property']}, - {text: ' = ', scopes: []}, - {text: 'html', scopes: ['function']}, - {text: ' ', scopes: []}, - {text: '`', scopes: ['string']}, - {text: '', scopes: ['string', 'html']} - ], [ - {text: 'a ', scopes: ['string', 'html']}, - {text: '${', scopes: ['string', 'html', 'interpolation']}, - {text: 'b', scopes: ['string', 'html']}, - {text: '}', scopes: ['string', 'html', 'interpolation']}, - {text: '<', scopes: ['string', 'html']}, - {text: 'img', scopes: ['string', 'html', 'tag']}, - {text: ' ', scopes: ['string', 'html']}, - {text: 'src', scopes: ['string', 'html', 'attr']}, - {text: '="d">', scopes: ['string', 'html']} - ], [ - {text: '`', scopes: ['string']}, - {text: ';', scopes: []}, + { text: 'node.', scopes: [] }, + { text: 'innerHTML', scopes: ['property'] }, + { text: ' = ', scopes: [] }, + { text: 'html', scopes: ['function'] }, + { text: ' ', scopes: [] }, + { text: '`', scopes: ['string'] }, + { text: '', scopes: ['string', 'html'] } ], + [ + { text: 'a ', scopes: ['string', 'html'] }, + { text: '${', scopes: ['string', 'html', 'interpolation'] }, + { text: 'b', scopes: ['string', 'html'] }, + { text: '}', scopes: ['string', 'html', 'interpolation'] }, + { text: '<', scopes: ['string', 'html'] }, + { text: 'img', scopes: ['string', 'html', 'tag'] }, + { text: ' ', scopes: ['string', 'html'] }, + { text: 'src', scopes: ['string', 'html', 'attr'] }, + { text: '="d">', scopes: ['string', 'html'] } + ], + [{ text: '`', scopes: ['string'] }, { text: ';', scopes: [] }] ]) const range = buffer.findSync('html') @@ -576,22 +579,21 @@ describe('TreeSitterLanguageMode', () => { expectTokensToEqual(editor, [ [ - {text: 'node.', scopes: []}, - {text: 'innerHTML', scopes: ['property']}, - {text: ' = ', scopes: []}, - {text: 'xml', scopes: ['function']}, - {text: ' ', scopes: []}, - {text: '`', scopes: ['string']} - ], [ - {text: 'a ', scopes: ['string']}, - {text: '${', scopes: ['string', 'interpolation']}, - {text: 'b', scopes: ['string']}, - {text: '}', scopes: ['string', 'interpolation']}, - {text: '', scopes: ['string']}, - ], [ - {text: '`', scopes: ['string']}, - {text: ';', scopes: []}, + { text: 'node.', scopes: [] }, + { text: 'innerHTML', scopes: ['property'] }, + { text: ' = ', scopes: [] }, + { text: 'xml', scopes: ['function'] }, + { text: ' ', scopes: [] }, + { text: '`', scopes: ['string'] } ], + [ + { text: 'a ', scopes: ['string'] }, + { text: '${', scopes: ['string', 'interpolation'] }, + { text: 'b', scopes: ['string'] }, + { text: '}', scopes: ['string', 'interpolation'] }, + { text: '', scopes: ['string'] } + ], + [{ text: '`', scopes: ['string'] }, { text: ';', scopes: [] }] ]) }) @@ -600,33 +602,37 @@ describe('TreeSitterLanguageMode', () => { atom.grammars.addGrammar(htmlGrammar) buffer.setText('\n
    \n
    ') - const languageMode = new TreeSitterLanguageMode({buffer, grammar: htmlGrammar, grammars: atom.grammars}) + const languageMode = new TreeSitterLanguageMode({ + buffer, + grammar: htmlGrammar, + grammars: atom.grammars + }) buffer.setLanguageMode(languageMode) expectTokensToEqual(editor, [ [ - {text: '<', scopes: ['html']}, - {text: 'script', scopes: ['html', 'tag']}, - {text: '>', scopes: ['html']}, + { text: '<', scopes: ['html'] }, + { text: 'script', scopes: ['html', 'tag'] }, + { text: '>', scopes: ['html'] } ], [ - {text: 'hello', scopes: ['html', 'function']}, - {text: '();', scopes: ['html']}, + { text: 'hello', scopes: ['html', 'function'] }, + { text: '();', scopes: ['html'] } ], [ - {text: '', scopes: ['html']}, + { text: '', scopes: ['html'] } ], [ - {text: '<', scopes: ['html']}, - {text: 'div', scopes: ['html', 'tag']}, - {text: '>', scopes: ['html']}, + { text: '<', scopes: ['html'] }, + { text: 'div', scopes: ['html', 'tag'] }, + { text: '>', scopes: ['html'] } ], [ - {text: '', scopes: ['html']}, + { text: '', scopes: ['html'] } ] ]) }) @@ -635,78 +641,92 @@ describe('TreeSitterLanguageMode', () => { atom.grammars.addGrammar(jsGrammar) buffer.setText('node.innerHTML = html `\na ${b}\n`;') - const languageMode = new TreeSitterLanguageMode({buffer, grammar: jsGrammar, grammars: atom.grammars}) + const languageMode = new TreeSitterLanguageMode({ + buffer, + grammar: jsGrammar, + grammars: atom.grammars + }) buffer.setLanguageMode(languageMode) expectTokensToEqual(editor, [ [ - {text: 'node.', scopes: []}, - {text: 'innerHTML', scopes: ['property']}, - {text: ' = ', scopes: []}, - {text: 'html', scopes: ['function']}, - {text: ' ', scopes: []}, - {text: '`', scopes: ['string']} - ], [ - {text: 'a ', scopes: ['string']}, - {text: '${', scopes: ['string', 'interpolation']}, - {text: 'b', scopes: ['string']}, - {text: '}', scopes: ['string', 'interpolation']}, - {text: '', scopes: ['string']}, - ], [ - {text: '`', scopes: ['string']}, - {text: ';', scopes: []}, + { text: 'node.', scopes: [] }, + { text: 'innerHTML', scopes: ['property'] }, + { text: ' = ', scopes: [] }, + { text: 'html', scopes: ['function'] }, + { text: ' ', scopes: [] }, + { text: '`', scopes: ['string'] } ], + [ + { text: 'a ', scopes: ['string'] }, + { text: '${', scopes: ['string', 'interpolation'] }, + { text: 'b', scopes: ['string'] }, + { text: '}', scopes: ['string', 'interpolation'] }, + { text: '', scopes: ['string'] } + ], + [{ text: '`', scopes: ['string'] }, { text: ';', scopes: [] }] ]) atom.grammars.addGrammar(htmlGrammar) await nextHighlightingUpdate(languageMode) expectTokensToEqual(editor, [ [ - {text: 'node.', scopes: []}, - {text: 'innerHTML', scopes: ['property']}, - {text: ' = ', scopes: []}, - {text: 'html', scopes: ['function']}, - {text: ' ', scopes: []}, - {text: '`', scopes: ['string']}, - {text: '', scopes: ['string', 'html']} - ], [ - {text: 'a ', scopes: ['string', 'html']}, - {text: '${', scopes: ['string', 'html', 'interpolation']}, - {text: 'b', scopes: ['string', 'html']}, - {text: '}', scopes: ['string', 'html', 'interpolation']}, - {text: '<', scopes: ['string', 'html']}, - {text: 'img', scopes: ['string', 'html', 'tag']}, - {text: ' ', scopes: ['string', 'html']}, - {text: 'src', scopes: ['string', 'html', 'attr']}, - {text: '="d">', scopes: ['string', 'html']} - ], [ - {text: '`', scopes: ['string']}, - {text: ';', scopes: []}, + { text: 'node.', scopes: [] }, + { text: 'innerHTML', scopes: ['property'] }, + { text: ' = ', scopes: [] }, + { text: 'html', scopes: ['function'] }, + { text: ' ', scopes: [] }, + { text: '`', scopes: ['string'] }, + { text: '', scopes: ['string', 'html'] } ], + [ + { text: 'a ', scopes: ['string', 'html'] }, + { text: '${', scopes: ['string', 'html', 'interpolation'] }, + { text: 'b', scopes: ['string', 'html'] }, + { text: '}', scopes: ['string', 'html', 'interpolation'] }, + { text: '<', scopes: ['string', 'html'] }, + { text: 'img', scopes: ['string', 'html', 'tag'] }, + { text: ' ', scopes: ['string', 'html'] }, + { text: 'src', scopes: ['string', 'html', 'attr'] }, + { text: '="d">', scopes: ['string', 'html'] } + ], + [{ text: '`', scopes: ['string'] }, { text: ';', scopes: [] }] ]) }) it('handles injections that intersect', async () => { - const ejsGrammar = new TreeSitterGrammar(atom.grammars, ejsGrammarPath, { - id: 'ejs', - parser: 'tree-sitter-embedded-template', - scopes: { - '"<%="': 'directive', - '"%>"': 'directive', - }, - injectionPoints: [ - { - type: 'template', - language (node) { return 'javascript' }, - content (node) { return node.descendantsOfType('code') } + const ejsGrammar = new TreeSitterGrammar( + atom.grammars, + ejsGrammarPath, + { + id: 'ejs', + parser: 'tree-sitter-embedded-template', + scopes: { + '"<%="': 'directive', + '"%>"': 'directive' }, - { - type: 'template', - language (node) { return 'html' }, - content (node) { return node.descendantsOfType('content') } - } - ] - }) + injectionPoints: [ + { + type: 'template', + language (node) { + return 'javascript' + }, + content (node) { + return node.descendantsOfType('code') + } + }, + { + type: 'template', + language (node) { + return 'html' + }, + content (node) { + return node.descendantsOfType('content') + } + } + ] + } + ) atom.grammars.addGrammar(jsGrammar) atom.grammars.addGrammar(htmlGrammar) @@ -715,41 +735,41 @@ describe('TreeSitterLanguageMode', () => { const languageMode = new TreeSitterLanguageMode({ buffer, grammar: ejsGrammar, - grammars: atom.grammars, + grammars: atom.grammars }) buffer.setLanguageMode(languageMode) expectTokensToEqual(editor, [ [ - {text: '<', scopes: ['html']}, - {text: 'body', scopes: ['html', 'tag']}, - {text: '>', scopes: ['html']} + { text: '<', scopes: ['html'] }, + { text: 'body', scopes: ['html', 'tag'] }, + { text: '>', scopes: ['html'] } ], [ - {text: '<', scopes: ['html']}, - {text: 'script', scopes: ['html', 'tag']}, - {text: '>', scopes: ['html']} + { text: '<', scopes: ['html'] }, + { text: 'script', scopes: ['html', 'tag'] }, + { text: '>', scopes: ['html'] } ], [ - {text: 'b', scopes: ['html', 'function']}, - {text: '(', scopes: ['html']}, - {text: '<%=', scopes: ['html', 'directive']}, - {text: ' c.', scopes: ['html']}, - {text: 'd', scopes: ['html', 'property']}, - {text: ' ', scopes: ['html']}, - {text: '%>', scopes: ['html', 'directive']}, - {text: ')', scopes: ['html']}, + { text: 'b', scopes: ['html', 'function'] }, + { text: '(', scopes: ['html'] }, + { text: '<%=', scopes: ['html', 'directive'] }, + { text: ' c.', scopes: ['html'] }, + { text: 'd', scopes: ['html', 'property'] }, + { text: ' ', scopes: ['html'] }, + { text: '%>', scopes: ['html', 'directive'] }, + { text: ')', scopes: ['html'] } ], [ - {text: '', scopes: ['html']} + { text: '', scopes: ['html'] } ], [ - {text: '', scopes: ['html']} - ], + { text: '', scopes: ['html'] } + ] ]) }) @@ -758,18 +778,18 @@ describe('TreeSitterLanguageMode', () => { editor.onDidTokenize(event => { expectTokensToEqual(editor, [ [ - {text: '<', scopes: ['html']}, - {text: 'script', scopes: ['html', 'tag']}, - {text: '>', scopes: ['html']}, + { text: '<', scopes: ['html'] }, + { text: 'script', scopes: ['html', 'tag'] }, + { text: '>', scopes: ['html'] } ], [ - {text: 'hello', scopes: ['html', 'function']}, - {text: '();', scopes: ['html']}, + { text: 'hello', scopes: ['html', 'function'] }, + { text: '();', scopes: ['html'] } ], [ - {text: '', scopes: ['html']}, + { text: '', scopes: ['html'] } ] ]) resolve() @@ -808,7 +828,10 @@ describe('TreeSitterLanguageMode', () => { it('matches the highlighting of a freshly-opened editor', async () => { jasmine.useRealClock() - const text = fs.readFileSync(path.join(__dirname, 'fixtures', 'sample.js'), 'utf8') + const text = fs.readFileSync( + path.join(__dirname, 'fixtures', 'sample.js'), + 'utf8' + ) atom.grammars.loadGrammarSync(jsGrammarPath) atom.grammars.assignLanguageMode(buffer, 'source.js') buffer.getLanguageMode().syncOperationLimit = 0 @@ -831,7 +854,10 @@ describe('TreeSitterLanguageMode', () => { const range = getRandomBufferRange(random, buffer) if (editRoll < 2) { - const linesToInsert = buildRandomLines(random, range.getExtent().row + 1) + const linesToInsert = buildRandomLines( + random, + range.getExtent().row + 1 + ) // console.log('replace', range.toString(), JSON.stringify(linesToInsert)) buffer.setTextInRange(range, linesToInsert) } else if (editRoll < 5) { @@ -857,14 +883,15 @@ describe('TreeSitterLanguageMode', () => { // Create a fresh buffer and editor with the same text. const buffer2 = new TextBuffer(buffer.getText()) - const editor2 = new TextEditor({buffer: buffer2}) + const editor2 = new TextEditor({ buffer: buffer2 }) atom.grammars.assignLanguageMode(buffer2, 'source.js') // Verify that the the two buffers have the same syntax highlighting. await buffer.getLanguageMode().parseCompletePromise() await buffer2.getLanguageMode().parseCompletePromise() expect(buffer.getLanguageMode().tree.rootNode.toString()).toEqual( - buffer2.getLanguageMode().tree.rootNode.toString(), `Seed: ${seed}` + buffer2.getLanguageMode().tree.rootNode.toString(), + `Seed: ${seed}` ) for (let j = 0, n = editor.getScreenLineCount(); j < n; j++) { @@ -890,17 +917,17 @@ describe('TreeSitterLanguageMode', () => { parser: 'tree-sitter-javascript', folds: [ { - start: {type: '{', index: 0}, - end: {type: '}', index: -1} + start: { type: '{', index: 0 }, + end: { type: '}', index: -1 } }, { - start: {type: '(', index: 0}, - end: {type: ')', index: -1} + start: { type: '(', index: 0 }, + end: { type: ')', index: -1 } } ] }) - buffer.setText(dedent ` + buffer.setText(dedent` module.exports = class A { getB (c, @@ -911,7 +938,7 @@ describe('TreeSitterLanguageMode', () => { } `) - const languageMode = new TreeSitterLanguageMode({buffer, grammar}) + const languageMode = new TreeSitterLanguageMode({ buffer, grammar }) buffer.setLanguageMode(languageMode) expect(editor.isFoldableAtBufferRow(0)).toBe(false) @@ -922,7 +949,7 @@ describe('TreeSitterLanguageMode', () => { expect(editor.isFoldableAtBufferRow(5)).toBe(false) editor.foldBufferRow(2) - expect(getDisplayText(editor)).toBe(dedent ` + expect(getDisplayText(editor)).toBe(dedent` module.exports = class A { getB (c,…) { @@ -932,7 +959,7 @@ describe('TreeSitterLanguageMode', () => { `) editor.foldBufferRow(4) - expect(getDisplayText(editor)).toBe(dedent ` + expect(getDisplayText(editor)).toBe(dedent` module.exports = class A { getB (c,…) {…} @@ -945,17 +972,17 @@ describe('TreeSitterLanguageMode', () => { parser: 'tree-sitter-javascript', folds: [ { - start: {type: '{', index: 0}, - end: {type: '}', index: -1} + start: { type: '{', index: 0 }, + end: { type: '}', index: -1 } }, { - start: {type: '(', index: 0}, - end: {type: ')', index: -1} + start: { type: '(', index: 0 }, + end: { type: ')', index: -1 } } ] }) - buffer.setText(dedent ` + buffer.setText(dedent` if (a) { b } else if (c) { @@ -965,13 +992,13 @@ describe('TreeSitterLanguageMode', () => { } `) - const languageMode = new TreeSitterLanguageMode({buffer, grammar}) + const languageMode = new TreeSitterLanguageMode({ buffer, grammar }) buffer.setLanguageMode(languageMode) // Avoid bringing the `else if...` up onto the same screen line as the preceding `if`. editor.foldBufferRow(1) editor.foldBufferRow(3) - expect(getDisplayText(editor)).toBe(dedent ` + expect(getDisplayText(editor)).toBe(dedent` if (a) {… } else if (c) {… } else { @@ -981,7 +1008,7 @@ describe('TreeSitterLanguageMode', () => { // It's ok to bring the final `}` onto the same screen line as the preceding `else`. editor.foldBufferRow(5) - expect(getDisplayText(editor)).toBe(dedent ` + expect(getDisplayText(editor)).toBe(dedent` if (a) {… } else if (c) {… } else {…} @@ -996,20 +1023,20 @@ describe('TreeSitterLanguageMode', () => { // (the closing tag). { type: 'jsx_element', - start: {index: 0}, - end: {index: -1} + start: { index: 0 }, + end: { index: -1 } }, // End the fold at the *second* to last child of the self-closing tag: the `/`. { type: 'jsx_self_closing_element', - start: {index: 1}, - end: {index: -2} + start: { index: 1 }, + end: { index: -2 } } ] }) - buffer.setText(dedent ` + buffer.setText(dedent` const element1 = @@ -1020,7 +1047,7 @@ describe('TreeSitterLanguageMode', () => { `) - const languageMode = new TreeSitterLanguageMode({buffer, grammar}) + const languageMode = new TreeSitterLanguageMode({ buffer, grammar }) buffer.setLanguageMode(languageMode) expect(editor.isFoldableAtBufferRow(0)).toBe(true) @@ -1031,7 +1058,7 @@ describe('TreeSitterLanguageMode', () => { expect(editor.isFoldableAtBufferRow(5)).toBe(false) editor.foldBufferRow(0) - expect(getDisplayText(editor)).toBe(dedent ` + expect(getDisplayText(editor)).toBe(dedent` const element1 = const element2 = @@ -1041,7 +1068,7 @@ describe('TreeSitterLanguageMode', () => { `) editor.foldBufferRow(4) - expect(getDisplayText(editor)).toBe(dedent ` + expect(getDisplayText(editor)).toBe(dedent` const element1 = const element2 = … @@ -1055,11 +1082,11 @@ describe('TreeSitterLanguageMode', () => { folds: [ // By default, for a node with no children, folds are started at the *end* of the first // line of a node, and ended at the *beginning* of the last line. - {type: 'comment'} + { type: 'comment' } ] }) - buffer.setText(dedent ` + buffer.setText(dedent` /** * Important */ @@ -1068,7 +1095,7 @@ describe('TreeSitterLanguageMode', () => { */ `) - const languageMode = new TreeSitterLanguageMode({buffer, grammar}) + const languageMode = new TreeSitterLanguageMode({ buffer, grammar }) buffer.setLanguageMode(languageMode) expect(editor.isFoldableAtBufferRow(0)).toBe(true) @@ -1078,7 +1105,7 @@ describe('TreeSitterLanguageMode', () => { expect(editor.isFoldableAtBufferRow(4)).toBe(false) editor.foldBufferRow(0) - expect(getDisplayText(editor)).toBe(dedent ` + expect(getDisplayText(editor)).toBe(dedent` /**… */ const x = 1 /* Also important @@ -1086,7 +1113,7 @@ describe('TreeSitterLanguageMode', () => { `) editor.foldBufferRow(3) - expect(getDisplayText(editor)).toBe(dedent ` + expect(getDisplayText(editor)).toBe(dedent` /**… */ const x = 1 /*…*/ `) @@ -1099,26 +1126,26 @@ describe('TreeSitterLanguageMode', () => { // If the #ifdef has an `#else` clause, then end the fold there. { type: ['preproc_ifdef', 'preproc_elif'], - start: {index: 1}, - end: {type: ['preproc_else', 'preproc_elif']} + start: { index: 1 }, + end: { type: ['preproc_else', 'preproc_elif'] } }, // Otherwise, end the fold at the last child - the `#endif`. { type: 'preproc_ifdef', - start: {index: 1}, - end: {index: -1} + start: { index: 1 }, + end: { index: -1 } }, // When folding an `#else` clause, the fold extends to the end of the clause. { type: 'preproc_else', - start: {index: 0} + start: { index: 0 } } ] }) - buffer.setText(dedent ` + buffer.setText(dedent` #ifndef FOO_H_ #define FOO_H_ @@ -1142,11 +1169,11 @@ describe('TreeSitterLanguageMode', () => { #endif `) - const languageMode = new TreeSitterLanguageMode({buffer, grammar}) + const languageMode = new TreeSitterLanguageMode({ buffer, grammar }) buffer.setLanguageMode(languageMode) editor.foldBufferRow(3) - expect(getDisplayText(editor)).toBe(dedent ` + expect(getDisplayText(editor)).toBe(dedent` #ifndef FOO_H_ #define FOO_H_ @@ -1167,7 +1194,7 @@ describe('TreeSitterLanguageMode', () => { `) editor.foldBufferRow(8) - expect(getDisplayText(editor)).toBe(dedent ` + expect(getDisplayText(editor)).toBe(dedent` #ifndef FOO_H_ #define FOO_H_ @@ -1184,13 +1211,13 @@ describe('TreeSitterLanguageMode', () => { `) editor.foldBufferRow(0) - expect(getDisplayText(editor)).toBe(dedent ` + expect(getDisplayText(editor)).toBe(dedent` #ifndef FOO_H_… #endif `) editor.foldAllAtIndentLevel(1) - expect(getDisplayText(editor)).toBe(dedent ` + expect(getDisplayText(editor)).toBe(dedent` #ifndef FOO_H_ #define FOO_H_ @@ -1210,20 +1237,20 @@ describe('TreeSitterLanguageMode', () => { folds: [ { type: 'element', - start: {index: 0}, - end: {index: -1} + start: { index: 0 }, + end: { index: -1 } } ] }) - buffer.setText(dedent ` + buffer.setText(dedent` `) - const languageMode = new TreeSitterLanguageMode({buffer, grammar}) + const languageMode = new TreeSitterLanguageMode({ buffer, grammar }) buffer.setLanguageMode(languageMode) // Void elements have only one child @@ -1231,7 +1258,7 @@ describe('TreeSitterLanguageMode', () => { expect(editor.isFoldableAtBufferRow(2)).toBe(false) editor.foldBufferRow(0) - expect(getDisplayText(editor)).toBe(dedent ` + expect(getDisplayText(editor)).toBe(dedent` … `) @@ -1245,13 +1272,13 @@ describe('TreeSitterLanguageMode', () => { // just to demonstrate the targeting of named vs anonymous nodes. { type: 'elsif', - start: {index: 1}, + start: { index: 1 }, // There are no double quotes around the `elsif` type. This indicates // that we're targeting a *named* node in the syntax tree. The fold // should end at the nested `elsif` node, not at the token that represents // the literal string "elsif". - end: {type: ['else', 'elsif']} + end: { type: ['else', 'elsif'] } }, { type: 'else', @@ -1260,12 +1287,12 @@ describe('TreeSitterLanguageMode', () => { // we're targetting an *anonymous* node in the syntax tree. The fold // should start at the token representing the literal string "else", // not at an `else` node. - start: {type: '"else"'} + start: { type: '"else"' } } ] }) - buffer.setText(dedent ` + buffer.setText(dedent` if a b elsif c @@ -1275,20 +1302,20 @@ describe('TreeSitterLanguageMode', () => { end `) - const languageMode = new TreeSitterLanguageMode({buffer, grammar}) + const languageMode = new TreeSitterLanguageMode({ buffer, grammar }) buffer.setLanguageMode(languageMode) expect(languageMode.tree.rootNode.toString()).toBe( - "(program (if (identifier) (then " + - "(identifier)) " + - "(elsif (identifier) (then " + - "(identifier)) " + - "(else " + - "(identifier)))))" + '(program (if (identifier) (then ' + + '(identifier)) ' + + '(elsif (identifier) (then ' + + '(identifier)) ' + + '(else ' + + '(identifier)))))' ) editor.foldBufferRow(2) - expect(getDisplayText(editor)).toBe(dedent ` + expect(getDisplayText(editor)).toBe(dedent` if a b elsif c… @@ -1298,7 +1325,7 @@ describe('TreeSitterLanguageMode', () => { `) editor.foldBufferRow(4) - expect(getDisplayText(editor)).toBe(dedent ` + expect(getDisplayText(editor)).toBe(dedent` if a b elsif c… @@ -1312,13 +1339,13 @@ describe('TreeSitterLanguageMode', () => { parser: 'tree-sitter-javascript', folds: [ { - start: {type: '{', index: 0}, - end: {type: '}', index: -1} + start: { type: '{', index: 0 }, + end: { type: '}', index: -1 } } ] }) - buffer.setText(dedent ` + buffer.setText(dedent` class A { // a constructor (b) { @@ -1327,7 +1354,7 @@ describe('TreeSitterLanguageMode', () => { } `) - const languageMode = new TreeSitterLanguageMode({buffer, grammar}) + const languageMode = new TreeSitterLanguageMode({ buffer, grammar }) buffer.setLanguageMode(languageMode) expect(languageMode.isFoldableAtRow(0)).toBe(true) expect(languageMode.isFoldableAtRow(1)).toBe(false) @@ -1345,17 +1372,21 @@ describe('TreeSitterLanguageMode', () => { describe('when folding a node that ends with a line break', () => { it('ends the fold at the end of the previous line', async () => { - const grammar = new TreeSitterGrammar(atom.grammars, pythonGrammarPath, { - parser: 'tree-sitter-python', - folds: [ - { - type: 'function_definition', - start: {type: ':'} - } - ] - }) + const grammar = new TreeSitterGrammar( + atom.grammars, + pythonGrammarPath, + { + parser: 'tree-sitter-python', + folds: [ + { + type: 'function_definition', + start: { type: ':' } + } + ] + } + ) - buffer.setText(dedent ` + buffer.setText(dedent` def ab(): print 'a' print 'b' @@ -1365,10 +1396,10 @@ describe('TreeSitterLanguageMode', () => { print 'd' `) - buffer.setLanguageMode(new TreeSitterLanguageMode({buffer, grammar})) + buffer.setLanguageMode(new TreeSitterLanguageMode({ buffer, grammar })) editor.foldBufferRow(0) - expect(getDisplayText(editor)).toBe(dedent ` + expect(getDisplayText(editor)).toBe(dedent` def ab():… def cd(): @@ -1379,31 +1410,39 @@ describe('TreeSitterLanguageMode', () => { }) it('folds code in injected languages', async () => { - const htmlGrammar = new TreeSitterGrammar(atom.grammars, htmlGrammarPath, { - scopeName: 'html', - parser: 'tree-sitter-html', - scopes: {}, - folds: [{ - type: ['element', 'raw_element'], - start: {index: 0}, - end: {index: -1} - }], - injectionRegExp: 'html' - }) + const htmlGrammar = new TreeSitterGrammar( + atom.grammars, + htmlGrammarPath, + { + scopeName: 'html', + parser: 'tree-sitter-html', + scopes: {}, + folds: [ + { + type: ['element', 'raw_element'], + start: { index: 0 }, + end: { index: -1 } + } + ], + injectionRegExp: 'html' + } + ) const jsGrammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, { scopeName: 'javascript', parser: 'tree-sitter-javascript', scopes: {}, - folds: [{ - type: ['template_string'], - start: {index: 0}, - end: {index: -1}, - }, - { - start: {index: 0, type: '('}, - end: {index: -1, type: ')'} - }], + folds: [ + { + type: ['template_string'], + start: { index: 0 }, + end: { index: -1 } + }, + { + start: { index: 0, type: '(' }, + end: { index: -1, type: ')' } + } + ], injectionRegExp: 'javascript', injectionPoints: [HTML_TEMPLATE_LITERAL_INJECTION_POINT] }) @@ -1422,7 +1461,11 @@ describe('TreeSitterLanguageMode', () => { \` ` ) - const languageMode = new TreeSitterLanguageMode({buffer, grammar: jsGrammar, grammars: atom.grammars}) + const languageMode = new TreeSitterLanguageMode({ + buffer, + grammar: jsGrammar, + grammars: atom.grammars + }) buffer.setLanguageMode(languageMode) editor.foldBufferRow(2) @@ -1467,32 +1510,32 @@ describe('TreeSitterLanguageMode', () => { buffer.setText('foo({bar: baz});') - buffer.setLanguageMode(new TreeSitterLanguageMode({buffer, grammar})) - expect(editor.scopeDescriptorForBufferPosition([0, 'foo({b'.length]).getScopesArray()).toEqual([ - 'source.js', - 'property.name' - ]) - expect(editor.scopeDescriptorForBufferPosition([0, 'foo({'.length]).getScopesArray()).toEqual([ - 'source.js', - 'property.name' - ]) + buffer.setLanguageMode(new TreeSitterLanguageMode({ buffer, grammar })) + expect( + editor + .scopeDescriptorForBufferPosition([0, 'foo({b'.length]) + .getScopesArray() + ).toEqual(['source.js', 'property.name']) + expect( + editor + .scopeDescriptorForBufferPosition([0, 'foo({'.length]) + .getScopesArray() + ).toEqual(['source.js', 'property.name']) // Drive-by test for .tokenForPosition() const token = editor.tokenForBufferPosition([0, 'foo({b'.length]) expect(token.value).toBe('bar') - expect(token.scopes).toEqual([ - 'source.js', - 'property.name' - ]) + expect(token.scopes).toEqual(['source.js', 'property.name']) buffer.setText('// baz\n') // Adjust position when at end of line - buffer.setLanguageMode(new TreeSitterLanguageMode({buffer, grammar})) - expect(editor.scopeDescriptorForBufferPosition([0, '// baz'.length]).getScopesArray()).toEqual([ - 'source.js', - 'comment.block' - ]) + buffer.setLanguageMode(new TreeSitterLanguageMode({ buffer, grammar })) + expect( + editor + .scopeDescriptorForBufferPosition([0, '// baz'.length]) + .getScopesArray() + ).toEqual(['source.js', 'comment.block']) }) it('includes nodes in injected syntax trees', async () => { @@ -1509,16 +1552,20 @@ describe('TreeSitterLanguageMode', () => { injectionPoints: [HTML_TEMPLATE_LITERAL_INJECTION_POINT] }) - const htmlGrammar = new TreeSitterGrammar(atom.grammars, htmlGrammarPath, { - scopeName: 'text.html', - parser: 'tree-sitter-html', - scopes: { - fragment: 'text.html', - raw_element: 'script.tag' - }, - injectionRegExp: 'html', - injectionPoints: [SCRIPT_TAG_INJECTION_POINT] - }) + const htmlGrammar = new TreeSitterGrammar( + atom.grammars, + htmlGrammarPath, + { + scopeName: 'text.html', + parser: 'tree-sitter-html', + scopes: { + fragment: 'text.html', + raw_element: 'script.tag' + }, + injectionRegExp: 'html', + injectionPoints: [SCRIPT_TAG_INJECTION_POINT] + } + ) atom.grammars.addGrammar(jsGrammar) atom.grammars.addGrammar(htmlGrammar) @@ -1533,11 +1580,17 @@ describe('TreeSitterLanguageMode', () => {
    `) - const languageMode = new TreeSitterLanguageMode({buffer, grammar: htmlGrammar, grammars: atom.grammars}) + const languageMode = new TreeSitterLanguageMode({ + buffer, + grammar: htmlGrammar, + grammars: atom.grammars + }) buffer.setLanguageMode(languageMode) const position = buffer.findSync('name').start - expect(languageMode.scopeDescriptorForPosition(position).getScopesArray()).toEqual([ + expect( + languageMode.scopeDescriptorForPosition(position).getScopesArray() + ).toEqual([ 'text.html', 'script.tag', 'source.js', @@ -1558,10 +1611,10 @@ describe('TreeSitterLanguageMode', () => { }) buffer.setText('a; ') - buffer.setLanguageMode(new TreeSitterLanguageMode({buffer, grammar})) - expect(editor.scopeDescriptorForBufferPosition([0, 3]).getScopesArray()).toEqual([ - 'source.js' - ]) + buffer.setLanguageMode(new TreeSitterLanguageMode({ buffer, grammar })) + expect( + editor.scopeDescriptorForBufferPosition([0, 3]).getScopesArray() + ).toEqual(['source.js']) }) it('works when the given position is between tokens', () => { @@ -1570,19 +1623,18 @@ describe('TreeSitterLanguageMode', () => { parser: 'tree-sitter-javascript', scopes: { program: 'source.js', - comment: 'comment.block', + comment: 'comment.block' } }) buffer.setText('a // b') - buffer.setLanguageMode(new TreeSitterLanguageMode({buffer, grammar})) - expect(editor.scopeDescriptorForBufferPosition([0, 2]).getScopesArray()).toEqual([ - 'source.js' - ]) - expect(editor.scopeDescriptorForBufferPosition([0, 3]).getScopesArray()).toEqual([ - 'source.js', - 'comment.block' - ]) + buffer.setLanguageMode(new TreeSitterLanguageMode({ buffer, grammar })) + expect( + editor.scopeDescriptorForBufferPosition([0, 2]).getScopesArray() + ).toEqual(['source.js']) + expect( + editor.scopeDescriptorForBufferPosition([0, 3]).getScopesArray() + ).toEqual(['source.js', 'comment.block']) }) }) @@ -1595,8 +1647,12 @@ describe('TreeSitterLanguageMode', () => { buffer.setText('foo({bar: baz});') - buffer.setLanguageMode(new TreeSitterLanguageMode({buffer, grammar})) - expect(editor.syntaxTreeScopeDescriptorForBufferPosition([0, 6]).getScopesArray()).toEqual([ + buffer.setLanguageMode(new TreeSitterLanguageMode({ buffer, grammar })) + expect( + editor + .syntaxTreeScopeDescriptorForBufferPosition([0, 6]) + .getScopesArray() + ).toEqual([ 'source.js', 'program', 'expression_statement', @@ -1609,12 +1665,12 @@ describe('TreeSitterLanguageMode', () => { buffer.setText('//bar\n') - buffer.setLanguageMode(new TreeSitterLanguageMode({buffer, grammar})) - expect(editor.syntaxTreeScopeDescriptorForBufferPosition([0, 5]).getScopesArray()).toEqual([ - 'source.js', - 'program', - 'comment' - ]) + buffer.setLanguageMode(new TreeSitterLanguageMode({ buffer, grammar })) + expect( + editor + .syntaxTreeScopeDescriptorForBufferPosition([0, 5]) + .getScopesArray() + ).toEqual(['source.js', 'program', 'comment']) }) it('includes nodes in injected syntax trees', async () => { @@ -1626,13 +1682,17 @@ describe('TreeSitterLanguageMode', () => { injectionPoints: [HTML_TEMPLATE_LITERAL_INJECTION_POINT] }) - const htmlGrammar = new TreeSitterGrammar(atom.grammars, htmlGrammarPath, { - scopeName: 'text.html', - parser: 'tree-sitter-html', - scopes: {}, - injectionRegExp: 'html', - injectionPoints: [SCRIPT_TAG_INJECTION_POINT] - }) + const htmlGrammar = new TreeSitterGrammar( + atom.grammars, + htmlGrammarPath, + { + scopeName: 'text.html', + parser: 'tree-sitter-html', + scopes: {}, + injectionRegExp: 'html', + injectionPoints: [SCRIPT_TAG_INJECTION_POINT] + } + ) atom.grammars.addGrammar(jsGrammar) atom.grammars.addGrammar(htmlGrammar) @@ -1647,11 +1707,19 @@ describe('TreeSitterLanguageMode', () => {
    `) - const languageMode = new TreeSitterLanguageMode({buffer, grammar: htmlGrammar, grammars: atom.grammars}) + const languageMode = new TreeSitterLanguageMode({ + buffer, + grammar: htmlGrammar, + grammars: atom.grammars + }) buffer.setLanguageMode(languageMode) const position = buffer.findSync('name').start - expect(editor.syntaxTreeScopeDescriptorForBufferPosition(position).getScopesArray()).toEqual([ + expect( + editor + .syntaxTreeScopeDescriptorForBufferPosition(position) + .getScopesArray() + ).toEqual([ 'text.html', 'fragment', 'element', @@ -1680,13 +1748,15 @@ describe('TreeSitterLanguageMode', () => { buffer.setText('foo({bar: baz});') - buffer.setLanguageMode(new TreeSitterLanguageMode({buffer, grammar})) - expect(editor.bufferRangeForScopeAtPosition(null, [0, 6])).toEqual( - [[0, 5], [0, 8]] - ) - expect(editor.bufferRangeForScopeAtPosition(null, [0, 9])).toEqual( - [[0, 8], [0, 9]] - ) + buffer.setLanguageMode(new TreeSitterLanguageMode({ buffer, grammar })) + expect(editor.bufferRangeForScopeAtPosition(null, [0, 6])).toEqual([ + [0, 5], + [0, 8] + ]) + expect(editor.bufferRangeForScopeAtPosition(null, [0, 9])).toEqual([ + [0, 8], + [0, 9] + ]) }) it('includes nodes in injected syntax trees', async () => { @@ -1698,13 +1768,17 @@ describe('TreeSitterLanguageMode', () => { injectionPoints: [HTML_TEMPLATE_LITERAL_INJECTION_POINT] }) - const htmlGrammar = new TreeSitterGrammar(atom.grammars, htmlGrammarPath, { - scopeName: 'html', - parser: 'tree-sitter-html', - scopes: {}, - injectionRegExp: 'html', - injectionPoints: [SCRIPT_TAG_INJECTION_POINT] - }) + const htmlGrammar = new TreeSitterGrammar( + atom.grammars, + htmlGrammarPath, + { + scopeName: 'html', + parser: 'tree-sitter-html', + scopes: {}, + injectionRegExp: 'html', + injectionPoints: [SCRIPT_TAG_INJECTION_POINT] + } + ) atom.grammars.addGrammar(jsGrammar) atom.grammars.addGrammar(htmlGrammar) @@ -1719,14 +1793,19 @@ describe('TreeSitterLanguageMode', () => {
    `) - const languageMode = new TreeSitterLanguageMode({buffer, grammar: htmlGrammar, grammars: atom.grammars}) + const languageMode = new TreeSitterLanguageMode({ + buffer, + grammar: htmlGrammar, + grammars: atom.grammars + }) buffer.setLanguageMode(languageMode) const nameProperty = buffer.findSync('name') - const {start} = nameProperty - const position = Object.assign({}, start, {column: start.column + 2}) - expect(languageMode.bufferRangeForScopeAtPosition(null, position)) - .toEqual(nameProperty) + const { start } = nameProperty + const position = Object.assign({}, start, { column: start.column + 2 }) + expect( + languageMode.bufferRangeForScopeAtPosition(null, position) + ).toEqual(nameProperty) }) }) @@ -1736,20 +1815,20 @@ describe('TreeSitterLanguageMode', () => { scopeName: 'javascript', parser: 'tree-sitter-javascript', scopes: { - 'property_identifier': 'variable.other.object.property', - 'template_string': 'string.quoted.template' + property_identifier: 'variable.other.object.property', + template_string: 'string.quoted.template' } }) buffer.setText('a(`${b({ccc: ddd})} eee`);') - buffer.setLanguageMode(new TreeSitterLanguageMode({buffer, grammar})) - expect(editor.bufferRangeForScopeAtPosition('.variable.property', [0, 9])).toEqual( - [[0, 8], [0, 11]] - ) - expect(editor.bufferRangeForScopeAtPosition('.string.quoted', [0, 6])).toEqual( - [[0, 2], [0, 24]] - ) + buffer.setLanguageMode(new TreeSitterLanguageMode({ buffer, grammar })) + expect( + editor.bufferRangeForScopeAtPosition('.variable.property', [0, 9]) + ).toEqual([[0, 8], [0, 11]]) + expect( + editor.bufferRangeForScopeAtPosition('.string.quoted', [0, 6]) + ).toEqual([[0, 2], [0, 24]]) }) it('includes nodes in injected syntax trees', async () => { @@ -1757,21 +1836,25 @@ describe('TreeSitterLanguageMode', () => { scopeName: 'javascript', parser: 'tree-sitter-javascript', scopes: { - 'property_identifier': 'variable.other.object.property', + property_identifier: 'variable.other.object.property' }, injectionRegExp: 'javascript', injectionPoints: [HTML_TEMPLATE_LITERAL_INJECTION_POINT] }) - const htmlGrammar = new TreeSitterGrammar(atom.grammars, htmlGrammarPath, { - scopeName: 'html', - parser: 'tree-sitter-html', - scopes: { - 'element': 'meta.element.html' - }, - injectionRegExp: 'html', - injectionPoints: [SCRIPT_TAG_INJECTION_POINT] - }) + const htmlGrammar = new TreeSitterGrammar( + atom.grammars, + htmlGrammarPath, + { + scopeName: 'html', + parser: 'tree-sitter-html', + scopes: { + element: 'meta.element.html' + }, + injectionRegExp: 'html', + injectionPoints: [SCRIPT_TAG_INJECTION_POINT] + } + ) atom.grammars.addGrammar(jsGrammar) atom.grammars.addGrammar(htmlGrammar) @@ -1786,16 +1869,28 @@ describe('TreeSitterLanguageMode', () => {
    `) - const languageMode = new TreeSitterLanguageMode({buffer, grammar: htmlGrammar, grammars: atom.grammars}) + const languageMode = new TreeSitterLanguageMode({ + buffer, + grammar: htmlGrammar, + grammars: atom.grammars + }) buffer.setLanguageMode(languageMode) const nameProperty = buffer.findSync('name') - const {start} = nameProperty - const position = Object.assign({}, start, {column: start.column + 2}) - expect(languageMode.bufferRangeForScopeAtPosition('.object.property', position)) - .toEqual(nameProperty) - expect(languageMode.bufferRangeForScopeAtPosition('.meta.element.html', position)) - .toEqual(buffer.findSync('\\${person\\.name}')) + const { start } = nameProperty + const position = Object.assign({}, start, { column: start.column + 2 }) + expect( + languageMode.bufferRangeForScopeAtPosition( + '.object.property', + position + ) + ).toEqual(nameProperty) + expect( + languageMode.bufferRangeForScopeAtPosition( + '.meta.element.html', + position + ) + ).toEqual(buffer.findSync('\\${person\\.name}')) }) it('accepts node-matching functions as selectors', async () => { @@ -1807,13 +1902,17 @@ describe('TreeSitterLanguageMode', () => { injectionPoints: [HTML_TEMPLATE_LITERAL_INJECTION_POINT] }) - const htmlGrammar = new TreeSitterGrammar(atom.grammars, htmlGrammarPath, { - scopeName: 'html', - parser: 'tree-sitter-html', - scopes: {}, - injectionRegExp: 'html', - injectionPoints: [SCRIPT_TAG_INJECTION_POINT] - }) + const htmlGrammar = new TreeSitterGrammar( + atom.grammars, + htmlGrammarPath, + { + scopeName: 'html', + parser: 'tree-sitter-html', + scopes: {}, + injectionRegExp: 'html', + injectionPoints: [SCRIPT_TAG_INJECTION_POINT] + } + ) atom.grammars.addGrammar(jsGrammar) atom.grammars.addGrammar(htmlGrammar) @@ -1828,16 +1927,25 @@ describe('TreeSitterLanguageMode', () => { `) - const languageMode = new TreeSitterLanguageMode({buffer, grammar: htmlGrammar, grammars: atom.grammars}) + const languageMode = new TreeSitterLanguageMode({ + buffer, + grammar: htmlGrammar, + grammars: atom.grammars + }) buffer.setLanguageMode(languageMode) const nameProperty = buffer.findSync('name') - const {start} = nameProperty - const position = Object.assign({}, start, {column: start.column + 2}) + const { start } = nameProperty + const position = Object.assign({}, start, { column: start.column + 2 }) const templateStringInCallExpression = node => - node.type === 'template_string' && node.parent.type === 'call_expression' - expect(languageMode.bufferRangeForScopeAtPosition(templateStringInCallExpression, position)) - .toEqual([[3, 19], [5, 15]]) + node.type === 'template_string' && + node.parent.type === 'call_expression' + expect( + languageMode.bufferRangeForScopeAtPosition( + templateStringInCallExpression, + position + ) + ).toEqual([[3, 19], [5, 15]]) }) }) }) @@ -1850,16 +1958,16 @@ describe('TreeSitterLanguageMode', () => { }) buffer.setText('foo(bar({x: 2}));') - const languageMode = new TreeSitterLanguageMode({buffer, grammar}) + const languageMode = new TreeSitterLanguageMode({ buffer, grammar }) buffer.setLanguageMode(languageMode) expect(languageMode.getSyntaxNodeAtPosition([0, 6]).range).toEqual( buffer.findSync('bar') ) const findFoo = node => node.type === 'call_expression' && node.firstChild.text === 'foo' - expect(languageMode.getSyntaxNodeAtPosition([0, 6], findFoo).range).toEqual( - [[0, 0], [0, buffer.getText().length - 1]] - ) + expect( + languageMode.getSyntaxNodeAtPosition([0, 6], findFoo).range + ).toEqual([[0, 0], [0, buffer.getText().length - 1]]) }) }) @@ -1868,26 +1976,35 @@ describe('TreeSitterLanguageMode', () => { const jsGrammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, { scopeName: 'javascript', parser: 'tree-sitter-javascript', - comments: {start: '//'}, + comments: { start: '//' }, injectionRegExp: 'javascript', injectionPoints: [HTML_TEMPLATE_LITERAL_INJECTION_POINT] }) - const htmlGrammar = new TreeSitterGrammar(atom.grammars, htmlGrammarPath, { - scopeName: 'html', - parser: 'tree-sitter-html', - scopes: {}, - comments: {start: ''}, - injectionRegExp: 'html', - injectionPoints: [SCRIPT_TAG_INJECTION_POINT] - }) + const htmlGrammar = new TreeSitterGrammar( + atom.grammars, + htmlGrammarPath, + { + scopeName: 'html', + parser: 'tree-sitter-html', + scopes: {}, + comments: { start: '' }, + injectionRegExp: 'html', + injectionPoints: [SCRIPT_TAG_INJECTION_POINT] + } + ) atom.grammars.addGrammar(jsGrammar) atom.grammars.addGrammar(htmlGrammar) - const languageMode = new TreeSitterLanguageMode({buffer, grammar: htmlGrammar, grammars: atom.grammars}) + const languageMode = new TreeSitterLanguageMode({ + buffer, + grammar: htmlGrammar, + grammars: atom.grammars + }) buffer.setLanguageMode(languageMode) - buffer.setText(` + buffer.setText( + `
    hi
    - `.trim()) + `.trim() + ) + const htmlCommentStrings = { + commentStartString: '' + } + const jsCommentStrings = { + commentStartString: '//', + commentEndString: undefined + } - const htmlCommentStrings = {commentStartString: ''} - const jsCommentStrings = {commentStartString: '//', commentEndString: undefined} - - expect(languageMode.commentStringsForPosition(new Point(0, 0))).toEqual(htmlCommentStrings) - expect(languageMode.commentStringsForPosition(new Point(1, 0))).toEqual(htmlCommentStrings) - expect(languageMode.commentStringsForPosition(new Point(2, 0))).toEqual(jsCommentStrings) - expect(languageMode.commentStringsForPosition(new Point(3, 0))).toEqual(jsCommentStrings) - expect(languageMode.commentStringsForPosition(new Point(4, 0))).toEqual(htmlCommentStrings) - expect(languageMode.commentStringsForPosition(new Point(5, 0))).toEqual(jsCommentStrings) - expect(languageMode.commentStringsForPosition(new Point(6, 0))).toEqual(htmlCommentStrings) + expect(languageMode.commentStringsForPosition(new Point(0, 0))).toEqual( + htmlCommentStrings + ) + expect(languageMode.commentStringsForPosition(new Point(1, 0))).toEqual( + htmlCommentStrings + ) + expect(languageMode.commentStringsForPosition(new Point(2, 0))).toEqual( + jsCommentStrings + ) + expect(languageMode.commentStringsForPosition(new Point(3, 0))).toEqual( + jsCommentStrings + ) + expect(languageMode.commentStringsForPosition(new Point(4, 0))).toEqual( + htmlCommentStrings + ) + expect(languageMode.commentStringsForPosition(new Point(5, 0))).toEqual( + jsCommentStrings + ) + expect(languageMode.commentStringsForPosition(new Point(6, 0))).toEqual( + htmlCommentStrings + ) }) }) @@ -1915,17 +2052,17 @@ describe('TreeSitterLanguageMode', () => { it('expands and contracts the selection based on the syntax tree', async () => { const grammar = new TreeSitterGrammar(atom.grammars, jsGrammarPath, { parser: 'tree-sitter-javascript', - scopes: {'program': 'source'} + scopes: { program: 'source' } }) - buffer.setText(dedent ` + buffer.setText(dedent` function a (b, c, d) { eee.f() g() } `) - buffer.setLanguageMode(new TreeSitterLanguageMode({buffer, grammar})) + buffer.setLanguageMode(new TreeSitterLanguageMode({ buffer, grammar })) editor.setCursorBufferPosition([1, 3]) editor.selectLargerSyntaxNode() @@ -1937,7 +2074,9 @@ describe('TreeSitterLanguageMode', () => { editor.selectLargerSyntaxNode() expect(editor.getSelectedText()).toBe('{\n eee.f()\n g()\n}') editor.selectLargerSyntaxNode() - expect(editor.getSelectedText()).toBe('function a (b, c, d) {\n eee.f()\n g()\n}') + expect(editor.getSelectedText()).toBe( + 'function a (b, c, d) {\n eee.f()\n g()\n}' + ) editor.selectSmallerSyntaxNode() expect(editor.getSelectedText()).toBe('{\n eee.f()\n g()\n}') @@ -1956,9 +2095,9 @@ describe('TreeSitterLanguageMode', () => { scopeName: 'javascript', parser: 'tree-sitter-javascript', scopes: { - 'property_identifier': 'property', + property_identifier: 'property', 'call_expression > identifier': 'function', - 'template_string': 'string', + template_string: 'string', 'template_substitution > "${"': 'interpolation', 'template_substitution > "}"': 'interpolation' }, @@ -1966,24 +2105,35 @@ describe('TreeSitterLanguageMode', () => { injectionPoints: [HTML_TEMPLATE_LITERAL_INJECTION_POINT] }) - const htmlGrammar = new TreeSitterGrammar(atom.grammars, htmlGrammarPath, { - scopeName: 'html', - parser: 'tree-sitter-html', - scopes: { - fragment: 'html', - tag_name: 'tag', - attribute_name: 'attr' - }, - injectionRegExp: 'html' - }) + const htmlGrammar = new TreeSitterGrammar( + atom.grammars, + htmlGrammarPath, + { + scopeName: 'html', + parser: 'tree-sitter-html', + scopes: { + fragment: 'html', + tag_name: 'tag', + attribute_name: 'attr' + }, + injectionRegExp: 'html' + } + ) atom.grammars.addGrammar(htmlGrammar) buffer.setText('a = html ` c${def()}e${f}g `') - const languageMode = new TreeSitterLanguageMode({buffer, grammar: jsGrammar, grammars: atom.grammars}) + const languageMode = new TreeSitterLanguageMode({ + buffer, + grammar: jsGrammar, + grammars: atom.grammars + }) buffer.setLanguageMode(languageMode) - editor.setCursorBufferPosition({row: 0, column: buffer.getText().indexOf('ef()')}) + editor.setCursorBufferPosition({ + row: 0, + column: buffer.getText().indexOf('ef()') + }) editor.selectLargerSyntaxNode() expect(editor.getSelectedText()).toBe('def') editor.selectLargerSyntaxNode() @@ -2023,7 +2173,6 @@ function expectTokensToEqual (editor, expectedTokenLines) { // Assert that the correct tokens are returned regardless of which row // the highlighting iterator starts on. for (let startRow = 0; startRow <= lastRow; startRow++) { - // Clear the screen line cache between iterations, but not on the first // iteration, so that the first iteration tests that the cache has been // correctly invalidated by any changes. @@ -2035,13 +2184,17 @@ function expectTokensToEqual (editor, expectedTokenLines) { const tokenLines = [] for (let row = startRow; row <= lastRow; row++) { - tokenLines[row] = editor.tokensForScreenRow(row).map(({text, scopes}) => ({ - text, - scopes: scopes.map(scope => scope - .split(' ') - .map(className => className.replace('syntax--', '')) - .join(' ')) - })) + tokenLines[row] = editor + .tokensForScreenRow(row) + .map(({ text, scopes }) => ({ + text, + scopes: scopes.map(scope => + scope + .split(' ') + .map(className => className.replace('syntax--', '')) + .join(' ') + ) + })) } for (let row = startRow; row <= lastRow; row++) { @@ -2050,7 +2203,10 @@ function expectTokensToEqual (editor, expectedTokenLines) { expect(tokenLine.length).toEqual(expectedTokenLine.length) for (let i = 0; i < tokenLine.length; i++) { - expect(tokenLine[i]).toEqual(expectedTokenLine[i], `Token ${i}, startRow: ${startRow}`) + expect(tokenLine[i]).toEqual( + expectedTokenLine[i], + `Token ${i}, startRow: ${startRow}` + ) } } } @@ -2063,7 +2219,10 @@ function expectTokensToEqual (editor, expectedTokenLines) { const HTML_TEMPLATE_LITERAL_INJECTION_POINT = { type: 'call_expression', language (node) { - if (node.lastChild.type === 'template_string' && node.firstChild.type === 'identifier') { + if ( + node.lastChild.type === 'template_string' && + node.firstChild.type === 'identifier' + ) { return node.firstChild.text } }, @@ -2074,6 +2233,10 @@ const HTML_TEMPLATE_LITERAL_INJECTION_POINT = { const SCRIPT_TAG_INJECTION_POINT = { type: 'raw_element', - language () { return 'javascript' }, - content (node) { return node.child(1) } + language () { + return 'javascript' + }, + content (node) { + return node.child(1) + } } diff --git a/spec/update-process-env-spec.js b/spec/update-process-env-spec.js index f7948d998..db702bd5b 100644 --- a/spec/update-process-env-spec.js +++ b/spec/update-process-env-spec.js @@ -1,12 +1,22 @@ /** @babel */ /* eslint-env jasmine */ -import {it, fit, ffit, fffit, beforeEach, afterEach} from './async-spec-helpers' +import { + it, + fit, + ffit, + fffit, + beforeEach, + afterEach +} from './async-spec-helpers' import path from 'path' import childProcess from 'child_process' -import {updateProcessEnv, shouldGetEnvFromShell} from '../src/update-process-env' +import { + updateProcessEnv, + shouldGetEnvFromShell +} from '../src/update-process-env' import dedent from 'dedent' -import {EventEmitter} from 'events' +import { EventEmitter } from 'events' import mockSpawn from 'mock-spawn' const temp = require('temp').track() @@ -46,7 +56,13 @@ describe('updateProcessEnv(launchEnv)', function () { const initialProcessEnv = process.env - await updateProcessEnv({ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', PWD: '/the/dir', TERM: 'xterm-something', KEY1: 'value1', KEY2: 'value2'}) + await updateProcessEnv({ + ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', + PWD: '/the/dir', + TERM: 'xterm-something', + KEY1: 'value1', + KEY2: 'value2' + }) expect(process.env).toEqual({ ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', PWD: '/the/dir', @@ -74,7 +90,12 @@ describe('updateProcessEnv(launchEnv)', function () { const initialProcessEnv = process.env - await updateProcessEnv({ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', PROMPT: '$P$G', KEY1: 'value1', KEY2: 'value2'}) + await updateProcessEnv({ + ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', + PROMPT: '$P$G', + KEY1: 'value1', + KEY2: 'value2' + }) expect(process.env).toEqual({ ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', PROMPT: '$P$G', @@ -103,13 +124,15 @@ describe('updateProcessEnv(launchEnv)', function () { await updateProcessEnv({ ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', - PSModulePath: 'C:\\Program Files\\WindowsPowerShell\\Modules;C:\\WINDOWS\\system32\\WindowsPowerShell\\v1.0\\Modules\\', + PSModulePath: + 'C:\\Program Files\\WindowsPowerShell\\Modules;C:\\WINDOWS\\system32\\WindowsPowerShell\\v1.0\\Modules\\', KEY1: 'value1', KEY2: 'value2' }) expect(process.env).toEqual({ ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', - PSModulePath: 'C:\\Program Files\\WindowsPowerShell\\Modules;C:\\WINDOWS\\system32\\WindowsPowerShell\\v1.0\\Modules\\', + PSModulePath: + 'C:\\Program Files\\WindowsPowerShell\\Modules;C:\\WINDOWS\\system32\\WindowsPowerShell\\v1.0\\Modules\\', KEY1: 'value1', KEY2: 'value2', NODE_ENV: 'the-node-env', @@ -133,7 +156,10 @@ describe('updateProcessEnv(launchEnv)', function () { ATOM_HOME: '/the/atom/home' } - await updateProcessEnv({ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', PWD: '/the/dir'}) + await updateProcessEnv({ + ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', + PWD: '/the/dir' + }) expect(process.env).toEqual({ PWD: '/the/dir', ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', @@ -142,7 +168,11 @@ describe('updateProcessEnv(launchEnv)', function () { ATOM_HOME: '/the/atom/home' }) - await updateProcessEnv({ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', PWD: '/the/dir', ATOM_HOME: path.join(newAtomHomePath, 'non-existent')}) + await updateProcessEnv({ + ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', + PWD: '/the/dir', + ATOM_HOME: path.join(newAtomHomePath, 'non-existent') + }) expect(process.env).toEqual({ ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', PWD: '/the/dir', @@ -151,7 +181,11 @@ describe('updateProcessEnv(launchEnv)', function () { ATOM_HOME: '/the/atom/home' }) - await updateProcessEnv({ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', PWD: '/the/dir', ATOM_HOME: newAtomHomePath}) + await updateProcessEnv({ + ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', + PWD: '/the/dir', + ATOM_HOME: newAtomHomePath + }) expect(process.env).toEqual({ ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', PWD: '/the/dir', @@ -169,7 +203,13 @@ describe('updateProcessEnv(launchEnv)', function () { ATOM_HOME: '/the/atom/home' } - await updateProcessEnv({ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', PWD: '/the/dir', NODE_ENV: 'the-node-env', NODE_PATH: '/the/node/path', ATOM_HOME: '/the/atom/home'}) + await updateProcessEnv({ + ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', + PWD: '/the/dir', + NODE_ENV: 'the-node-env', + NODE_PATH: '/the/node/path', + ATOM_HOME: '/the/atom/home' + }) expect(process.env).toEqual({ ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', PWD: '/the/dir', @@ -178,7 +218,12 @@ describe('updateProcessEnv(launchEnv)', function () { ATOM_HOME: '/the/atom/home' }) - await updateProcessEnv({PWD: '/the/dir', NODE_ENV: 'the-node-env', NODE_PATH: '/the/node/path', ATOM_HOME: '/the/atom/home'}) + await updateProcessEnv({ + PWD: '/the/dir', + NODE_ENV: 'the-node-env', + NODE_PATH: '/the/node/path', + ATOM_HOME: '/the/atom/home' + }) expect(process.env).toEqual({ ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', PWD: '/the/dir', @@ -215,16 +260,21 @@ describe('updateProcessEnv(launchEnv)', function () { describe('when the launch environment does not come from a shell', function () { describe('on macOS', function () { - it('updates process.env to match the environment in the user\'s login shell', async function () { + it("updates process.env to match the environment in the user's login shell", async function () { if (process.platform === 'win32') return // TestsThatFailOnWin32 process.platform = 'darwin' process.env.SHELL = '/my/custom/bash' - spawn.setDefault(spawn.simple(0, dedent` + spawn.setDefault( + spawn.simple( + 0, + dedent` FOO=BAR=BAZ=QUUX TERM=xterm-something PATH=/usr/bin:/bin:/usr/sbin:/sbin:/crazy/path - `)) + ` + ) + ) await updateProcessEnv(process.env) expect(spawn.calls.length).toBe(1) expect(spawn.calls[0].command).toBe('/my/custom/bash') @@ -241,16 +291,21 @@ describe('updateProcessEnv(launchEnv)', function () { }) describe('on linux', function () { - it('updates process.env to match the environment in the user\'s login shell', async function () { + it("updates process.env to match the environment in the user's login shell", async function () { if (process.platform === 'win32') return // TestsThatFailOnWin32 process.platform = 'linux' process.env.SHELL = '/my/custom/bash' - spawn.setDefault(spawn.simple(0, dedent` + spawn.setDefault( + spawn.simple( + 0, + dedent` FOO=BAR=BAZ=QUUX TERM=xterm-something PATH=/usr/bin:/bin:/usr/sbin:/sbin:/crazy/path - `)) + ` + ) + ) await updateProcessEnv(process.env) expect(spawn.calls.length).toBe(1) expect(spawn.calls[0].command).toBe('/my/custom/bash') @@ -270,11 +325,11 @@ describe('updateProcessEnv(launchEnv)', function () { it('does not update process.env', async function () { process.platform = 'win32' spyOn(childProcess, 'spawn') - process.env = {FOO: 'bar'} + process.env = { FOO: 'bar' } await updateProcessEnv(process.env) expect(childProcess.spawn).not.toHaveBeenCalled() - expect(process.env).toEqual({FOO: 'bar'}) + expect(process.env).toEqual({ FOO: 'bar' }) }) }) @@ -283,30 +338,52 @@ describe('updateProcessEnv(launchEnv)', function () { if (process.platform === 'win32') return // TestsThatFailOnWin32 process.platform = 'darwin' - expect(shouldGetEnvFromShell({SHELL: '/bin/sh'})).toBe(true) - expect(shouldGetEnvFromShell({SHELL: '/usr/local/bin/sh'})).toBe(true) - expect(shouldGetEnvFromShell({SHELL: '/bin/bash'})).toBe(true) - expect(shouldGetEnvFromShell({SHELL: '/usr/local/bin/bash'})).toBe(true) - expect(shouldGetEnvFromShell({SHELL: '/bin/zsh'})).toBe(true) - expect(shouldGetEnvFromShell({SHELL: '/usr/local/bin/zsh'})).toBe(true) - expect(shouldGetEnvFromShell({SHELL: '/bin/fish'})).toBe(true) - expect(shouldGetEnvFromShell({SHELL: '/usr/local/bin/fish'})).toBe(true) + expect(shouldGetEnvFromShell({ SHELL: '/bin/sh' })).toBe(true) + expect(shouldGetEnvFromShell({ SHELL: '/usr/local/bin/sh' })).toBe(true) + expect(shouldGetEnvFromShell({ SHELL: '/bin/bash' })).toBe(true) + expect(shouldGetEnvFromShell({ SHELL: '/usr/local/bin/bash' })).toBe( + true + ) + expect(shouldGetEnvFromShell({ SHELL: '/bin/zsh' })).toBe(true) + expect(shouldGetEnvFromShell({ SHELL: '/usr/local/bin/zsh' })).toBe( + true + ) + expect(shouldGetEnvFromShell({ SHELL: '/bin/fish' })).toBe(true) + expect(shouldGetEnvFromShell({ SHELL: '/usr/local/bin/fish' })).toBe( + true + ) process.platform = 'linux' - expect(shouldGetEnvFromShell({SHELL: '/bin/sh'})).toBe(true) - expect(shouldGetEnvFromShell({SHELL: '/usr/local/bin/sh'})).toBe(true) - expect(shouldGetEnvFromShell({SHELL: '/bin/bash'})).toBe(true) - expect(shouldGetEnvFromShell({SHELL: '/usr/local/bin/bash'})).toBe(true) - expect(shouldGetEnvFromShell({SHELL: '/bin/zsh'})).toBe(true) - expect(shouldGetEnvFromShell({SHELL: '/usr/local/bin/zsh'})).toBe(true) - expect(shouldGetEnvFromShell({SHELL: '/bin/fish'})).toBe(true) - expect(shouldGetEnvFromShell({SHELL: '/usr/local/bin/fish'})).toBe(true) + expect(shouldGetEnvFromShell({ SHELL: '/bin/sh' })).toBe(true) + expect(shouldGetEnvFromShell({ SHELL: '/usr/local/bin/sh' })).toBe(true) + expect(shouldGetEnvFromShell({ SHELL: '/bin/bash' })).toBe(true) + expect(shouldGetEnvFromShell({ SHELL: '/usr/local/bin/bash' })).toBe( + true + ) + expect(shouldGetEnvFromShell({ SHELL: '/bin/zsh' })).toBe(true) + expect(shouldGetEnvFromShell({ SHELL: '/usr/local/bin/zsh' })).toBe( + true + ) + expect(shouldGetEnvFromShell({ SHELL: '/bin/fish' })).toBe(true) + expect(shouldGetEnvFromShell({ SHELL: '/usr/local/bin/fish' })).toBe( + true + ) }) it('returns false when the environment indicates that Atom was launched from a shell', function () { process.platform = 'darwin' - expect(shouldGetEnvFromShell({ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', SHELL: '/bin/sh'})).toBe(false) + expect( + shouldGetEnvFromShell({ + ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', + SHELL: '/bin/sh' + }) + ).toBe(false) process.platform = 'linux' - expect(shouldGetEnvFromShell({ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', SHELL: '/bin/sh'})).toBe(false) + expect( + shouldGetEnvFromShell({ + ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', + SHELL: '/bin/sh' + }) + ).toBe(false) }) it('returns false when the shell is undefined or empty', function () { diff --git a/spec/uri-handler-registry-spec.js b/spec/uri-handler-registry-spec.js index d2da93087..b17bfa16e 100644 --- a/spec/uri-handler-registry-spec.js +++ b/spec/uri-handler-registry-spec.js @@ -2,7 +2,7 @@ import url from 'url' -import {it} from './async-spec-helpers' +import { it } from './async-spec-helpers' import URIHandlerRegistry from '../src/uri-handler-registry' @@ -24,11 +24,17 @@ describe('URIHandlerRegistry', () => { expect(otherPackageSpy).not.toHaveBeenCalled() registry.handleURI('atom://test-package/path') - expect(testPackageSpy).toHaveBeenCalledWith(url.parse('atom://test-package/path', true), 'atom://test-package/path') + expect(testPackageSpy).toHaveBeenCalledWith( + url.parse('atom://test-package/path', true), + 'atom://test-package/path' + ) expect(otherPackageSpy).not.toHaveBeenCalled() registry.handleURI('atom://other-package/path') - expect(otherPackageSpy).toHaveBeenCalledWith(url.parse('atom://other-package/path', true), 'atom://other-package/path') + expect(otherPackageSpy).toHaveBeenCalledWith( + url.parse('atom://other-package/path', true), + 'atom://other-package/path' + ) }) it('keeps track of the most recent URIs', () => { @@ -50,9 +56,18 @@ describe('URIHandlerRegistry', () => { uris.forEach(u => registry.handleURI(u)) expect(changeSpy.callCount).toBe(5) - expect(registry.getRecentlyHandledURIs()).toEqual(uris.map((u, idx) => { - return {id: idx + 1, uri: u, handled: !u.match(/fake/), host: url.parse(u).host} - }).reverse()) + expect(registry.getRecentlyHandledURIs()).toEqual( + uris + .map((u, idx) => { + return { + id: idx + 1, + uri: u, + handled: !u.match(/fake/), + host: url.parse(u).host + } + }) + .reverse() + ) registry.handleURI('atom://another/url') expect(changeSpy.callCount).toBe(6) @@ -63,7 +78,7 @@ describe('URIHandlerRegistry', () => { }) it('refuses to handle bad URLs', () => { - [ + ;[ 'atom:package/path', 'atom:8080://package/path', 'user:pass@atom://package/path', diff --git a/spec/view-registry-spec.js b/spec/view-registry-spec.js index db8b077f1..b38ffa5f3 100644 --- a/spec/view-registry-spec.js +++ b/spec/view-registry-spec.js @@ -22,8 +22,7 @@ describe('ViewRegistry', () => { it('returns the given DOM node', () => { const node = document.createElement('div') expect(registry.getView(node)).toBe(node) - }) - ) + })) describe('when passed an object with an element property', () => it("returns the element property if it's an instance of HTMLElement", () => { @@ -35,8 +34,7 @@ describe('ViewRegistry', () => { const component = new TestComponent() expect(registry.getView(component)).toBe(component.element) - }) - ) + })) describe('when passed an object with a getElement function', () => it("returns the return value of getElement if it's an instance of HTMLElement", () => { @@ -51,8 +49,7 @@ describe('ViewRegistry', () => { const component = new TestComponent() expect(registry.getView(component)).toBe(component.myElement) - }) - ) + })) describe('when passed a model object', () => { describe("when a view provider is registered matching the object's constructor", () => @@ -70,7 +67,7 @@ describe('ViewRegistry', () => { const model = new TestModel() - registry.addViewProvider(TestModel, (model) => + registry.addViewProvider(TestModel, model => new TestView().initialize(model) ) @@ -82,12 +79,11 @@ describe('ViewRegistry', () => { const view2 = registry.getView(subclassModel) expect(view2 instanceof TestView).toBe(true) expect(view2.model).toBe(subclassModel) - }) - ) + })) describe('when a view provider is registered generically, and works with the object', () => it('constructs a view element and assigns the model on it', () => { - registry.addViewProvider((model) => { + registry.addViewProvider(model => { if (model.a === 'b') { const element = document.createElement('div') element.className = 'test-element' @@ -95,18 +91,16 @@ describe('ViewRegistry', () => { } }) - const view = registry.getView({a: 'b'}) + const view = registry.getView({ a: 'b' }) expect(view.className).toBe('test-element') - expect(() => registry.getView({a: 'c'})).toThrow() - }) - ) + expect(() => registry.getView({ a: 'c' })).toThrow() + })) describe("when no view provider is registered for the object's constructor", () => it('throws an exception', () => { expect(() => registry.getView({})).toThrow() - }) - ) + })) }) }) @@ -120,22 +114,23 @@ describe('ViewRegistry', () => { } } - const disposable = registry.addViewProvider(TestModel, (model) => + const disposable = registry.addViewProvider(TestModel, model => new TestView().initialize(model) ) expect(registry.getView(new TestModel()) instanceof TestView).toBe(true) disposable.dispose() expect(() => registry.getView(new TestModel())).toThrow() - }) - ) + })) describe('::updateDocument(fn) and ::readDocument(fn)', () => { let frameRequests = null beforeEach(() => { frameRequests = [] - spyOn(window, 'requestAnimationFrame').andCallFake(fn => frameRequests.push(fn)) + spyOn(window, 'requestAnimationFrame').andCallFake(fn => + frameRequests.push(fn) + ) }) it('performs all pending writes before all pending reads on the next animation frame', () => { @@ -201,16 +196,19 @@ describe('ViewRegistry', () => { let updateCalled = false let readCalled = false - waitsFor('getNextUpdatePromise to resolve', (done) => { + waitsFor('getNextUpdatePromise to resolve', done => { registry.getNextUpdatePromise().then(() => { expect(updateCalled).toBe(true) expect(readCalled).toBe(true) done() }) - registry.updateDocument(() => { updateCalled = true }) - registry.readDocument(() => { readCalled = true }) + registry.updateDocument(() => { + updateCalled = true + }) + registry.readDocument(() => { + readCalled = true + }) }) - }) - ) + })) }) diff --git a/spec/window-event-handler-spec.js b/spec/window-event-handler-spec.js index b5000388c..6f840f3bf 100644 --- a/spec/window-event-handler-spec.js +++ b/spec/window-event-handler-spec.js @@ -14,7 +14,10 @@ describe('WindowEventHandler', () => { return loadSettings }) atom.project.destroy() - windowEventHandler = new WindowEventHandler({atomEnvironment: atom, applicationDelegate: atom.applicationDelegate}) + windowEventHandler = new WindowEventHandler({ + atomEnvironment: atom, + applicationDelegate: atom.applicationDelegate + }) windowEventHandler.initialize(window, document) }) @@ -25,45 +28,44 @@ describe('WindowEventHandler', () => { describe('when the window is loaded', () => it("doesn't have .is-blurred on the body tag", () => { - if (process.platform === 'win32') { return } // Win32TestFailures - can not steal focus + if (process.platform === 'win32') { + return + } // Win32TestFailures - can not steal focus expect(document.body.className).not.toMatch('is-blurred') - }) - ) + })) describe('when the window is blurred', () => { beforeEach(() => window.dispatchEvent(new CustomEvent('blur'))) afterEach(() => document.body.classList.remove('is-blurred')) - it('adds the .is-blurred class on the body', () => expect(document.body.className).toMatch('is-blurred')) + it('adds the .is-blurred class on the body', () => + expect(document.body.className).toMatch('is-blurred')) describe('when the window is focused again', () => it('removes the .is-blurred class from the body', () => { window.dispatchEvent(new CustomEvent('focus')) expect(document.body.className).not.toMatch('is-blurred') - }) - ) + })) }) - + describe('resize event', () => it('calls storeWindowDimensions', () => { spyOn(atom, 'storeWindowDimensions') window.dispatchEvent(new CustomEvent('resize')) expect(atom.storeWindowDimensions).toHaveBeenCalled() - }) - ) - + })) + describe('window:close event', () => it('closes the window', () => { spyOn(atom, 'close') window.dispatchEvent(new CustomEvent('window:close')) expect(atom.close).toHaveBeenCalled() - }) - ) + })) describe('when a link is clicked', () => { it('opens the http/https links in an external application', () => { - const {shell} = require('electron') + const { shell } = require('electron') spyOn(shell, 'openExternal') const link = document.createElement('a') @@ -71,7 +73,11 @@ describe('WindowEventHandler', () => { link.appendChild(linkChild) link.href = 'http://github.com' jasmine.attachToDOM(link) - const fakeEvent = {target: linkChild, currentTarget: link, preventDefault: () => {}} + const fakeEvent = { + target: linkChild, + currentTarget: link, + preventDefault: () => {} + } windowEventHandler.handleLinkClick(fakeEvent) expect(shell.openExternal).toHaveBeenCalled() @@ -104,7 +110,11 @@ describe('WindowEventHandler', () => { link.appendChild(linkChild) link.href = 'atom://github.com' jasmine.attachToDOM(link) - const fakeEvent = {target: linkChild, currentTarget: link, preventDefault: () => {}} + const fakeEvent = { + target: linkChild, + currentTarget: link, + preventDefault: () => {} + } windowEventHandler.handleLinkClick(fakeEvent) expect(uriHandler.handleURI).toHaveBeenCalled() @@ -118,12 +128,13 @@ describe('WindowEventHandler', () => { jasmine.attachToDOM(form) let defaultPrevented = false - const event = new CustomEvent('submit', {bubbles: true}) - event.preventDefault = () => { defaultPrevented = true } + const event = new CustomEvent('submit', { bubbles: true }) + event.preventDefault = () => { + defaultPrevented = true + } form.dispatchEvent(event) expect(defaultPrevented).toBe(true) - }) - ) + })) describe('core:focus-next and core:focus-previous', () => { describe('when there is no currently focused element', () => @@ -138,14 +149,17 @@ describe('WindowEventHandler', () => { const elements = wrapperDiv.firstChild jasmine.attachToDOM(elements) - elements.dispatchEvent(new CustomEvent('core:focus-next', {bubbles: true})) + elements.dispatchEvent( + new CustomEvent('core:focus-next', { bubbles: true }) + ) expect(document.activeElement.tabIndex).toBe(1) document.body.focus() - elements.dispatchEvent(new CustomEvent('core:focus-previous', {bubbles: true})) + elements.dispatchEvent( + new CustomEvent('core:focus-previous', { bubbles: true }) + ) expect(document.activeElement.tabIndex).toBe(2) - }) - ) + })) describe('when a tabindex is set on the currently focused element', () => it('focuses the element with the next highest/lowest tabindex, skipping disabled elements', () => { @@ -166,60 +180,85 @@ describe('WindowEventHandler', () => { elements.querySelector('[tabindex="1"]').focus() - elements.dispatchEvent(new CustomEvent('core:focus-next', {bubbles: true})) + elements.dispatchEvent( + new CustomEvent('core:focus-next', { bubbles: true }) + ) expect(document.activeElement.tabIndex).toBe(2) - elements.dispatchEvent(new CustomEvent('core:focus-next', {bubbles: true})) + elements.dispatchEvent( + new CustomEvent('core:focus-next', { bubbles: true }) + ) expect(document.activeElement.tabIndex).toBe(3) - elements.dispatchEvent(new CustomEvent('core:focus-next', {bubbles: true})) + elements.dispatchEvent( + new CustomEvent('core:focus-next', { bubbles: true }) + ) expect(document.activeElement.tabIndex).toBe(5) - elements.dispatchEvent(new CustomEvent('core:focus-next', {bubbles: true})) + elements.dispatchEvent( + new CustomEvent('core:focus-next', { bubbles: true }) + ) expect(document.activeElement.tabIndex).toBe(7) - elements.dispatchEvent(new CustomEvent('core:focus-next', {bubbles: true})) + elements.dispatchEvent( + new CustomEvent('core:focus-next', { bubbles: true }) + ) expect(document.activeElement.tabIndex).toBe(1) - elements.dispatchEvent(new CustomEvent('core:focus-previous', {bubbles: true})) + elements.dispatchEvent( + new CustomEvent('core:focus-previous', { bubbles: true }) + ) expect(document.activeElement.tabIndex).toBe(7) - elements.dispatchEvent(new CustomEvent('core:focus-previous', {bubbles: true})) + elements.dispatchEvent( + new CustomEvent('core:focus-previous', { bubbles: true }) + ) expect(document.activeElement.tabIndex).toBe(5) - elements.dispatchEvent(new CustomEvent('core:focus-previous', {bubbles: true})) + elements.dispatchEvent( + new CustomEvent('core:focus-previous', { bubbles: true }) + ) expect(document.activeElement.tabIndex).toBe(3) - elements.dispatchEvent(new CustomEvent('core:focus-previous', {bubbles: true})) + elements.dispatchEvent( + new CustomEvent('core:focus-previous', { bubbles: true }) + ) expect(document.activeElement.tabIndex).toBe(2) - elements.dispatchEvent(new CustomEvent('core:focus-previous', {bubbles: true})) + elements.dispatchEvent( + new CustomEvent('core:focus-previous', { bubbles: true }) + ) expect(document.activeElement.tabIndex).toBe(1) - elements.dispatchEvent(new CustomEvent('core:focus-previous', {bubbles: true})) + elements.dispatchEvent( + new CustomEvent('core:focus-previous', { bubbles: true }) + ) expect(document.activeElement.tabIndex).toBe(7) - }) - ) + })) }) describe('when keydown events occur on the document', () => it('dispatches the event via the KeymapManager and CommandRegistry', () => { const dispatchedCommands = [] atom.commands.onWillDispatch(command => dispatchedCommands.push(command)) - atom.commands.add('*', {'foo-command': () => {}}) - atom.keymaps.add('source-name', {'*': {'x': 'foo-command'}}) + atom.commands.add('*', { 'foo-command': () => {} }) + atom.keymaps.add('source-name', { '*': { x: 'foo-command' } }) - const event = KeymapManager.buildKeydownEvent('x', {target: document.createElement('div')}) + const event = KeymapManager.buildKeydownEvent('x', { + target: document.createElement('div') + }) document.dispatchEvent(event) expect(dispatchedCommands.length).toBe(1) expect(dispatchedCommands[0].type).toBe('foo-command') - }) - ) + })) describe('native key bindings', () => it("correctly dispatches them to active elements with the '.native-key-bindings' class", () => { - const webContentsSpy = jasmine.createSpyObj('webContents', ['copy', 'paste']) + const webContentsSpy = jasmine.createSpyObj('webContents', [ + 'copy', + 'paste' + ]) spyOn(atom.applicationDelegate, 'getCurrentWindow').andReturn({ webContents: webContentsSpy, on: () => {} @@ -248,6 +287,5 @@ describe('WindowEventHandler', () => { expect(webContentsSpy.copy).not.toHaveBeenCalled() expect(webContentsSpy.paste).not.toHaveBeenCalled() - }) - ) + })) }) diff --git a/spec/workspace-center-spec.js b/spec/workspace-center-spec.js index 7c01078c3..055b463db 100644 --- a/spec/workspace-center-spec.js +++ b/spec/workspace-center-spec.js @@ -2,7 +2,14 @@ const TextEditor = require('../src/text-editor') -import {it, fit, ffit, fffit, beforeEach, afterEach} from './async-spec-helpers' +import { + it, + fit, + ffit, + fffit, + beforeEach, + afterEach +} from './async-spec-helpers' describe('WorkspaceCenter', () => { describe('.observeTextEditors()', () => { @@ -12,20 +19,25 @@ describe('WorkspaceCenter', () => { const observed = [] const editorAddedBeforeRegisteringObserver = new TextEditor() - const nonEditorItemAddedBeforeRegisteringObserver = document.createElement('div') + const nonEditorItemAddedBeforeRegisteringObserver = document.createElement( + 'div' + ) pane.activateItem(editorAddedBeforeRegisteringObserver) pane.activateItem(nonEditorItemAddedBeforeRegisteringObserver) workspaceCenter.observeTextEditors(editor => observed.push(editor)) const editorAddedAfterRegisteringObserver = new TextEditor() - const nonEditorItemAddedAfterRegisteringObserver = document.createElement('div') + const nonEditorItemAddedAfterRegisteringObserver = document.createElement( + 'div' + ) pane.activateItem(editorAddedAfterRegisteringObserver) pane.activateItem(nonEditorItemAddedAfterRegisteringObserver) - expect(observed).toEqual( - [editorAddedBeforeRegisteringObserver, editorAddedAfterRegisteringObserver] - ) + expect(observed).toEqual([ + editorAddedBeforeRegisteringObserver, + editorAddedAfterRegisteringObserver + ]) }) }) }) diff --git a/spec/workspace-element-spec.js b/spec/workspace-element-spec.js index 7564f6931..b11e8b443 100644 --- a/spec/workspace-element-spec.js +++ b/spec/workspace-element-spec.js @@ -1,11 +1,18 @@ /** @babel */ -const {ipcRenderer} = require('electron') +const { ipcRenderer } = require('electron') const etch = require('etch') const path = require('path') const temp = require('temp').track() -const {Disposable} = require('event-kit') -const {it, fit, ffit, fffit, beforeEach, afterEach} = require('./async-spec-helpers') +const { Disposable } = require('event-kit') +const { + it, + fit, + ffit, + fffit, + beforeEach, + afterEach +} = require('./async-spec-helpers') const getNextUpdatePromise = () => etch.getScheduler().nextUpdatePromise @@ -35,19 +42,39 @@ describe('WorkspaceElement', () => { const dock = atom.workspace.getLeftDock() dock.show() jasmine.attachToDOM(atom.workspace.getElement()) - expect(atom.workspace.getActivePaneContainer()).toBe(atom.workspace.getCenter()) - dock.getActivePane().getElement().focus() + expect(atom.workspace.getActivePaneContainer()).toBe( + atom.workspace.getCenter() + ) + dock + .getActivePane() + .getElement() + .focus() expect(atom.workspace.getActivePaneContainer()).toBe(dock) }) }) describe('finding the nearest visible pane in a specific direction', () => { - let pane1, pane2, pane3, pane4, pane5, pane6, pane7, pane8, pane9, - leftDockPane, rightDockPane, bottomDockPane, workspace, workspaceElement + let pane1, + pane2, + pane3, + pane4, + pane5, + pane6, + pane7, + pane8, + pane9, + leftDockPane, + rightDockPane, + bottomDockPane, + workspace, + workspaceElement beforeEach(function () { atom.config.set('core.destroyEmptyPanes', false) - expect(document.hasFocus()).toBe(true, 'Document needs to be focused to run this test') + expect(document.hasFocus()).toBe( + true, + 'Document needs to be focused to run this test' + ) workspace = atom.workspace @@ -104,14 +131,20 @@ describe('WorkspaceElement', () => { describe('finding the nearest pane above', () => { describe('when there are multiple rows above the pane', () => { it('returns the pane in the adjacent row above', () => { - nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection('above', pane8) + nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection( + 'above', + pane8 + ) expect(nearestPaneElement).toBe(pane5.getElement()) }) }) describe('when there are no rows above the pane', () => { it('returns null', () => { - nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection('above', pane2) + nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection( + 'above', + pane2 + ) expect(nearestPaneElement).toBeUndefined() // TODO Expect toBeNull() }) }) @@ -119,7 +152,10 @@ describe('WorkspaceElement', () => { describe('when the bottom dock contains the pane', () => { it('returns the pane in the adjacent row above', () => { workspace.getBottomDock().show() - nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection('above', bottomDockPane) + nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection( + 'above', + bottomDockPane + ) expect(nearestPaneElement).toBe(pane7.getElement()) }) }) @@ -128,14 +164,20 @@ describe('WorkspaceElement', () => { describe('finding the nearest pane below', () => { describe('when there are multiple rows below the pane', () => { it('returns the pane in the adjacent row below', () => { - nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection('below', pane2) + nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection( + 'below', + pane2 + ) expect(nearestPaneElement).toBe(pane5.getElement()) }) }) describe('when there are no rows below the pane', () => { it('returns null', () => { - nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection('below', pane8) + nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection( + 'below', + pane8 + ) expect(nearestPaneElement).toBeUndefined() // TODO Expect toBeNull() }) }) @@ -144,7 +186,10 @@ describe('WorkspaceElement', () => { describe("when the workspace center's bottommost row contains the pane", () => { it("returns the pane in the bottom dock's adjacent row below", () => { workspace.getBottomDock().show() - nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection('below', pane8) + nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection( + 'below', + pane8 + ) expect(nearestPaneElement).toBe(bottomDockPane.getElement()) }) }) @@ -154,14 +199,20 @@ describe('WorkspaceElement', () => { describe('finding the nearest pane to the left', () => { describe('when there are multiple columns to the left of the pane', () => { it('returns the pane in the adjacent column to the left', () => { - nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection('left', pane6) + nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection( + 'left', + pane6 + ) expect(nearestPaneElement).toBe(pane5.getElement()) }) }) describe('when there are no columns to the left of the pane', () => { it('returns null', () => { - nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection('left', pane4) + nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection( + 'left', + pane4 + ) expect(nearestPaneElement).toBeUndefined() // TODO Expect toBeNull() }) }) @@ -169,7 +220,10 @@ describe('WorkspaceElement', () => { describe('when the right dock contains the pane', () => { it('returns the pane in the adjacent column to the left', () => { workspace.getRightDock().show() - nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection('left', rightDockPane) + nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection( + 'left', + rightDockPane + ) expect(nearestPaneElement).toBe(pane3.getElement()) }) }) @@ -178,7 +232,10 @@ describe('WorkspaceElement', () => { describe("when the workspace center's leftmost column contains the pane", () => { it("returns the pane in the left dock's adjacent column to the left", () => { workspace.getLeftDock().show() - nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection('left', pane4) + nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection( + 'left', + pane4 + ) expect(nearestPaneElement).toBe(leftDockPane.getElement()) }) }) @@ -187,7 +244,10 @@ describe('WorkspaceElement', () => { it("returns the pane in the left dock's adjacent column to the left", () => { workspace.getLeftDock().show() workspace.getBottomDock().show() - nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection('left', bottomDockPane) + nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection( + 'left', + bottomDockPane + ) expect(nearestPaneElement).toBe(leftDockPane.getElement()) }) }) @@ -197,14 +257,20 @@ describe('WorkspaceElement', () => { describe('finding the nearest pane to the right', () => { describe('when there are multiple columns to the right of the pane', () => { it('returns the pane in the adjacent column to the right', () => { - nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection('right', pane4) + nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection( + 'right', + pane4 + ) expect(nearestPaneElement).toBe(pane5.getElement()) }) }) describe('when there are no columns to the right of the pane', () => { it('returns null', () => { - nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection('right', pane6) + nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection( + 'right', + pane6 + ) expect(nearestPaneElement).toBeUndefined() // TODO Expect toBeNull() }) }) @@ -212,7 +278,10 @@ describe('WorkspaceElement', () => { describe('when the left dock contains the pane', () => { it('returns the pane in the adjacent column to the right', () => { workspace.getLeftDock().show() - nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection('right', leftDockPane) + nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection( + 'right', + leftDockPane + ) expect(nearestPaneElement).toBe(pane1.getElement()) }) }) @@ -221,7 +290,10 @@ describe('WorkspaceElement', () => { describe("when the workspace center's rightmost column contains the pane", () => { it("returns the pane in the right dock's adjacent column to the right", () => { workspace.getRightDock().show() - nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection('right', pane6) + nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection( + 'right', + pane6 + ) expect(nearestPaneElement).toBe(rightDockPane.getElement()) }) }) @@ -230,7 +302,10 @@ describe('WorkspaceElement', () => { it("returns the pane in the right dock's adjacent column to the right", () => { workspace.getRightDock().show() workspace.getBottomDock().show() - nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection('right', bottomDockPane) + nearestPaneElement = workspaceElement.nearestVisiblePaneInDirection( + 'right', + bottomDockPane + ) expect(nearestPaneElement).toBe(rightDockPane.getElement()) }) }) @@ -243,7 +318,10 @@ describe('WorkspaceElement', () => { beforeEach(function () { atom.config.set('core.destroyEmptyPanes', false) - expect(document.hasFocus()).toBe(true, 'Document needs to be focused to run this test') + expect(document.hasFocus()).toBe( + true, + 'Document needs to be focused to run this test' + ) workspace = atom.workspace expect(workspace.getLeftDock().isVisible()).toBe(false) @@ -267,16 +345,14 @@ describe('WorkspaceElement', () => { startingPane.activate() workspaceElement.focusPaneViewAbove() expect(document.activeElement).toBe(paneAbove.getElement()) - }) - ) + })) describe('when there are no rows above the focused pane', () => it('keeps the current pane focused', function () { startingPane.activate() workspaceElement.focusPaneViewAbove() expect(document.activeElement).toBe(startingPane.getElement()) - }) - ) + })) }) describe('::focusPaneViewBelow()', function () { @@ -286,16 +362,14 @@ describe('WorkspaceElement', () => { startingPane.activate() workspaceElement.focusPaneViewBelow() expect(document.activeElement).toBe(paneBelow.getElement()) - }) - ) + })) describe('when there are no rows below the focused pane', () => it('keeps the current pane focused', function () { startingPane.activate() workspaceElement.focusPaneViewBelow() expect(document.activeElement).toBe(startingPane.getElement()) - }) - ) + })) }) describe('::focusPaneViewOnLeft()', function () { @@ -305,16 +379,14 @@ describe('WorkspaceElement', () => { startingPane.activate() workspaceElement.focusPaneViewOnLeft() expect(document.activeElement).toBe(paneOnLeft.getElement()) - }) - ) + })) describe('when there are no columns to the left of the focused pane', () => it('keeps the current pane focused', function () { startingPane.activate() workspaceElement.focusPaneViewOnLeft() expect(document.activeElement).toBe(startingPane.getElement()) - }) - ) + })) }) describe('::focusPaneViewOnRight()', function () { @@ -324,16 +396,14 @@ describe('WorkspaceElement', () => { startingPane.activate() workspaceElement.focusPaneViewOnRight() expect(document.activeElement).toBe(paneOnRight.getElement()) - }) - ) + })) describe('when there are no columns to the right of the focused pane', () => it('keeps the current pane focused', function () { startingPane.activate() workspaceElement.focusPaneViewOnRight() expect(document.activeElement).toBe(startingPane.getElement()) - }) - ) + })) }) describe('::moveActiveItemToPaneAbove(keepOriginal)', function () { @@ -346,8 +416,7 @@ describe('WorkspaceElement', () => { workspaceElement.moveActiveItemToPaneAbove() expect(workspace.paneForItem(item)).toBe(paneAbove) expect(paneAbove.getActiveItem()).toBe(item) - }) - ) + })) describe('when there are no rows above the focused pane', () => it('keeps the active pane focused', function () { @@ -356,8 +425,7 @@ describe('WorkspaceElement', () => { startingPane.activateItem(item) workspaceElement.moveActiveItemToPaneAbove() expect(workspace.paneForItem(item)).toBe(startingPane) - }) - ) + })) describe('when `keepOriginal: true` is passed in the params', () => it('keeps the item and adds a copy of it to the adjacent pane', function () { @@ -367,11 +435,10 @@ describe('WorkspaceElement', () => { const paneAbove = startingPane.splitUp() startingPane.activate() startingPane.activateItem(itemA) - workspaceElement.moveActiveItemToPaneAbove({keepOriginal: true}) + workspaceElement.moveActiveItemToPaneAbove({ keepOriginal: true }) expect(workspace.paneForItem(itemA)).toBe(startingPane) expect(paneAbove.getActiveItem()).toBe(itemB) - }) - ) + })) }) describe('::moveActiveItemToPaneBelow(keepOriginal)', function () { @@ -384,8 +451,7 @@ describe('WorkspaceElement', () => { workspaceElement.moveActiveItemToPaneBelow() expect(workspace.paneForItem(item)).toBe(paneBelow) expect(paneBelow.getActiveItem()).toBe(item) - }) - ) + })) describe('when there are no rows below the focused pane', () => it('keeps the active item in the focused pane', function () { @@ -394,8 +460,7 @@ describe('WorkspaceElement', () => { startingPane.activateItem(item) workspaceElement.moveActiveItemToPaneBelow() expect(workspace.paneForItem(item)).toBe(startingPane) - }) - ) + })) describe('when `keepOriginal: true` is passed in the params', () => it('keeps the item and adds a copy of it to the adjacent pane', function () { @@ -405,11 +470,10 @@ describe('WorkspaceElement', () => { const paneBelow = startingPane.splitDown() startingPane.activate() startingPane.activateItem(itemA) - workspaceElement.moveActiveItemToPaneBelow({keepOriginal: true}) + workspaceElement.moveActiveItemToPaneBelow({ keepOriginal: true }) expect(workspace.paneForItem(itemA)).toBe(startingPane) expect(paneBelow.getActiveItem()).toBe(itemB) - }) - ) + })) }) describe('::moveActiveItemToPaneOnLeft(keepOriginal)', function () { @@ -422,8 +486,7 @@ describe('WorkspaceElement', () => { workspaceElement.moveActiveItemToPaneOnLeft() expect(workspace.paneForItem(item)).toBe(paneOnLeft) expect(paneOnLeft.getActiveItem()).toBe(item) - }) - ) + })) describe('when there are no columns to the left of the focused pane', () => it('keeps the active item in the focused pane', function () { @@ -432,8 +495,7 @@ describe('WorkspaceElement', () => { startingPane.activateItem(item) workspaceElement.moveActiveItemToPaneOnLeft() expect(workspace.paneForItem(item)).toBe(startingPane) - }) - ) + })) describe('when `keepOriginal: true` is passed in the params', () => it('keeps the item and adds a copy of it to the adjacent pane', function () { @@ -443,11 +505,10 @@ describe('WorkspaceElement', () => { const paneOnLeft = startingPane.splitLeft() startingPane.activate() startingPane.activateItem(itemA) - workspaceElement.moveActiveItemToPaneOnLeft({keepOriginal: true}) + workspaceElement.moveActiveItemToPaneOnLeft({ keepOriginal: true }) expect(workspace.paneForItem(itemA)).toBe(startingPane) expect(paneOnLeft.getActiveItem()).toBe(itemB) - }) - ) + })) }) describe('::moveActiveItemToPaneOnRight(keepOriginal)', function () { @@ -460,8 +521,7 @@ describe('WorkspaceElement', () => { workspaceElement.moveActiveItemToPaneOnRight() expect(workspace.paneForItem(item)).toBe(paneOnRight) expect(paneOnRight.getActiveItem()).toBe(item) - }) - ) + })) describe('when there are no columns to the right of the focused pane', () => it('keeps the active item in the focused pane', function () { @@ -470,8 +530,7 @@ describe('WorkspaceElement', () => { startingPane.activateItem(item) workspaceElement.moveActiveItemToPaneOnRight() expect(workspace.paneForItem(item)).toBe(startingPane) - }) - ) + })) describe('when `keepOriginal: true` is passed in the params', () => it('keeps the item and adds a copy of it to the adjacent pane', function () { @@ -481,11 +540,10 @@ describe('WorkspaceElement', () => { const paneOnRight = startingPane.splitRight() startingPane.activate() startingPane.activateItem(itemA) - workspaceElement.moveActiveItemToPaneOnRight({keepOriginal: true}) + workspaceElement.moveActiveItemToPaneOnRight({ keepOriginal: true }) expect(workspace.paneForItem(itemA)).toBe(startingPane) expect(paneOnRight.getActiveItem()).toBe(itemB) - }) - ) + })) }) describe('::moveActiveItemToNearestPaneInDirection(direction, params)', () => { @@ -499,10 +557,14 @@ describe('WorkspaceElement', () => { workspace.getBottomDock().show() startingPane.activate() startingPane.activateItem(item) - workspaceElement.moveActiveItemToNearestPaneInDirection('below', {keepOriginal: false}) + workspaceElement.moveActiveItemToNearestPaneInDirection('below', { + keepOriginal: false + }) expect(workspace.paneForItem(item)).toBe(startingPane) - workspaceElement.moveActiveItemToNearestPaneInDirection('below', {keepOriginal: true}) + workspaceElement.moveActiveItemToNearestPaneInDirection('below', { + keepOriginal: true + }) expect(workspace.paneForItem(item)).toBe(startingPane) }) }) @@ -516,7 +578,9 @@ describe('WorkspaceElement', () => { startingPane.activate() startingPane.activateItem(item) workspaceElement.focusPaneViewAbove() - workspaceElement.moveActiveItemToNearestPaneInDirection('below', {keepOriginal: true}) + workspaceElement.moveActiveItemToNearestPaneInDirection('below', { + keepOriginal: true + }) expect(workspace.paneForItem(item)).toBe(startingPane) expect(paneBelow.getItems().length).toEqual(0) }) @@ -538,18 +602,30 @@ describe('WorkspaceElement', () => { await Promise.all([ atom.workspace.open({ element: document.createElement('div'), - getDefaultLocation() { return 'left' }, - getPreferredWidth() { return 150 } + getDefaultLocation () { + return 'left' + }, + getPreferredWidth () { + return 150 + } }), atom.workspace.open({ element: document.createElement('div'), - getDefaultLocation() { return 'right' }, - getPreferredWidth() { return 150 } + getDefaultLocation () { + return 'right' + }, + getPreferredWidth () { + return 150 + } }), atom.workspace.open({ element: document.createElement('div'), - getDefaultLocation() { return 'bottom' }, - getPreferredHeight() { return 100 } + getDefaultLocation () { + return 'bottom' + }, + getPreferredHeight () { + return 100 + } }) ]) @@ -567,21 +643,21 @@ describe('WorkspaceElement', () => { // --- Right Dock --- // Mouse over where the toggle button would be if the dock were hovered - moveMouse({clientX: 440, clientY: 150}) + moveMouse({ clientX: 440, clientY: 150 }) await getNextUpdatePromise() expectToggleButtonHidden(leftDock) expectToggleButtonHidden(rightDock) expectToggleButtonHidden(bottomDock) // Mouse over the dock - moveMouse({clientX: 460, clientY: 150}) + moveMouse({ clientX: 460, clientY: 150 }) await getNextUpdatePromise() expectToggleButtonHidden(leftDock) expectToggleButtonVisible(rightDock, 'icon-chevron-right') expectToggleButtonHidden(bottomDock) // Mouse over the toggle button - moveMouse({clientX: 440, clientY: 150}) + moveMouse({ clientX: 440, clientY: 150 }) await getNextUpdatePromise() expectToggleButtonHidden(leftDock) expectToggleButtonVisible(rightDock, 'icon-chevron-right') @@ -594,10 +670,10 @@ describe('WorkspaceElement', () => { expectToggleButtonHidden(rightDock) // Mouse to edge of the window - moveMouse({clientX: 575, clientY: 150}) + moveMouse({ clientX: 575, clientY: 150 }) await getNextUpdatePromise() expectToggleButtonHidden(rightDock) - moveMouse({clientX: 598, clientY: 150}) + moveMouse({ clientX: 598, clientY: 150 }) await getNextUpdatePromise() expectToggleButtonVisible(rightDock, 'icon-chevron-left') @@ -610,21 +686,21 @@ describe('WorkspaceElement', () => { // --- Left Dock --- // Mouse over where the toggle button would be if the dock were hovered - moveMouse({clientX: 160, clientY: 150}) + moveMouse({ clientX: 160, clientY: 150 }) await getNextUpdatePromise() expectToggleButtonHidden(leftDock) expectToggleButtonHidden(rightDock) expectToggleButtonHidden(bottomDock) // Mouse over the dock - moveMouse({clientX: 140, clientY: 150}) + moveMouse({ clientX: 140, clientY: 150 }) await getNextUpdatePromise() expectToggleButtonVisible(leftDock, 'icon-chevron-left') expectToggleButtonHidden(rightDock) expectToggleButtonHidden(bottomDock) // Mouse over the toggle button - moveMouse({clientX: 160, clientY: 150}) + moveMouse({ clientX: 160, clientY: 150 }) await getNextUpdatePromise() expectToggleButtonVisible(leftDock, 'icon-chevron-left') expectToggleButtonHidden(rightDock) @@ -637,10 +713,10 @@ describe('WorkspaceElement', () => { expectToggleButtonHidden(leftDock) // Mouse to edge of the window - moveMouse({clientX: 25, clientY: 150}) + moveMouse({ clientX: 25, clientY: 150 }) await getNextUpdatePromise() expectToggleButtonHidden(leftDock) - moveMouse({clientX: 2, clientY: 150}) + moveMouse({ clientX: 2, clientY: 150 }) await getNextUpdatePromise() expectToggleButtonVisible(leftDock, 'icon-chevron-right') @@ -653,21 +729,21 @@ describe('WorkspaceElement', () => { // --- Bottom Dock --- // Mouse over where the toggle button would be if the dock were hovered - moveMouse({clientX: 300, clientY: 190}) + moveMouse({ clientX: 300, clientY: 190 }) await getNextUpdatePromise() expectToggleButtonHidden(leftDock) expectToggleButtonHidden(rightDock) expectToggleButtonHidden(bottomDock) // Mouse over the dock - moveMouse({clientX: 300, clientY: 210}) + moveMouse({ clientX: 300, clientY: 210 }) await getNextUpdatePromise() expectToggleButtonHidden(leftDock) expectToggleButtonHidden(rightDock) expectToggleButtonVisible(bottomDock, 'icon-chevron-down') // Mouse over the toggle button - moveMouse({clientX: 300, clientY: 195}) + moveMouse({ clientX: 300, clientY: 195 }) await getNextUpdatePromise() expectToggleButtonHidden(leftDock) expectToggleButtonHidden(rightDock) @@ -680,10 +756,10 @@ describe('WorkspaceElement', () => { expectToggleButtonHidden(bottomDock) // Mouse to edge of the window - moveMouse({clientX: 300, clientY: 290}) + moveMouse({ clientX: 300, clientY: 290 }) await getNextUpdatePromise() expectToggleButtonHidden(leftDock) - moveMouse({clientX: 300, clientY: 299}) + moveMouse({ clientX: 300, clientY: 299 }) await getNextUpdatePromise() expectToggleButtonVisible(bottomDock, 'icon-chevron-up') @@ -699,12 +775,16 @@ describe('WorkspaceElement', () => { advanceClock(100) } - function expectToggleButtonHidden(dock) { - expect(dock.refs.toggleButton.element).not.toHaveClass('atom-dock-toggle-button-visible') + function expectToggleButtonHidden (dock) { + expect(dock.refs.toggleButton.element).not.toHaveClass( + 'atom-dock-toggle-button-visible' + ) } - function expectToggleButtonVisible(dock, iconClass) { - expect(dock.refs.toggleButton.element).toHaveClass('atom-dock-toggle-button-visible') + function expectToggleButtonVisible (dock, iconClass) { + expect(dock.refs.toggleButton.element).toHaveClass( + 'atom-dock-toggle-button-visible' + ) expect(dock.refs.toggleButton.refs.iconElement).toHaveClass(iconClass) } }) @@ -713,10 +793,12 @@ describe('WorkspaceElement', () => { it('has a class based on the style of the scrollbar', () => { let observeCallback const scrollbarStyle = require('scrollbar-style') - spyOn(scrollbarStyle, 'observePreferredScrollbarStyle').andCallFake(cb => { - observeCallback = cb - return new Disposable(() => {}) - }) + spyOn(scrollbarStyle, 'observePreferredScrollbarStyle').andCallFake( + cb => { + observeCallback = cb + return new Disposable(() => {}) + } + ) const workspaceElement = atom.workspace.getElement() observeCallback('legacy') @@ -741,11 +823,15 @@ describe('WorkspaceElement', () => { it("updates the font-size based on the 'editor.fontSize' config value", async () => { const initialCharWidth = editor.getDefaultCharWidth() - expect(getComputedStyle(editorElement).fontSize).toBe(atom.config.get('editor.fontSize') + 'px') + expect(getComputedStyle(editorElement).fontSize).toBe( + atom.config.get('editor.fontSize') + 'px' + ) atom.config.set('editor.fontSize', atom.config.get('editor.fontSize') + 5) await editorElement.component.getNextUpdatePromise() - expect(getComputedStyle(editorElement).fontSize).toBe(atom.config.get('editor.fontSize') + 'px') + expect(getComputedStyle(editorElement).fontSize).toBe( + atom.config.get('editor.fontSize') + 'px' + ) expect(editor.getDefaultCharWidth()).toBeGreaterThan(initialCharWidth) }) @@ -765,7 +851,9 @@ describe('WorkspaceElement', () => { const initialLineHeight = editor.getLineHeightInPixels() atom.config.set('editor.lineHeight', '30px') await editorElement.component.getNextUpdatePromise() - expect(getComputedStyle(editorElement).lineHeight).toBe(atom.config.get('editor.lineHeight')) + expect(getComputedStyle(editorElement).lineHeight).toBe( + atom.config.get('editor.lineHeight') + ) expect(editor.getLineHeightInPixels()).not.toBe(initialLineHeight) }) @@ -774,37 +862,47 @@ describe('WorkspaceElement', () => { atom.config.set('editor.fontSize', 12) // Zoom out - editorElement.querySelector('span').dispatchEvent(new WheelEvent('mousewheel', { - wheelDeltaY: -10, - ctrlKey: true - })) + editorElement.querySelector('span').dispatchEvent( + new WheelEvent('mousewheel', { + wheelDeltaY: -10, + ctrlKey: true + }) + ) expect(atom.config.get('editor.fontSize')).toBe(11) // Zoom in - editorElement.querySelector('span').dispatchEvent(new WheelEvent('mousewheel', { - wheelDeltaY: 10, - ctrlKey: true - })) + editorElement.querySelector('span').dispatchEvent( + new WheelEvent('mousewheel', { + wheelDeltaY: 10, + ctrlKey: true + }) + ) expect(atom.config.get('editor.fontSize')).toBe(12) // Not on an atom-text-editor - workspaceElement.dispatchEvent(new WheelEvent('mousewheel', { - wheelDeltaY: 10, - ctrlKey: true - })) + workspaceElement.dispatchEvent( + new WheelEvent('mousewheel', { + wheelDeltaY: 10, + ctrlKey: true + }) + ) expect(atom.config.get('editor.fontSize')).toBe(12) // No ctrl key - editorElement.querySelector('span').dispatchEvent(new WheelEvent('mousewheel', { - wheelDeltaY: 10 - })) + editorElement.querySelector('span').dispatchEvent( + new WheelEvent('mousewheel', { + wheelDeltaY: 10 + }) + ) expect(atom.config.get('editor.fontSize')).toBe(12) atom.config.set('editor.zoomFontWhenCtrlScrolling', false) - editorElement.querySelector('span').dispatchEvent(new WheelEvent('mousewheel', { - wheelDeltaY: 10, - ctrlKey: true - })) + editorElement.querySelector('span').dispatchEvent( + new WheelEvent('mousewheel', { + wheelDeltaY: 10, + ctrlKey: true + }) + ) expect(atom.config.get('editor.fontSize')).toBe(12) }) }) @@ -813,22 +911,40 @@ describe('WorkspaceElement', () => { it('inserts panel container elements in the correct places in the DOM', () => { const workspaceElement = atom.workspace.getElement() - const leftContainer = workspaceElement.querySelector('atom-panel-container.left') - const rightContainer = workspaceElement.querySelector('atom-panel-container.right') + const leftContainer = workspaceElement.querySelector( + 'atom-panel-container.left' + ) + const rightContainer = workspaceElement.querySelector( + 'atom-panel-container.right' + ) expect(leftContainer.nextSibling).toBe(workspaceElement.verticalAxis) expect(rightContainer.previousSibling).toBe(workspaceElement.verticalAxis) - const topContainer = workspaceElement.querySelector('atom-panel-container.top') - const bottomContainer = workspaceElement.querySelector('atom-panel-container.bottom') + const topContainer = workspaceElement.querySelector( + 'atom-panel-container.top' + ) + const bottomContainer = workspaceElement.querySelector( + 'atom-panel-container.bottom' + ) expect(topContainer.nextSibling).toBe(workspaceElement.paneContainer) - expect(bottomContainer.previousSibling).toBe(workspaceElement.paneContainer) + expect(bottomContainer.previousSibling).toBe( + workspaceElement.paneContainer + ) - const headerContainer = workspaceElement.querySelector('atom-panel-container.header') - const footerContainer = workspaceElement.querySelector('atom-panel-container.footer') + const headerContainer = workspaceElement.querySelector( + 'atom-panel-container.header' + ) + const footerContainer = workspaceElement.querySelector( + 'atom-panel-container.footer' + ) expect(headerContainer.nextSibling).toBe(workspaceElement.horizontalAxis) - expect(footerContainer.previousSibling).toBe(workspaceElement.horizontalAxis) + expect(footerContainer.previousSibling).toBe( + workspaceElement.horizontalAxis + ) - const modalContainer = workspaceElement.querySelector('atom-panel-container.modal') + const modalContainer = workspaceElement.querySelector( + 'atom-panel-container.modal' + ) expect(modalContainer.parentNode).toBe(workspaceElement) }) @@ -838,18 +954,20 @@ describe('WorkspaceElement', () => { expect(workspaceElement.offsetWidth).toBeGreaterThan(0) const headerItem = document.createElement('div') - atom.workspace.addHeaderPanel({item: headerItem}) + atom.workspace.addHeaderPanel({ item: headerItem }) expect(headerItem.offsetWidth).toEqual(workspaceElement.offsetWidth) const footerItem = document.createElement('div') - atom.workspace.addFooterPanel({item: footerItem}) + atom.workspace.addFooterPanel({ item: footerItem }) expect(footerItem.offsetWidth).toEqual(workspaceElement.offsetWidth) }) it('shrinks horizontal axis according to header/footer panels height', () => { const workspaceElement = atom.workspace.getElement() workspaceElement.style.height = '100px' - const horizontalAxisElement = workspaceElement.querySelector('atom-workspace-axis.horizontal') + const horizontalAxisElement = workspaceElement.querySelector( + 'atom-workspace-axis.horizontal' + ) jasmine.attachToDOM(workspaceElement) const originalHorizontalAxisHeight = horizontalAxisElement.offsetHeight @@ -858,15 +976,19 @@ describe('WorkspaceElement', () => { const headerItem = document.createElement('div') headerItem.style.height = '10px' - atom.workspace.addHeaderPanel({item: headerItem}) + atom.workspace.addHeaderPanel({ item: headerItem }) expect(headerItem.offsetHeight).toBeGreaterThan(0) const footerItem = document.createElement('div') footerItem.style.height = '15px' - atom.workspace.addFooterPanel({item: footerItem}) + atom.workspace.addFooterPanel({ item: footerItem }) expect(footerItem.offsetHeight).toBeGreaterThan(0) - expect(horizontalAxisElement.offsetHeight).toEqual(originalHorizontalAxisHeight - headerItem.offsetHeight - footerItem.offsetHeight) + expect(horizontalAxisElement.offsetHeight).toEqual( + originalHorizontalAxisHeight - + headerItem.offsetHeight - + footerItem.offsetHeight + ) }) }) @@ -895,39 +1017,60 @@ describe('WorkspaceElement', () => { // No active item. Use first project directory. atom.commands.dispatch(workspaceElement, 'window:run-package-specs') - expect(ipcRenderer.send).toHaveBeenCalledWith('run-package-specs', path.join(projectPaths[0], 'spec'), {}) + expect(ipcRenderer.send).toHaveBeenCalledWith( + 'run-package-specs', + path.join(projectPaths[0], 'spec'), + {} + ) ipcRenderer.send.reset() // Active item doesn't implement ::getPath(). Use first project directory. const item = document.createElement('div') atom.workspace.getActivePane().activateItem(item) atom.commands.dispatch(workspaceElement, 'window:run-package-specs') - expect(ipcRenderer.send).toHaveBeenCalledWith('run-package-specs', path.join(projectPaths[0], 'spec'), {}) + expect(ipcRenderer.send).toHaveBeenCalledWith( + 'run-package-specs', + path.join(projectPaths[0], 'spec'), + {} + ) ipcRenderer.send.reset() // Active item has no path. Use first project directory. item.getPath = () => null atom.commands.dispatch(workspaceElement, 'window:run-package-specs') - expect(ipcRenderer.send).toHaveBeenCalledWith('run-package-specs', path.join(projectPaths[0], 'spec'), {}) + expect(ipcRenderer.send).toHaveBeenCalledWith( + 'run-package-specs', + path.join(projectPaths[0], 'spec'), + {} + ) ipcRenderer.send.reset() // Active item has path. Use project path for item path. item.getPath = () => path.join(projectPaths[1], 'a-file.txt') atom.commands.dispatch(workspaceElement, 'window:run-package-specs') - expect(ipcRenderer.send).toHaveBeenCalledWith('run-package-specs', path.join(projectPaths[1], 'spec'), {}) + expect(ipcRenderer.send).toHaveBeenCalledWith( + 'run-package-specs', + path.join(projectPaths[1], 'spec'), + {} + ) ipcRenderer.send.reset() }) - it("passes additional options to the spec window", () => { + it('passes additional options to the spec window', () => { const workspaceElement = atom.workspace.getElement() spyOn(ipcRenderer, 'send') const projectPath = temp.mkdirSync('dir1-') atom.project.setPaths([projectPath]) - workspaceElement.runPackageSpecs({env: {ATOM_GITHUB_BABEL_ENV: 'coverage'}}) + workspaceElement.runPackageSpecs({ + env: { ATOM_GITHUB_BABEL_ENV: 'coverage' } + }) expect(ipcRenderer.send).toHaveBeenCalledWith( - 'run-package-specs', path.join(projectPath, 'spec'), {env: {ATOM_GITHUB_BABEL_ENV: 'coverage'}}) + 'run-package-specs', + path.join(projectPath, 'spec'), + { env: { ATOM_GITHUB_BABEL_ENV: 'coverage' } } + ) }) }) }) diff --git a/spec/workspace-spec.js b/spec/workspace-spec.js index 091588a70..265ae2ba9 100644 --- a/spec/workspace-spec.js +++ b/spec/workspace-spec.js @@ -10,7 +10,15 @@ const _ = require('underscore-plus') const fstream = require('fstream') const fs = require('fs-plus') const AtomEnvironment = require('../src/atom-environment') -const {it, fit, ffit, fffit, beforeEach, afterEach, conditionPromise} = require('./async-spec-helpers') +const { + it, + fit, + ffit, + fffit, + beforeEach, + afterEach, + conditionPromise +} = require('./async-spec-helpers') describe('Workspace', () => { let workspace @@ -20,7 +28,10 @@ describe('Workspace', () => { workspace = atom.workspace workspace.resetFontSize() spyOn(atom.applicationDelegate, 'confirm') - setDocumentEdited = spyOn(atom.applicationDelegate, 'setWindowDocumentEdited') + setDocumentEdited = spyOn( + atom.applicationDelegate, + 'setWindowDocumentEdited' + ) atom.project.setPaths([atom.project.getDirectories()[0].resolve('dir')]) waits(1) @@ -35,10 +46,10 @@ describe('Workspace', () => { } }) - function simulateReload() { + function simulateReload () { waitsForPromise(() => { const workspaceState = workspace.serialize() - const projectState = atom.project.serialize({isUnloading: true}) + const projectState = atom.project.serialize({ isUnloading: true }) workspace.destroy() atom.project.destroy() atom.project = new Project({ @@ -71,18 +82,26 @@ describe('Workspace', () => { describe('when the workspace contains text editors', () => { it('constructs the view with the same panes', () => { const pane1 = atom.workspace.getActivePane() - const pane2 = pane1.splitRight({copyActiveItem: true}) - const pane3 = pane2.splitRight({copyActiveItem: true}) + const pane2 = pane1.splitRight({ copyActiveItem: true }) + const pane3 = pane2.splitRight({ copyActiveItem: true }) let pane4 = null - waitsForPromise(() => atom.workspace.open(null).then(editor => editor.setText('An untitled editor.'))) - waitsForPromise(() => - atom.workspace.open('b').then(editor => pane2.activateItem(editor.copy())) + atom.workspace + .open(null) + .then(editor => editor.setText('An untitled editor.')) ) waitsForPromise(() => - atom.workspace.open('../sample.js').then(editor => pane3.activateItem(editor)) + atom.workspace + .open('b') + .then(editor => pane2.activateItem(editor.copy())) + ) + + waitsForPromise(() => + atom.workspace + .open('../sample.js') + .then(editor => pane3.activateItem(editor)) ) runs(() => { @@ -91,7 +110,9 @@ describe('Workspace', () => { }) waitsForPromise(() => - atom.workspace.open('../sample.txt').then(editor => pane4.activateItem(editor)) + atom.workspace + .open('../sample.txt') + .then(editor => pane4.activateItem(editor)) ) runs(() => { @@ -103,11 +124,19 @@ describe('Workspace', () => { runs(() => { expect(atom.workspace.getTextEditors().length).toBe(5) - const [editor1, editor2, untitledEditor, editor3, editor4] = atom.workspace.getTextEditors() + const [ + editor1, + editor2, + untitledEditor, + editor3, + editor4 + ] = atom.workspace.getTextEditors() const firstDirectory = atom.project.getDirectories()[0] expect(firstDirectory).toBeDefined() expect(editor1.getPath()).toBe(firstDirectory.resolve('b')) - expect(editor2.getPath()).toBe(firstDirectory.resolve('../sample.txt')) + expect(editor2.getPath()).toBe( + firstDirectory.resolve('../sample.txt') + ) expect(editor2.getCursorScreenPosition()).toEqual([0, 2]) expect(editor3.getPath()).toBe(firstDirectory.resolve('b')) expect(editor4.getPath()).toBe(firstDirectory.resolve('../sample.js')) @@ -115,9 +144,17 @@ describe('Workspace', () => { expect(untitledEditor.getPath()).toBeUndefined() expect(untitledEditor.getText()).toBe('An untitled editor.') - expect(atom.workspace.getActiveTextEditor().getPath()).toBe(editor3.getPath()) - const pathEscaped = fs.tildify(escapeStringRegex(atom.project.getPaths()[0])) - expect(document.title).toMatch(new RegExp(`^${path.basename(editor3.getLongTitle())} \\u2014 ${pathEscaped}`)) + expect(atom.workspace.getActiveTextEditor().getPath()).toBe( + editor3.getPath() + ) + const pathEscaped = fs.tildify( + escapeStringRegex(atom.project.getPaths()[0]) + ) + expect(document.title).toMatch( + new RegExp( + `^${path.basename(editor3.getLongTitle())} \\u2014 ${pathEscaped}` + ) + ) }) }) }) @@ -150,25 +187,47 @@ describe('Workspace', () => { let editor1 let editor2 - waitsForPromise(() => workspace.open().then(editor => { editor1 = editor })) + waitsForPromise(() => + workspace.open().then(editor => { + editor1 = editor + }) + ) runs(() => { expect(editor1.getPath()).toBeUndefined() expect(workspace.getActivePane().items).toEqual([editor1]) expect(workspace.getActivePaneItem()).toBe(editor1) expect(workspace.getActivePane().activate).toHaveBeenCalled() - expect(openEvents).toEqual([{uri: undefined, pane: workspace.getActivePane(), item: editor1, index: 0}]) + expect(openEvents).toEqual([ + { + uri: undefined, + pane: workspace.getActivePane(), + item: editor1, + index: 0 + } + ]) openEvents = [] }) - waitsForPromise(() => workspace.open().then(editor => { editor2 = editor })) + waitsForPromise(() => + workspace.open().then(editor => { + editor2 = editor + }) + ) runs(() => { expect(editor2.getPath()).toBeUndefined() expect(workspace.getActivePane().items).toEqual([editor1, editor2]) expect(workspace.getActivePaneItem()).toBe(editor2) expect(workspace.getActivePane().activate).toHaveBeenCalled() - expect(openEvents).toEqual([{uri: undefined, pane: workspace.getActivePane(), item: editor2, index: 1}]) + expect(openEvents).toEqual([ + { + uri: undefined, + pane: workspace.getActivePane(), + item: editor2, + index: 1 + } + ]) }) }) }) @@ -185,7 +244,9 @@ describe('Workspace', () => { editor1 = o return workspace.open('b').then(o => { editor2 = o - return workspace.open('a').then(o => { editor = o }) + return workspace.open('a').then(o => { + editor = o + }) }) }) ) @@ -229,7 +290,9 @@ describe('Workspace', () => { } dock.getActivePane().addItem(item) expect(dock.getPaneItems()).toHaveLength(1) - waitsForPromise(() => atom.workspace.open(ITEM_URI, {searchAllPanes: true})) + waitsForPromise(() => + atom.workspace.open(ITEM_URI, { searchAllPanes: true }) + ) runs(() => { expect(atom.workspace.getPaneItems()).toHaveLength(1) expect(dock.getPaneItems()).toHaveLength(1) @@ -242,7 +305,11 @@ describe('Workspace', () => { it('adds the item to the workspace', () => { let editor waitsForPromise(() => workspace.open('a')) - waitsForPromise(() => workspace.open('b', {activateItem: false}).then(o => { editor = o })) + waitsForPromise(() => + workspace.open('b', { activateItem: false }).then(o => { + editor = o + }) + ) runs(() => { expect(workspace.getPaneItems()).toContain(editor) expect(workspace.getActivePaneItem()).not.toBe(editor) @@ -262,7 +329,11 @@ describe('Workspace', () => { it('adds and activates a new editor for the given path on the active pane', () => { let editor = null - waitsForPromise(() => workspace.open('a').then(o => { editor = o })) + waitsForPromise(() => + workspace.open('a').then(o => { + editor = o + }) + ) runs(() => { const firstDirectory = atom.project.getDirectories()[0] @@ -278,10 +349,16 @@ describe('Workspace', () => { let editor0 = null let editor1 = null - waitsForPromise(() => Promise.all([ - workspace.open('spartacus.txt').then(o0 => { editor0 = o0 }), - workspace.open('spartacus.txt').then(o1 => { editor1 = o1 }), - ])) + waitsForPromise(() => + Promise.all([ + workspace.open('spartacus.txt').then(o0 => { + editor0 = o0 + }), + workspace.open('spartacus.txt').then(o1 => { + editor1 = o1 + }) + ]) + ) runs(() => { expect(editor0).toEqual(editor1) @@ -296,7 +373,9 @@ describe('Workspace', () => { } const opener = jasmine.createSpy().andReturn(item) const dock = atom.workspace.getRightDock() - spyOn(atom.workspace.itemLocationStore, 'load').andReturn(Promise.resolve()) + spyOn(atom.workspace.itemLocationStore, 'load').andReturn( + Promise.resolve() + ) spyOn(atom.workspace, 'getOpeners').andReturn([opener]) expect(dock.getPaneItems()).toHaveLength(0) waitsForPromise(() => atom.workspace.open('a')) @@ -314,10 +393,12 @@ describe('Workspace', () => { getDefaultLocation: () => 'left', getElement: () => document.createElement('div') } - const opener = uri => uri === ITEM_URI ? item : null + const opener = uri => (uri === ITEM_URI ? item : null) const dock = atom.workspace.getRightDock() spyOn(atom.workspace.itemLocationStore, 'load').andCallFake(uri => - uri === 'atom://test' ? Promise.resolve('right') : Promise.resolve() + uri === 'atom://test' + ? Promise.resolve('right') + : Promise.resolve() ) spyOn(atom.workspace, 'getOpeners').andReturn([opener]) expect(dock.getPaneItems()).toHaveLength(0) @@ -331,18 +412,26 @@ describe('Workspace', () => { }) describe('when an item with the given uri exists in an inactive pane container', () => { - it('activates that item if it is in that container\'s active pane', async () => { + it("activates that item if it is in that container's active pane", async () => { const item = await atom.workspace.open('a') atom.workspace.getLeftDock().activate() - expect(await atom.workspace.open('a', {searchAllPanes: false})).toBe(item) - expect(atom.workspace.getActivePaneContainer().getLocation()).toBe('center') + expect( + await atom.workspace.open('a', { searchAllPanes: false }) + ).toBe(item) + expect(atom.workspace.getActivePaneContainer().getLocation()).toBe( + 'center' + ) expect(atom.workspace.getPaneItems()).toEqual([item]) atom.workspace.getActivePane().splitRight() atom.workspace.getLeftDock().activate() - const item2 = await atom.workspace.open('a', {searchAllPanes: false}) + const item2 = await atom.workspace.open('a', { + searchAllPanes: false + }) expect(item2).not.toBe(item) - expect(atom.workspace.getActivePaneContainer().getLocation()).toBe('center') + expect(atom.workspace.getActivePaneContainer().getLocation()).toBe( + 'center' + ) expect(atom.workspace.getPaneItems()).toEqual([item, item2]) }) }) @@ -358,17 +447,21 @@ describe('Workspace', () => { waitsForPromise(() => { pane1.activate() - return workspace.open('a').then(o => { editor1 = o }) + return workspace.open('a').then(o => { + editor1 = o + }) }) waitsForPromise(() => { pane2.activate() - return workspace.open('b').then(o => { editor2 = o }) + return workspace.open('b').then(o => { + editor2 = o + }) }) runs(() => expect(workspace.getActivePaneItem()).toBe(editor2)) - waitsForPromise(() => workspace.open('a', {searchAllPanes: true})) + waitsForPromise(() => workspace.open('a', { searchAllPanes: true })) runs(() => { expect(workspace.getActivePane()).toBe(pane1) @@ -383,9 +476,17 @@ describe('Workspace', () => { const pane1 = workspace.getActivePane().splitRight() pane0.activate() - const promise0 = workspace.open('spartacus.txt', {searchAllPanes: true}).then(o0 => { editor0 = o0 }) + const promise0 = workspace + .open('spartacus.txt', { searchAllPanes: true }) + .then(o0 => { + editor0 = o0 + }) pane1.activate() - const promise1 = workspace.open('spartacus.txt', {searchAllPanes: true}).then(o1 => { editor1 = o1 }) + const promise1 = workspace + .open('spartacus.txt', { searchAllPanes: true }) + .then(o1 => { + editor1 = o1 + }) waitsForPromise(() => Promise.all([promise0, promise1])) @@ -408,7 +509,9 @@ describe('Workspace', () => { } dock.getActivePane().addItem(item) spyOn(dock.paneForItem(item), 'activate') - waitsForPromise(() => atom.workspace.open(ITEM_URI, {searchAllPanes: true})) + waitsForPromise(() => + atom.workspace.open(ITEM_URI, { searchAllPanes: true }) + ) runs(() => expect(dock.paneForItem(item).activate).toHaveBeenCalled()) }) }) @@ -416,7 +519,11 @@ describe('Workspace', () => { describe('when no editor for the given uri is open in any pane', () => { it('opens an editor for the given uri in the active pane', () => { let editor = null - waitsForPromise(() => workspace.open('a', {searchAllPanes: true}).then(o => { editor = o })) + waitsForPromise(() => + workspace.open('a', { searchAllPanes: true }).then(o => { + editor = o + }) + ) runs(() => expect(workspace.getActivePaneItem()).toBe(editor)) }) @@ -425,8 +532,13 @@ describe('Workspace', () => { describe('when attempting to open an editor in a dock', () => { it('opens the editor in the workspace center', async () => { - await atom.workspace.open('sample.txt', {location: 'right'}) - expect(atom.workspace.getCenter().getActivePaneItem().getFileName()).toEqual('sample.txt') + await atom.workspace.open('sample.txt', { location: 'right' }) + expect( + atom.workspace + .getCenter() + .getActivePaneItem() + .getFileName() + ).toEqual('sample.txt') }) }) @@ -457,7 +569,7 @@ describe('Workspace', () => { const item = document.createElement('div') await atom.workspace.open(item) - await atom.workspace.open(null, {split: 'right'}) + await atom.workspace.open(null, { split: 'right' }) expect(atom.workspace.getActivePaneItem()).not.toBe(item) expect(atom.workspace.getActivePane().getItems().length).toBe(1) @@ -468,7 +580,9 @@ describe('Workspace', () => { rejection = error } - expect(rejection.message).toMatch(/The workspace can only contain one instance of item/) + expect(rejection.message).toMatch( + /The workspace can only contain one instance of item/ + ) }) }) }) @@ -481,7 +595,11 @@ describe('Workspace', () => { expect(workspace.getActivePane()).toBe(pane2) let editor = null - waitsForPromise(() => workspace.open('a', {split: 'left'}).then(o => { editor = o })) + waitsForPromise(() => + workspace.open('a', { split: 'left' }).then(o => { + editor = o + }) + ) runs(() => { expect(workspace.getActivePane()).toBe(pane1) @@ -492,7 +610,9 @@ describe('Workspace', () => { // Focus right pane and reopen the file on the left waitsForPromise(() => { pane2.focus() - return workspace.open('a', {split: 'left'}).then(o => { editor = o }) + return workspace.open('a', { split: 'left' }).then(o => { + editor = o + }) }) runs(() => { @@ -512,7 +632,11 @@ describe('Workspace', () => { pane1.activate() expect(workspace.getActivePane()).toBe(pane1) - waitsForPromise(() => workspace.open('a', {split: 'left'}).then(o => { editor = o })) + waitsForPromise(() => + workspace.open('a', { split: 'left' }).then(o => { + editor = o + }) + ) runs(() => { expect(workspace.getActivePane()).toBe(pane1) @@ -526,7 +650,11 @@ describe('Workspace', () => { let editor = null const pane1 = workspace.getActivePane() let pane2 = null - waitsForPromise(() => workspace.open('a', {split: 'right'}).then(o => { editor = o })) + waitsForPromise(() => + workspace.open('a', { split: 'right' }).then(o => { + editor = o + }) + ) runs(() => { pane2 = workspace.getPanes().filter(p => p !== pane1)[0] @@ -538,7 +666,9 @@ describe('Workspace', () => { // Focus right pane and reopen the file on the right waitsForPromise(() => { pane1.focus() - return workspace.open('a', {split: 'right'}).then(o => { editor = o }) + return workspace.open('a', { split: 'right' }).then(o => { + editor = o + }) }) runs(() => { @@ -558,14 +688,22 @@ describe('Workspace', () => { expect(workspace.getActivePane()).toBe(pane1) let pane4 = null - waitsForPromise(() => workspace.open('a', {split: 'right'}).then(o => { editor = o })) + waitsForPromise(() => + workspace.open('a', { split: 'right' }).then(o => { + editor = o + }) + ) runs(() => { pane4 = workspace.getPanes().filter(p => p !== pane1)[0] expect(workspace.getActivePane()).toBe(pane4) expect(pane4.items).toEqual([editor]) - expect(workspace.getCenter().paneContainer.root.children[0]).toBe(pane1) - expect(workspace.getCenter().paneContainer.root.children[1]).toBe(pane4) + expect(workspace.getCenter().paneContainer.root.children[0]).toBe( + pane1 + ) + expect(workspace.getCenter().paneContainer.root.children[1]).toBe( + pane4 + ) }) }) }) @@ -578,7 +716,11 @@ describe('Workspace', () => { expect(workspace.getActivePane()).toBe(pane2) let editor = null - waitsForPromise(() => workspace.open('a', {split: 'up'}).then(o => { editor = o })) + waitsForPromise(() => + workspace.open('a', { split: 'up' }).then(o => { + editor = o + }) + ) runs(() => { expect(workspace.getActivePane()).toBe(pane1) @@ -589,7 +731,9 @@ describe('Workspace', () => { // Focus bottom pane and reopen the file on the top waitsForPromise(() => { pane2.focus() - return workspace.open('a', {split: 'up'}).then(o => { editor = o }) + return workspace.open('a', { split: 'up' }).then(o => { + editor = o + }) }) runs(() => { @@ -609,7 +753,11 @@ describe('Workspace', () => { pane1.activate() expect(workspace.getActivePane()).toBe(pane1) - waitsForPromise(() => workspace.open('a', {split: 'up'}).then(o => { editor = o })) + waitsForPromise(() => + workspace.open('a', { split: 'up' }).then(o => { + editor = o + }) + ) runs(() => { expect(workspace.getActivePane()).toBe(pane1) @@ -623,7 +771,11 @@ describe('Workspace', () => { let editor = null const pane1 = workspace.getActivePane() let pane2 = null - waitsForPromise(() => workspace.open('a', {split: 'down'}).then(o => { editor = o })) + waitsForPromise(() => + workspace.open('a', { split: 'down' }).then(o => { + editor = o + }) + ) runs(() => { pane2 = workspace.getPanes().filter(p => p !== pane1)[0] @@ -635,7 +787,9 @@ describe('Workspace', () => { // Focus bottom pane and reopen the file on the right waitsForPromise(() => { pane1.focus() - return workspace.open('a', {split: 'down'}).then(o => { editor = o }) + return workspace.open('a', { split: 'down' }).then(o => { + editor = o + }) }) runs(() => { @@ -654,14 +808,22 @@ describe('Workspace', () => { expect(workspace.getActivePane()).toBe(pane1) let pane4 = null - waitsForPromise(() => workspace.open('a', {split: 'down'}).then(o => { editor = o })) + waitsForPromise(() => + workspace.open('a', { split: 'down' }).then(o => { + editor = o + }) + ) runs(() => { pane4 = workspace.getPanes().filter(p => p !== pane1)[0] expect(workspace.getActivePane()).toBe(pane4) expect(pane4.items).toEqual([editor]) - expect(workspace.getCenter().paneContainer.root.children[0]).toBe(pane1) - expect(workspace.getCenter().paneContainer.root.children[1]).toBe(pane2) + expect(workspace.getCenter().paneContainer.root.children[0]).toBe( + pane1 + ) + expect(workspace.getCenter().paneContainer.root.children[1]).toBe( + pane2 + ) }) }) }) @@ -670,29 +832,68 @@ describe('Workspace', () => { describe('when an initialLine and initialColumn are specified', () => { it('moves the cursor to the indicated location', () => { - waitsForPromise(() => workspace.open('a', {initialLine: 1, initialColumn: 5})) + waitsForPromise(() => + workspace.open('a', { initialLine: 1, initialColumn: 5 }) + ) - runs(() => expect(workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([1, 5])) + runs(() => + expect( + workspace.getActiveTextEditor().getCursorBufferPosition() + ).toEqual([1, 5]) + ) - waitsForPromise(() => workspace.open('a', {initialLine: 2, initialColumn: 4})) + waitsForPromise(() => + workspace.open('a', { initialLine: 2, initialColumn: 4 }) + ) - runs(() => expect(workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([2, 4])) + runs(() => + expect( + workspace.getActiveTextEditor().getCursorBufferPosition() + ).toEqual([2, 4]) + ) - waitsForPromise(() => workspace.open('a', {initialLine: 0, initialColumn: 0})) + waitsForPromise(() => + workspace.open('a', { initialLine: 0, initialColumn: 0 }) + ) - runs(() => expect(workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([0, 0])) + runs(() => + expect( + workspace.getActiveTextEditor().getCursorBufferPosition() + ).toEqual([0, 0]) + ) - waitsForPromise(() => workspace.open('a', {initialLine: NaN, initialColumn: 4})) + waitsForPromise(() => + workspace.open('a', { initialLine: NaN, initialColumn: 4 }) + ) - runs(() => expect(workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([0, 4])) + runs(() => + expect( + workspace.getActiveTextEditor().getCursorBufferPosition() + ).toEqual([0, 4]) + ) - waitsForPromise(() => workspace.open('a', {initialLine: 2, initialColumn: NaN})) + waitsForPromise(() => + workspace.open('a', { initialLine: 2, initialColumn: NaN }) + ) - runs(() => expect(workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([2, 0])) + runs(() => + expect( + workspace.getActiveTextEditor().getCursorBufferPosition() + ).toEqual([2, 0]) + ) - waitsForPromise(() => workspace.open('a', {initialLine: Infinity, initialColumn: Infinity})) + waitsForPromise(() => + workspace.open('a', { + initialLine: Infinity, + initialColumn: Infinity + }) + ) - runs(() => expect(workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([2, 11])) + runs(() => + expect( + workspace.getActiveTextEditor().getCursorBufferPosition() + ).toEqual([2, 11]) + ) }) }) @@ -701,7 +902,9 @@ describe('Workspace', () => { spyOn(fs, 'getSizeSync').andReturn(size * 1048577) let selectedButtonIndex = 1 // cancel - atom.applicationDelegate.confirm.andCallFake((options, callback) => callback(selectedButtonIndex)) + atom.applicationDelegate.confirm.andCallFake((options, callback) => + callback(selectedButtonIndex) + ) let editor = await workspace.open('sample.js') if (shouldPrompt) { @@ -739,12 +942,12 @@ describe('Workspace', () => { it('returns the resource returned by the custom opener', () => { const fooOpener = (pathToOpen, options) => { if (pathToOpen != null ? pathToOpen.match(/\.foo/) : undefined) { - return {foo: pathToOpen, options} + return { foo: pathToOpen, options } } } - const barOpener = (pathToOpen) => { + const barOpener = pathToOpen => { if (pathToOpen != null ? pathToOpen.match(/^bar:\/\//) : undefined) { - return {bar: pathToOpen} + return { bar: pathToOpen } } } workspace.addOpener(fooOpener) @@ -752,29 +955,51 @@ describe('Workspace', () => { waitsForPromise(() => { const pathToOpen = atom.project.getDirectories()[0].resolve('a.foo') - return workspace.open(pathToOpen, {hey: 'there'}).then(item => expect(item).toEqual({foo: pathToOpen, options: {hey: 'there'}})) + return workspace.open(pathToOpen, { hey: 'there' }).then(item => + expect(item).toEqual({ + foo: pathToOpen, + options: { hey: 'there' } + }) + ) }) waitsForPromise(() => - workspace.open('bar://baz').then(item => expect(item).toEqual({bar: 'bar://baz'}))) + workspace + .open('bar://baz') + .then(item => expect(item).toEqual({ bar: 'bar://baz' })) + ) }) }) it("adds the file to the application's recent documents list", () => { - if (process.platform !== 'darwin') { return } // Feature only supported on macOS + if (process.platform !== 'darwin') { + return + } // Feature only supported on macOS spyOn(atom.applicationDelegate, 'addRecentDocument') waitsForPromise(() => workspace.open()) - runs(() => expect(atom.applicationDelegate.addRecentDocument).not.toHaveBeenCalled()) + runs(() => + expect( + atom.applicationDelegate.addRecentDocument + ).not.toHaveBeenCalled() + ) waitsForPromise(() => workspace.open('something://a/url')) - runs(() => expect(atom.applicationDelegate.addRecentDocument).not.toHaveBeenCalled()) + runs(() => + expect( + atom.applicationDelegate.addRecentDocument + ).not.toHaveBeenCalled() + ) waitsForPromise(() => workspace.open(__filename)) - runs(() => expect(atom.applicationDelegate.addRecentDocument).toHaveBeenCalledWith(__filename)) + runs(() => + expect(atom.applicationDelegate.addRecentDocument).toHaveBeenCalledWith( + __filename + ) + ) }) it('notifies ::onDidAddTextEditor observers', () => { @@ -783,14 +1008,24 @@ describe('Workspace', () => { workspace.onDidAddTextEditor(newEditorHandler) let editor = null - waitsForPromise(() => workspace.open(absolutePath).then(e => { editor = e })) + waitsForPromise(() => + workspace.open(absolutePath).then(e => { + editor = e + }) + ) - runs(() => expect(newEditorHandler.argsForCall[0][0].textEditor).toBe(editor)) + runs(() => + expect(newEditorHandler.argsForCall[0][0].textEditor).toBe(editor) + ) }) describe('when there is an error opening the file', () => { let notificationSpy = null - beforeEach(() => atom.notifications.onDidAddNotification(notificationSpy = jasmine.createSpy())) + beforeEach(() => + atom.notifications.onDidAddNotification( + (notificationSpy = jasmine.createSpy()) + ) + ) describe('when a file does not exist', () => { it('creates an empty buffer for the specified path', () => { @@ -881,9 +1116,11 @@ describe('Workspace', () => { ) it('rejects the promise', () => { - waitsFor((done) => { + waitsFor(done => { workspace.open('file1').catch(error => { - expect(error.message).toBe('I dont even know what is happening right now!!') + expect(error.message).toBe( + 'I dont even know what is happening right now!!' + ) done() }) }) @@ -897,7 +1134,7 @@ describe('Workspace', () => { let pane = null waitsForPromise(() => - atom.workspace.open('sample.js', {pending: true}).then(o => { + atom.workspace.open('sample.js', { pending: true }).then(o => { editor = o pane = atom.workspace.getActivePane() }) @@ -917,11 +1154,15 @@ describe('Workspace', () => { let editor2 = null waitsForPromise(() => - atom.workspace.open('sample.txt').then(o => { editor1 = o }) + atom.workspace.open('sample.txt').then(o => { + editor1 = o + }) ) waitsForPromise(() => - atom.workspace.open('sample2.txt', {pending: true}).then(o => { editor2 = o }) + atom.workspace.open('sample2.txt', { pending: true }).then(o => { + editor2 = o + }) ) runs(() => { @@ -942,11 +1183,13 @@ describe('Workspace', () => { let rightPane = null waitsForPromise(() => - atom.workspace.open('sample.js', {pending: true, split: 'right'}).then(o => { - editor1 = o - rightPane = atom.workspace.getActivePane() - spyOn(rightPane, 'destroy').andCallThrough() - }) + atom.workspace + .open('sample.js', { pending: true, split: 'right' }) + .then(o => { + editor1 = o + rightPane = atom.workspace.getActivePane() + spyOn(rightPane, 'destroy').andCallThrough() + }) ) runs(() => { @@ -957,7 +1200,9 @@ describe('Workspace', () => { }) waitsForPromise(() => - atom.workspace.open('sample.txt', {pending: true}).then(o => { editor2 = o }) + atom.workspace.open('sample.txt', { pending: true }).then(o => { + editor2 = o + }) ) runs(() => { @@ -967,15 +1212,19 @@ describe('Workspace', () => { }) }) - describe('when opening an editor with a buffer that isn\'t part of the project', () => { + describe("when opening an editor with a buffer that isn't part of the project", () => { it('adds the buffer to the project', async () => { const buffer = new TextBuffer() - const editor = new TextEditor({buffer}) + const editor = new TextEditor({ buffer }) await atom.workspace.open(editor) - expect(atom.project.getBuffers().map(buffer => buffer.id)).toContain(buffer.id) - expect(buffer.getLanguageMode().getLanguageId()).toBe('text.plain.null-grammar') + expect(atom.project.getBuffers().map(buffer => buffer.id)).toContain( + buffer.id + ) + expect(buffer.getLanguageMode().getLanguageId()).toBe( + 'text.plain.null-grammar' + ) }) }) }) @@ -985,21 +1234,42 @@ describe('Workspace', () => { const uri = 'atom://test-pane-for-item' const item = { element: document.createElement('div'), - getURI () { return uri } + getURI () { + return uri + } } atom.workspace.getActivePane().activateItem(item) - expect(atom.workspace.paneForItem(item)).toBe(atom.workspace.getCenter().getActivePane()) - expect(atom.workspace.paneContainerForItem(item)).toBe(atom.workspace.getCenter()) - expect(atom.workspace.paneForURI(uri)).toBe(atom.workspace.getCenter().getActivePane()) - expect(atom.workspace.paneContainerForURI(uri)).toBe(atom.workspace.getCenter()) + expect(atom.workspace.paneForItem(item)).toBe( + atom.workspace.getCenter().getActivePane() + ) + expect(atom.workspace.paneContainerForItem(item)).toBe( + atom.workspace.getCenter() + ) + expect(atom.workspace.paneForURI(uri)).toBe( + atom.workspace.getCenter().getActivePane() + ) + expect(atom.workspace.paneContainerForURI(uri)).toBe( + atom.workspace.getCenter() + ) atom.workspace.getActivePane().destroyActiveItem() - atom.workspace.getLeftDock().getActivePane().activateItem(item) - expect(atom.workspace.paneForItem(item)).toBe(atom.workspace.getLeftDock().getActivePane()) - expect(atom.workspace.paneContainerForItem(item)).toBe(atom.workspace.getLeftDock()) - expect(atom.workspace.paneForURI(uri)).toBe(atom.workspace.getLeftDock().getActivePane()) - expect(atom.workspace.paneContainerForURI(uri)).toBe(atom.workspace.getLeftDock()) + atom.workspace + .getLeftDock() + .getActivePane() + .activateItem(item) + expect(atom.workspace.paneForItem(item)).toBe( + atom.workspace.getLeftDock().getActivePane() + ) + expect(atom.workspace.paneContainerForItem(item)).toBe( + atom.workspace.getLeftDock() + ) + expect(atom.workspace.paneForURI(uri)).toBe( + atom.workspace.getLeftDock().getActivePane() + ) + expect(atom.workspace.paneContainerForURI(uri)).toBe( + atom.workspace.getLeftDock() + ) }) }) @@ -1061,13 +1331,21 @@ describe('Workspace', () => { describe('when the location resolves to a dock', () => { it('adds or shows the item and its dock if it is not currently visible, and otherwise hides the containing dock', async () => { const item1 = { - getDefaultLocation () { return 'left' }, - getElement () { return (this.element = document.createElement('div')) } + getDefaultLocation () { + return 'left' + }, + getElement () { + return (this.element = document.createElement('div')) + } } const item2 = { - getDefaultLocation () { return 'left' }, - getElement () { return (this.element = document.createElement('div')) } + getDefaultLocation () { + return 'left' + }, + getElement () { + return (this.element = document.createElement('div')) + } } const dock = workspace.getLeftDock() @@ -1098,13 +1376,21 @@ describe('Workspace', () => { describe('when the location resolves to the center', () => { it('adds or shows the item if it is not currently the active pane item, and otherwise removes the item', async () => { const item1 = { - getDefaultLocation () { return 'center' }, - getElement () { return (this.element = document.createElement('div')) } + getDefaultLocation () { + return 'center' + }, + getElement () { + return (this.element = document.createElement('div')) + } } const item2 = { - getDefaultLocation () { return 'center' }, - getElement () { return (this.element = document.createElement('div')) } + getDefaultLocation () { + return 'center' + }, + getElement () { + return (this.element = document.createElement('div')) + } } expect(workspace.getActivePaneItem()).toBeUndefined() @@ -1124,43 +1410,45 @@ describe('Workspace', () => { describe('active pane containers', () => { it('maintains the active pane and item globally across active pane containers', () => { const leftDock = workspace.getLeftDock() - const leftItem1 = {element: document.createElement('div')} - const leftItem2 = {element: document.createElement('div')} - const leftItem3 = {element: document.createElement('div')} + const leftItem1 = { element: document.createElement('div') } + const leftItem2 = { element: document.createElement('div') } + const leftItem3 = { element: document.createElement('div') } const leftPane1 = leftDock.getActivePane() leftPane1.addItems([leftItem1, leftItem2]) - const leftPane2 = leftPane1.splitDown({items: [leftItem3]}) + const leftPane2 = leftPane1.splitDown({ items: [leftItem3] }) const rightDock = workspace.getRightDock() - const rightItem1 = {element: document.createElement('div')} - const rightItem2 = {element: document.createElement('div')} - const rightItem3 = {element: document.createElement('div')} + const rightItem1 = { element: document.createElement('div') } + const rightItem2 = { element: document.createElement('div') } + const rightItem3 = { element: document.createElement('div') } const rightPane1 = rightDock.getActivePane() rightPane1.addItems([rightItem1, rightItem2]) - const rightPane2 = rightPane1.splitDown({items: [rightItem3]}) + const rightPane2 = rightPane1.splitDown({ items: [rightItem3] }) const bottomDock = workspace.getBottomDock() - const bottomItem1 = {element: document.createElement('div')} - const bottomItem2 = {element: document.createElement('div')} - const bottomItem3 = {element: document.createElement('div')} + const bottomItem1 = { element: document.createElement('div') } + const bottomItem2 = { element: document.createElement('div') } + const bottomItem3 = { element: document.createElement('div') } const bottomPane1 = bottomDock.getActivePane() bottomPane1.addItems([bottomItem1, bottomItem2]) - const bottomPane2 = bottomPane1.splitDown({items: [bottomItem3]}) + const bottomPane2 = bottomPane1.splitDown({ items: [bottomItem3] }) const center = workspace.getCenter() - const centerItem1 = {element: document.createElement('div')} - const centerItem2 = {element: document.createElement('div')} - const centerItem3 = {element: document.createElement('div')} + const centerItem1 = { element: document.createElement('div') } + const centerItem2 = { element: document.createElement('div') } + const centerItem3 = { element: document.createElement('div') } const centerPane1 = center.getActivePane() centerPane1.addItems([centerItem1, centerItem2]) - const centerPane2 = centerPane1.splitDown({items: [centerItem3]}) + const centerPane2 = centerPane1.splitDown({ items: [centerItem3] }) const activePaneContainers = [] const activePanes = [] const activeItems = [] - workspace.onDidChangeActivePaneContainer((container) => activePaneContainers.push(container)) - workspace.onDidChangeActivePane((pane) => activePanes.push(pane)) - workspace.onDidChangeActivePaneItem((item) => activeItems.push(item)) + workspace.onDidChangeActivePaneContainer(container => + activePaneContainers.push(container) + ) + workspace.onDidChangeActivePane(pane => activePanes.push(pane)) + workspace.onDidChangeActivePaneItem(item => activeItems.push(item)) function clearEvents () { activePaneContainers.length = 0 activePanes.length = 0 @@ -1255,11 +1543,18 @@ describe('Workspace', () => { describe('::onDidStopChangingActivePaneItem()', () => { it('invokes observers when the active item of the active pane stops changing', () => { const pane1 = atom.workspace.getCenter().getActivePane() - const pane2 = pane1.splitRight({items: [document.createElement('div'), document.createElement('div')]}); - atom.workspace.getLeftDock().getActivePane().addItem(document.createElement('div')) + const pane2 = pane1.splitRight({ + items: [document.createElement('div'), document.createElement('div')] + }) + atom.workspace + .getLeftDock() + .getActivePane() + .addItem(document.createElement('div')) emittedItems = [] - atom.workspace.onDidStopChangingActivePaneItem(item => emittedItems.push(item)) + atom.workspace.onDidStopChangingActivePaneItem(item => + emittedItems.push(item) + ) pane2.activateNextItem() pane2.activateNextItem() @@ -1267,7 +1562,9 @@ describe('Workspace', () => { atom.workspace.getLeftDock().activate() advanceClock(100) - expect(emittedItems).toEqual([atom.workspace.getLeftDock().getActivePaneItem()]) + expect(emittedItems).toEqual([ + atom.workspace.getLeftDock().getActivePaneItem() + ]) }) }) @@ -1281,15 +1578,23 @@ describe('Workspace', () => { const coffeeScriptGrammarUsed = jasmine.createSpy('coffeescript') atom.packages.triggerDeferredActivationHooks() - atom.packages.onDidTriggerActivationHook('language-javascript:grammar-used', () => { - atom.workspace.observeTextEditors(observeTextEditorsSpy) - javascriptGrammarUsed() - }) - atom.packages.onDidTriggerActivationHook('language-coffee-script:grammar-used', coffeeScriptGrammarUsed) + atom.packages.onDidTriggerActivationHook( + 'language-javascript:grammar-used', + () => { + atom.workspace.observeTextEditors(observeTextEditorsSpy) + javascriptGrammarUsed() + } + ) + atom.packages.onDidTriggerActivationHook( + 'language-coffee-script:grammar-used', + coffeeScriptGrammarUsed + ) expect(javascriptGrammarUsed).not.toHaveBeenCalled() expect(observeTextEditorsSpy).not.toHaveBeenCalled() - const editor = await atom.workspace.open('sample.js', {autoIndent: false}) + const editor = await atom.workspace.open('sample.js', { + autoIndent: false + }) expect(javascriptGrammarUsed).toHaveBeenCalled() expect(observeTextEditorsSpy.callCount).toBe(1) @@ -1309,15 +1614,23 @@ describe('Workspace', () => { const coffeeScriptGrammarUsed = jasmine.createSpy('coffeescript') atom.packages.triggerDeferredActivationHooks() - atom.packages.onDidTriggerActivationHook('source.js:root-scope-used', () => { - atom.workspace.observeTextEditors(observeTextEditorsSpy) - javascriptGrammarUsed() - }) - atom.packages.onDidTriggerActivationHook('source.coffee:root-scope-used', coffeeScriptGrammarUsed) + atom.packages.onDidTriggerActivationHook( + 'source.js:root-scope-used', + () => { + atom.workspace.observeTextEditors(observeTextEditorsSpy) + javascriptGrammarUsed() + } + ) + atom.packages.onDidTriggerActivationHook( + 'source.coffee:root-scope-used', + coffeeScriptGrammarUsed + ) expect(javascriptGrammarUsed).not.toHaveBeenCalled() expect(observeTextEditorsSpy).not.toHaveBeenCalled() - const editor = await atom.workspace.open('sample.js', {autoIndent: false}) + const editor = await atom.workspace.open('sample.js', { + autoIndent: false + }) expect(javascriptGrammarUsed).toHaveBeenCalled() expect(observeTextEditorsSpy.callCount).toBe(1) @@ -1331,11 +1644,13 @@ describe('Workspace', () => { it("opens the uri associated with the last closed pane that isn't currently open", () => { const pane = workspace.getActivePane() waitsForPromise(() => - workspace.open('a').then(() => - workspace.open('b').then(() => - workspace.open('file1').then(() => workspace.open()) + workspace + .open('a') + .then(() => + workspace + .open('b') + .then(() => workspace.open('file1').then(() => workspace.open())) ) - ) ) runs(() => { @@ -1353,11 +1668,17 @@ describe('Workspace', () => { expect(workspace.getActivePaneItem().getURI()).not.toBeUndefined() // destroy all items - expect(workspace.getActivePaneItem().getURI()).toBe(firstDirectory.resolve('file1')) + expect(workspace.getActivePaneItem().getURI()).toBe( + firstDirectory.resolve('file1') + ) pane.destroyActiveItem() - expect(workspace.getActivePaneItem().getURI()).toBe(firstDirectory.resolve('b')) + expect(workspace.getActivePaneItem().getURI()).toBe( + firstDirectory.resolve('b') + ) pane.destroyActiveItem() - expect(workspace.getActivePaneItem().getURI()).toBe(firstDirectory.resolve('a')) + expect(workspace.getActivePaneItem().getURI()).toBe( + firstDirectory.resolve('a') + ) pane.destroyActiveItem() // reopens items with uris @@ -1366,16 +1687,28 @@ describe('Workspace', () => { waitsForPromise(() => workspace.reopenItem()) - runs(() => expect(workspace.getActivePaneItem().getURI()).toBe(firstDirectory.resolve('a'))) + runs(() => + expect(workspace.getActivePaneItem().getURI()).toBe( + firstDirectory.resolve('a') + ) + ) // does not reopen items that are already open waitsForPromise(() => workspace.open('b')) - runs(() => expect(workspace.getActivePaneItem().getURI()).toBe(firstDirectory.resolve('b'))) + runs(() => + expect(workspace.getActivePaneItem().getURI()).toBe( + firstDirectory.resolve('b') + ) + ) waitsForPromise(() => workspace.reopenItem()) - runs(() => expect(workspace.getActivePaneItem().getURI()).toBe(firstDirectory.resolve('file1'))) + runs(() => + expect(workspace.getActivePaneItem().getURI()).toBe( + firstDirectory.resolve('file1') + ) + ) }) }) @@ -1431,14 +1764,16 @@ describe('Workspace', () => { describe('::openLicense()', () => { it('opens the license as plain-text in a buffer', () => { waitsForPromise(() => workspace.openLicense()) - runs(() => expect(workspace.getActivePaneItem().getText()).toMatch(/Copyright/)) + runs(() => + expect(workspace.getActivePaneItem().getText()).toMatch(/Copyright/) + ) }) }) describe('::isTextEditor(obj)', () => { it('returns true when the passed object is an instance of `TextEditor`', () => { expect(workspace.isTextEditor(new TextEditor())).toBe(true) - expect(workspace.isTextEditor({getText: () => null})).toBe(false) + expect(workspace.isTextEditor({ getText: () => null })).toBe(false) expect(workspace.isTextEditor(null)).toBe(false) expect(workspace.isTextEditor(undefined)).toBe(false) }) @@ -1509,12 +1844,15 @@ describe('Workspace', () => { workspace.observeActiveTextEditor(editor => observed.push(editor)) const editorAddedAfterRegisteringObserver = new TextEditor() - const nonEditorItemAddedAfterRegisteringObserver = document.createElement('div') + const nonEditorItemAddedAfterRegisteringObserver = document.createElement( + 'div' + ) pane.activateItem(editorAddedAfterRegisteringObserver) - expect(observed).toEqual( - [activeEditorBeforeRegisteringObserver, editorAddedAfterRegisteringObserver] - ) + expect(observed).toEqual([ + activeEditorBeforeRegisteringObserver, + editorAddedAfterRegisteringObserver + ]) }) }) @@ -1602,7 +1940,7 @@ describe('Workspace', () => { atom.grammars.assignLanguageMode(editor, 'source.js') expect(editor.getGrammar().name).toBe('JavaScript') - workspace.getActivePane().splitRight({copyActiveItem: true}) + workspace.getActivePane().splitRight({ copyActiveItem: true }) const newEditor = workspace.getActiveTextEditor() expect(newEditor).not.toBe(editor) expect(newEditor.getGrammar().name).toBe('JavaScript') @@ -1612,36 +1950,45 @@ describe('Workspace', () => { it('stores the active grammars used by all the open editors', () => { waitsForPromise(() => atom.packages.activatePackage('language-javascript')) - waitsForPromise(() => atom.packages.activatePackage('language-coffee-script')) + waitsForPromise(() => + atom.packages.activatePackage('language-coffee-script') + ) waitsForPromise(() => atom.packages.activatePackage('language-todo')) waitsForPromise(() => atom.workspace.open('sample.coffee')) runs(() => { - atom.workspace.getActiveTextEditor().setText(dedent ` + atom.workspace.getActiveTextEditor().setText(dedent` i = /test/; #FIXME\ `) - const atom2 = new AtomEnvironment({applicationDelegate: atom.applicationDelegate}) + const atom2 = new AtomEnvironment({ + applicationDelegate: atom.applicationDelegate + }) atom2.initialize({ window: document.createElement('div'), - document: Object.assign( - document.createElement('div'), - { - body: document.createElement('div'), - head: document.createElement('div') - } - ) + document: Object.assign(document.createElement('div'), { + body: document.createElement('div'), + head: document.createElement('div') + }) }) atom2.packages.loadPackage('language-javascript') atom2.packages.loadPackage('language-coffee-script') atom2.packages.loadPackage('language-todo') atom2.project.deserialize(atom.project.serialize()) - atom2.workspace.deserialize(atom.workspace.serialize(), atom2.deserializers) + atom2.workspace.deserialize( + atom.workspace.serialize(), + atom2.deserializers + ) - expect(atom2.grammars.getGrammars().map(grammar => grammar.scopeName).sort()).toEqual([ + expect( + atom2.grammars + .getGrammars() + .map(grammar => grammar.scopeName) + .sort() + ).toEqual([ 'source.coffee', 'source.js', 'source.js.regexp', @@ -1658,7 +2005,10 @@ describe('Workspace', () => { describe('document.title', () => { describe('when there is no item open', () => { - it('sets the title to the project path', () => expect(document.title).toMatch(escapeStringRegex(fs.tildify(atom.project.getPaths()[0])))) + it('sets the title to the project path', () => + expect(document.title).toMatch( + escapeStringRegex(fs.tildify(atom.project.getPaths()[0])) + )) it("sets the title to 'untitled' if there is no project path", () => { atom.project.setPaths([]) @@ -1675,16 +2025,24 @@ describe('Workspace', () => { it("sets the title to the pane item's title plus the item's path", () => { const item = atom.workspace.getActivePaneItem() - const pathEscaped = fs.tildify(escapeStringRegex(path.dirname(item.getPath()))) - expect(document.title).toMatch(new RegExp(`^${item.getTitle()} \\u2014 ${pathEscaped}`)) + const pathEscaped = fs.tildify( + escapeStringRegex(path.dirname(item.getPath())) + ) + expect(document.title).toMatch( + new RegExp(`^${item.getTitle()} \\u2014 ${pathEscaped}`) + ) }) describe('when the title of the active pane item changes', () => { it("updates the window title based on the item's new title", () => { const editor = atom.workspace.getActivePaneItem() editor.buffer.setPath(path.join(temp.dir, 'hi')) - const pathEscaped = fs.tildify(escapeStringRegex(path.dirname(editor.getPath()))) - expect(document.title).toMatch(new RegExp(`^${editor.getTitle()} \\u2014 ${pathEscaped}`)) + const pathEscaped = fs.tildify( + escapeStringRegex(path.dirname(editor.getPath())) + ) + expect(document.title).toMatch( + new RegExp(`^${editor.getTitle()} \\u2014 ${pathEscaped}`) + ) }) }) @@ -1692,8 +2050,12 @@ describe('Workspace', () => { it("updates the title to the new item's title plus the project path", () => { atom.workspace.getActivePane().activateNextItem() const item = atom.workspace.getActivePaneItem() - const pathEscaped = fs.tildify(escapeStringRegex(path.dirname(item.getPath()))) - expect(document.title).toMatch(new RegExp(`^${item.getTitle()} \\u2014 ${pathEscaped}`)) + const pathEscaped = fs.tildify( + escapeStringRegex(path.dirname(item.getPath())) + ) + expect(document.title).toMatch( + new RegExp(`^${item.getTitle()} \\u2014 ${pathEscaped}`) + ) }) }) @@ -1709,15 +2071,17 @@ describe('Workspace', () => { }) describe('when the active pane item is inside a project path', () => { - beforeEach(() => - waitsForPromise(() => atom.workspace.open('b')) - ) + beforeEach(() => waitsForPromise(() => atom.workspace.open('b'))) describe('when there is an active pane item', () => { it("sets the title to the pane item's title plus the project path", () => { const item = atom.workspace.getActivePaneItem() - const pathEscaped = fs.tildify(escapeStringRegex(atom.project.getPaths()[0])) - expect(document.title).toMatch(new RegExp(`^${item.getTitle()} \\u2014 ${pathEscaped}`)) + const pathEscaped = fs.tildify( + escapeStringRegex(atom.project.getPaths()[0]) + ) + expect(document.title).toMatch( + new RegExp(`^${item.getTitle()} \\u2014 ${pathEscaped}`) + ) }) }) @@ -1725,8 +2089,12 @@ describe('Workspace', () => { it("updates the window title based on the item's new title", () => { const editor = atom.workspace.getActivePaneItem() editor.buffer.setPath(path.join(atom.project.getPaths()[0], 'hi')) - const pathEscaped = fs.tildify(escapeStringRegex(atom.project.getPaths()[0])) - expect(document.title).toMatch(new RegExp(`^${editor.getTitle()} \\u2014 ${pathEscaped}`)) + const pathEscaped = fs.tildify( + escapeStringRegex(atom.project.getPaths()[0]) + ) + expect(document.title).toMatch( + new RegExp(`^${editor.getTitle()} \\u2014 ${pathEscaped}`) + ) }) }) @@ -1734,8 +2102,12 @@ describe('Workspace', () => { it("updates the title to the new item's title plus the project path", () => { atom.workspace.getActivePane().activateNextItem() const item = atom.workspace.getActivePaneItem() - const pathEscaped = fs.tildify(escapeStringRegex(atom.project.getPaths()[0])) - expect(document.title).toMatch(new RegExp(`^${item.getTitle()} \\u2014 ${pathEscaped}`)) + const pathEscaped = fs.tildify( + escapeStringRegex(atom.project.getPaths()[0]) + ) + expect(document.title).toMatch( + new RegExp(`^${item.getTitle()} \\u2014 ${pathEscaped}`) + ) }) }) @@ -1743,7 +2115,9 @@ describe('Workspace', () => { it("updates the title to the project's first path", () => { atom.workspace.getActivePane().destroy() expect(atom.workspace.getActivePaneItem()).toBeUndefined() - expect(document.title).toMatch(escapeStringRegex(fs.tildify(atom.project.getPaths()[0]))) + expect(document.title).toMatch( + escapeStringRegex(fs.tildify(atom.project.getPaths()[0])) + ) }) }) @@ -1764,25 +2138,33 @@ describe('Workspace', () => { it("updates the title to contain the project's path", () => { document.title = null - const atom2 = new AtomEnvironment({applicationDelegate: atom.applicationDelegate}) + const atom2 = new AtomEnvironment({ + applicationDelegate: atom.applicationDelegate + }) atom2.initialize({ window: document.createElement('div'), - document: Object.assign( - document.createElement('div'), - { - body: document.createElement('div'), - head: document.createElement('div') - } - ) + document: Object.assign(document.createElement('div'), { + body: document.createElement('div'), + head: document.createElement('div') + }) }) - waitsForPromise(() => atom2.project.deserialize(atom.project.serialize())) + waitsForPromise(() => + atom2.project.deserialize(atom.project.serialize()) + ) runs(() => { - atom2.workspace.deserialize(atom.workspace.serialize(), atom2.deserializers) + atom2.workspace.deserialize( + atom.workspace.serialize(), + atom2.deserializers + ) const item = atom2.workspace.getActivePaneItem() - const pathEscaped = fs.tildify(escapeStringRegex(atom.project.getPaths()[0])) - expect(document.title).toMatch(new RegExp(`^${item.getLongTitle()} \\u2014 ${pathEscaped}`)) + const pathEscaped = fs.tildify( + escapeStringRegex(atom.project.getPaths()[0]) + ) + expect(document.title).toMatch( + new RegExp(`^${item.getLongTitle()} \\u2014 ${pathEscaped}`) + ) atom2.destroy() }) @@ -1798,7 +2180,7 @@ describe('Workspace', () => { waitsForPromise(() => atom.workspace.open('a')) waitsForPromise(() => atom.workspace.open('b')) runs(() => { - [item1, item2] = atom.workspace.getPaneItems() + ;[item1, item2] = atom.workspace.getPaneItems() }) }) @@ -1832,31 +2214,46 @@ describe('Workspace', () => { // Don't use ES6 classes because then we'll have to call `super()` which we can't do with // HTMLElement - function TestItemElement () { this.constructor = TestItemElement } - function Ctor () { this.constructor = TestItemElement } + function TestItemElement () { + this.constructor = TestItemElement + } + function Ctor () { + this.constructor = TestItemElement + } Ctor.prototype = HTMLElement.prototype TestItemElement.prototype = new Ctor() TestItemElement.__super__ = HTMLElement.prototype - TestItemElement.prototype.initialize = function (model) { this.model = model; return this } - TestItemElement.prototype.getModel = function () { return this.model } + TestItemElement.prototype.initialize = function (model) { + this.model = model + return this + } + TestItemElement.prototype.getModel = function () { + return this.model + } beforeEach(() => - atom.views.addViewProvider(TestItem, model => new TestItemElement().initialize(model)) + atom.views.addViewProvider(TestItem, model => + new TestItemElement().initialize(model) + ) ) describe('::addLeftPanel(model)', () => { it('adds a panel to the correct panel container', () => { let addPanelSpy expect(atom.workspace.getLeftPanels().length).toBe(0) - atom.workspace.panelContainers.left.onDidAddPanel(addPanelSpy = jasmine.createSpy()) + atom.workspace.panelContainers.left.onDidAddPanel( + (addPanelSpy = jasmine.createSpy()) + ) const model = new TestItem() - const panel = atom.workspace.addLeftPanel({item: model}) + const panel = atom.workspace.addLeftPanel({ item: model }) expect(panel).toBeDefined() - expect(addPanelSpy).toHaveBeenCalledWith({panel, index: 0}) + expect(addPanelSpy).toHaveBeenCalledWith({ panel, index: 0 }) - const itemView = atom.views.getView(atom.workspace.getLeftPanels()[0].getItem()) + const itemView = atom.views.getView( + atom.workspace.getLeftPanels()[0].getItem() + ) expect(itemView instanceof TestItemElement).toBe(true) expect(itemView.getModel()).toBe(model) }) @@ -1866,15 +2263,19 @@ describe('Workspace', () => { it('adds a panel to the correct panel container', () => { let addPanelSpy expect(atom.workspace.getRightPanels().length).toBe(0) - atom.workspace.panelContainers.right.onDidAddPanel(addPanelSpy = jasmine.createSpy()) + atom.workspace.panelContainers.right.onDidAddPanel( + (addPanelSpy = jasmine.createSpy()) + ) const model = new TestItem() - const panel = atom.workspace.addRightPanel({item: model}) + const panel = atom.workspace.addRightPanel({ item: model }) expect(panel).toBeDefined() - expect(addPanelSpy).toHaveBeenCalledWith({panel, index: 0}) + expect(addPanelSpy).toHaveBeenCalledWith({ panel, index: 0 }) - const itemView = atom.views.getView(atom.workspace.getRightPanels()[0].getItem()) + const itemView = atom.views.getView( + atom.workspace.getRightPanels()[0].getItem() + ) expect(itemView instanceof TestItemElement).toBe(true) expect(itemView.getModel()).toBe(model) }) @@ -1884,15 +2285,19 @@ describe('Workspace', () => { it('adds a panel to the correct panel container', () => { let addPanelSpy expect(atom.workspace.getTopPanels().length).toBe(0) - atom.workspace.panelContainers.top.onDidAddPanel(addPanelSpy = jasmine.createSpy()) + atom.workspace.panelContainers.top.onDidAddPanel( + (addPanelSpy = jasmine.createSpy()) + ) const model = new TestItem() - const panel = atom.workspace.addTopPanel({item: model}) + const panel = atom.workspace.addTopPanel({ item: model }) expect(panel).toBeDefined() - expect(addPanelSpy).toHaveBeenCalledWith({panel, index: 0}) + expect(addPanelSpy).toHaveBeenCalledWith({ panel, index: 0 }) - const itemView = atom.views.getView(atom.workspace.getTopPanels()[0].getItem()) + const itemView = atom.views.getView( + atom.workspace.getTopPanels()[0].getItem() + ) expect(itemView instanceof TestItemElement).toBe(true) expect(itemView.getModel()).toBe(model) }) @@ -1902,15 +2307,19 @@ describe('Workspace', () => { it('adds a panel to the correct panel container', () => { let addPanelSpy expect(atom.workspace.getBottomPanels().length).toBe(0) - atom.workspace.panelContainers.bottom.onDidAddPanel(addPanelSpy = jasmine.createSpy()) + atom.workspace.panelContainers.bottom.onDidAddPanel( + (addPanelSpy = jasmine.createSpy()) + ) const model = new TestItem() - const panel = atom.workspace.addBottomPanel({item: model}) + const panel = atom.workspace.addBottomPanel({ item: model }) expect(panel).toBeDefined() - expect(addPanelSpy).toHaveBeenCalledWith({panel, index: 0}) + expect(addPanelSpy).toHaveBeenCalledWith({ panel, index: 0 }) - const itemView = atom.views.getView(atom.workspace.getBottomPanels()[0].getItem()) + const itemView = atom.views.getView( + atom.workspace.getBottomPanels()[0].getItem() + ) expect(itemView instanceof TestItemElement).toBe(true) expect(itemView.getModel()).toBe(model) }) @@ -1920,15 +2329,19 @@ describe('Workspace', () => { it('adds a panel to the correct panel container', () => { let addPanelSpy expect(atom.workspace.getHeaderPanels().length).toBe(0) - atom.workspace.panelContainers.header.onDidAddPanel(addPanelSpy = jasmine.createSpy()) + atom.workspace.panelContainers.header.onDidAddPanel( + (addPanelSpy = jasmine.createSpy()) + ) const model = new TestItem() - const panel = atom.workspace.addHeaderPanel({item: model}) + const panel = atom.workspace.addHeaderPanel({ item: model }) expect(panel).toBeDefined() - expect(addPanelSpy).toHaveBeenCalledWith({panel, index: 0}) + expect(addPanelSpy).toHaveBeenCalledWith({ panel, index: 0 }) - const itemView = atom.views.getView(atom.workspace.getHeaderPanels()[0].getItem()) + const itemView = atom.views.getView( + atom.workspace.getHeaderPanels()[0].getItem() + ) expect(itemView instanceof TestItemElement).toBe(true) expect(itemView.getModel()).toBe(model) }) @@ -1938,15 +2351,19 @@ describe('Workspace', () => { it('adds a panel to the correct panel container', () => { let addPanelSpy expect(atom.workspace.getFooterPanels().length).toBe(0) - atom.workspace.panelContainers.footer.onDidAddPanel(addPanelSpy = jasmine.createSpy()) + atom.workspace.panelContainers.footer.onDidAddPanel( + (addPanelSpy = jasmine.createSpy()) + ) const model = new TestItem() - const panel = atom.workspace.addFooterPanel({item: model}) + const panel = atom.workspace.addFooterPanel({ item: model }) expect(panel).toBeDefined() - expect(addPanelSpy).toHaveBeenCalledWith({panel, index: 0}) + expect(addPanelSpy).toHaveBeenCalledWith({ panel, index: 0 }) - const itemView = atom.views.getView(atom.workspace.getFooterPanels()[0].getItem()) + const itemView = atom.views.getView( + atom.workspace.getFooterPanels()[0].getItem() + ) expect(itemView instanceof TestItemElement).toBe(true) expect(itemView.getModel()).toBe(model) }) @@ -1956,15 +2373,19 @@ describe('Workspace', () => { it('adds a panel to the correct panel container', () => { let addPanelSpy expect(atom.workspace.getModalPanels().length).toBe(0) - atom.workspace.panelContainers.modal.onDidAddPanel(addPanelSpy = jasmine.createSpy()) + atom.workspace.panelContainers.modal.onDidAddPanel( + (addPanelSpy = jasmine.createSpy()) + ) const model = new TestItem() - const panel = atom.workspace.addModalPanel({item: model}) + const panel = atom.workspace.addModalPanel({ item: model }) expect(panel).toBeDefined() - expect(addPanelSpy).toHaveBeenCalledWith({panel, index: 0}) + expect(addPanelSpy).toHaveBeenCalledWith({ panel, index: 0 }) - const itemView = atom.views.getView(atom.workspace.getModalPanels()[0].getItem()) + const itemView = atom.views.getView( + atom.workspace.getModalPanels()[0].getItem() + ) expect(itemView instanceof TestItemElement).toBe(true) expect(itemView.getModel()).toBe(model) }) @@ -1973,7 +2394,7 @@ describe('Workspace', () => { describe('::panelForItem(item)', () => { it('returns the panel associated with the item', () => { const item = new TestItem() - const panel = atom.workspace.addLeftPanel({item}) + const panel = atom.workspace.addLeftPanel({ item }) const itemWithNoPanel = new TestItem() @@ -1989,13 +2410,17 @@ describe('Workspace', () => { const results = [] waitsForPromise(() => atom.workspace.scan( - /(a)+/, {leadingContextLineCount: 1, trailingContextLineCount: 1}, - result => results.push(result)) + /(a)+/, + { leadingContextLineCount: 1, trailingContextLineCount: 1 }, + result => results.push(result) + ) ) runs(() => { expect(results).toHaveLength(3) - expect(results[0].filePath).toBe(atom.project.getDirectories()[0].resolve('a')) + expect(results[0].filePath).toBe( + atom.project.getDirectories()[0].resolve('a') + ) expect(results[0].matches).toHaveLength(3) expect(results[0].matches[0]).toEqual({ matchText: 'aaa', @@ -2010,13 +2435,17 @@ describe('Workspace', () => { it('works with with escaped literals (like $ and ^)', () => { const results = [] - waitsForPromise(() => atom.workspace.scan( - /\$\w+/, {leadingContextLineCount: 1, trailingContextLineCount: 1}, - result => results.push(result))) + waitsForPromise(() => + atom.workspace.scan( + /\$\w+/, + { leadingContextLineCount: 1, trailingContextLineCount: 1 }, + result => results.push(result) + ) + ) runs(() => { expect(results.length).toBe(1) - const {filePath, matches} = results[0] + const { filePath, matches } = results[0] expect(filePath).toBe(atom.project.getDirectories()[0].resolve('a')) expect(matches).toHaveLength(1) expect(matches[0]).toEqual({ @@ -2064,7 +2493,9 @@ describe('Workspace', () => { it('ignores case if the regex includes the `i` flag', () => { const results = [] - waitsForPromise(() => atom.workspace.scan(/DOLLAR/i, result => results.push(result))) + waitsForPromise(() => + atom.workspace.scan(/DOLLAR/i, result => results.push(result)) + ) runs(() => expect(results).toHaveLength(1)) }) @@ -2074,7 +2505,12 @@ describe('Workspace', () => { let ignoredPath beforeEach(() => { - const sourceProjectPath = path.join(__dirname, 'fixtures', 'git', 'working-dir') + const sourceProjectPath = path.join( + __dirname, + 'fixtures', + 'git', + 'working-dir' + ) projectPath = path.join(temp.mkdirSync('atom')) const writerStream = fstream.Writer(projectPath) @@ -2086,7 +2522,10 @@ describe('Workspace', () => { }) runs(() => { - fs.rename(path.join(projectPath, 'git.git'), path.join(projectPath, '.git')) + fs.rename( + path.join(projectPath, 'git.git'), + path.join(projectPath, '.git') + ) ignoredPath = path.join(projectPath, 'ignored.txt') fs.writeFileSync(ignoredPath, 'this match should not be included') }) @@ -2119,10 +2558,14 @@ describe('Workspace', () => { const paths = [] let matches = [] waitsForPromise(() => - atom.workspace.scan(/aaa/, {paths: [`a-dir${path.sep}`]}, result => { - paths.push(result.filePath) - matches = matches.concat(result.matches) - }) + atom.workspace.scan( + /aaa/, + { paths: [`a-dir${path.sep}`] }, + result => { + paths.push(result.filePath) + matches = matches.concat(result.matches) + } + ) ) runs(() => { @@ -2177,11 +2620,16 @@ describe('Workspace', () => { }) ) - waitsForPromise(() => atom.workspace.scan(/a|Elephant/, result => results.push(result))) + waitsForPromise(() => + atom.workspace.scan(/a|Elephant/, result => results.push(result)) + ) runs(() => { expect(results).toHaveLength(3) - const resultForA = _.find(results, ({filePath}) => path.basename(filePath) === 'a') + const resultForA = _.find( + results, + ({ filePath }) => path.basename(filePath) === 'a' + ) expect(resultForA.matches).toHaveLength(1) expect(resultForA.matches[0].matchText).toBe('Elephant') }) @@ -2198,7 +2646,9 @@ describe('Workspace', () => { }) ) - waitsForPromise(() => atom.workspace.scan(/Elephant/, result => results.push(result))) + waitsForPromise(() => + atom.workspace.scan(/Elephant/, result => results.push(result)) + ) runs(() => expect(results).toHaveLength(0)) }) @@ -2225,7 +2675,9 @@ describe('Workspace', () => { it("searches matching files in all of the project's root directories", () => { const resultPaths = [] waitsForPromise(() => - atom.workspace.scan(/aaaa/, ({filePath}) => resultPaths.push(filePath)) + atom.workspace.scan(/aaaa/, ({ filePath }) => + resultPaths.push(filePath) + ) ) runs(() => expect(resultPaths.sort()).toEqual([file1, file2].sort())) @@ -2236,7 +2688,7 @@ describe('Workspace', () => { waitsForPromise(() => { const resultPaths = [] return atom.workspace - .scan(/aaaa/, {paths: ['dir']}, ({filePath}) => { + .scan(/aaaa/, { paths: ['dir'] }, ({ filePath }) => { if (!resultPaths.includes(filePath)) { resultPaths.push(filePath) } @@ -2247,33 +2699,45 @@ describe('Workspace', () => { waitsForPromise(() => { const resultPaths = [] return atom.workspace - .scan(/aaaa/, {paths: [path.join('dir', 'a-dir')]}, ({filePath}) => { - if (!resultPaths.includes(filePath)) { - resultPaths.push(filePath) + .scan( + /aaaa/, + { paths: [path.join('dir', 'a-dir')] }, + ({ filePath }) => { + if (!resultPaths.includes(filePath)) { + resultPaths.push(filePath) + } } - }) + ) .then(() => expect(resultPaths).toEqual([file1])) }) waitsForPromise(() => { const resultPaths = [] return atom.workspace - .scan(/aaaa/, {paths: [path.basename(dir2)]}, ({filePath}) => { - if (!resultPaths.includes(filePath)) { - resultPaths.push(filePath) + .scan( + /aaaa/, + { paths: [path.basename(dir2)] }, + ({ filePath }) => { + if (!resultPaths.includes(filePath)) { + resultPaths.push(filePath) + } } - }) + ) .then(() => expect(resultPaths).toEqual([file2])) }) waitsForPromise(() => { const resultPaths = [] return atom.workspace - .scan(/aaaa/, {paths: [path.join(path.basename(dir2), 'a-dir')]}, ({filePath}) => { - if (!resultPaths.includes(filePath)) { - resultPaths.push(filePath) + .scan( + /aaaa/, + { paths: [path.join(path.basename(dir2), 'a-dir')] }, + ({ filePath }) => { + if (!resultPaths.includes(filePath)) { + resultPaths.push(filePath) + } } - }) + ) .then(() => expect(resultPaths).toEqual([file2])) }) }) @@ -2310,13 +2774,19 @@ describe('Workspace', () => { beforeEach(() => { fakeSearch = null onFakeSearchCreated = null - atom.packages.serviceHub.provide('atom.directory-searcher', '0.1.0', { - canSearchDirectory (directory) { return directory.getPath() === dir1 }, - search (directory, regex, options) { - fakeSearch = new FakeSearch(options) - return fakeSearch + atom.packages.serviceHub.provide( + 'atom.directory-searcher', + '0.1.0', + { + canSearchDirectory (directory) { + return directory.getPath() === dir1 + }, + search (directory, regex, options) { + fakeSearch = new FakeSearch(options) + return fakeSearch + } } - }) + ) waitsFor(() => atom.workspace.directorySearchers.length > 0) }) @@ -2338,24 +2808,32 @@ describe('Workspace', () => { } onFakeSearchCreated = fakeSearch => { fakeSearch.options.didMatch(searchResult) - fakeSearch.options.didSearchPaths(numPathsToPretendToSearchInCustomDirectorySearcher) + fakeSearch.options.didSearchPaths( + numPathsToPretendToSearchInCustomDirectorySearcher + ) fakeSearch.hoistedResolve() } const resultPaths = [] const onPathsSearched = jasmine.createSpy('onPathsSearched') waitsForPromise(() => - atom.workspace.scan(/aaaa/, {onPathsSearched}, ({filePath}) => resultPaths.push(filePath)) + atom.workspace.scan(/aaaa/, { onPathsSearched }, ({ filePath }) => + resultPaths.push(filePath) + ) ) runs(() => { - expect(resultPaths.sort()).toEqual([foreignFilePath, file2].sort()) + expect(resultPaths.sort()).toEqual( + [foreignFilePath, file2].sort() + ) // onPathsSearched should be called once by each DirectorySearcher. The order is not // guaranteed, so we can only verify the total number of paths searched is correct // after the second call. expect(onPathsSearched.callCount).toBe(2) expect(onPathsSearched.mostRecentCall.args[0]).toBe( - numPathsToPretendToSearchInCustomDirectorySearcher + numPathsSearchedInDir2) + numPathsToPretendToSearchInCustomDirectorySearcher + + numPathsSearchedInDir2 + ) }) }) @@ -2371,7 +2849,11 @@ describe('Workspace', () => { expect(fakeSearch.cancelled).toBe(true) }) - waitsForPromise(() => thenable.then(promiseResult => { resultOfPromiseSearch = promiseResult })) + waitsForPromise(() => + thenable.then(promiseResult => { + resultOfPromiseSearch = promiseResult + }) + ) runs(() => expect(resultOfPromiseSearch).toBe('cancelled')) }) @@ -2380,21 +2862,34 @@ describe('Workspace', () => { // This provider's search should be cancelled when the first provider fails let cancelableSearch let fakeSearch2 = null - atom.packages.serviceHub.provide('atom.directory-searcher', '0.1.0', { - canSearchDirectory (directory) { return directory.getPath() === dir2 }, - search (directory, regex, options) { - fakeSearch2 = new FakeSearch(options) - return fakeSearch2 + atom.packages.serviceHub.provide( + 'atom.directory-searcher', + '0.1.0', + { + canSearchDirectory (directory) { + return directory.getPath() === dir2 + }, + search (directory, regex, options) { + fakeSearch2 = new FakeSearch(options) + return fakeSearch2 + } } - }) + ) let didReject = false - const promise = cancelableSearch = atom.workspace.scan(/aaaa/, () => {}) + const promise = (cancelableSearch = atom.workspace.scan( + /aaaa/, + () => {} + )) waitsFor('fakeSearch to be defined', () => fakeSearch != null) runs(() => fakeSearch.hoistedReject()) - waitsForPromise(() => cancelableSearch.catch(() => { didReject = true })) + waitsForPromise(() => + cancelableSearch.catch(() => { + didReject = true + }) + ) waitsFor(done => promise.then(null, done)) @@ -2424,7 +2919,12 @@ describe('Workspace', () => { expect(fs.existsSync(missingPath)).toBeFalsy() waitsForPromise(() => - atom.workspace.replace(/items/gi, 'items', [missingPath], (result, error) => errors.push(error)) + atom.workspace.replace( + /items/gi, + 'items', + [missingPath], + (result, error) => errors.push(error) + ) ) runs(() => { @@ -2441,7 +2941,9 @@ describe('Workspace', () => { const results = [] waitsForPromise(() => - atom.workspace.replace(/items/gi, 'items', [filePath], result => results.push(result)) + atom.workspace.replace(/items/gi, 'items', [filePath], result => + results.push(result) + ) ) runs(() => { @@ -2457,7 +2959,9 @@ describe('Workspace', () => { const results = [] waitsForPromise(() => - atom.workspace.replace(/;$/gmi, 'items', [filePath], result => results.push(result)) + atom.workspace.replace(/;$/gim, 'items', [filePath], result => + results.push(result) + ) ) runs(() => { @@ -2471,17 +2975,26 @@ describe('Workspace', () => { describe('when a buffer is already open', () => { it('replaces properly and saves when not modified', () => { const filePath = path.join(projectDir, 'sample.js') - fs.copyFileSync(path.join(fixturesDir, 'sample.js'), path.join(projectDir, 'sample.js')) + fs.copyFileSync( + path.join(fixturesDir, 'sample.js'), + path.join(projectDir, 'sample.js') + ) let editor = null const results = [] - waitsForPromise(() => atom.workspace.open('sample.js').then(o => { editor = o })) + waitsForPromise(() => + atom.workspace.open('sample.js').then(o => { + editor = o + }) + ) runs(() => expect(editor.isModified()).toBeFalsy()) waitsForPromise(() => - atom.workspace.replace(/items/gi, 'items', [filePath], result => results.push(result)) + atom.workspace.replace(/items/gi, 'items', [filePath], result => + results.push(result) + ) ) runs(() => { @@ -2497,13 +3010,21 @@ describe('Workspace', () => { const filePath = path.join(projectDir, 'sample.js') const commentFilePath = path.join(projectDir, 'sample-with-comments.js') fs.copyFileSync(path.join(fixturesDir, 'sample.js'), filePath) - fs.copyFileSync(path.join(fixturesDir, 'sample-with-comments.js'), path.join(projectDir, 'sample-with-comments.js')) + fs.copyFileSync( + path.join(fixturesDir, 'sample-with-comments.js'), + path.join(projectDir, 'sample-with-comments.js') + ) const results = [] waitsForPromise(() => atom.workspace.open('sample-with-comments.js')) waitsForPromise(() => - atom.workspace.replace(/items/gi, 'items', [commentFilePath], result => results.push(result)) + atom.workspace.replace( + /items/gi, + 'items', + [commentFilePath], + result => results.push(result) + ) ) runs(() => { @@ -2519,7 +3040,11 @@ describe('Workspace', () => { let editor = null const results = [] - waitsForPromise(() => atom.workspace.open('sample.js').then(o => { editor = o })) + waitsForPromise(() => + atom.workspace.open('sample.js').then(o => { + editor = o + }) + ) runs(() => { editor.buffer.setTextInRange([[0, 0], [0, 0]], 'omg') @@ -2527,7 +3052,9 @@ describe('Workspace', () => { }) waitsForPromise(() => - atom.workspace.replace(/items/gi, 'okthen', [filePath], result => results.push(result)) + atom.workspace.replace(/items/gi, 'okthen', [filePath], result => + results.push(result) + ) ) runs(() => { @@ -2545,9 +3072,11 @@ describe('Workspace', () => { let editor, notificationSpy beforeEach(() => { - waitsForPromise(() => atom.workspace.open('sample.js').then(o => { - editor = o - })) + waitsForPromise(() => + atom.workspace.open('sample.js').then(o => { + editor = o + }) + ) notificationSpy = jasmine.createSpy('did-add-notification') atom.notifications.onDidAddNotification(notificationSpy) @@ -2562,8 +3091,12 @@ describe('Workspace', () => { waitsForPromise(() => atom.workspace.saveActivePaneItem().then(() => { expect(notificationSpy).toHaveBeenCalled() - expect(notificationSpy.mostRecentCall.args[0].getType()).toBe('warning') - expect(notificationSpy.mostRecentCall.args[0].getMessage()).toContain('Unable to save') + expect(notificationSpy.mostRecentCall.args[0].getType()).toBe( + 'warning' + ) + expect( + notificationSpy.mostRecentCall.args[0].getMessage() + ).toContain('Unable to save') }) ) }) @@ -2576,15 +3109,21 @@ describe('Workspace', () => { waitsForPromise(() => atom.workspace.saveActivePaneItem().then(() => { expect(notificationSpy).toHaveBeenCalled() - expect(notificationSpy.mostRecentCall.args[0].getType()).toBe('warning') - expect(notificationSpy.mostRecentCall.args[0].getMessage()).toContain('Unable to save') + expect(notificationSpy.mostRecentCall.args[0].getType()).toBe( + 'warning' + ) + expect( + notificationSpy.mostRecentCall.args[0].getMessage() + ).toContain('Unable to save') }) ) }) it('emits a warning notification when the user does not have permission', () => { spyOn(editor, 'save').andCallFake(() => { - const error = new Error("EACCES, permission denied '/Some/dir/and-a-file.js'") + const error = new Error( + "EACCES, permission denied '/Some/dir/and-a-file.js'" + ) error.code = 'EACCES' error.path = '/Some/dir/and-a-file.js' throw error @@ -2593,15 +3132,21 @@ describe('Workspace', () => { waitsForPromise(() => atom.workspace.saveActivePaneItem().then(() => { expect(notificationSpy).toHaveBeenCalled() - expect(notificationSpy.mostRecentCall.args[0].getType()).toBe('warning') - expect(notificationSpy.mostRecentCall.args[0].getMessage()).toContain('Unable to save') + expect(notificationSpy.mostRecentCall.args[0].getType()).toBe( + 'warning' + ) + expect( + notificationSpy.mostRecentCall.args[0].getMessage() + ).toContain('Unable to save') }) ) }) it('emits a warning notification when the operation is not permitted', () => { spyOn(editor, 'save').andCallFake(() => { - const error = new Error("EPERM, operation not permitted '/Some/dir/and-a-file.js'") + const error = new Error( + "EPERM, operation not permitted '/Some/dir/and-a-file.js'" + ) error.code = 'EPERM' error.path = '/Some/dir/and-a-file.js' throw error @@ -2610,15 +3155,21 @@ describe('Workspace', () => { waitsForPromise(() => atom.workspace.saveActivePaneItem().then(() => { expect(notificationSpy).toHaveBeenCalled() - expect(notificationSpy.mostRecentCall.args[0].getType()).toBe('warning') - expect(notificationSpy.mostRecentCall.args[0].getMessage()).toContain('Unable to save') + expect(notificationSpy.mostRecentCall.args[0].getType()).toBe( + 'warning' + ) + expect( + notificationSpy.mostRecentCall.args[0].getMessage() + ).toContain('Unable to save') }) ) }) it('emits a warning notification when the file is already open by another app', () => { spyOn(editor, 'save').andCallFake(() => { - const error = new Error("EBUSY, resource busy or locked '/Some/dir/and-a-file.js'") + const error = new Error( + "EBUSY, resource busy or locked '/Some/dir/and-a-file.js'" + ) error.code = 'EBUSY' error.path = '/Some/dir/and-a-file.js' throw error @@ -2627,15 +3178,21 @@ describe('Workspace', () => { waitsForPromise(() => atom.workspace.saveActivePaneItem().then(() => { expect(notificationSpy).toHaveBeenCalled() - expect(notificationSpy.mostRecentCall.args[0].getType()).toBe('warning') - expect(notificationSpy.mostRecentCall.args[0].getMessage()).toContain('Unable to save') + expect(notificationSpy.mostRecentCall.args[0].getType()).toBe( + 'warning' + ) + expect( + notificationSpy.mostRecentCall.args[0].getMessage() + ).toContain('Unable to save') }) ) }) it('emits a warning notification when the file system is read-only', () => { spyOn(editor, 'save').andCallFake(() => { - const error = new Error("EROFS, read-only file system '/Some/dir/and-a-file.js'") + const error = new Error( + "EROFS, read-only file system '/Some/dir/and-a-file.js'" + ) error.code = 'EROFS' error.path = '/Some/dir/and-a-file.js' throw error @@ -2644,8 +3201,12 @@ describe('Workspace', () => { waitsForPromise(() => atom.workspace.saveActivePaneItem().then(() => { expect(notificationSpy).toHaveBeenCalled() - expect(notificationSpy.mostRecentCall.args[0].getType()).toBe('warning') - expect(notificationSpy.mostRecentCall.args[0].getMessage()).toContain('Unable to save') + expect(notificationSpy.mostRecentCall.args[0].getType()).toBe( + 'warning' + ) + expect( + notificationSpy.mostRecentCall.args[0].getMessage() + ).toContain('Unable to save') }) ) }) @@ -2655,7 +3216,7 @@ describe('Workspace', () => { throw new Error('no one knows') }) - waitsForPromise({shouldReject: true}, () => + waitsForPromise({ shouldReject: true }, () => atom.workspace.saveActivePaneItem() ) }) @@ -2672,7 +3233,7 @@ describe('Workspace', () => { atom.config.set('core.destroyEmptyPanes', false) const pane1 = atom.workspace.getActivePane() - const pane2 = pane1.splitRight({copyActiveItem: true}) + const pane2 = pane1.splitRight({ copyActiveItem: true }) expect(atom.workspace.getCenter().getPanes().length).toBe(2) expect(pane2.getItems().length).toBe(1) @@ -2819,13 +3380,25 @@ describe('Workspace', () => { expect(workspace.getVisiblePaneContainers()).toEqual([center]) leftDock.show() - expect(workspace.getVisiblePaneContainers().sort()).toEqual([center, leftDock]) + expect(workspace.getVisiblePaneContainers().sort()).toEqual([ + center, + leftDock + ]) rightDock.show() - expect(workspace.getVisiblePaneContainers().sort()).toEqual([center, leftDock, rightDock]) + expect(workspace.getVisiblePaneContainers().sort()).toEqual([ + center, + leftDock, + rightDock + ]) bottomDock.show() - expect(workspace.getVisiblePaneContainers().sort()).toEqual([center, leftDock, rightDock, bottomDock]) + expect(workspace.getVisiblePaneContainers().sort()).toEqual([ + center, + leftDock, + rightDock, + bottomDock + ]) }) }) @@ -2835,7 +3408,7 @@ describe('Workspace', () => { atom.config.set('core.allowPendingPaneItems', false) waitsForPromise(() => - atom.workspace.open('sample.js', {pending: true}).then(() => { + atom.workspace.open('sample.js', { pending: true }).then(() => { pane = atom.workspace.getActivePane() }) ) @@ -2852,9 +3425,18 @@ describe('Workspace', () => { const rubyGrammarUsed = jasmine.createSpy('ruby grammar used') const cGrammarUsed = jasmine.createSpy('c grammar used') - atom.packages.onDidTriggerActivationHook('language-javascript:grammar-used', javascriptGrammarUsed) - atom.packages.onDidTriggerActivationHook('language-ruby:grammar-used', rubyGrammarUsed) - atom.packages.onDidTriggerActivationHook('language-c:grammar-used', cGrammarUsed) + atom.packages.onDidTriggerActivationHook( + 'language-javascript:grammar-used', + javascriptGrammarUsed + ) + atom.packages.onDidTriggerActivationHook( + 'language-ruby:grammar-used', + rubyGrammarUsed + ) + atom.packages.onDidTriggerActivationHook( + 'language-c:grammar-used', + cGrammarUsed + ) await atom.packages.activatePackage('language-ruby') await atom.packages.activatePackage('language-javascript') @@ -2865,12 +3447,18 @@ describe('Workspace', () => { expect(javascriptGrammarUsed).toHaveBeenCalled() // Hooks are triggered when changing existing editors grammars - atom.grammars.assignLanguageMode(atom.workspace.getActiveTextEditor(), 'source.c') + atom.grammars.assignLanguageMode( + atom.workspace.getActiveTextEditor(), + 'source.c' + ) expect(cGrammarUsed).toHaveBeenCalled() // Hooks are triggered when editors are added in other ways. - atom.workspace.getActivePane().splitRight({copyActiveItem: true}) - atom.grammars.assignLanguageMode(atom.workspace.getActiveTextEditor(), 'source.ruby') + atom.workspace.getActivePane().splitRight({ copyActiveItem: true }) + atom.grammars.assignLanguageMode( + atom.workspace.getActiveTextEditor(), + 'source.ruby' + ) expect(rubyGrammarUsed).toHaveBeenCalled() }) }) @@ -2927,7 +3515,10 @@ describe('Workspace', () => { const dockPane = atom.workspace.getRightDock().getActivePane() spyOn(workspace.itemLocationStore, 'save') centerPane.moveItemToPane(item, dockPane) - expect(workspace.itemLocationStore.save).toHaveBeenCalledWith(ITEM_URI, 'right') + expect(workspace.itemLocationStore.save).toHaveBeenCalledWith( + ITEM_URI, + 'right' + ) }) it("clears the location if it's the default", () => { From d7d6d0838f2066ec51dd41559e4b6eeba1adca77 Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Fri, 22 Feb 2019 09:55:30 +0100 Subject: [PATCH 103/112] Remove unused vars from specs --- spec/application-delegate-spec.js | 9 +- spec/atom-environment-spec.js | 9 +- spec/atom-paths-spec.js | 9 +- spec/command-installer-spec.js | 3 - spec/command-registry-spec.js | 9 +- spec/config-file-spec.js | 6 +- spec/dock-spec.js | 11 +- spec/git-repository-provider-spec.js | 2 +- spec/git-repository-spec.js | 11 +- spec/grammar-registry-spec.js | 11 +- spec/history-manager-spec.js | 10 +- spec/package-manager-spec.js | 2 +- spec/package-transpilation-registry-spec.js | 10 +- spec/pane-container-spec.js | 7 +- spec/pane-spec.js | 3 - spec/panel-spec.js | 2 +- spec/reopen-project-menu-manager-spec.js | 11 +- spec/state-store-spec.js | 9 +- spec/style-manager-spec.js | 2 +- spec/text-editor-component-spec.js | 188 +++++++++----------- spec/text-editor-element-spec.js | 9 +- spec/text-editor-registry-spec.js | 3 +- spec/text-editor-spec.js | 60 ++----- spec/text-mate-language-mode-spec.js | 11 +- spec/tree-sitter-language-mode-spec.js | 9 +- spec/update-process-env-spec.js | 10 +- spec/workspace-center-spec.js | 9 +- spec/workspace-element-spec.js | 12 +- spec/workspace-spec.js | 8 +- 29 files changed, 134 insertions(+), 321 deletions(-) diff --git a/spec/application-delegate-spec.js b/spec/application-delegate-spec.js index 97326aa24..abe86d92d 100644 --- a/spec/application-delegate-spec.js +++ b/spec/application-delegate-spec.js @@ -1,13 +1,6 @@ /** @babel */ -import { - it, - fit, - ffit, - fffit, - beforeEach, - afterEach -} from './async-spec-helpers' +import { it } from './async-spec-helpers' import ApplicationDelegate from '../src/application-delegate' describe('ApplicationDelegate', function () { diff --git a/spec/atom-environment-spec.js b/spec/atom-environment-spec.js index 8e5dd5dba..a032b8eb2 100644 --- a/spec/atom-environment-spec.js +++ b/spec/atom-environment-spec.js @@ -1,12 +1,9 @@ const { it, - fit, - ffit, beforeEach, afterEach, conditionPromise } = require('./async-spec-helpers') -const _ = require('underscore-plus') const fs = require('fs') const path = require('path') const temp = require('temp').track() @@ -74,7 +71,7 @@ describe('AtomEnvironment', () => { it('will open the dev tools when an error is triggered', async () => { try { - a + 1 + a + 1 // eslint-ignore-line no-unused-vars } catch (e) { window.onerror.call(window, e.toString(), 'abc', 2, 3, e) } @@ -442,7 +439,6 @@ describe('AtomEnvironment', () => { describe('adding a project folder', () => { it('does nothing if the user dismisses the file picker', () => { const initialPaths = atom.project.getPaths() - const tempDirectory = temp.mkdirSync('a-new-directory') spyOn(atom, 'pickFolder').andCallFake(callback => callback(null)) atom.addProjectFolder() expect(atom.project.getPaths()).toEqual(initialPaths) @@ -455,7 +451,7 @@ describe('AtomEnvironment', () => { }) it('adds the selected folder to the project', async () => { - const initialPaths = atom.project.setPaths([]) + atom.project.setPaths([]) const tempDirectory = temp.mkdirSync('a-new-directory') spyOn(atom, 'pickFolder').andCallFake(callback => callback([tempDirectory]) @@ -657,7 +653,6 @@ describe('AtomEnvironment', () => { describe('::destroy()', () => { it('does not throw exceptions when unsubscribing from ipc events (regression)', async () => { - const configDirPath = temp.mkdirSync('atom-spec-environment') const fakeDocument = { addEventListener () {}, removeEventListener () {}, diff --git a/spec/atom-paths-spec.js b/spec/atom-paths-spec.js index 438154d72..b7644e7cd 100644 --- a/spec/atom-paths-spec.js +++ b/spec/atom-paths-spec.js @@ -1,13 +1,6 @@ /** @babel */ -import { - it, - fit, - ffit, - fffit, - beforeEach, - afterEach -} from './async-spec-helpers' +import { it, beforeEach, afterEach } from './async-spec-helpers' import { app } from 'remote' import atomPaths from '../src/atom-paths' import fs from 'fs-plus' diff --git a/spec/command-installer-spec.js b/spec/command-installer-spec.js index 2afa715fe..fb114928f 100644 --- a/spec/command-installer-spec.js +++ b/spec/command-installer-spec.js @@ -3,9 +3,6 @@ const fs = require('fs-plus') const temp = require('temp').track() const { it, - fit, - ffit, - fffit, beforeEach, afterEach } = require('./async-spec-helpers') diff --git a/spec/command-registry-spec.js b/spec/command-registry-spec.js index 285cec055..f49ebe942 100644 --- a/spec/command-registry-spec.js +++ b/spec/command-registry-spec.js @@ -1,13 +1,6 @@ const CommandRegistry = require('../src/command-registry') const _ = require('underscore-plus') -const { - it, - fit, - ffit, - fffit, - beforeEach, - afterEach -} = require('./async-spec-helpers') +const { it, beforeEach, afterEach } = require('./async-spec-helpers') describe('CommandRegistry', () => { let registry, parent, child, grandchild diff --git a/spec/config-file-spec.js b/spec/config-file-spec.js index a053c9755..1350853f5 100644 --- a/spec/config-file-spec.js +++ b/spec/config-file-spec.js @@ -1,10 +1,8 @@ const { it, - fit, - ffit, + beforeEach, - afterEach, - conditionPromise + afterEach } = require('./async-spec-helpers') const fs = require('fs-plus') const path = require('path') diff --git a/spec/dock-spec.js b/spec/dock-spec.js index 6b97b6aa8..d7bd5b1cb 100644 --- a/spec/dock-spec.js +++ b/spec/dock-spec.js @@ -2,14 +2,7 @@ const Grim = require('grim') -import { - it, - fit, - ffit, - fffit, - beforeEach, - afterEach -} from './async-spec-helpers' +import { it } from './async-spec-helpers' import etch from 'etch' const getNextUpdatePromise = () => etch.getScheduler().nextUpdatePromise @@ -344,7 +337,7 @@ describe('Dock', () => { }, serialize: () => ({ deserializer: 'DockTestItem' }) } - const itemDeserializer = atom.deserializers.add({ + atom.deserializers.add({ name: 'DockTestItem', deserialize: () => item }) diff --git a/spec/git-repository-provider-spec.js b/spec/git-repository-provider-spec.js index d70d7db3f..28e2f5eb8 100644 --- a/spec/git-repository-provider-spec.js +++ b/spec/git-repository-provider-spec.js @@ -4,7 +4,7 @@ const temp = require('temp').track() const { Directory } = require('pathwatcher') const GitRepository = require('../src/git-repository') const GitRepositoryProvider = require('../src/git-repository-provider') -const { it, fit, ffit, fffit, beforeEach } = require('./async-spec-helpers') +const { it, beforeEach } = require('./async-spec-helpers') describe('GitRepositoryProvider', () => { let provider diff --git a/spec/git-repository-spec.js b/spec/git-repository-spec.js index 60a0846ac..ade09da88 100644 --- a/spec/git-repository-spec.js +++ b/spec/git-repository-spec.js @@ -1,11 +1,4 @@ -const { - it, - fit, - ffit, - fffit, - beforeEach, - afterEach -} = require('./async-spec-helpers') +const { it, beforeEach, afterEach } = require('./async-spec-helpers') const path = require('path') const fs = require('fs-plus') const temp = require('temp').track() @@ -424,8 +417,6 @@ describe('GitRepository', () => { await project2.deserialize(atom.project.serialize({ isUnloading: false })) buffer = project2.getBuffers()[0] - - const originalContent = buffer.getText() buffer.append('changes') statusHandler = jasmine.createSpy('statusHandler') diff --git a/spec/grammar-registry-spec.js b/spec/grammar-registry-spec.js index 2f7d82299..729d52563 100644 --- a/spec/grammar-registry-spec.js +++ b/spec/grammar-registry-spec.js @@ -1,11 +1,4 @@ -const { - it, - fit, - ffit, - fffit, - beforeEach, - afterEach -} = require('./async-spec-helpers') +const { it, beforeEach, afterEach } = require('./async-spec-helpers') const dedent = require('dedent') const path = require('path') @@ -307,7 +300,7 @@ describe('GrammarRegistry', () => { require.resolve('language-javascript/grammars/javascript.cson') ) - const disposable = grammarRegistry.maintainLanguageMode(buffer) + grammarRegistry.maintainLanguageMode(buffer) expect(retainedBufferCount(grammarRegistry)).toBe(1) expect(subscriptionCount(grammarRegistry)).toBe(3) diff --git a/spec/history-manager-spec.js b/spec/history-manager-spec.js index 2d1a09cdc..5f7366118 100644 --- a/spec/history-manager-spec.js +++ b/spec/history-manager-spec.js @@ -1,12 +1,4 @@ -const { - it, - fit, - ffit, - fffit, - beforeEach, - afterEach -} = require('./async-spec-helpers') -const { Emitter, Disposable, CompositeDisposable } = require('event-kit') +const { it, beforeEach, afterEach } = require('./async-spec-helpers') const { HistoryManager, HistoryProject } = require('../src/history-manager') const StateStore = require('../src/state-store') diff --git a/spec/package-manager-spec.js b/spec/package-manager-spec.js index 9dec5bde6..6e67508b4 100644 --- a/spec/package-manager-spec.js +++ b/spec/package-manager-spec.js @@ -8,7 +8,7 @@ const { Disposable } = require('atom') const { buildKeydownEvent } = require('../src/keymap-extensions') const { mockLocalStorage } = require('./spec-helper') const ModuleCache = require('../src/module-cache') -const { it, fit, ffit, beforeEach, afterEach } = require('./async-spec-helpers') +const { it, beforeEach, afterEach } = require('./async-spec-helpers') describe('PackageManager', () => { function createTestElement (className) { diff --git a/spec/package-transpilation-registry-spec.js b/spec/package-transpilation-registry-spec.js index 90a06ea6c..32b3f375b 100644 --- a/spec/package-transpilation-registry-spec.js +++ b/spec/package-transpilation-registry-spec.js @@ -1,15 +1,7 @@ /** @babel */ -import fs from 'fs' import path from 'path' -import { - it, - fit, - ffit, - fffit, - beforeEach, - afterEach -} from './async-spec-helpers' +import { it, beforeEach } from './async-spec-helpers' import PackageTranspilationRegistry from '../src/package-transpilation-registry' diff --git a/spec/pane-container-spec.js b/spec/pane-container-spec.js index 50a60d2b0..7450d870b 100644 --- a/spec/pane-container-spec.js +++ b/spec/pane-container-spec.js @@ -1,11 +1,8 @@ const PaneContainer = require('../src/pane-container') const { it, - fit, - ffit, - fffit, - beforeEach, - afterEach + + beforeEach } = require('./async-spec-helpers') describe('PaneContainer', () => { diff --git a/spec/pane-spec.js b/spec/pane-spec.js index b87e9e8ad..17fffaec7 100644 --- a/spec/pane-spec.js +++ b/spec/pane-spec.js @@ -5,9 +5,6 @@ const Pane = require('../src/pane') const PaneContainer = require('../src/pane-container') const { it, - fit, - ffit, - fffit, beforeEach, conditionPromise, timeoutPromise diff --git a/spec/panel-spec.js b/spec/panel-spec.js index 7e1365a67..5165e550c 100644 --- a/spec/panel-spec.js +++ b/spec/panel-spec.js @@ -108,7 +108,7 @@ describe('Panel', () => { describe('creating an atom-panel via markup', () => { it('does not throw an error', () => { - const element = document.createElement('atom-panel') + document.createElement('atom-panel') }) }) }) diff --git a/spec/reopen-project-menu-manager-spec.js b/spec/reopen-project-menu-manager-spec.js index 100111242..f5745bc76 100644 --- a/spec/reopen-project-menu-manager-spec.js +++ b/spec/reopen-project-menu-manager-spec.js @@ -1,14 +1,7 @@ /** @babel */ -import { - it, - fit, - ffit, - fffit, - beforeEach, - afterEach -} from './async-spec-helpers' -import { Emitter, Disposable, CompositeDisposable } from 'event-kit' +import { it, beforeEach } from './async-spec-helpers' +import { Disposable } from 'event-kit' const ReopenProjectMenuManager = require('../src/reopen-project-menu-manager') diff --git a/spec/state-store-spec.js b/spec/state-store-spec.js index 95583f8cd..d890877ab 100644 --- a/spec/state-store-spec.js +++ b/spec/state-store-spec.js @@ -1,12 +1,5 @@ /** @babel */ -import { - it, - fit, - ffit, - fffit, - beforeEach, - afterEach -} from './async-spec-helpers' +import { it } from './async-spec-helpers' const StateStore = require('../src/state-store.js') diff --git a/spec/style-manager-spec.js b/spec/style-manager-spec.js index e29dedb0c..95ec0dacf 100644 --- a/spec/style-manager-spec.js +++ b/spec/style-manager-spec.js @@ -152,7 +152,7 @@ describe('StyleManager', () => { describe('when a sourcePath parameter is specified', () => { it('ensures a maximum of one style element for the given source path, updating a previous if it exists', () => { - const disposable1 = styleManager.addStyleSheet('a {color: red}', { + styleManager.addStyleSheet('a {color: red}', { sourcePath: '/foo/bar' }) expect(addEvents.length).toBe(1) diff --git a/spec/text-editor-component-spec.js b/spec/text-editor-component-spec.js index d58a749d6..42e243830 100644 --- a/spec/text-editor-component-spec.js +++ b/spec/text-editor-component-spec.js @@ -1,12 +1,9 @@ const { it, - fit, - ffit, - fffit, + beforeEach, afterEach, - conditionPromise, - timeoutPromise + conditionPromise } = require('./async-spec-helpers') const Random = require('../script/node_modules/random-seed') @@ -194,7 +191,7 @@ describe('TextEditorComponent', () => { }) it('re-renders lines when their height changes', async () => { - const { component, element, editor } = buildComponent({ + const { component, element } = buildComponent({ rowsPerTile: 3, autoHeight: false }) @@ -235,7 +232,7 @@ describe('TextEditorComponent', () => { }) it('makes the content at least as tall as the scroll container client height', async () => { - const { component, element, editor } = buildComponent({ + const { component, editor } = buildComponent({ text: 'a'.repeat(100), width: 50, height: 100 @@ -253,11 +250,10 @@ describe('TextEditorComponent', () => { }) it('honors the scrollPastEnd option by adding empty space equivalent to the clientHeight to the end of the content area', async () => { - const { component, element, editor } = buildComponent({ + const { component, editor } = buildComponent({ autoHeight: false, autoWidth: false }) - const { scrollContainer } = component.refs await editor.update({ scrollPastEnd: true }) await setEditorHeightInLines(component, 6) @@ -307,7 +303,7 @@ describe('TextEditorComponent', () => { }) it('gives the line number tiles an explicit width and height so their layout can be strictly contained', async () => { - const { component, element, editor } = buildComponent({ rowsPerTile: 3 }) + const { component, editor } = buildComponent({ rowsPerTile: 3 }) const lineNumberGutterElement = component.refs.gutterContainer.refs.lineNumberGutter.element @@ -344,7 +340,7 @@ describe('TextEditorComponent', () => { }) it('keeps the number of tiles stable when the visible line count changes during vertical scrolling', async () => { - const { component, element, editor } = buildComponent({ + const { component } = buildComponent({ rowsPerTile: 3, autoHeight: false }) @@ -359,7 +355,7 @@ describe('TextEditorComponent', () => { }) it('recycles tiles on resize', async () => { - const { component, element, editor } = buildComponent({ + const { component } = buildComponent({ rowsPerTile: 2, autoHeight: false }) @@ -371,7 +367,7 @@ describe('TextEditorComponent', () => { }) it("updates lines numbers when a row's foldability changes (regression)", async () => { - const { component, element, editor } = buildComponent({ text: 'abc\n' }) + const { component, editor } = buildComponent({ text: 'abc\n' }) editor.setCursorBufferPosition([1, 0]) await component.getNextUpdatePromise() expect( @@ -392,7 +388,7 @@ describe('TextEditorComponent', () => { }) it('shows the foldable icon on the last screen row of a buffer row that can be folded', async () => { - const { component, element, editor } = buildComponent({ + const { component } = buildComponent({ text: 'abc\n de\nfghijklm\n no', softWrapped: true }) @@ -415,7 +411,7 @@ describe('TextEditorComponent', () => { }) it('renders dummy vertical and horizontal scrollbars when content overflows', async () => { - const { component, element, editor } = buildComponent({ + const { component, editor } = buildComponent({ height: 100, width: 100 }) @@ -708,7 +704,7 @@ describe('TextEditorComponent', () => { }) it('places the hidden input element at the location of the last cursor if it is visible', async () => { - const { component, element, editor } = buildComponent({ + const { component, editor } = buildComponent({ height: 60, width: 120, rowsPerTile: 2 @@ -789,7 +785,7 @@ describe('TextEditorComponent', () => { }) it('decorates the line numbers of folded lines', async () => { - const { component, element, editor } = buildComponent() + const { component, editor } = buildComponent() editor.foldBufferRow(1) await component.getNextUpdatePromise() expect( @@ -799,7 +795,7 @@ describe('TextEditorComponent', () => { it('makes lines at least as wide as the scrollContainer', async () => { const { component, element, editor } = buildComponent() - const { scrollContainer, gutterContainer } = component.refs + const { scrollContainer } = component.refs editor.setText('a') await component.getNextUpdatePromise() @@ -815,7 +811,6 @@ describe('TextEditorComponent', () => { }) const editorPadding = 3 element.style.padding = editorPadding + 'px' - const { gutterContainer, scrollContainer } = component.refs const initialWidth = element.offsetWidth const initialHeight = element.offsetHeight expect(initialWidth).toBe( @@ -854,7 +849,7 @@ describe('TextEditorComponent', () => { }) it('does not render the line number gutter at all if the isLineNumberGutterVisible parameter is false', () => { - const { component, element, editor } = buildComponent({ + const { element } = buildComponent({ lineNumberGutterVisible: false }) expect(element.querySelector('.line-number')).toBe(null) @@ -1063,7 +1058,7 @@ describe('TextEditorComponent', () => { it('does not blow away class names added to the element by packages when changing the class name', async () => { assertDocumentFocused() - const { component, element, editor } = buildComponent() + const { component, element } = buildComponent() element.classList.add('a', 'b') expect(element.className).toBe('editor a b') element.focus() @@ -1076,7 +1071,7 @@ describe('TextEditorComponent', () => { it('does not blow away class names managed by the component when packages change the element class name', async () => { assertDocumentFocused() - const { component, element, editor } = buildComponent({ mini: true }) + const { component, element } = buildComponent({ mini: true }) element.classList.add('a', 'b') element.focus() await component.getNextUpdatePromise() @@ -1087,7 +1082,7 @@ describe('TextEditorComponent', () => { }) it('ignores resize events when the editor is hidden', async () => { - const { component, element, editor } = buildComponent({ + const { component, element } = buildComponent({ autoHeight: false }) element.style.height = 5 * component.getLineHeight() + 'px' @@ -1258,13 +1253,13 @@ describe('TextEditorComponent', () => { describe('mini editors', () => { it('adds the mini attribute and class even when the element is not attached', () => { { - const { element, editor } = buildComponent({ mini: true }) + const { element } = buildComponent({ mini: true }) expect(element.hasAttribute('mini')).toBe(true) expect(element.classList.contains('mini')).toBe(true) } { - const { element, editor } = buildComponent({ + const { element } = buildComponent({ mini: true, attach: false }) @@ -1274,7 +1269,7 @@ describe('TextEditorComponent', () => { }) it('does not render the gutter container', () => { - const { component, element, editor } = buildComponent({ mini: true }) + const { component, element } = buildComponent({ mini: true }) expect(component.refs.gutterContainer).toBeUndefined() expect(element.querySelector('gutter-container')).toBeNull() }) @@ -1299,7 +1294,7 @@ describe('TextEditorComponent', () => { }) it('does not render scrollbars', async () => { - const { component, element, editor } = buildComponent({ + const { component, editor } = buildComponent({ mini: true, autoHeight: false }) @@ -1321,7 +1316,7 @@ describe('TextEditorComponent', () => { }) it('focuses the hidden input element and adds the is-focused class when focused', async () => { - const { component, element, editor } = buildComponent() + const { component, element } = buildComponent() const { hiddenInput } = component.refs.cursorsAndInput.refs expect(document.activeElement).not.toBe(hiddenInput) @@ -1341,7 +1336,7 @@ describe('TextEditorComponent', () => { }) it('updates the component when the hidden input is focused directly', async () => { - const { component, element, editor } = buildComponent() + const { component, element } = buildComponent() const { hiddenInput } = component.refs.cursorsAndInput.refs expect(element.classList.contains('is-focused')).toBe(false) expect(document.activeElement).not.toBe(hiddenInput) @@ -1352,7 +1347,7 @@ describe('TextEditorComponent', () => { }) it('gracefully handles a focus event that occurs prior to the attachedCallback of the element', () => { - const { component, element, editor } = buildComponent({ attach: false }) + const { component, element } = buildComponent({ attach: false }) const parent = document.createElement( 'text-editor-component-test-element' ) @@ -1365,7 +1360,7 @@ describe('TextEditorComponent', () => { }) it('gracefully handles a focus event that occurs prior to detecting the element has become visible', async () => { - const { component, element, editor } = buildComponent({ attach: false }) + const { component, element } = buildComponent({ attach: false }) element.style.display = 'none' jasmine.attachToDOM(element) element.style.display = 'block' @@ -1475,7 +1470,6 @@ describe('TextEditorComponent', () => { it('automatically scrolls horizontally when the requested range is within the horizontal scroll margin of the right edge of the gutter or right edge of the scroll container', async () => { const { component, element, editor } = buildComponent() - const { scrollContainer } = component.refs element.style.width = component.getGutterContainerWidth() + 3 * @@ -1560,7 +1554,6 @@ describe('TextEditorComponent', () => { const { component, element, editor } = buildComponent({ autoHeight: false }) - const { scrollContainer } = component.refs element.style.height = component.getContentHeight() / 2 + 'px' element.style.width = component.getScrollWidth() + 'px' await component.getNextUpdatePromise() @@ -1587,7 +1580,7 @@ describe('TextEditorComponent', () => { describe('logical scroll positions', () => { it('allows the scrollTop to be changed and queried in terms of rows via setScrollTopRow and getScrollTopRow', () => { - const { component, element, editor } = buildComponent({ + const { component, element } = buildComponent({ attach: false, height: 80 }) @@ -1682,7 +1675,7 @@ describe('TextEditorComponent', () => { describe('scrolling via the mouse wheel', () => { it('scrolls vertically or horizontally depending on whether deltaX or deltaY is larger', () => { const scrollSensitivity = 30 - const { component, editor } = buildComponent({ + const { component } = buildComponent({ height: 50, width: 50, scrollSensitivity @@ -1737,7 +1730,7 @@ describe('TextEditorComponent', () => { it('inverts deltaX and deltaY when holding shift on Windows and Linux', async () => { const scrollSensitivity = 50 - const { component, editor } = buildComponent({ + const { component } = buildComponent({ height: 50, width: 50, scrollSensitivity @@ -1864,7 +1857,7 @@ describe('TextEditorComponent', () => { describe('scrolling via the API', () => { it('ignores scroll requests to NaN, null or undefined positions', async () => { - const { component, element, editor } = buildComponent({ + const { component } = buildComponent({ rowsPerTile: 2, autoHeight: false }) @@ -1901,7 +1894,7 @@ describe('TextEditorComponent', () => { describe('line and line number decorations', () => { it('adds decoration classes on screen lines spanned by decorated markers', async () => { - const { component, element, editor } = buildComponent({ + const { component, editor } = buildComponent({ softWrapped: true }) await setEditorWidthInCharacters(component, 55) @@ -1914,10 +1907,10 @@ describe('TextEditorComponent', () => { const marker1 = editor.markScreenRange([[1, 10], [3, 10]]) const layer = editor.addMarkerLayer() - const marker2 = layer.markScreenPosition([5, 0]) - const marker3 = layer.markScreenPosition([8, 0]) + layer.markScreenPosition([5, 0]) + layer.markScreenPosition([8, 0]) const marker4 = layer.markScreenPosition([10, 0]) - const markerDecoration = editor.decorateMarker(marker1, { + editor.decorateMarker(marker1, { type: ['line', 'line-number'], class: 'a' }) @@ -2048,7 +2041,7 @@ describe('TextEditorComponent', () => { }) it('honors the onlyEmpty and onlyNonEmpty decoration options', async () => { - const { component, element, editor } = buildComponent() + const { component, editor } = buildComponent() const marker = editor.markScreenPosition([1, 0]) editor.decorateMarker(marker, { type: ['line', 'line-number'], @@ -2121,7 +2114,7 @@ describe('TextEditorComponent', () => { }) it('honors the onlyHead option', async () => { - const { component, element, editor } = buildComponent() + const { component, editor } = buildComponent() const marker = editor.markScreenRange([[1, 4], [3, 4]]) editor.decorateMarker(marker, { type: ['line', 'line-number'], @@ -2145,7 +2138,7 @@ describe('TextEditorComponent', () => { }) it('only decorates the last row of non-empty ranges that end at column 0 if omitEmptyLastRow is false', async () => { - const { component, element, editor } = buildComponent() + const { component, editor } = buildComponent() const marker = editor.markScreenRange([[1, 0], [3, 0]]) editor.decorateMarker(marker, { type: ['line', 'line-number'], @@ -2180,7 +2173,7 @@ describe('TextEditorComponent', () => { }) it('does not decorate invalidated markers', async () => { - const { component, element, editor } = buildComponent() + const { component, editor } = buildComponent() const marker = editor.markScreenRange([[1, 0], [3, 0]], { invalidate: 'touch' }) @@ -2533,7 +2526,7 @@ describe('TextEditorComponent', () => { } it('renders overlay elements at the specified screen position unless it would overflow the window', async () => { - const { component, element, editor } = buildComponent({ + const { component, editor } = buildComponent({ width: 200, height: 100, attach: false @@ -2634,7 +2627,7 @@ describe('TextEditorComponent', () => { }) it('does not attempt to avoid overflowing the window if `avoidOverflow` is false on the decoration', async () => { - const { component, element, editor } = buildComponent({ + const { component, editor } = buildComponent({ width: 200, height: 100, attach: false @@ -2646,7 +2639,7 @@ describe('TextEditorComponent', () => { overlayElement.style.margin = '3px' overlayElement.style.backgroundColor = 'red' const marker = editor.markScreenPosition([4, 25]) - const decoration = editor.decorateMarker(marker, { + editor.decorateMarker(marker, { type: 'overlay', item: overlayElement, avoidOverflow: false @@ -2666,7 +2659,7 @@ describe('TextEditorComponent', () => { describe('custom gutter decorations', () => { it('arranges custom gutters based on their priority', async () => { - const { component, element, editor } = buildComponent() + const { component, editor } = buildComponent() editor.addGutter({ name: 'e', priority: 2 }) editor.addGutter({ name: 'a', priority: -2 }) editor.addGutter({ name: 'd', priority: 1 }) @@ -2683,7 +2676,7 @@ describe('TextEditorComponent', () => { }) it('adjusts the left edge of the scroll container based on changes to the gutter container width', async () => { - const { component, element, editor } = buildComponent() + const { component, editor } = buildComponent() const { scrollContainer, gutterContainer } = component.refs function checkScrollContainerLeft () { @@ -2740,7 +2733,7 @@ describe('TextEditorComponent', () => { }) it('can show and hide custom gutters', async () => { - const { component, element, editor } = buildComponent() + const { component, editor } = buildComponent() const gutterA = editor.addGutter({ name: 'a', priority: -1 }) const gutterB = editor.addGutter({ name: 'b', priority: 1 }) const gutterAElement = gutterA.getElement() @@ -2978,25 +2971,16 @@ describe('TextEditorComponent', () => { height: 33, position: 'before' }) - const { - item: item4, - decoration: decoration4 - } = createBlockDecorationAtScreenRow(editor, 7, { + const { item: item4 } = createBlockDecorationAtScreenRow(editor, 7, { height: 44, position: 'before' }) - const { - item: item5, - decoration: decoration5 - } = createBlockDecorationAtScreenRow(editor, 7, { + const { item: item5 } = createBlockDecorationAtScreenRow(editor, 7, { height: 50, marginBottom: 5, position: 'after' }) - const { - item: item6, - decoration: decoration6 - } = createBlockDecorationAtScreenRow(editor, 12, { + const { item: item6 } = createBlockDecorationAtScreenRow(editor, 12, { height: 60, marginTop: 6, position: 'after' @@ -3343,7 +3327,7 @@ describe('TextEditorComponent', () => { }) it('correctly positions line numbers when block decorations are located at tile boundaries', async () => { - const { editor, component, element } = buildComponent({ rowsPerTile: 3 }) + const { editor, component } = buildComponent({ rowsPerTile: 3 }) createBlockDecorationAtScreenRow(editor, 0, { height: 5, position: 'before' @@ -3378,7 +3362,7 @@ describe('TextEditorComponent', () => { }) it('removes block decorations whose markers have been destroyed', async () => { - const { editor, component, element } = buildComponent({ rowsPerTile: 3 }) + const { editor, component } = buildComponent({ rowsPerTile: 3 }) const { marker } = createBlockDecorationAtScreenRow(editor, 2, { height: 5, position: 'before' @@ -3408,7 +3392,7 @@ describe('TextEditorComponent', () => { 3, { height: 44, position: 'before', invalidate: 'touch' } ) - const { component, element } = buildComponent({ editor, rowsPerTile: 3 }) + const { component } = buildComponent({ editor, rowsPerTile: 3 }) // Invalidating the marker removes the block decoration. editor.getBuffer().deleteRows(2, 3) @@ -3460,7 +3444,7 @@ describe('TextEditorComponent', () => { it('does not render block decorations when decorating invalid markers', async () => { const editor = buildEditor({ rowsPerTile: 3, autoHeight: false }) - const { component, element } = buildComponent({ editor, rowsPerTile: 3 }) + const { component } = buildComponent({ editor, rowsPerTile: 3 }) const marker = editor.markScreenPosition([3, 0], { invalidate: 'touch' }) const item = document.createElement('div') @@ -3468,7 +3452,7 @@ describe('TextEditorComponent', () => { item.style.width = 30 + 'px' editor.getBuffer().deleteRows(1, 4) - const decoration = editor.decorateMarker(marker, { + editor.decorateMarker(marker, { type: 'block', item, position: 'before' @@ -3498,12 +3482,11 @@ describe('TextEditorComponent', () => { it('does not try to remeasure block decorations whose markers are invalid (regression)', async () => { const editor = buildEditor({ rowsPerTile: 3, autoHeight: false }) - const { component, element } = buildComponent({ editor, rowsPerTile: 3 }) - const { decoration, marker } = createBlockDecorationAtScreenRow( - editor, - 2, - { height: '12px', invalidate: 'touch' } - ) + const { component } = buildComponent({ editor, rowsPerTile: 3 }) + createBlockDecorationAtScreenRow(editor, 2, { + height: '12px', + invalidate: 'touch' + }) editor.getBuffer().deleteRows(0, 3) await component.getNextUpdatePromise() @@ -3579,7 +3562,7 @@ describe('TextEditorComponent', () => { const marker = editor.markScreenPosition([0, 0]) const item = document.createElement('div') item.textContent = 'block decoration' - const decoration = editor.decorateMarker(marker, { + editor.decorateMarker(marker, { type: 'block', item }) @@ -3596,7 +3579,7 @@ describe('TextEditorComponent', () => { const marker = editor.markScreenPosition([0, 0]) const item = document.createElement('div') item.textContent = 'block decoration that could wrap many times' - const decoration = editor.decorateMarker(marker, { + editor.decorateMarker(marker, { type: 'block', item }) @@ -3685,7 +3668,7 @@ describe('TextEditorComponent', () => { return lists }, [[], []]) - const [afterItems, afterDecorations] = [undefined, 1, 6, undefined, 6, 2] + const [afterItems] = [undefined, 1, 6, undefined, 6, 2] .map(order => { return createBlockDecorationAtScreenRow(editor, 2, { height: 10, @@ -3986,7 +3969,7 @@ describe('TextEditorComponent', () => { }) it('does not create empty text nodes when a text decoration ends right after a text tag', async () => { - const { component, element, editor } = buildComponent() + const { component, editor } = buildComponent() const marker = editor.markBufferRange([[0, 8], [0, 29]]) editor.decorateMarker(marker, { type: 'text', class: 'a' }) await component.getNextUpdatePromise() @@ -4009,7 +3992,7 @@ describe('TextEditorComponent', () => { describe('when there is only one cursor', () => { it('positions the cursor on single-click or when middle-clicking', async () => { for (const button of [0, 1]) { - const { component, element, editor } = buildComponent() + const { component, editor } = buildComponent() const { lineHeight } = component.measurements editor.setCursorScreenPosition([Infinity, Infinity], { @@ -4319,7 +4302,7 @@ describe('TextEditorComponent', () => { }) it('expands the last selection on shift-click', () => { - const { component, element, editor } = buildComponent() + const { component, editor } = buildComponent() editor.setCursorScreenPosition([2, 18], { autoscroll: false }) component.didMouseDownOnContent( @@ -4493,8 +4476,7 @@ describe('TextEditorComponent', () => { ) const { - didDrag, - didStopDragging + didDrag } = component.handleMouseDragUntilMouseUp.argsForCall[1][0] didDrag(clientPositionForCharacter(component, 0, 8)) expect(editor.getSelectedScreenRange()).toEqual([[0, 4], [1, 5]]) @@ -4522,8 +4504,7 @@ describe('TextEditorComponent', () => { ) const { - didDrag, - didStopDragging + didDrag } = component.handleMouseDragUntilMouseUp.argsForCall[2][0] didDrag(clientPositionForCharacter(component, 1, 8)) expect(editor.getSelectedScreenRange()).toEqual([[1, 0], [3, 0]]) @@ -4554,7 +4535,7 @@ describe('TextEditorComponent', () => { }) it('autoscrolls the content when dragging near the edge of the scroll container', async () => { - const { component, element, editor } = buildComponent({ + const { component } = buildComponent({ width: 200, height: 200 }) @@ -4585,8 +4566,7 @@ describe('TextEditorComponent', () => { clientY: 100 }) const { - didDrag, - didStopDragging + didDrag } = component.handleMouseDragUntilMouseUp.argsForCall[0][0] didDrag({ clientX: 199, clientY: 199 }) @@ -4914,11 +4894,10 @@ describe('TextEditorComponent', () => { }) it('autoscrolls when dragging near the top or bottom of the gutter', async () => { - const { component, editor } = buildComponent({ + const { component } = buildComponent({ width: 200, height: 200 }) - const { scrollContainer } = component.refs spyOn(component, 'handleMouseDragUntilMouseUp') let previousScrollTop = 0 @@ -4944,8 +4923,7 @@ describe('TextEditorComponent', () => { clientY: 100 }) const { - didDrag, - didStopDragging + didDrag } = component.handleMouseDragUntilMouseUp.argsForCall[0][0] didDrag({ clientX: 199, clientY: 199 }) assertScrolledDown() @@ -4995,7 +4973,7 @@ describe('TextEditorComponent', () => { describe('on the scrollbars', () => { it('delegates the mousedown events to the parent component unless the mousedown was on the actual scrollbar', async () => { - const { component, element, editor } = buildComponent({ height: 100 }) + const { component, editor } = buildComponent({ height: 100 }) await setEditorWidthInCharacters(component, 6) const verticalScrollbar = component.refs.verticalScrollbar @@ -5055,7 +5033,7 @@ describe('TextEditorComponent', () => { describe('keyboard input', () => { it('handles inserted accented characters via the press-and-hold menu on macOS correctly', () => { - const { editor, component, element } = buildComponent({ + const { editor, component } = buildComponent({ text: '', chromeVersion: 57 }) @@ -5417,7 +5395,7 @@ describe('TextEditorComponent', () => { }) it('maintains the scrollTopRow and scrollLeftColumn when the font size changes', async () => { - const { component, element, editor } = buildComponent({ + const { component, element } = buildComponent({ rowsPerTile: 1, autoHeight: false }) @@ -5440,7 +5418,7 @@ describe('TextEditorComponent', () => { }) it('gracefully handles the editor being hidden after a styling change', async () => { - const { component, element, editor } = buildComponent({ + const { component, element } = buildComponent({ autoHeight: false }) element.style.fontSize = @@ -5527,7 +5505,7 @@ describe('TextEditorComponent', () => { }) it('does not throw an exception on attachment when setting the soft-wrap column', () => { - const { component, element, editor } = buildComponent({ + const { element, editor } = buildComponent({ width: 435, attach: false, updatedSynchronously: true @@ -5565,7 +5543,7 @@ describe('TextEditorComponent', () => { describe('pixelPositionForScreenPosition(point)', () => { it('returns the pixel position for the given point, regardless of whether or not it is currently on screen', async () => { - const { component, element, editor } = buildComponent({ + const { component, editor } = buildComponent({ rowsPerTile: 2, autoHeight: false }) @@ -5636,7 +5614,7 @@ describe('TextEditorComponent', () => { }) it('does not get the component into an inconsistent state when the model has unflushed changes (regression)', async () => { - const { component, element, editor } = buildComponent({ + const { component, editor } = buildComponent({ rowsPerTile: 2, autoHeight: false, text: '' @@ -5649,12 +5627,12 @@ describe('TextEditorComponent', () => { }) it('does not shift cursors downward or render off-screen content when measuring off-screen lines (regression)', async () => { - const { component, element, editor } = buildComponent({ + const { component, element } = buildComponent({ rowsPerTile: 2, autoHeight: false }) await setEditorHeightInLines(component, 3) - const { top, left } = component.pixelPositionForScreenPosition({ + component.pixelPositionForScreenPosition({ row: 12, column: 1 }) @@ -5679,7 +5657,7 @@ describe('TextEditorComponent', () => { describe('screenPositionForPixelPosition', () => { it('returns the screen position for the given pixel position, regardless of whether or not it is currently on screen', async () => { - const { component, element, editor } = buildComponent({ + const { component, editor } = buildComponent({ rowsPerTile: 2, autoHeight: false }) @@ -5749,7 +5727,7 @@ describe('TextEditorComponent', () => { describe('model methods that delegate to the component / element', () => { it('delegates setHeight and getHeight to the component', async () => { - const { component, element, editor } = buildComponent({ + const { component, editor } = buildComponent({ autoHeight: false }) spyOn(Grim, 'deprecate') @@ -5763,7 +5741,7 @@ describe('TextEditorComponent', () => { }) it('delegates setWidth and getWidth to the component', async () => { - const { component, element, editor } = buildComponent() + const { component, editor } = buildComponent() spyOn(Grim, 'deprecate') expect(editor.getWidth()).toBe(component.getScrollContainerWidth()) expect(Grim.deprecate.callCount).toBe(1) @@ -6138,10 +6116,6 @@ function getElementHeight (element) { return height } -function getNextTickPromise () { - return new Promise(resolve => process.nextTick(resolve)) -} - function queryOnScreenLineNumberElements (element) { return Array.from(element.querySelectorAll('.line-number:not(.dummy)')) } diff --git a/spec/text-editor-element-spec.js b/spec/text-editor-element-spec.js index b22d2c782..941dba78e 100644 --- a/spec/text-editor-element-spec.js +++ b/spec/text-editor-element-spec.js @@ -1,12 +1,7 @@ const { it, - fit, - ffit, - fffit, - beforeEach, - afterEach, - conditionPromise, - timeoutPromise + + beforeEach } = require('./async-spec-helpers') const TextEditor = require('../src/text-editor') const TextEditorElement = require('../src/text-editor-element') diff --git a/spec/text-editor-registry-spec.js b/spec/text-editor-registry-spec.js index c6303e4fd..715762855 100644 --- a/spec/text-editor-registry-spec.js +++ b/spec/text-editor-registry-spec.js @@ -2,7 +2,7 @@ const TextEditorRegistry = require('../src/text-editor-registry') const TextEditor = require('../src/text-editor') const TextBuffer = require('text-buffer') const { Point, Range } = TextBuffer -const { it, fit, ffit, fffit } = require('./async-spec-helpers') +const { it } = require('./async-spec-helpers') const dedent = require('dedent') describe('TextEditorRegistry', function () { @@ -287,7 +287,6 @@ describe('TextEditorRegistry', function () { atom.grammars.assignLanguageMode(editor, 'source.js') atom.config.set('editor.tabType', 'auto') await initialPackageActivation - const languageMode = editor.getBuffer().getLanguageMode() editor.setText(dedent` { diff --git a/spec/text-editor-spec.js b/spec/text-editor-spec.js index 60c8076df..569c3e4cd 100644 --- a/spec/text-editor-spec.js +++ b/spec/text-editor-spec.js @@ -1,12 +1,8 @@ const { it, - fit, - ffit, - fffit, + beforeEach, - afterEach, - conditionPromise, - timeoutPromise + afterEach } = require('./async-spec-helpers') const fs = require('fs') @@ -384,7 +380,7 @@ describe('TextEditor', () => { it('merges multiple cursors', () => { editor.setCursorScreenPosition([0, 0]) editor.addCursorAtScreenPosition([0, 1]) - const [cursor1, cursor2] = editor.getCursors() + const [cursor1] = editor.getCursors() editor.setCursorScreenPosition([4, 7]) expect(editor.getCursors().length).toBe(1) expect(editor.getCursors()).toEqual([cursor1]) @@ -450,7 +446,7 @@ describe('TextEditor', () => { it('merges cursors when they overlap', () => { editor.addCursorAtScreenPosition([1, 0]) - const [cursor1, cursor2] = editor.getCursors() + const [cursor1] = editor.getCursors() editor.moveUp() expect(editor.getCursors()).toEqual([cursor1]) @@ -551,7 +547,7 @@ describe('TextEditor', () => { it('merges cursors when they overlap', () => { editor.setCursorScreenPosition([12, 2]) editor.addCursorAtScreenPosition([11, 2]) - const [cursor1, cursor2] = editor.getCursors() + const [cursor1] = editor.getCursors() editor.moveDown() expect(editor.getCursors()).toEqual([cursor1]) @@ -668,7 +664,7 @@ describe('TextEditor', () => { editor.setCursorScreenPosition([0, 0]) editor.addCursorAtScreenPosition([0, 1]) - const [cursor1, cursor2] = editor.getCursors() + const [cursor1] = editor.getCursors() editor.moveLeft() expect(editor.getCursors()).toEqual([cursor1]) expect(cursor1.getBufferPosition()).toEqual([0, 0]) @@ -754,7 +750,7 @@ describe('TextEditor', () => { it('merges cursors when they overlap', () => { editor.setCursorScreenPosition([12, 2]) editor.addCursorAtScreenPosition([12, 1]) - const [cursor1, cursor2] = editor.getCursors() + const [cursor1] = editor.getCursors() editor.moveRight() expect(editor.getCursors()).toEqual([cursor1]) @@ -1501,8 +1497,9 @@ describe('TextEditor', () => { describe('::getCursorScreenPositions()', () => { it('returns the cursor positions in the order they were added', () => { editor.foldBufferRow(4) - const cursor1 = editor.addCursorAtBufferPosition([8, 5]) - const cursor2 = editor.addCursorAtBufferPosition([3, 5]) + editor.addCursorAtBufferPosition([8, 5]) + editor.addCursorAtBufferPosition([3, 5]) + expect(editor.getCursorScreenPositions()).toEqual([ [0, 0], [5, 5], @@ -1643,7 +1640,7 @@ describe('TextEditor', () => { [[1, 10], [1, 20]], [[2, 15], [3, 25]] ]) - const [selection1, selection2, selection3] = editor.getSelections() + const [selection1] = editor.getSelections() editor.selectDown() expect(editor.getSelections()).toEqual([selection1]) @@ -1656,7 +1653,7 @@ describe('TextEditor', () => { [[[0, 9], [0, 13]], [[1, 10], [1, 20]]], { reversed: true } ) - const [selection1, selection2] = editor.getSelections() + const [selection1] = editor.getSelections() editor.selectUp() expect(editor.getSelections().length).toBe(1) @@ -1670,7 +1667,7 @@ describe('TextEditor', () => { [[[0, 9], [0, 13]], [[0, 13], [1, 20]]], { reversed: true } ) - const [selection1, selection2] = editor.getSelections() + const [selection1] = editor.getSelections() editor.selectLeft() expect(editor.getSelections()).toEqual([selection1]) @@ -1680,7 +1677,7 @@ describe('TextEditor', () => { it('merges selections when they intersect when moving right', () => { editor.setSelectedBufferRanges([[[0, 9], [0, 14]], [[0, 14], [1, 20]]]) - const [selection1, selection2] = editor.getSelections() + const [selection1] = editor.getSelections() editor.selectRight() expect(editor.getSelections()).toEqual([selection1]) @@ -2310,7 +2307,7 @@ describe('TextEditor', () => { selection = editor.getLastSelection() editor.setSelectedBufferRanges([[[2, 2], [3, 3]], [[4, 4], [5, 5]]]) - const [selection1, selection2] = editor.getSelections() + const [selection1] = editor.getSelections() expect(selection1).toBe(selection) expect(selection1.getBufferRange()).toEqual([[2, 2], [3, 3]]) }) @@ -2374,7 +2371,7 @@ describe('TextEditor', () => { selection = editor.getLastSelection() editor.setSelectedScreenRanges([[[2, 2], [3, 4]], [[4, 4], [5, 5]]]) - const [selection1, selection2] = editor.getSelections() + const [selection1] = editor.getSelections() expect(selection1).toBe(selection) expect(selection1.getScreenRange()).toEqual([[2, 2], [3, 4]]) }) @@ -4724,8 +4721,6 @@ describe('TextEditor', () => { it('deletes as normal', () => { editor.foldBufferRow(4) editor.setCursorScreenPosition([3, 4]) - const cursorPositionBefore = editor.getCursorScreenPosition() - editor.delete() expect(buffer.lineForRow(3)).toBe( @@ -5236,19 +5231,6 @@ describe('TextEditor', () => { }) describe('.pasteText()', () => { - const copyText = function (text, { startColumn, textEditor } = {}) { - if (startColumn == null) startColumn = 0 - if (textEditor == null) textEditor = editor - textEditor.setCursorBufferPosition([0, 0]) - textEditor.insertText(text) - const numberOfNewlines = text.match(/\n/g).length - const endColumn = text.match(/[^\n]*$/)[0].length - textEditor - .getLastSelection() - .setBufferRange([[0, startColumn], [numberOfNewlines, endColumn]]) - return textEditor.cutSelectedText() - } - it('pastes text into the buffer', () => { editor.setSelectedBufferRanges([[[0, 4], [0, 13]], [[1, 6], [1, 10]]]) atom.clipboard.write('first') @@ -5854,7 +5836,6 @@ describe('TextEditor', () => { editor.delete() editor.delete() - const selections = editor.getSelections() expect(buffer.lineForRow(1)).toBe(' var = function( {') expect(editor.getSelectedBufferRanges()).toEqual([ @@ -6108,7 +6089,7 @@ describe('TextEditor', () => { editor.addCursorAtScreenPosition([0, 2]) editor.addCursorAtScreenPosition([1, 2]) - const [cursor1, cursor2, cursor3] = editor.getCursors() + const [cursor1, , cursor3] = editor.getCursors() expect(editor.getCursors().length).toBe(3) buffer.delete([[0, 0], [0, 2]]) @@ -7874,11 +7855,8 @@ describe('TextEditor', () => { it("does not throw errors after the marker's containing layer is destroyed", () => { const layer = editor.addMarkerLayer() - const marker = layer.markBufferRange([[2, 4], [6, 8]]) - const decoration = editor.decorateMarker(marker, { - type: 'highlight', - class: 'foo' - }) + layer.markBufferRange([[2, 4], [6, 8]]) + layer.destroy() editor.decorationsStateForScreenRowRange(0, 5) }) diff --git a/spec/text-mate-language-mode-spec.js b/spec/text-mate-language-mode-spec.js index 3b1aae9b5..be713ec78 100644 --- a/spec/text-mate-language-mode-spec.js +++ b/spec/text-mate-language-mode-spec.js @@ -1,17 +1,10 @@ const NullGrammar = require('../src/null-grammar') const TextMateLanguageMode = require('../src/text-mate-language-mode') const TextBuffer = require('text-buffer') -const { Point, Range } = TextBuffer +const { Point } = TextBuffer const _ = require('underscore-plus') const dedent = require('dedent') -const { - it, - fit, - ffit, - fffit, - beforeEach, - afterEach -} = require('./async-spec-helpers') +const { it, beforeEach, afterEach } = require('./async-spec-helpers') describe('TextMateLanguageMode', () => { let languageMode, buffer, config diff --git a/spec/tree-sitter-language-mode-spec.js b/spec/tree-sitter-language-mode-spec.js index e4b41b994..749544f17 100644 --- a/spec/tree-sitter-language-mode-spec.js +++ b/spec/tree-sitter-language-mode-spec.js @@ -1,11 +1,4 @@ -const { - it, - fit, - ffit, - fffit, - beforeEach, - afterEach -} = require('./async-spec-helpers') +const { it, beforeEach, afterEach } = require('./async-spec-helpers') const fs = require('fs') const path = require('path') diff --git a/spec/update-process-env-spec.js b/spec/update-process-env-spec.js index db702bd5b..54b6a9038 100644 --- a/spec/update-process-env-spec.js +++ b/spec/update-process-env-spec.js @@ -1,14 +1,7 @@ /** @babel */ /* eslint-env jasmine */ -import { - it, - fit, - ffit, - fffit, - beforeEach, - afterEach -} from './async-spec-helpers' +import { it, beforeEach, afterEach } from './async-spec-helpers' import path from 'path' import childProcess from 'child_process' import { @@ -16,7 +9,6 @@ import { shouldGetEnvFromShell } from '../src/update-process-env' import dedent from 'dedent' -import { EventEmitter } from 'events' import mockSpawn from 'mock-spawn' const temp = require('temp').track() diff --git a/spec/workspace-center-spec.js b/spec/workspace-center-spec.js index 055b463db..681074557 100644 --- a/spec/workspace-center-spec.js +++ b/spec/workspace-center-spec.js @@ -2,14 +2,7 @@ const TextEditor = require('../src/text-editor') -import { - it, - fit, - ffit, - fffit, - beforeEach, - afterEach -} from './async-spec-helpers' +import { it } from './async-spec-helpers' describe('WorkspaceCenter', () => { describe('.observeTextEditors()', () => { diff --git a/spec/workspace-element-spec.js b/spec/workspace-element-spec.js index b11e8b443..d3d6e0fd5 100644 --- a/spec/workspace-element-spec.js +++ b/spec/workspace-element-spec.js @@ -5,14 +5,7 @@ const etch = require('etch') const path = require('path') const temp = require('temp').track() const { Disposable } = require('event-kit') -const { - it, - fit, - ffit, - fffit, - beforeEach, - afterEach -} = require('./async-spec-helpers') +const { it, beforeEach, afterEach } = require('./async-spec-helpers') const getNextUpdatePromise = () => etch.getScheduler().nextUpdatePromise @@ -62,7 +55,6 @@ describe('WorkspaceElement', () => { pane6, pane7, pane8, - pane9, leftDockPane, rightDockPane, bottomDockPane, @@ -104,7 +96,7 @@ describe('WorkspaceElement', () => { pane6 = pane5.splitRight() pane8 = pane7.splitRight() - pane9 = pane8.splitRight() + pane8.splitRight() const leftDock = workspace.getLeftDock() const rightDock = workspace.getRightDock() diff --git a/spec/workspace-spec.js b/spec/workspace-spec.js index 265ae2ba9..cba8db6cf 100644 --- a/spec/workspace-spec.js +++ b/spec/workspace-spec.js @@ -12,9 +12,6 @@ const fs = require('fs-plus') const AtomEnvironment = require('../src/atom-environment') const { it, - fit, - ffit, - fffit, beforeEach, afterEach, conditionPromise @@ -1844,9 +1841,6 @@ describe('Workspace', () => { workspace.observeActiveTextEditor(editor => observed.push(editor)) const editorAddedAfterRegisteringObserver = new TextEditor() - const nonEditorItemAddedAfterRegisteringObserver = document.createElement( - 'div' - ) pane.activateItem(editorAddedAfterRegisteringObserver) expect(observed).toEqual([ @@ -1904,7 +1898,7 @@ describe('Workspace', () => { const nonEditorItem1 = document.createElement('div') const nonEditorItem2 = document.createElement('div') pane.activateItem(nonEditorItem1) - pane.activateItem(nonEditorItem1) + pane.activateItem(nonEditorItem2) expect(observed).toEqual([]) }) From cd302135f0a19c6f3d03dd555d228556f523c741 Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Fri, 22 Feb 2019 11:44:30 +0100 Subject: [PATCH 104/112] Fix undefined variables from specs --- spec/atom-environment-spec.js | 10 +++++----- spec/atom-paths-spec.js | 1 + spec/main-process/file-recovery-service.test.js | 1 + spec/main-process/parse-command-line.test.js | 1 + spec/reopen-project-menu-manager-spec.js | 9 +++++---- spec/text-editor-element-spec.js | 2 +- spec/text-mate-language-mode-spec.js | 8 ++++++-- spec/workspace-element-spec.js | 3 ++- spec/workspace-spec.js | 4 ++-- 9 files changed, 24 insertions(+), 15 deletions(-) diff --git a/spec/atom-environment-spec.js b/spec/atom-environment-spec.js index a032b8eb2..9fb6a1999 100644 --- a/spec/atom-environment-spec.js +++ b/spec/atom-environment-spec.js @@ -71,9 +71,9 @@ describe('AtomEnvironment', () => { it('will open the dev tools when an error is triggered', async () => { try { - a + 1 // eslint-ignore-line no-unused-vars + a + 1 // eslint-disable-line no-undef } catch (e) { - window.onerror.call(window, e.toString(), 'abc', 2, 3, e) + window.onerror(e.toString(), 'abc', 2, 3, e) } await devToolsPromise @@ -92,7 +92,7 @@ describe('AtomEnvironment', () => { let error = null atom.onWillThrowError(willThrowSpy) try { - a + 1 + a + 1 // eslint-disable-line no-undef } catch (e) { error = e window.onerror.call(window, e.toString(), 'abc', 2, 3, e) @@ -113,7 +113,7 @@ describe('AtomEnvironment', () => { atom.onWillThrowError(willThrowSpy) try { - a + 1 + a + 1 // eslint-disable-line no-undef } catch (e) { window.onerror.call(window, e.toString(), 'abc', 2, 3, e) } @@ -132,7 +132,7 @@ describe('AtomEnvironment', () => { let error = null atom.onDidThrowError(didThrowSpy) try { - a + 1 + a + 1 // eslint-disable-line no-undef } catch (e) { error = e window.onerror.call(window, e.toString(), 'abc', 2, 3, e) diff --git a/spec/atom-paths-spec.js b/spec/atom-paths-spec.js index b7644e7cd..b7e489aef 100644 --- a/spec/atom-paths-spec.js +++ b/spec/atom-paths-spec.js @@ -73,6 +73,7 @@ describe('AtomPaths', () => { }) describe('setUserData', () => { + let tempAtomConfigPath = null let tempAtomHomePath = null let electronUserDataPath = null let defaultElectronUserDataPath = null diff --git a/spec/main-process/file-recovery-service.test.js b/spec/main-process/file-recovery-service.test.js index 25484f6c2..c47ffb944 100644 --- a/spec/main-process/file-recovery-service.test.js +++ b/spec/main-process/file-recovery-service.test.js @@ -3,6 +3,7 @@ const FileRecoveryService = require('../../src/main-process/file-recovery-servic const fs = require('fs-plus') const fsreal = require('fs') const EventEmitter = require('events').EventEmitter +const { assert } = require('chai') const sinon = require('sinon') const { escapeRegExp } = require('underscore-plus') const temp = require('temp').track() diff --git a/spec/main-process/parse-command-line.test.js b/spec/main-process/parse-command-line.test.js index 2fcece469..6b5ac3ba5 100644 --- a/spec/main-process/parse-command-line.test.js +++ b/spec/main-process/parse-command-line.test.js @@ -1,3 +1,4 @@ +const { assert } = require('chai') const parseCommandLine = require('../../src/main-process/parse-command-line') describe('parseCommandLine', () => { diff --git a/spec/reopen-project-menu-manager-spec.js b/spec/reopen-project-menu-manager-spec.js index f5745bc76..442c1a0e5 100644 --- a/spec/reopen-project-menu-manager-spec.js +++ b/spec/reopen-project-menu-manager-spec.js @@ -5,7 +5,7 @@ import { Disposable } from 'event-kit' const ReopenProjectMenuManager = require('../src/reopen-project-menu-manager') -numberRange = (low, high) => { +function numberRange (low, high) { const size = high - low const result = new Array(size) for (var i = 0; i < size; i++) result[i] = low + i @@ -15,6 +15,7 @@ numberRange = (low, high) => { describe('ReopenProjectMenuManager', () => { let menuManager, commandRegistry, config, historyManager, reopenProjects let commandDisposable, configDisposable, historyDisposable + let openFunction beforeEach(() => { menuManager = jasmine.createSpyObj('MenuManager', ['add']) @@ -92,7 +93,7 @@ describe('ReopenProjectMenuManager', () => { ]) reopenProjects.update() - reopenProjectCommand = + const reopenProjectCommand = commandRegistry.add.calls[0].args[1]['application:reopen-project'] reopenProjectCommand({ detail: { index: 1 } }) @@ -101,7 +102,7 @@ describe('ReopenProjectMenuManager', () => { }) it('does not call open when no command detail is supplied', () => { - reopenProjectCommand = + const reopenProjectCommand = commandRegistry.add.calls[0].args[1]['application:reopen-project'] reopenProjectCommand({}) @@ -109,7 +110,7 @@ describe('ReopenProjectMenuManager', () => { }) it('does not call open when no command detail index is supplied', () => { - reopenProjectCommand = + const reopenProjectCommand = commandRegistry.add.calls[0].args[1]['application:reopen-project'] reopenProjectCommand({ detail: { anything: 'here' } }) diff --git a/spec/text-editor-element-spec.js b/spec/text-editor-element-spec.js index 941dba78e..758384f9e 100644 --- a/spec/text-editor-element-spec.js +++ b/spec/text-editor-element-spec.js @@ -370,7 +370,7 @@ describe('TextEditorElement', () => { describe('::setScrollTop and ::setScrollLeft', () => { it('changes the scroll position', async () => { - element = buildTextEditorElement() + const element = buildTextEditorElement() element.getModel().update({ autoHeight: false }) element.getModel().setText('lorem\nipsum\ndolor\nsit\namet') element.setHeight(20) diff --git a/spec/text-mate-language-mode-spec.js b/spec/text-mate-language-mode-spec.js index be713ec78..eedb4b63d 100644 --- a/spec/text-mate-language-mode-spec.js +++ b/spec/text-mate-language-mode-spec.js @@ -1038,6 +1038,8 @@ describe('TextMateLanguageMode', () => { }) describe('.isFoldableAtRow(row)', () => { + let editor + beforeEach(() => { buffer = atom.project.bufferForPathSync('sample.js') buffer.insert([10, 0], ' // multi-line\n // comment\n // block\n') @@ -1145,6 +1147,8 @@ describe('TextMateLanguageMode', () => { }) describe('.getFoldableRangesAtIndentLevel', () => { + let editor + it('returns the ranges that can be folded at the given indent level', () => { buffer = new TextBuffer(dedent` if (a) { @@ -1258,7 +1262,7 @@ describe('TextMateLanguageMode', () => { it('works with multi-line comments', async () => { await atom.packages.activatePackage('language-javascript') - editor = await atom.workspace.open('sample-with-comments.js', { + const editor = await atom.workspace.open('sample-with-comments.js', { autoIndent: false }) fullyTokenize(editor.getBuffer().getLanguageMode()) @@ -1409,7 +1413,7 @@ describe('TextMateLanguageMode', () => { it('searches upward and downward for surrounding comment lines and folds them as a single fold', async () => { await atom.packages.activatePackage('language-javascript') - editor = await atom.workspace.open('sample-with-comments.js') + const editor = await atom.workspace.open('sample-with-comments.js') editor.buffer.insert( [1, 0], ' //this is a comment\n // and\n //more docs\n\n//second comment' diff --git a/spec/workspace-element-spec.js b/spec/workspace-element-spec.js index d3d6e0fd5..930fedeae 100644 --- a/spec/workspace-element-spec.js +++ b/spec/workspace-element-spec.js @@ -47,7 +47,8 @@ describe('WorkspaceElement', () => { }) describe('finding the nearest visible pane in a specific direction', () => { - let pane1, + let nearestPaneElement, + pane1, pane2, pane3, pane4, diff --git a/spec/workspace-spec.js b/spec/workspace-spec.js index cba8db6cf..c5e3ff668 100644 --- a/spec/workspace-spec.js +++ b/spec/workspace-spec.js @@ -1548,7 +1548,7 @@ describe('Workspace', () => { .getActivePane() .addItem(document.createElement('div')) - emittedItems = [] + const emittedItems = [] atom.workspace.onDidStopChangingActivePaneItem(item => emittedItems.push(item) ) @@ -1831,7 +1831,7 @@ describe('Workspace', () => { describe('::observeActiveTextEditor()', () => { it('invokes the observer with current active text editor and each time a different text editor becomes active', () => { const pane = workspace.getCenter().getActivePane() - observed = [] + const observed = [] const inactiveEditorBeforeRegisteringObserver = new TextEditor() const activeEditorBeforeRegisteringObserver = new TextEditor() From 6c46cf924355d0735123c6c932552271930b69b8 Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Fri, 22 Feb 2019 12:19:35 +0100 Subject: [PATCH 105/112] Fix remaining linter issues --- spec/atom-environment-spec.js | 14 ++++++------ spec/atom-paths-spec.js | 3 ++- spec/text-editor-component-spec.js | 30 +++++++++++++------------- spec/text-editor-registry-spec.js | 4 ++++ spec/text-editor-spec.js | 2 +- spec/text-mate-language-mode-spec.js | 1 - spec/theme-manager-spec.js | 4 +--- spec/tree-sitter-language-mode-spec.js | 8 ++++--- 8 files changed, 35 insertions(+), 31 deletions(-) diff --git a/spec/atom-environment-spec.js b/spec/atom-environment-spec.js index 9fb6a1999..6b83035d9 100644 --- a/spec/atom-environment-spec.js +++ b/spec/atom-environment-spec.js @@ -95,7 +95,7 @@ describe('AtomEnvironment', () => { a + 1 // eslint-disable-line no-undef } catch (e) { error = e - window.onerror.call(window, e.toString(), 'abc', 2, 3, e) + window.onerror(e.toString(), 'abc', 2, 3, e) } delete willThrowSpy.mostRecentCall.args[0].preventDefault @@ -115,7 +115,7 @@ describe('AtomEnvironment', () => { try { a + 1 // eslint-disable-line no-undef } catch (e) { - window.onerror.call(window, e.toString(), 'abc', 2, 3, e) + window.onerror(e.toString(), 'abc', 2, 3, e) } expect(willThrowSpy).toHaveBeenCalled() @@ -135,7 +135,7 @@ describe('AtomEnvironment', () => { a + 1 // eslint-disable-line no-undef } catch (e) { error = e - window.onerror.call(window, e.toString(), 'abc', 2, 3, e) + window.onerror(e.toString(), 'abc', 2, 3, e) } expect(didThrowSpy).toHaveBeenCalledWith({ message: error.toString(), @@ -678,12 +678,12 @@ describe('AtomEnvironment', () => { let atomEnvironment, envLoaded, spy beforeEach(() => { - let resolve = null - const promise = new Promise(r => { - resolve = r + let resolvePromise = null + const promise = new Promise(resolve => { + resolvePromise = resolve }) envLoaded = () => { - resolve() + resolvePromise() return promise } atomEnvironment = new AtomEnvironment({ diff --git a/spec/atom-paths-spec.js b/spec/atom-paths-spec.js index b7e489aef..0b2a8cdf9 100644 --- a/spec/atom-paths-spec.js +++ b/spec/atom-paths-spec.js @@ -22,8 +22,9 @@ describe('AtomPaths', () => { describe('when a portable .atom folder exists', () => { beforeEach(() => { delete process.env.ATOM_HOME - if (!fs.existsSync(portableAtomHomePath)) + if (!fs.existsSync(portableAtomHomePath)) { fs.mkdirSync(portableAtomHomePath) + } }) afterEach(() => { diff --git a/spec/text-editor-component-spec.js b/spec/text-editor-component-spec.js index 42e243830..a1cd8d67e 100644 --- a/spec/text-editor-component-spec.js +++ b/spec/text-editor-component-spec.js @@ -173,21 +173,19 @@ describe('TextEditorComponent', () => { expect(actualWidth).toBe(expectedWidth + 'px') } - { - // Make sure we do not throw an error if a synchronous update is - // triggered before measuring the longest line from a - // previously-scheduled update. - editor.getBuffer().insert(Point(12, Infinity), 'x'.repeat(100)) - expect(editor.getLongestScreenRow()).toBe(12) + // Make sure we do not throw an error if a synchronous update is + // triggered before measuring the longest line from a + // previously-scheduled update. + editor.getBuffer().insert(Point(12, Infinity), 'x'.repeat(100)) + expect(editor.getLongestScreenRow()).toBe(12) - TextEditorComponent.getScheduler().readDocument(() => { - // This will happen before the measurement phase of the update - // triggered above. - component.pixelPositionForScreenPosition(Point(11, Infinity)) - }) + TextEditorComponent.getScheduler().readDocument(() => { + // This will happen before the measurement phase of the update + // triggered above. + component.pixelPositionForScreenPosition(Point(11, Infinity)) + }) - await component.getNextUpdatePromise() - } + await component.getNextUpdatePromise() }) it('re-renders lines when their height changes', async () => { @@ -1186,10 +1184,12 @@ describe('TextEditorComponent', () => { } else if (k < 95) { editor.setSelectedBufferRange(range) } else { - if (random(2)) + if (random(2)) { component.setScrollTop(random(component.getScrollHeight())) - if (random(2)) + } + if (random(2)) { component.setScrollLeft(random(component.getScrollWidth())) + } } component.scheduleUpdate() diff --git a/spec/text-editor-registry-spec.js b/spec/text-editor-registry-spec.js index 715762855..82afa3b0f 100644 --- a/spec/text-editor-registry-spec.js +++ b/spec/text-editor-registry-spec.js @@ -296,11 +296,13 @@ describe('TextEditorRegistry', function () { let disposable = registry.maintainConfig(editor) expect(editor.getSoftTabs()).toBe(true) + /* eslint-disable no-tabs */ editor.setText(dedent` { hello; } `) + /* eslint-enable no-tabs */ disposable.dispose() disposable = registry.maintainConfig(editor) expect(editor.getSoftTabs()).toBe(false) @@ -317,6 +319,7 @@ describe('TextEditorRegistry', function () { disposable = registry.maintainConfig(editor) expect(editor.getSoftTabs()).toBe(false) + /* eslint-disable no-tabs */ editor.setText(dedent` /* * Comment with a leading space. @@ -326,6 +329,7 @@ describe('TextEditorRegistry', function () { hello; } `) + /* eslint-enable no-tabs */ disposable.dispose() disposable = registry.maintainConfig(editor) expect(editor.getSoftTabs()).toBe(false) diff --git a/spec/text-editor-spec.js b/spec/text-editor-spec.js index 569c3e4cd..f70ec4a1e 100644 --- a/spec/text-editor-spec.js +++ b/spec/text-editor-spec.js @@ -4272,7 +4272,7 @@ describe('TextEditor', () => { await atom.packages.activatePackage('language-go') editor.update({ autoIndent: true }) atom.grammars.assignLanguageMode(editor, 'source.go') - editor.setText('fmt.Printf("some%s",\n "thing")') + editor.setText('fmt.Printf("some%s",\n "thing")') // eslint-disable-line no-tabs editor.setCursorBufferPosition([1, 10]) editor.insertNewline() expect(editor.indentationForBufferRow(1)).toBe(1) diff --git a/spec/text-mate-language-mode-spec.js b/spec/text-mate-language-mode-spec.js index eedb4b63d..6f60d527a 100644 --- a/spec/text-mate-language-mode-spec.js +++ b/spec/text-mate-language-mode-spec.js @@ -59,7 +59,6 @@ describe('TextMateLanguageMode', () => { languageMode = new TextMateLanguageMode({ buffer, config, - config, grammar: atom.grammars.grammarForScopeName('source.js') }) languageMode.startTokenizing() diff --git a/spec/theme-manager-spec.js b/spec/theme-manager-spec.js index 2de214921..2e4f74b50 100644 --- a/spec/theme-manager-spec.js +++ b/spec/theme-manager-spec.js @@ -498,9 +498,7 @@ h2 { expect(note.getType()).toBe('error') expect(note.getMessage()).toContain('Error loading') expect( - atom.styles.styleElementsBySourcePath[ - atom.styles.getUserStyleSheetPath() - ] + atom.styles.styleElementsBySourcePath[atom.styles.getUserStyleSheetPath()] ).toBeUndefined() }) }) diff --git a/spec/tree-sitter-language-mode-spec.js b/spec/tree-sitter-language-mode-spec.js index 749544f17..09f134cb0 100644 --- a/spec/tree-sitter-language-mode-spec.js +++ b/spec/tree-sitter-language-mode-spec.js @@ -1,3 +1,5 @@ +/* eslint-disable no-template-curly-in-string */ + const { it, beforeEach, afterEach } = require('./async-spec-helpers') const fs = require('fs') @@ -830,7 +832,7 @@ describe('TreeSitterLanguageMode', () => { buffer.getLanguageMode().syncOperationLimit = 0 const initialSeed = Date.now() - for (let i = 0, trial_count = 10; i < trial_count; i++) { + for (let i = 0, trialCount = 10; i < trialCount; i++) { let seed = initialSeed + i // seed = 1541201470759 const random = Random(seed) @@ -842,7 +844,7 @@ describe('TreeSitterLanguageMode', () => { editor.displayLayer.getScreenLines() // Make several random edits. - for (let j = 0, edit_count = 1 + random(4); j < edit_count; j++) { + for (let j = 0, editCount = 1 + random(4); j < editCount; j++) { const editRoll = random(10) const range = getRandomBufferRange(random, buffer) @@ -894,7 +896,7 @@ describe('TreeSitterLanguageMode', () => { if (jasmine.getEnv().currentSpec.results().failedCount > 0) { console.log(tokens1) console.log(tokens2) - debugger + debugger // eslint-disable-line no-debugger break } } From 8daaf3834eaa09e1b962d42984930e1bc8a357a8 Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Fri, 22 Feb 2019 12:19:52 +0100 Subject: [PATCH 106/112] Enable linter on spec/ folder --- script/lib/lint-java-script-paths.js | 45 +++++++++++++++++++--------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/script/lib/lint-java-script-paths.js b/script/lib/lint-java-script-paths.js index 64ff22610..35815f7ae 100644 --- a/script/lib/lint-java-script-paths.js +++ b/script/lib/lint-java-script-paths.js @@ -6,29 +6,46 @@ const path = require('path') const CONFIG = require('../config') -module.exports = function () { +module.exports = async function () { const globPathsToLint = [ path.join(CONFIG.repositoryRootPath, 'exports', '**', '*.js'), path.join(CONFIG.repositoryRootPath, 'packages', '**', '*.js'), path.join(CONFIG.repositoryRootPath, 'script', '**', '*.js'), + path.join(CONFIG.repositoryRootPath, 'spec', '**', '*.js'), path.join(CONFIG.repositoryRootPath, 'src', '**', '*.js'), path.join(CONFIG.repositoryRootPath, 'static', '*.js') ] - return expandGlobPaths(globPathsToLint).then((paths) => { - return new Promise((resolve, reject) => { - standard.lintFiles(paths, (error, lintOutput) => { - if (error) { - reject(error) - } else { - const errors = [] - for (let result of lintOutput.results) { - for (let message of result.messages) { - errors.push({path: result.filePath, lineNumber: message.line, message: message.message, rule: message.ruleId}) - } + const globPathsToIgnore = [ + path.join(CONFIG.repositoryRootPath, 'spec', 'fixtures', '**', '*.js') + ] + + const [includePaths, excludePaths] = await Promise.all([ + expandGlobPaths(globPathsToLint), + expandGlobPaths(globPathsToIgnore) + ]) + + const paths = includePaths.filter( + myPath => excludePaths.indexOf(myPath) === -1 + ) + + return new Promise((resolve, reject) => { + standard.lintFiles(paths, (error, lintOutput) => { + if (error) { + reject(error) + } else { + const errors = [] + for (let result of lintOutput.results) { + for (let message of result.messages) { + errors.push({ + path: result.filePath, + lineNumber: message.line, + message: message.message, + rule: message.ruleId + }) } - resolve(errors) } - }) + resolve(errors) + } }) }) } From ccfd761a06e2dc6ce44e0bffcbb08659a1de3f2c Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Fri, 22 Feb 2019 16:47:32 +0100 Subject: [PATCH 107/112] Fix linting issue after rebase --- spec/git-repository-provider-spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/git-repository-provider-spec.js b/spec/git-repository-provider-spec.js index 28e2f5eb8..b0ccec89c 100644 --- a/spec/git-repository-provider-spec.js +++ b/spec/git-repository-provider-spec.js @@ -158,7 +158,7 @@ describe('GitRepositoryProvider', () => { fs.writeFileSync(path.join(dirPath, '.git', 'refs'), '') const directory = new Directory(dirPath) - const repo = provider.repositoryForDirectorySync(directory) + const repo = provider.repositoryForDirectorySync(directory) expect(repo).toBe(null) }) }) From 55cdc398f6fdf680ed2b8738ba101e4064192b0b Mon Sep 17 00:00:00 2001 From: Landon Abney Date: Tue, 26 Feb 2019 19:00:44 +0100 Subject: [PATCH 108/112] Use `includes` instead of `indexOf` Co-Authored-By: rafeca --- script/lib/lint-java-script-paths.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/lib/lint-java-script-paths.js b/script/lib/lint-java-script-paths.js index 35815f7ae..f237820ff 100644 --- a/script/lib/lint-java-script-paths.js +++ b/script/lib/lint-java-script-paths.js @@ -25,7 +25,7 @@ module.exports = async function () { ]) const paths = includePaths.filter( - myPath => excludePaths.indexOf(myPath) === -1 + myPath => !excludePaths.includes(myPath) ) return new Promise((resolve, reject) => { From 2dd2c299b3b08ab7abeeb5482d9f664efb5517eb Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Wed, 27 Feb 2019 11:32:07 +0100 Subject: [PATCH 109/112] Keep unneeded block in TextEditor spec as it's a common pattern --- spec/text-editor-component-spec.js | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/spec/text-editor-component-spec.js b/spec/text-editor-component-spec.js index a1cd8d67e..4cef9f136 100644 --- a/spec/text-editor-component-spec.js +++ b/spec/text-editor-component-spec.js @@ -173,19 +173,22 @@ describe('TextEditorComponent', () => { expect(actualWidth).toBe(expectedWidth + 'px') } - // Make sure we do not throw an error if a synchronous update is - // triggered before measuring the longest line from a - // previously-scheduled update. - editor.getBuffer().insert(Point(12, Infinity), 'x'.repeat(100)) - expect(editor.getLongestScreenRow()).toBe(12) + // eslint-disable-next-line no-lone-blocks + { + // Make sure we do not throw an error if a synchronous update is + // triggered before measuring the longest line from a + // previously-scheduled update. + editor.getBuffer().insert(Point(12, Infinity), 'x'.repeat(100)) + expect(editor.getLongestScreenRow()).toBe(12) - TextEditorComponent.getScheduler().readDocument(() => { - // This will happen before the measurement phase of the update - // triggered above. - component.pixelPositionForScreenPosition(Point(11, Infinity)) - }) + TextEditorComponent.getScheduler().readDocument(() => { + // This will happen before the measurement phase of the update + // triggered above. + component.pixelPositionForScreenPosition(Point(11, Infinity)) + }) - await component.getNextUpdatePromise() + await component.getNextUpdatePromise() + } }) it('re-renders lines when their height changes', async () => { From a93808d1a85ee723f5f16f0d3c39e47a0f5fbfff Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Thu, 28 Feb 2019 20:39:21 +0100 Subject: [PATCH 110/112] Always use global it, beforeEach and afterEach methods --- packages/about/spec/about-spec.js | 2 -- packages/about/spec/about-status-bar-spec.js | 7 +------ packages/about/spec/update-view-spec.js | 1 - packages/dev-live-reload/spec/dev-live-reload-spec.js | 2 -- packages/dev-live-reload/spec/ui-watcher-spec.js | 7 +------ packages/grammar-selector/spec/grammar-selector-spec.js | 1 - packages/link/spec/link-spec.js | 2 -- spec/application-delegate-spec.js | 1 - spec/atom-environment-spec.js | 7 +------ spec/atom-paths-spec.js | 1 - spec/command-installer-spec.js | 5 ----- spec/command-registry-spec.js | 1 - spec/config-file-spec.js | 6 ------ spec/dock-spec.js | 1 - spec/git-repository-provider-spec.js | 1 - spec/git-repository-spec.js | 1 - spec/grammar-registry-spec.js | 2 -- spec/history-manager-spec.js | 2 -- spec/native-watcher-registry-spec.js | 2 -- spec/package-manager-spec.js | 1 - spec/package-transpilation-registry-spec.js | 2 -- spec/pane-container-spec.js | 5 ----- spec/pane-spec.js | 7 +------ spec/path-watcher-spec.js | 2 +- spec/reopen-project-menu-manager-spec.js | 1 - spec/state-store-spec.js | 1 - spec/text-editor-component-spec.js | 8 +------- spec/text-editor-element-spec.js | 5 ----- spec/text-editor-registry-spec.js | 1 - spec/text-editor-spec.js | 7 ------- spec/text-mate-language-mode-spec.js | 1 - spec/tree-sitter-language-mode-spec.js | 2 -- spec/update-process-env-spec.js | 2 -- spec/uri-handler-registry-spec.js | 2 -- spec/workspace-center-spec.js | 2 -- spec/workspace-element-spec.js | 1 - spec/workspace-spec.js | 7 +------ 37 files changed, 7 insertions(+), 102 deletions(-) diff --git a/packages/about/spec/about-spec.js b/packages/about/spec/about-spec.js index f3352e806..21aa4c5eb 100644 --- a/packages/about/spec/about-spec.js +++ b/packages/about/spec/about-spec.js @@ -1,5 +1,3 @@ -const { it, beforeEach } = require('./helpers/async-spec-helpers') - describe('About', () => { let workspaceElement diff --git a/packages/about/spec/about-status-bar-spec.js b/packages/about/spec/about-status-bar-spec.js index 4190674df..a67c0511c 100644 --- a/packages/about/spec/about-status-bar-spec.js +++ b/packages/about/spec/about-status-bar-spec.js @@ -1,9 +1,4 @@ -const { - it, - beforeEach, - afterEach, - conditionPromise -} = require('./helpers/async-spec-helpers') +const { conditionPromise } = require('./helpers/async-spec-helpers') const MockUpdater = require('./mocks/updater') describe('the status bar', () => { diff --git a/packages/about/spec/update-view-spec.js b/packages/about/spec/update-view-spec.js index 2f593b5bd..8e6587b59 100644 --- a/packages/about/spec/update-view-spec.js +++ b/packages/about/spec/update-view-spec.js @@ -1,5 +1,4 @@ const { shell } = require('electron') -const { it, beforeEach, afterEach } = require('./helpers/async-spec-helpers') const main = require('../lib/main') const AboutView = require('../lib/components/about-view') const UpdateView = require('../lib/components/update-view') diff --git a/packages/dev-live-reload/spec/dev-live-reload-spec.js b/packages/dev-live-reload/spec/dev-live-reload-spec.js index 99b7fe261..7351e0f99 100644 --- a/packages/dev-live-reload/spec/dev-live-reload-spec.js +++ b/packages/dev-live-reload/spec/dev-live-reload-spec.js @@ -1,5 +1,3 @@ -const { it, fit, ffit, afterEach, beforeEach } = require('./async-spec-helpers') // eslint-disable-line no-unused-vars - describe('Dev Live Reload', () => { describe('package activation', () => { let [pack, mainModule] = [] diff --git a/packages/dev-live-reload/spec/ui-watcher-spec.js b/packages/dev-live-reload/spec/ui-watcher-spec.js index ffce8034c..0027dd5c3 100644 --- a/packages/dev-live-reload/spec/ui-watcher-spec.js +++ b/packages/dev-live-reload/spec/ui-watcher-spec.js @@ -2,12 +2,7 @@ const path = require('path') const UIWatcher = require('../lib/ui-watcher') -const { - it, - afterEach, - beforeEach, - conditionPromise -} = require('./async-spec-helpers') +const { conditionPromise } = require('./async-spec-helpers') describe('UIWatcher', () => { let uiWatcher = null diff --git a/packages/grammar-selector/spec/grammar-selector-spec.js b/packages/grammar-selector/spec/grammar-selector-spec.js index 1c27d95a5..400fd6241 100644 --- a/packages/grammar-selector/spec/grammar-selector-spec.js +++ b/packages/grammar-selector/spec/grammar-selector-spec.js @@ -1,6 +1,5 @@ const path = require('path') const SelectListView = require('atom-select-list') -const { it, fit, ffit, beforeEach, afterEach } = require('./async-spec-helpers') // eslint-disable-line describe('GrammarSelector', () => { let [editor, textGrammar, jsGrammar] = [] diff --git a/packages/link/spec/link-spec.js b/packages/link/spec/link-spec.js index 0c0b817a2..e31d3f6ca 100644 --- a/packages/link/spec/link-spec.js +++ b/packages/link/spec/link-spec.js @@ -1,7 +1,5 @@ const { shell } = require('electron') -const { it, fit, ffit, afterEach, beforeEach } = require('./async-spec-helpers') // eslint-disable-line no-unused-vars - describe('link package', () => { beforeEach(async () => { await atom.packages.activatePackage('language-gfm') diff --git a/spec/application-delegate-spec.js b/spec/application-delegate-spec.js index abe86d92d..044e257b5 100644 --- a/spec/application-delegate-spec.js +++ b/spec/application-delegate-spec.js @@ -1,6 +1,5 @@ /** @babel */ -import { it } from './async-spec-helpers' import ApplicationDelegate from '../src/application-delegate' describe('ApplicationDelegate', function () { diff --git a/spec/atom-environment-spec.js b/spec/atom-environment-spec.js index 6b83035d9..537617d56 100644 --- a/spec/atom-environment-spec.js +++ b/spec/atom-environment-spec.js @@ -1,9 +1,4 @@ -const { - it, - beforeEach, - afterEach, - conditionPromise -} = require('./async-spec-helpers') +const { conditionPromise } = require('./async-spec-helpers') const fs = require('fs') const path = require('path') const temp = require('temp').track() diff --git a/spec/atom-paths-spec.js b/spec/atom-paths-spec.js index 0b2a8cdf9..cc4bb769b 100644 --- a/spec/atom-paths-spec.js +++ b/spec/atom-paths-spec.js @@ -1,6 +1,5 @@ /** @babel */ -import { it, beforeEach, afterEach } from './async-spec-helpers' import { app } from 'remote' import atomPaths from '../src/atom-paths' import fs from 'fs-plus' diff --git a/spec/command-installer-spec.js b/spec/command-installer-spec.js index fb114928f..1cf6af5c2 100644 --- a/spec/command-installer-spec.js +++ b/spec/command-installer-spec.js @@ -1,11 +1,6 @@ const path = require('path') const fs = require('fs-plus') const temp = require('temp').track() -const { - it, - beforeEach, - afterEach -} = require('./async-spec-helpers') const CommandInstaller = require('../src/command-installer') describe('CommandInstaller on #darwin', () => { diff --git a/spec/command-registry-spec.js b/spec/command-registry-spec.js index f49ebe942..597a72c35 100644 --- a/spec/command-registry-spec.js +++ b/spec/command-registry-spec.js @@ -1,6 +1,5 @@ const CommandRegistry = require('../src/command-registry') const _ = require('underscore-plus') -const { it, beforeEach, afterEach } = require('./async-spec-helpers') describe('CommandRegistry', () => { let registry, parent, child, grandchild diff --git a/spec/config-file-spec.js b/spec/config-file-spec.js index 1350853f5..d5ae98170 100644 --- a/spec/config-file-spec.js +++ b/spec/config-file-spec.js @@ -1,9 +1,3 @@ -const { - it, - - beforeEach, - afterEach -} = require('./async-spec-helpers') const fs = require('fs-plus') const path = require('path') const temp = require('temp').track() diff --git a/spec/dock-spec.js b/spec/dock-spec.js index d7bd5b1cb..8d2a0907c 100644 --- a/spec/dock-spec.js +++ b/spec/dock-spec.js @@ -2,7 +2,6 @@ const Grim = require('grim') -import { it } from './async-spec-helpers' import etch from 'etch' const getNextUpdatePromise = () => etch.getScheduler().nextUpdatePromise diff --git a/spec/git-repository-provider-spec.js b/spec/git-repository-provider-spec.js index b0ccec89c..5a4c4ba07 100644 --- a/spec/git-repository-provider-spec.js +++ b/spec/git-repository-provider-spec.js @@ -4,7 +4,6 @@ const temp = require('temp').track() const { Directory } = require('pathwatcher') const GitRepository = require('../src/git-repository') const GitRepositoryProvider = require('../src/git-repository-provider') -const { it, beforeEach } = require('./async-spec-helpers') describe('GitRepositoryProvider', () => { let provider diff --git a/spec/git-repository-spec.js b/spec/git-repository-spec.js index ade09da88..ed5699843 100644 --- a/spec/git-repository-spec.js +++ b/spec/git-repository-spec.js @@ -1,4 +1,3 @@ -const { it, beforeEach, afterEach } = require('./async-spec-helpers') const path = require('path') const fs = require('fs-plus') const temp = require('temp').track() diff --git a/spec/grammar-registry-spec.js b/spec/grammar-registry-spec.js index 729d52563..34cea04b5 100644 --- a/spec/grammar-registry-spec.js +++ b/spec/grammar-registry-spec.js @@ -1,5 +1,3 @@ -const { it, beforeEach, afterEach } = require('./async-spec-helpers') - const dedent = require('dedent') const path = require('path') const fs = require('fs-plus') diff --git a/spec/history-manager-spec.js b/spec/history-manager-spec.js index 5f7366118..bdf670425 100644 --- a/spec/history-manager-spec.js +++ b/spec/history-manager-spec.js @@ -1,5 +1,3 @@ -const { it, beforeEach, afterEach } = require('./async-spec-helpers') - const { HistoryManager, HistoryProject } = require('../src/history-manager') const StateStore = require('../src/state-store') diff --git a/spec/native-watcher-registry-spec.js b/spec/native-watcher-registry-spec.js index c83028c73..89f08d79e 100644 --- a/spec/native-watcher-registry-spec.js +++ b/spec/native-watcher-registry-spec.js @@ -1,7 +1,5 @@ /** @babel */ -import { it, beforeEach } from './async-spec-helpers' - import path from 'path' import { Emitter } from 'event-kit' diff --git a/spec/package-manager-spec.js b/spec/package-manager-spec.js index 6e67508b4..599fb0ff9 100644 --- a/spec/package-manager-spec.js +++ b/spec/package-manager-spec.js @@ -8,7 +8,6 @@ const { Disposable } = require('atom') const { buildKeydownEvent } = require('../src/keymap-extensions') const { mockLocalStorage } = require('./spec-helper') const ModuleCache = require('../src/module-cache') -const { it, beforeEach, afterEach } = require('./async-spec-helpers') describe('PackageManager', () => { function createTestElement (className) { diff --git a/spec/package-transpilation-registry-spec.js b/spec/package-transpilation-registry-spec.js index 32b3f375b..df2599db1 100644 --- a/spec/package-transpilation-registry-spec.js +++ b/spec/package-transpilation-registry-spec.js @@ -1,8 +1,6 @@ /** @babel */ import path from 'path' -import { it, beforeEach } from './async-spec-helpers' - import PackageTranspilationRegistry from '../src/package-transpilation-registry' const originalCompiler = { diff --git a/spec/pane-container-spec.js b/spec/pane-container-spec.js index 7450d870b..cd6da9939 100644 --- a/spec/pane-container-spec.js +++ b/spec/pane-container-spec.js @@ -1,9 +1,4 @@ const PaneContainer = require('../src/pane-container') -const { - it, - - beforeEach -} = require('./async-spec-helpers') describe('PaneContainer', () => { let confirm, params diff --git a/spec/pane-spec.js b/spec/pane-spec.js index 17fffaec7..c9ca0fb4b 100644 --- a/spec/pane-spec.js +++ b/spec/pane-spec.js @@ -3,12 +3,7 @@ const { Emitter } = require('event-kit') const Grim = require('grim') const Pane = require('../src/pane') const PaneContainer = require('../src/pane-container') -const { - it, - beforeEach, - conditionPromise, - timeoutPromise -} = require('./async-spec-helpers') +const { conditionPromise, timeoutPromise } = require('./async-spec-helpers') describe('Pane', () => { let confirm, showSaveDialog, deserializerDisposable diff --git a/spec/path-watcher-spec.js b/spec/path-watcher-spec.js index 050f9df45..f6fd2d098 100644 --- a/spec/path-watcher-spec.js +++ b/spec/path-watcher-spec.js @@ -1,6 +1,6 @@ /** @babel */ -import { it, beforeEach, afterEach, promisifySome } from './async-spec-helpers' +import { promisifySome } from './async-spec-helpers' import tempCb from 'temp' import fsCb from 'fs-plus' import path from 'path' diff --git a/spec/reopen-project-menu-manager-spec.js b/spec/reopen-project-menu-manager-spec.js index 442c1a0e5..f122eaa3b 100644 --- a/spec/reopen-project-menu-manager-spec.js +++ b/spec/reopen-project-menu-manager-spec.js @@ -1,6 +1,5 @@ /** @babel */ -import { it, beforeEach } from './async-spec-helpers' import { Disposable } from 'event-kit' const ReopenProjectMenuManager = require('../src/reopen-project-menu-manager') diff --git a/spec/state-store-spec.js b/spec/state-store-spec.js index d890877ab..7b206cdb2 100644 --- a/spec/state-store-spec.js +++ b/spec/state-store-spec.js @@ -1,5 +1,4 @@ /** @babel */ -import { it } from './async-spec-helpers' const StateStore = require('../src/state-store.js') diff --git a/spec/text-editor-component-spec.js b/spec/text-editor-component-spec.js index 4cef9f136..5529f8730 100644 --- a/spec/text-editor-component-spec.js +++ b/spec/text-editor-component-spec.js @@ -1,10 +1,4 @@ -const { - it, - - beforeEach, - afterEach, - conditionPromise -} = require('./async-spec-helpers') +const { conditionPromise } = require('./async-spec-helpers') const Random = require('../script/node_modules/random-seed') const { getRandomBufferRange, buildRandomLines } = require('./helpers/random') diff --git a/spec/text-editor-element-spec.js b/spec/text-editor-element-spec.js index 758384f9e..0d3f23c04 100644 --- a/spec/text-editor-element-spec.js +++ b/spec/text-editor-element-spec.js @@ -1,8 +1,3 @@ -const { - it, - - beforeEach -} = require('./async-spec-helpers') const TextEditor = require('../src/text-editor') const TextEditorElement = require('../src/text-editor-element') diff --git a/spec/text-editor-registry-spec.js b/spec/text-editor-registry-spec.js index 82afa3b0f..4175b863b 100644 --- a/spec/text-editor-registry-spec.js +++ b/spec/text-editor-registry-spec.js @@ -2,7 +2,6 @@ const TextEditorRegistry = require('../src/text-editor-registry') const TextEditor = require('../src/text-editor') const TextBuffer = require('text-buffer') const { Point, Range } = TextBuffer -const { it } = require('./async-spec-helpers') const dedent = require('dedent') describe('TextEditorRegistry', function () { diff --git a/spec/text-editor-spec.js b/spec/text-editor-spec.js index f70ec4a1e..4f4390561 100644 --- a/spec/text-editor-spec.js +++ b/spec/text-editor-spec.js @@ -1,10 +1,3 @@ -const { - it, - - beforeEach, - afterEach -} = require('./async-spec-helpers') - const fs = require('fs') const path = require('path') const temp = require('temp').track() diff --git a/spec/text-mate-language-mode-spec.js b/spec/text-mate-language-mode-spec.js index 6f60d527a..2fd155e6a 100644 --- a/spec/text-mate-language-mode-spec.js +++ b/spec/text-mate-language-mode-spec.js @@ -4,7 +4,6 @@ const TextBuffer = require('text-buffer') const { Point } = TextBuffer const _ = require('underscore-plus') const dedent = require('dedent') -const { it, beforeEach, afterEach } = require('./async-spec-helpers') describe('TextMateLanguageMode', () => { let languageMode, buffer, config diff --git a/spec/tree-sitter-language-mode-spec.js b/spec/tree-sitter-language-mode-spec.js index 09f134cb0..7cc210c40 100644 --- a/spec/tree-sitter-language-mode-spec.js +++ b/spec/tree-sitter-language-mode-spec.js @@ -1,7 +1,5 @@ /* eslint-disable no-template-curly-in-string */ -const { it, beforeEach, afterEach } = require('./async-spec-helpers') - const fs = require('fs') const path = require('path') const dedent = require('dedent') diff --git a/spec/update-process-env-spec.js b/spec/update-process-env-spec.js index 54b6a9038..5185f0198 100644 --- a/spec/update-process-env-spec.js +++ b/spec/update-process-env-spec.js @@ -1,7 +1,5 @@ /** @babel */ -/* eslint-env jasmine */ -import { it, beforeEach, afterEach } from './async-spec-helpers' import path from 'path' import childProcess from 'child_process' import { diff --git a/spec/uri-handler-registry-spec.js b/spec/uri-handler-registry-spec.js index b17bfa16e..a8faa4500 100644 --- a/spec/uri-handler-registry-spec.js +++ b/spec/uri-handler-registry-spec.js @@ -2,8 +2,6 @@ import url from 'url' -import { it } from './async-spec-helpers' - import URIHandlerRegistry from '../src/uri-handler-registry' describe('URIHandlerRegistry', () => { diff --git a/spec/workspace-center-spec.js b/spec/workspace-center-spec.js index 681074557..b5bf6ba91 100644 --- a/spec/workspace-center-spec.js +++ b/spec/workspace-center-spec.js @@ -2,8 +2,6 @@ const TextEditor = require('../src/text-editor') -import { it } from './async-spec-helpers' - describe('WorkspaceCenter', () => { describe('.observeTextEditors()', () => { it('invokes the observer with current and future text editors', () => { diff --git a/spec/workspace-element-spec.js b/spec/workspace-element-spec.js index 930fedeae..afcb9446a 100644 --- a/spec/workspace-element-spec.js +++ b/spec/workspace-element-spec.js @@ -5,7 +5,6 @@ const etch = require('etch') const path = require('path') const temp = require('temp').track() const { Disposable } = require('event-kit') -const { it, beforeEach, afterEach } = require('./async-spec-helpers') const getNextUpdatePromise = () => etch.getScheduler().nextUpdatePromise diff --git a/spec/workspace-spec.js b/spec/workspace-spec.js index c5e3ff668..50dd57682 100644 --- a/spec/workspace-spec.js +++ b/spec/workspace-spec.js @@ -10,12 +10,7 @@ const _ = require('underscore-plus') const fstream = require('fstream') const fs = require('fs-plus') const AtomEnvironment = require('../src/atom-environment') -const { - it, - beforeEach, - afterEach, - conditionPromise -} = require('./async-spec-helpers') +const { conditionPromise } = require('./async-spec-helpers') describe('Workspace', () => { let workspace From 67afbe60970fd3f1e0f10d74bb865c982f0d27a9 Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Thu, 28 Feb 2019 20:53:36 +0100 Subject: [PATCH 111/112] Stop using promisifySome --- spec/path-watcher-spec.js | 59 +++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 31 deletions(-) diff --git a/spec/path-watcher-spec.js b/spec/path-watcher-spec.js index f6fd2d098..ec1993f96 100644 --- a/spec/path-watcher-spec.js +++ b/spec/path-watcher-spec.js @@ -1,23 +1,21 @@ /** @babel */ -import { promisifySome } from './async-spec-helpers' -import tempCb from 'temp' -import fsCb from 'fs-plus' +import temp from 'temp' +import fs from 'fs-plus' import path from 'path' +import { promisify } from 'util' import { CompositeDisposable } from 'event-kit' import { watchPath, stopAllWatchers } from '../src/path-watcher' -tempCb.track() +temp.track() -const fs = promisifySome(fsCb, [ - 'writeFile', - 'mkdir', - 'symlink', - 'appendFile', - 'realpath' -]) -const temp = promisifySome(tempCb, ['mkdir']) +const writeFile = promisify(fs.writeFile) +const mkdir = promisify(fs.mkdir) +const appendFile = promisify(fs.appendFile) +const realpath = promisify(fs.realpath) + +const tempMkdir = promisify(temp.mkdir) describe('watchPath', function () { let subs @@ -55,14 +53,14 @@ describe('watchPath', function () { describe('watchPath()', function () { it('resolves the returned promise when the watcher begins listening', async function () { - const rootDir = await temp.mkdir('atom-fsmanager-test-') + const rootDir = await tempMkdir('atom-fsmanager-test-') const watcher = await watchPath(rootDir, {}, () => {}) expect(watcher.constructor.name).toBe('PathWatcher') }) it('reuses an existing native watcher and resolves getStartPromise immediately if attached to a running watcher', async function () { - const rootDir = await temp.mkdir('atom-fsmanager-test-') + const rootDir = await tempMkdir('atom-fsmanager-test-') const watcher0 = await watchPath(rootDir, {}, () => {}) const watcher1 = await watchPath(rootDir, {}, () => {}) @@ -71,7 +69,7 @@ describe('watchPath', function () { }) it("reuses existing native watchers even while they're still starting", async function () { - const rootDir = await temp.mkdir('atom-fsmanager-test-') + const rootDir = await tempMkdir('atom-fsmanager-test-') const [watcher0, watcher1] = await Promise.all([ watchPath(rootDir, {}, () => {}), @@ -81,7 +79,7 @@ describe('watchPath', function () { }) it("doesn't attach new watchers to a native watcher that's stopping", async function () { - const rootDir = await temp.mkdir('atom-fsmanager-test-') + const rootDir = await tempMkdir('atom-fsmanager-test-') const watcher0 = await watchPath(rootDir, {}, () => {}) const native0 = watcher0.native @@ -93,12 +91,12 @@ describe('watchPath', function () { }) it('reuses an existing native watcher on a parent directory and filters events', async function () { - const rootDir = await temp.mkdir('atom-fsmanager-test-').then(fs.realpath) + const rootDir = await tempMkdir('atom-fsmanager-test-').then(realpath) const rootFile = path.join(rootDir, 'rootfile.txt') const subDir = path.join(rootDir, 'subdir') const subFile = path.join(subDir, 'subfile.txt') - await fs.mkdir(subDir) + await mkdir(subDir) // Keep the watchers alive with an undisposed subscription const rootWatcher = await watchPath(rootDir, {}, () => {}) @@ -111,18 +109,17 @@ describe('watchPath', function () { waitForChanges(rootWatcher, subFile), waitForChanges(childWatcher, subFile) ]) - await fs.writeFile(subFile, 'subfile\n', { encoding: 'utf8' }) + await writeFile(subFile, 'subfile\n', { encoding: 'utf8' }) await firstChanges const nextRootEvent = waitForChanges(rootWatcher, rootFile) - await fs.writeFile(rootFile, 'rootfile\n', { encoding: 'utf8' }) + await writeFile(rootFile, 'rootfile\n', { encoding: 'utf8' }) await nextRootEvent }) it('adopts existing child watchers and filters events appropriately to them', async function () { - const parentDir = await temp - .mkdir('atom-fsmanager-test-') - .then(fs.realpath) + const parentDir = await tempMkdir('atom-fsmanager-test-') + .then(realpath) // Create the directory tree const rootFile = path.join(parentDir, 'rootfile.txt') @@ -131,12 +128,12 @@ describe('watchPath', function () { const subDir1 = path.join(parentDir, 'subdir1') const subFile1 = path.join(subDir1, 'subfile1.txt') - await fs.mkdir(subDir0) - await fs.mkdir(subDir1) + await mkdir(subDir0) + await mkdir(subDir1) await Promise.all([ - fs.writeFile(rootFile, 'rootfile\n', { encoding: 'utf8' }), - fs.writeFile(subFile0, 'subfile 0\n', { encoding: 'utf8' }), - fs.writeFile(subFile1, 'subfile 1\n', { encoding: 'utf8' }) + writeFile(rootFile, 'rootfile\n', { encoding: 'utf8' }), + writeFile(subFile0, 'subfile 0\n', { encoding: 'utf8' }), + writeFile(subFile1, 'subfile 1\n', { encoding: 'utf8' }) ]) // Begin the child watchers and keep them alive @@ -162,9 +159,9 @@ describe('watchPath', function () { // Ensure events are filtered correctly await Promise.all([ - fs.appendFile(rootFile, 'change\n', { encoding: 'utf8' }), - fs.appendFile(subFile0, 'change\n', { encoding: 'utf8' }), - fs.appendFile(subFile1, 'change\n', { encoding: 'utf8' }) + appendFile(rootFile, 'change\n', { encoding: 'utf8' }), + appendFile(subFile0, 'change\n', { encoding: 'utf8' }), + appendFile(subFile1, 'change\n', { encoding: 'utf8' }) ]) await Promise.all([ From ec705399e63b49417d0b250984cc20b5817a5254 Mon Sep 17 00:00:00 2001 From: Rafael Oleza Date: Fri, 1 Mar 2019 12:03:37 +0100 Subject: [PATCH 112/112] Remove uneeded methods from async-spec-helpers modules --- .../about/spec/helpers/async-spec-helpers.js | 39 ------- .../spec/async-spec-helpers.js | 80 ------------- .../spec/async-spec-helpers.js | 41 ------- packages/link/spec/async-spec-helpers.js | 106 ------------------ spec/async-spec-helpers.js | 72 ------------ 5 files changed, 338 deletions(-) delete mode 100644 packages/grammar-selector/spec/async-spec-helpers.js delete mode 100644 packages/link/spec/async-spec-helpers.js diff --git a/packages/about/spec/helpers/async-spec-helpers.js b/packages/about/spec/helpers/async-spec-helpers.js index 6d1d45963..58e17d323 100644 --- a/packages/about/spec/helpers/async-spec-helpers.js +++ b/packages/about/spec/helpers/async-spec-helpers.js @@ -3,35 +3,6 @@ const { now } = Date const { setTimeout } = global -export function beforeEach (fn) { - global.beforeEach(function () { - const result = fn() - if (result instanceof Promise) { - waitsForPromise(() => result) - } - }) -} - -export function afterEach (fn) { - global.afterEach(function () { - const result = fn() - if (result instanceof Promise) { - waitsForPromise(() => result) - } - }) -} - -;['it', 'fit', 'ffit', 'fffit'].forEach(function (name) { - module.exports[name] = function (description, fn) { - global[name](description, function () { - const result = fn() - if (result instanceof Promise) { - waitsForPromise(() => result) - } - }) - } -}) - export async function conditionPromise (condition) { const startTime = now() @@ -53,13 +24,3 @@ export function timeoutPromise (timeout) { setTimeout(resolve, timeout) }) } - -function waitsForPromise (fn) { - const promise = fn() - global.waitsFor('spec promise to resolve', function (done) { - promise.then(done, function (error) { - jasmine.getEnv().currentSpec.fail(error) - done() - }) - }) -} diff --git a/packages/dev-live-reload/spec/async-spec-helpers.js b/packages/dev-live-reload/spec/async-spec-helpers.js index 5a233973e..e78205989 100644 --- a/packages/dev-live-reload/spec/async-spec-helpers.js +++ b/packages/dev-live-reload/spec/async-spec-helpers.js @@ -1,39 +1,5 @@ /** @babel */ -export function beforeEach (fn) { - global.beforeEach(function () { - const result = fn() - if (result instanceof Promise) { - waitsForPromise(() => result) - } - }) -} - -export function afterEach (fn) { - global.afterEach(function () { - const result = fn() - if (result instanceof Promise) { - waitsForPromise(() => result) - } - }) -} - -;['it', 'fit', 'ffit', 'fffit'].forEach(function (name) { - module.exports[name] = function (description, fn) { - if (fn === undefined) { - global[name](description) - return - } - - global[name](description, function () { - const result = fn() - if (result instanceof Promise) { - waitsForPromise(() => result) - } - }) - } -}) - export async function conditionPromise ( condition, description = 'anonymous condition' @@ -58,49 +24,3 @@ export function timeoutPromise (timeout) { global.setTimeout(resolve, timeout) }) } - -function waitsForPromise (fn) { - const promise = fn() - global.waitsFor('spec promise to resolve', function (done) { - promise.then(done, function (error) { - jasmine.getEnv().currentSpec.fail(error) - done() - }) - }) -} - -export function emitterEventPromise (emitter, event, timeout = 15000) { - return new Promise((resolve, reject) => { - const timeoutHandle = setTimeout(() => { - reject(new Error(`Timed out waiting for '${event}' event`)) - }, timeout) - emitter.once(event, () => { - clearTimeout(timeoutHandle) - resolve() - }) - }) -} - -export function promisify (original) { - return function (...args) { - return new Promise((resolve, reject) => { - args.push((err, ...results) => { - if (err) { - reject(err) - } else { - resolve(...results) - } - }) - - return original(...args) - }) - } -} - -export function promisifySome (obj, fnNames) { - const result = {} - for (const fnName of fnNames) { - result[fnName] = promisify(obj[fnName]) - } - return result -} diff --git a/packages/grammar-selector/spec/async-spec-helpers.js b/packages/grammar-selector/spec/async-spec-helpers.js deleted file mode 100644 index 5fe94e859..000000000 --- a/packages/grammar-selector/spec/async-spec-helpers.js +++ /dev/null @@ -1,41 +0,0 @@ -exports.beforeEach = function beforeEach (fn) { - global.beforeEach(function () { - const result = fn() - if (result instanceof Promise) { - waitsForPromise('beforeEach promise', result) - } - }) -} - -exports.afterEach = function afterEach (fn) { - global.afterEach(function () { - const result = fn() - if (result instanceof Promise) { - waitsForPromise('afterEach promise', result) - } - }) -} -;['it', 'fit', 'ffit', 'fffit'].forEach(function (name) { - exports[name] = function (description, fn) { - if (fn === undefined) { - global[name](description) - return - } - - global[name](description, function () { - const result = fn() - if (result instanceof Promise) { - waitsForPromise('test promise', result) - } - }) - } -}) - -function waitsForPromise (message, promise) { - global.waitsFor(message, done => { - promise.then(done, error => { - jasmine.getEnv().currentSpec.fail(error) - done() - }) - }) -} diff --git a/packages/link/spec/async-spec-helpers.js b/packages/link/spec/async-spec-helpers.js deleted file mode 100644 index 5a233973e..000000000 --- a/packages/link/spec/async-spec-helpers.js +++ /dev/null @@ -1,106 +0,0 @@ -/** @babel */ - -export function beforeEach (fn) { - global.beforeEach(function () { - const result = fn() - if (result instanceof Promise) { - waitsForPromise(() => result) - } - }) -} - -export function afterEach (fn) { - global.afterEach(function () { - const result = fn() - if (result instanceof Promise) { - waitsForPromise(() => result) - } - }) -} - -;['it', 'fit', 'ffit', 'fffit'].forEach(function (name) { - module.exports[name] = function (description, fn) { - if (fn === undefined) { - global[name](description) - return - } - - global[name](description, function () { - const result = fn() - if (result instanceof Promise) { - waitsForPromise(() => result) - } - }) - } -}) - -export async function conditionPromise ( - condition, - description = 'anonymous condition' -) { - const startTime = Date.now() - - while (true) { - await timeoutPromise(100) - - if (await condition()) { - return - } - - if (Date.now() - startTime > 5000) { - throw new Error('Timed out waiting on ' + description) - } - } -} - -export function timeoutPromise (timeout) { - return new Promise(function (resolve) { - global.setTimeout(resolve, timeout) - }) -} - -function waitsForPromise (fn) { - const promise = fn() - global.waitsFor('spec promise to resolve', function (done) { - promise.then(done, function (error) { - jasmine.getEnv().currentSpec.fail(error) - done() - }) - }) -} - -export function emitterEventPromise (emitter, event, timeout = 15000) { - return new Promise((resolve, reject) => { - const timeoutHandle = setTimeout(() => { - reject(new Error(`Timed out waiting for '${event}' event`)) - }, timeout) - emitter.once(event, () => { - clearTimeout(timeoutHandle) - resolve() - }) - }) -} - -export function promisify (original) { - return function (...args) { - return new Promise((resolve, reject) => { - args.push((err, ...results) => { - if (err) { - reject(err) - } else { - resolve(...results) - } - }) - - return original(...args) - }) - } -} - -export function promisifySome (obj, fnNames) { - const result = {} - for (const fnName of fnNames) { - result[fnName] = promisify(obj[fnName]) - } - return result -} diff --git a/spec/async-spec-helpers.js b/spec/async-spec-helpers.js index c6a5920a5..840a04b2a 100644 --- a/spec/async-spec-helpers.js +++ b/spec/async-spec-helpers.js @@ -1,37 +1,3 @@ -function beforeEach (fn) { - global.beforeEach(() => { - const result = fn() - if (result instanceof Promise) { - waitsForPromise(() => result) - } - }) -} - -function afterEach (fn) { - global.afterEach(() => { - const result = fn() - if (result instanceof Promise) { - waitsForPromise(() => result) - } - }) -} - -;['it', 'fit', 'ffit', 'fffit'].forEach(name => { - exports[name] = (description, fn) => { - if (fn === undefined) { - global[name](description) - return - } - - global[name](description, () => { - const result = fn() - if (result instanceof Promise) { - waitsForPromise(() => result) - } - }) - } -}) - async function conditionPromise ( condition, description = 'anonymous condition' @@ -57,16 +23,6 @@ function timeoutPromise (timeout) { }) } -function waitsForPromise (fn) { - const promise = fn() - global.waitsFor('spec promise to resolve', done => { - promise.then(done, error => { - jasmine.getEnv().currentSpec.fail(error) - done() - }) - }) -} - function emitterEventPromise (emitter, event, timeout = 15000) { return new Promise((resolve, reject) => { const timeoutHandle = setTimeout(() => { @@ -79,34 +35,6 @@ function emitterEventPromise (emitter, event, timeout = 15000) { }) } -function promisify (original) { - return function (...args) { - return new Promise((resolve, reject) => { - args.push((err, ...results) => { - if (err) { - reject(err) - } else { - resolve(...results) - } - }) - - return original(...args) - }) - } -} - -function promisifySome (obj, fnNames) { - const result = {} - for (const fnName of fnNames) { - result[fnName] = promisify(obj[fnName]) - } - return result -} - -exports.afterEach = afterEach -exports.beforeEach = beforeEach exports.conditionPromise = conditionPromise exports.emitterEventPromise = emitterEventPromise -exports.promisify = promisify -exports.promisifySome = promisifySome exports.timeoutPromise = timeoutPromise