From f05a7c28b251d8d6905076152a8f040de78020ae Mon Sep 17 00:00:00 2001
From: Lee Dohm <1038121+lee-dohm@users.noreply.github.com>
Date: Mon, 1 Jan 2018 16:01:39 -0800
Subject: [PATCH 01/17] Convert all of the code to TypeScript
---
lib/index.coffee | 44 --------------
lib/index.ts | 40 +++++++++++++
lib/package-list.coffee | 33 -----------
lib/package-list.ts | 32 ++++++++++
lib/package-sync.coffee | 119 --------------------------------------
lib/package-sync.ts | 115 ++++++++++++++++++++++++++++++++++++
lib/season.d.ts | 7 +++
lib/status-message.coffee | 27 ---------
lib/status-message.ts | 46 +++++++++++++++
package.json | 43 +++++++++++++-
tsconfig.json | 8 +++
11 files changed, 289 insertions(+), 225 deletions(-)
delete mode 100644 lib/index.coffee
create mode 100644 lib/index.ts
delete mode 100644 lib/package-list.coffee
create mode 100644 lib/package-list.ts
delete mode 100644 lib/package-sync.coffee
create mode 100644 lib/package-sync.ts
create mode 100644 lib/season.d.ts
delete mode 100644 lib/status-message.coffee
create mode 100644 lib/status-message.ts
create mode 100644 tsconfig.json
diff --git a/lib/index.coffee b/lib/index.coffee
deleted file mode 100644
index e88cb55..0000000
--- a/lib/index.coffee
+++ /dev/null
@@ -1,44 +0,0 @@
-PackageSync = null
-packageSync = null
-
-# Loads the module on-demand.
-loadModule = ->
- PackageSync ?= require './package-sync'
- packageSync ?= new PackageSync()
-
-module.exports =
- activate: ->
- atom.commands.add 'atom-workspace', 'package-sync:create-package-list', ->
- loadModule()
- packageSync.createPackageList()
-
- atom.commands.add 'atom-workspace', 'package-sync:open-package-list', ->
- loadModule()
- packageSync.openPackageList()
-
- atom.commands.add 'atom-workspace', 'package-sync:sync', ->
- loadModule()
- packageSync.sync()
-
- atom.packages.onDidActivateInitialPackages ->
- atom.packages.onDidLoadPackage ->
- if atom.config.get('package-sync.createOnChange')
- loadModule()
- packageSync.createPackageList()
-
- atom.packages.onDidUnloadPackage ->
- if atom.config.get('package-sync.createOnChange')
- loadModule()
- packageSync.createPackageList()
-
- config:
- forceOverwrite:
- title: 'Overwrite packages.cson'
- description: 'Overwrite packages.cson even when it is present.'
- type: 'boolean'
- default: false
- createOnChange:
- title: 'Create on change'
- description: 'Create package list when packages are installed or removed.'
- type: 'boolean'
- default: false
diff --git a/lib/index.ts b/lib/index.ts
new file mode 100644
index 0000000..2a403de
--- /dev/null
+++ b/lib/index.ts
@@ -0,0 +1,40 @@
+import PackageSync from './package-sync'
+
+let packageSync: PackageSync | null = null
+
+function loadModule() : PackageSync {
+ if (!packageSync) {
+ const _PackageSync: typeof PackageSync = require('./package-sync')
+ packageSync = new _PackageSync()
+ }
+
+ return packageSync
+}
+
+export function activate() {
+ atom.commands.add('atom-workspace', 'package-sync:create-package-list', () => {
+ loadModule().createPackageList()
+ })
+
+ atom.commands.add('atom-workspace', 'package-sync:open-package-list', () => {
+ loadModule().openPackageList()
+ })
+
+ atom.commands.add('atom-workspace', 'package-sync:sync', () => {
+ loadModule().sync()
+ })
+
+ atom.packages.onDidActivateInitialPackages(() => {
+ atom.packages.onDidLoadPackage(() => {
+ if (atom.config.get('package-sync.createOnChange')) {
+ loadModule().createPackageList()
+ }
+ })
+
+ atom.packages.onDidUnloadPackage(() => {
+ if (atom.config.get('package-sync.createOnChange')) {
+ loadModule().createPackageList()
+ }
+ })
+ })
+}
diff --git a/lib/package-list.coffee b/lib/package-list.coffee
deleted file mode 100644
index 6345d8f..0000000
--- a/lib/package-list.coffee
+++ /dev/null
@@ -1,33 +0,0 @@
-CSON = require 'season'
-fs = require 'fs'
-path = require 'path'
-
-# Public: Represents the list of packages that the user wants synchronized.
-#
-# ## Events
-#
-# This class has no events.
-module.exports =
-class PackageList
- # Public: Gets the list of packages that the user wants synchronized.
- #
- # Returns an {Array} containing the package names.
- getPackages: ->
- if fs.existsSync(PackageList.getPackageListPath())
- obj = CSON.readFileSync(PackageList.getPackageListPath())
- obj['packages']
- else
- []
-
- # Public: Sets the list of packages to the list of available packages.
- setPackages: ->
- if atom.config.get('package-sync.forceOverwrite') or not fs.existsSync(PackageList.getPackageListPath())
- available = atom.packages.getAvailablePackageNames()
- packages = (name for name in available when not atom.packages.isBundledPackage(name))
- CSON.writeFileSync(PackageList.getPackageListPath(), {'packages': packages})
-
- # Internal: Gets the path to the package list.
- #
- # Returns a {String} containing the path to the list of available packages.
- @getPackageListPath: ->
- @packageListPath ?= path.join(atom.getConfigDirPath(), 'packages.cson')
diff --git a/lib/package-list.ts b/lib/package-list.ts
new file mode 100644
index 0000000..d9f6639
--- /dev/null
+++ b/lib/package-list.ts
@@ -0,0 +1,32 @@
+import * as CSON from 'season'
+import * as fs from 'fs'
+import * as path from 'path'
+
+interface PackagesFile {
+ packages: string[]
+}
+
+export default class PackageList {
+ static packageListPath = path.join(atom.getConfigDirPath(), 'packages.cson')
+
+ static getPackageListPath () {
+ return this.packageListPath
+ }
+
+ getPackages () : string[] {
+ if (fs.existsSync(PackageList.getPackageListPath())) {
+ let obj = CSON.readFileSync(PackageList.getPackageListPath()) as PackagesFile
+ return obj.packages
+ }
+
+ return []
+ }
+
+ setPackages () {
+ if (atom.config.get('package-sync.forceOverwrite') || !fs.existsSync(PackageList.getPackageListPath())) {
+ let available = atom.packages.getAvailablePackageNames()
+ let names = available.filter((name: string) => { !atom.packages.isBundledPackage(name) })
+ CSON.writeFileSync(PackageList.getPackageListPath(), {'packages': names})
+ }
+ }
+}
diff --git a/lib/package-sync.coffee b/lib/package-sync.coffee
deleted file mode 100644
index 013b435..0000000
--- a/lib/package-sync.coffee
+++ /dev/null
@@ -1,119 +0,0 @@
-fs = require 'fs'
-
-{BufferedProcess} = require 'atom'
-
-PackageList = require './package-list'
-StatusMessage = require './status-message'
-
-# Public: Performs the package synchronization.
-#
-# ## Events
-#
-# This class has no events.
-module.exports =
-class PackageSync
- # Internal: Path to `apm`.
- apmPath: atom.packages.getApmPath()
-
- # Internal: Process object of the current install.
- currentInstall: null
-
- # Internal: Timeout for messages that should be up longer.
- longMessageTimeout: 15000
-
- # Internal: Status bar message.
- message: null
-
- # Internal: Packages in the process of being installed.
- packagesToInstall: []
-
- # Internal: Timeout for messages that should be up for only a short time.
- shortMessageTimeout: 1000
-
- # Internal: Timeout for status bar message.
- timeout: null
-
- # Public: Creates the package list for the user from the list of available packages.
- createPackageList: ->
- new PackageList().setPackages()
-
- # Public: Opens the package list.
- openPackageList: ->
- atom.workspace.open(PackageList.getPackageListPath())
-
- # Public: Installs any packages that are missing from the `packages.cson` configuration file.
- sync: ->
- missing = @getMissingPackages()
- @installPackages(missing)
-
- # Internal: Displays a message in the status bar.
- #
- # If `timeout` is specified, the message will automatically be cleared in `timeout` milliseconds.
- #
- # message - A {String} containing the message to be displayed.
- # timeout - An optional {Number} specifying the time in milliseconds until the message will be
- # cleared.
- displayMessage: (message, timeout) ->
- clearTimeout(@timeout) if @timeout?
- if @message?
- @message.setText(message)
- else
- @message = new StatusMessage(message)
-
- @setMessageTimeout(timeout) if timeout?
-
- # Internal: Execute APM to install the given package.
- #
- # pkg - A {String} containing the name of the package to install.
- executeApm: (pkg) ->
- @displayMessage("Installing #{pkg}")
- command = @apmPath
- args = ['install', pkg]
- stdout = (output) ->
- stderr = (output) ->
- exit = (exitCode) =>
- if exitCode is 0
- if @packagesToInstall.length > 0
- @displayMessage("#{pkg} installed!", @shortMessageTimeout)
- else
- @displayMessage('Package Sync complete!', @longMessageTimeout)
- else
- @displayMessage("An error occurred installing #{pkg}", @longMessageTimeout)
-
- @currentInstall = null
- @installPackage()
-
- @currentInstall = new BufferedProcess({command, args, stdout, stderr, exit})
-
- # Internal: Gets the list of packages that are missing.
- #
- # Returns an {Array} of names of packages that need to be installed.
- getMissingPackages: ->
- list = new PackageList()
- syncPackages = list.getPackages()
- availablePackages = atom.packages.getAvailablePackageNames()
- value for value in syncPackages when value not in availablePackages
-
- # Internal: Installs the next package in the list.
- installPackage: ->
- # Exit if there is already an installation running or if there are no more
- # packages to install.
- return if @currentInstall? or @packagesToInstall.length is 0
- @executeApm(@packagesToInstall.shift())
-
- # Internal: Installs each of the packages in the given list.
- #
- # packages - An {Array} containing the names of packages to install.
- installPackages: (packages) ->
- @packagesToInstall.push(packages...)
- @installPackage()
-
- # Internal: Sets a timeout to remove the status bar message.
- #
- # timeout - The {Number} of milliseconds until the message should be removed.
- setMessageTimeout: (timeout) ->
- clearTimeout(@timeout) if @timeout?
- @timeout = setTimeout(=>
- @message.remove()
- @message = null
- , timeout)
diff --git a/lib/package-sync.ts b/lib/package-sync.ts
new file mode 100644
index 0000000..a10045b
--- /dev/null
+++ b/lib/package-sync.ts
@@ -0,0 +1,115 @@
+import * as fs from 'fs'
+
+import {BufferedProcess} from 'atom'
+
+import PackageList from './package-list'
+import StatusMessage from './status-message'
+
+export default class PackageSync {
+ readonly apmPath = atom.packages.getApmPath()
+ readonly longMessageTimeout = 15000
+ readonly shortMessageTimeout = 1000
+
+ currentInstall: BufferedProcess | null
+ message: StatusMessage | null
+ packagesToInstall: string[]
+ timeout: NodeJS.Timer | null
+
+ constructor () {
+ this.currentInstall = null
+ this.message = null
+ this.packagesToInstall = []
+ this.timeout = null
+ }
+
+ createPackageList () {
+ new PackageList().setPackages()
+ }
+
+ openPackageList () {
+ atom.workspace.open(PackageList.getPackageListPath())
+ }
+
+ sync () {
+ let missing = this.getMissingPackages()
+ this.installPackages(missing)
+ }
+
+ displayMessage (message: string, timeout?: number) {
+ if (this.timeout) {
+ clearTimeout(this.timeout)
+ }
+
+ if (this.message) {
+ this.message.setText(message)
+ } else {
+ this.message = new StatusMessage(message)
+ }
+
+ if (timeout) {
+ this.setMessageTimeout(timeout)
+ }
+ }
+
+ executeApm (pkg: string) {
+ this.displayMessage(`Installing ${pkg}`)
+
+ let command = this.apmPath
+ let args = ['install', pkg]
+ let stdout = (output: string) => {}
+ let stderr = (output: string) => {}
+ let exit = (exitCode: number) => {
+ if (exitCode === 0) {
+ if (this.packagesToInstall.length > 0) {
+ this.displayMessage(`${pkg} installed!`, this.shortMessageTimeout)
+ } else {
+ this.displayMessage('Package sync complete!', this.longMessageTimeout)
+ }
+ } else {
+ this.displayMessage(`An error occurred installing ${pkg}`, this.longMessageTimeout)
+ }
+
+ this.currentInstall = null
+ this.installPackage()
+ }
+
+ this.currentInstall = new BufferedProcess({command, args, stdout, stderr, exit})
+ }
+
+ getMissingPackages () {
+ let list = new PackageList()
+ let syncPackages = list.getPackages()
+ let availablePackages = atom.packages.getAvailablePackageNames()
+
+ return syncPackages.filter((value) => { !(value in availablePackages) })
+ }
+
+ installPackage () {
+ if (this.currentInstall) {
+ return
+ }
+
+ let nextPackage = this.packagesToInstall.shift()
+
+ if (nextPackage) {
+ this.executeApm(nextPackage)
+ }
+ }
+
+ installPackages (packages: string[]) {
+ this.packagesToInstall.push(...packages)
+ }
+
+ setMessageTimeout (timeout: number) {
+ if (this.timeout) {
+ clearTimeout(this.timeout)
+ }
+
+ this.timeout = setTimeout(() => {
+ if (this.message) {
+ this.message.remove()
+ this.message = null
+ }
+ }, timeout)
+ }
+}
diff --git a/lib/season.d.ts b/lib/season.d.ts
new file mode 100644
index 0000000..42642af
--- /dev/null
+++ b/lib/season.d.ts
@@ -0,0 +1,7 @@
+// Type definitions for atom/season
+
+declare module 'season' {
+ export function readFileSync(objectPath: string): object
+
+ export function writeFileSync(objectPath: string, obj: object): void
+}
diff --git a/lib/status-message.coffee b/lib/status-message.coffee
deleted file mode 100644
index b8ce422..0000000
--- a/lib/status-message.coffee
+++ /dev/null
@@ -1,27 +0,0 @@
-# Public: Displays a message in the status bar.
-module.exports =
-class StatusMessage
- # Public: Displays `message` in the status bar.
- #
- # If the status bar does not exist for whatever reason, no message is displayed and no error
- # occurs.
- #
- # message - A {String} containing the message to display.
- constructor: (message) ->
- @statusBar = document.querySelector('status-bar')
- if @statusBar
- @item = document.createElement('div')
- @item.classList.add('inline-block')
- @setText(message)
-
- @tile = @statusBar.addLeftTile({@item})
-
- # Public: Removes the message from the status bar.
- remove: ->
- @tile?.destroy()
-
- # Public: Updates the text of the message.
- #
- # text - A {String} containing the new message to display.
- setText: (text) ->
- @item.innerHTML = text if @statusBar
diff --git a/lib/status-message.ts b/lib/status-message.ts
new file mode 100644
index 0000000..5e7e583
--- /dev/null
+++ b/lib/status-message.ts
@@ -0,0 +1,46 @@
+import {StatusBar, Tile} from 'atom/status-bar'
+
+/**
+ * Displays a message in the status bar.
+ */
+export default class StatusMessage {
+ item: Element
+ statusBar: StatusBar
+ tile: Tile
+
+ /**
+ * Displays `message` in the status bar.
+ *
+ * If the status bar does not exist, no message is displayed and no error
+ * occurs.
+ */
+ constructor (message: string) {
+ this.statusBar = document.querySelector('status-bar') as StatusBar
+
+ if (this.statusBar) {
+ this.item = document.createElement('div')
+ this.item.classList.add('inline-block')
+ this.setText(message)
+
+ this.tile = this.statusBar.addLeftTile({item: this.item})
+ }
+ }
+
+ /**
+ * Removes the message from the status bar.
+ */
+ remove () {
+ if (this.tile) {
+ this.tile.destroy()
+ }
+ }
+
+ /**
+ * Updates the text of the message.
+ */
+ setText (text: string) {
+ if (this.statusBar) {
+ this.item.innerHTML = text
+ }
+ }
+}
diff --git a/package.json b/package.json
index bf60c04..4dc087c 100644
--- a/package.json
+++ b/package.json
@@ -12,9 +12,48 @@
"repository": "https://github.com/lee-dohm/package-sync",
"license": "MIT",
"engines": {
- "atom": ">=0.174.0 <2.0.0"
+ "atom": ">=1.23.1 <2.0.0"
},
"dependencies": {
- "season": "^5.2.0"
+ "atom-ts-transpiler": "^1.4.0",
+ "season": "^5.2.0",
+ "typescript": "^2.6.2",
+ "@types/atom": "^1.23.0",
+ "@types/node": "^8.5.2"
+ },
+ "devDependencies": {
+ "atom-mocha-test-runner": "^1.2.0",
+ "chai": "^4.1.2"
+ },
+ "atomTestRunner": "atom-mocha-test-runner",
+ "atomTranspilers": [
+ {
+ "transpiler": "atom-ts-transpiler",
+ "glob": "{!(node_modules)/**/,}*.ts?(x)",
+ "options": {
+ "compilerOptions": {
+ "target": "es5",
+ "module": "commonjs",
+ "strict": true,
+ "moduleResolution": "node"
+ },
+ "cacheKeyFiles": [],
+ "verbose": false
+ }
+ }
+ ],
+ "configSchema": {
+ "forceOverwrite": {
+ "title": "Overwrite packages list",
+ "description": "Overwrite packages list even when it is present",
+ "type": "boolean",
+ "default": false
+ },
+ "createOnChange": {
+ "title": "Create on change",
+ "description": "Create packages list when packages or themes are installed or removed",
+ "type": "boolean",
+ "default": false
+ }
}
}
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..e4e7528
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,8 @@
+{
+ "compilerOptions": {
+ "target": "es5",
+ "module": "commonjs",
+ "strict": true,
+ "moduleResolution": "node"
+ }
+}
From a73d05aac958f63a0e2fdf4f85b662dda2f9ea55 Mon Sep 17 00:00:00 2001
From: Lee Dohm <1038121+lee-dohm@users.noreply.github.com>
Date: Mon, 1 Jan 2018 16:02:33 -0800
Subject: [PATCH 02/17] Move all tests to Mocha
---
spec/{package-list-spec.coffee => package-list.test.coffee} | 2 ++
spec/{package-sync-spec.coffee => package-sync.test.coffee} | 0
spec/{status-message-spec.coffee => status-message.test.coffee} | 0
3 files changed, 2 insertions(+)
rename spec/{package-list-spec.coffee => package-list.test.coffee} (99%)
rename spec/{package-sync-spec.coffee => package-sync.test.coffee} (100%)
rename spec/{status-message-spec.coffee => status-message.test.coffee} (100%)
diff --git a/spec/package-list-spec.coffee b/spec/package-list.test.coffee
similarity index 99%
rename from spec/package-list-spec.coffee
rename to spec/package-list.test.coffee
index a52d6f9..73bead1 100644
--- a/spec/package-list-spec.coffee
+++ b/spec/package-list.test.coffee
@@ -7,6 +7,8 @@ PackageList = require '../lib/package-list'
h = require './helpers'
+expect = chai.expect
+
describe 'PackageList', ->
list = null
diff --git a/spec/package-sync-spec.coffee b/spec/package-sync.test.coffee
similarity index 100%
rename from spec/package-sync-spec.coffee
rename to spec/package-sync.test.coffee
diff --git a/spec/status-message-spec.coffee b/spec/status-message.test.coffee
similarity index 100%
rename from spec/status-message-spec.coffee
rename to spec/status-message.test.coffee
From 684027081f3fa80c281d81bee9e2ff7a8e33bce1 Mon Sep 17 00:00:00 2001
From: Lee Dohm <1038121+lee-dohm@users.noreply.github.com>
Date: Mon, 1 Jan 2018 16:19:52 -0800
Subject: [PATCH 03/17] Fix some stuff that got broken
---
lib/index.ts | 23 +++++++----------------
lib/package-list.ts | 5 +++--
2 files changed, 10 insertions(+), 18 deletions(-)
diff --git a/lib/index.ts b/lib/index.ts
index 2a403de..de82c00 100644
--- a/lib/index.ts
+++ b/lib/index.ts
@@ -1,39 +1,30 @@
import PackageSync from './package-sync'
-let packageSync: PackageSync | null = null
-
-function loadModule() : PackageSync {
- if (!packageSync) {
- const _PackageSync: typeof PackageSync = require('./package-sync')
- packageSync = new _PackageSync()
- }
-
- return packageSync
-}
-
export function activate() {
+ let packageSync = new PackageSync()
+
atom.commands.add('atom-workspace', 'package-sync:create-package-list', () => {
- loadModule().createPackageList()
+ packageSync.createPackageList()
})
atom.commands.add('atom-workspace', 'package-sync:open-package-list', () => {
- loadModule().openPackageList()
+ packageSync.openPackageList()
})
atom.commands.add('atom-workspace', 'package-sync:sync', () => {
- loadModule().sync()
+ packageSync.sync()
})
atom.packages.onDidActivateInitialPackages(() => {
atom.packages.onDidLoadPackage(() => {
if (atom.config.get('package-sync.createOnChange')) {
- loadModule().createPackageList()
+ packageSync.createPackageList()
}
})
atom.packages.onDidUnloadPackage(() => {
if (atom.config.get('package-sync.createOnChange')) {
- loadModule().createPackageList()
+ packageSync.createPackageList()
}
})
})
diff --git a/lib/package-list.ts b/lib/package-list.ts
index d9f6639..32e1831 100644
--- a/lib/package-list.ts
+++ b/lib/package-list.ts
@@ -25,8 +25,9 @@ export default class PackageList {
setPackages () {
if (atom.config.get('package-sync.forceOverwrite') || !fs.existsSync(PackageList.getPackageListPath())) {
let available = atom.packages.getAvailablePackageNames()
- let names = available.filter((name: string) => { !atom.packages.isBundledPackage(name) })
- CSON.writeFileSync(PackageList.getPackageListPath(), {'packages': names})
+ let names = available.filter((name: string) => { return !atom.packages.isBundledPackage(name) })
+
+ CSON.writeFileSync(PackageList.getPackageListPath(), {packages: names})
}
}
}
From a7520cd4f377b75e2a7837e459bb943ca96498d0 Mon Sep 17 00:00:00 2001
From: Lee Dohm <1038121+lee-dohm@users.noreply.github.com>
Date: Mon, 1 Jan 2018 16:25:43 -0800
Subject: [PATCH 04/17] :art:
---
lib/index.ts | 2 +-
lib/package-list.ts | 6 +++---
lib/package-sync.ts | 20 ++++++++++----------
lib/status-message.ts | 6 +++---
4 files changed, 17 insertions(+), 17 deletions(-)
diff --git a/lib/index.ts b/lib/index.ts
index de82c00..fb47c90 100644
--- a/lib/index.ts
+++ b/lib/index.ts
@@ -1,6 +1,6 @@
import PackageSync from './package-sync'
-export function activate() {
+export function activate(): void {
let packageSync = new PackageSync()
atom.commands.add('atom-workspace', 'package-sync:create-package-list', () => {
diff --git a/lib/package-list.ts b/lib/package-list.ts
index 32e1831..edcf64a 100644
--- a/lib/package-list.ts
+++ b/lib/package-list.ts
@@ -9,11 +9,11 @@ interface PackagesFile {
export default class PackageList {
static packageListPath = path.join(atom.getConfigDirPath(), 'packages.cson')
- static getPackageListPath () {
+ static getPackageListPath(): string {
return this.packageListPath
}
- getPackages () : string[] {
+ getPackages(): string[] {
if (fs.existsSync(PackageList.getPackageListPath())) {
let obj = CSON.readFileSync(PackageList.getPackageListPath()) as PackagesFile
return obj.packages
@@ -22,7 +22,7 @@ export default class PackageList {
return []
}
- setPackages () {
+ setPackages(): void {
if (atom.config.get('package-sync.forceOverwrite') || !fs.existsSync(PackageList.getPackageListPath())) {
let available = atom.packages.getAvailablePackageNames()
let names = available.filter((name: string) => { return !atom.packages.isBundledPackage(name) })
diff --git a/lib/package-sync.ts b/lib/package-sync.ts
index a10045b..d618795 100644
--- a/lib/package-sync.ts
+++ b/lib/package-sync.ts
@@ -15,27 +15,27 @@ export default class PackageSync {
packagesToInstall: string[]
timeout: NodeJS.Timer | null
- constructor () {
+ constructor() {
this.currentInstall = null
this.message = null
this.packagesToInstall = []
this.timeout = null
}
- createPackageList () {
+ createPackageList(): void {
new PackageList().setPackages()
}
- openPackageList () {
+ openPackageList(): void {
atom.workspace.open(PackageList.getPackageListPath())
}
- sync () {
+ sync(): void {
let missing = this.getMissingPackages()
this.installPackages(missing)
}
- displayMessage (message: string, timeout?: number) {
+ displayMessage(message: string, timeout?: number): void {
if (this.timeout) {
clearTimeout(this.timeout)
}
@@ -51,7 +51,7 @@ export default class PackageSync {
}
}
- executeApm (pkg: string) {
+ executeApm(pkg: string): void {
this.displayMessage(`Installing ${pkg}`)
let command = this.apmPath
@@ -76,7 +76,7 @@ export default class PackageSync {
this.currentInstall = new BufferedProcess({command, args, stdout, stderr, exit})
}
- getMissingPackages () {
+ getMissingPackages(): string[] {
let list = new PackageList()
let syncPackages = list.getPackages()
let availablePackages = atom.packages.getAvailablePackageNames()
@@ -84,7 +84,7 @@ export default class PackageSync {
return syncPackages.filter((value) => { !(value in availablePackages) })
}
- installPackage () {
+ installPackage(): void {
if (this.currentInstall) {
return
}
@@ -96,11 +96,11 @@ export default class PackageSync {
}
}
- installPackages (packages: string[]) {
+ installPackages(packages: string[]): void {
this.packagesToInstall.push(...packages)
}
- setMessageTimeout (timeout: number) {
+ setMessageTimeout(timeout: number): void {
if (this.timeout) {
clearTimeout(this.timeout)
}
diff --git a/lib/status-message.ts b/lib/status-message.ts
index 5e7e583..64c58cc 100644
--- a/lib/status-message.ts
+++ b/lib/status-message.ts
@@ -14,7 +14,7 @@ export default class StatusMessage {
* If the status bar does not exist, no message is displayed and no error
* occurs.
*/
- constructor (message: string) {
+ constructor(message: string) {
this.statusBar = document.querySelector('status-bar') as StatusBar
if (this.statusBar) {
@@ -29,7 +29,7 @@ export default class StatusMessage {
/**
* Removes the message from the status bar.
*/
- remove () {
+ remove(): void {
if (this.tile) {
this.tile.destroy()
}
@@ -38,7 +38,7 @@ export default class StatusMessage {
/**
* Updates the text of the message.
*/
- setText (text: string) {
+ setText(text: string): void {
if (this.statusBar) {
this.item.innerHTML = text
}
From ad3f6476266292d574bbe2234b29e944028b376d Mon Sep 17 00:00:00 2001
From: Lee Dohm <1038121+lee-dohm@users.noreply.github.com>
Date: Mon, 1 Jan 2018 17:29:10 -0800
Subject: [PATCH 05/17] :memo:
---
lib/package-list.ts | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/lib/package-list.ts b/lib/package-list.ts
index edcf64a..ec68e77 100644
--- a/lib/package-list.ts
+++ b/lib/package-list.ts
@@ -6,13 +6,22 @@ interface PackagesFile {
packages: string[]
}
+/**
+ * Represents the stored package list.
+ */
export default class PackageList {
static packageListPath = path.join(atom.getConfigDirPath(), 'packages.cson')
+ /**
+ * Gets the path to the stored package list.
+ */
static getPackageListPath(): string {
return this.packageListPath
}
+ /**
+ * Gets the packages from the list.
+ */
getPackages(): string[] {
if (fs.existsSync(PackageList.getPackageListPath())) {
let obj = CSON.readFileSync(PackageList.getPackageListPath()) as PackagesFile
@@ -22,6 +31,10 @@ export default class PackageList {
return []
}
+ /**
+ * Updates the stored package list with what is currently installed if the list doesn't exist or
+ * the `forceOverwrite` configuration option is set to `true`.
+ */
setPackages(): void {
if (atom.config.get('package-sync.forceOverwrite') || !fs.existsSync(PackageList.getPackageListPath())) {
let available = atom.packages.getAvailablePackageNames()
From 1921afd1452e6c60ac81d175844fe889a076148f Mon Sep 17 00:00:00 2001
From: Lee Dohm <1038121+lee-dohm@users.noreply.github.com>
Date: Mon, 1 Jan 2018 17:40:18 -0800
Subject: [PATCH 06/17] =?UTF-8?q?Start=20the=20packages=20installing=20?=
=?UTF-8?q?=F0=9F=98=B5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
lib/package-sync.ts | 1 +
1 file changed, 1 insertion(+)
diff --git a/lib/package-sync.ts b/lib/package-sync.ts
index d618795..d10fd7c 100644
--- a/lib/package-sync.ts
+++ b/lib/package-sync.ts
@@ -98,6 +98,7 @@ export default class PackageSync {
installPackages(packages: string[]): void {
this.packagesToInstall.push(...packages)
+ this.installPackage()
}
setMessageTimeout(timeout: number): void {
From a9bdb47013fa77311616d692f3dff4f4294a4564 Mon Sep 17 00:00:00 2001
From: Lee Dohm <1038121+lee-dohm@users.noreply.github.com>
Date: Mon, 1 Jan 2018 17:40:51 -0800
Subject: [PATCH 07/17] :memo:
---
lib/index.ts | 3 +++
lib/package-sync.ts | 30 ++++++++++++++++++++++++++++++
2 files changed, 33 insertions(+)
diff --git a/lib/index.ts b/lib/index.ts
index fb47c90..7ccbc43 100644
--- a/lib/index.ts
+++ b/lib/index.ts
@@ -1,5 +1,8 @@
import PackageSync from './package-sync'
+/**
+ * Activates the package.
+ */
export function activate(): void {
let packageSync = new PackageSync()
diff --git a/lib/package-sync.ts b/lib/package-sync.ts
index d10fd7c..600cfe2 100644
--- a/lib/package-sync.ts
+++ b/lib/package-sync.ts
@@ -22,19 +22,31 @@ export default class PackageSync {
this.timeout = null
}
+ /**
+ * Creates the package list.
+ */
createPackageList(): void {
new PackageList().setPackages()
}
+ /**
+ * Opens the package list in the workspace.
+ */
openPackageList(): void {
atom.workspace.open(PackageList.getPackageListPath())
}
+ /**
+ * Syncs the package list by installing any missing packages.
+ */
sync(): void {
let missing = this.getMissingPackages()
this.installPackages(missing)
}
+ /**
+ * Displays the `message` for the given `timeout` in milliseconds or indefinitely.
+ */
displayMessage(message: string, timeout?: number): void {
if (this.timeout) {
clearTimeout(this.timeout)
@@ -51,6 +63,12 @@ export default class PackageSync {
}
}
+ /**
+ * Executes apm to install the given package by name.
+ *
+ * When the given package is done installing, it attempts to install the next package in the
+ * `packagesToInstall` list.
+ */
executeApm(pkg: string): void {
this.displayMessage(`Installing ${pkg}`)
@@ -76,6 +94,9 @@ export default class PackageSync {
this.currentInstall = new BufferedProcess({command, args, stdout, stderr, exit})
}
+ /**
+ * Gets the list of missing package names by comparing against the current package list.
+ */
getMissingPackages(): string[] {
let list = new PackageList()
let syncPackages = list.getPackages()
@@ -84,6 +105,9 @@ export default class PackageSync {
return syncPackages.filter((value) => { !(value in availablePackages) })
}
+ /**
+ * Installs the next package in the list, if one exists.
+ */
installPackage(): void {
if (this.currentInstall) {
return
@@ -96,11 +120,17 @@ export default class PackageSync {
}
}
+ /**
+ * Queues up the given list of packages to be installed and starts the process.
+ */
installPackages(packages: string[]): void {
this.packagesToInstall.push(...packages)
this.installPackage()
}
+ /**
+ * Sets up a timeout for the currently displayed message.
+ */
setMessageTimeout(timeout: number): void {
if (this.timeout) {
clearTimeout(this.timeout)
From 37087e6c4dfcdd182ee07672a0362b617a3f115a Mon Sep 17 00:00:00 2001
From: Lee Dohm <1038121+lee-dohm@users.noreply.github.com>
Date: Mon, 1 Jan 2018 17:51:41 -0800
Subject: [PATCH 08/17] :memo: Add notes to the README
---
README.md | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/README.md b/README.md
index 0f0def5..c9a7091 100644
--- a/README.md
+++ b/README.md
@@ -55,6 +55,35 @@ Where the contents of the array is a list of packages to ensure are installed.
No keybindings are configured by default for the commands in this package.
+## Notes
+
+There are two primary use cases for this package:
+
+1. Ensure minimum set of packages installed
+ * Atom is allowed to have packages installed that are not in the list
+ * Package list is auto-generated once and then mostly manually updated
+1. Ensure that the list of installed packages is kept completely in sync
+ * Must install any missing packages
+ * Must remove any extra packages
+ * Package list is auto-updated when packages are installed or removed
+
+package-sync was originally intended to only satisfy the first scenario. It has since been pressed into service for the second scenario.
+
+### Minimum set of packages
+
+Operations:
+
+* Create package list from installed packages
+* Edit package list by hand
+* Ensure all packages in list are installed by syncing
+
+### Synchronize packages
+
+Operations:
+
+* Automated updating of package list
+* Ensure all packages are in sync by triggering sync
+
## Copyright
Copyright © 2014-2016 by [Lee Dohm](http://www.lee-dohm.com), [Lifted Studios](http://www.liftedstudios.com). See the [LICENSE](https://github.com/lee-dohm/package-sync/blob/master/LICENSE.md) for more details.
From 47f1f003c8997be779acd690d971c712976d39ba Mon Sep 17 00:00:00 2001
From: Lee Dohm <1038121+lee-dohm@users.noreply.github.com>
Date: Mon, 1 Jan 2018 19:46:54 -0800
Subject: [PATCH 09/17] Convert tests to TypeScript
---
lib/package-list.ts | 17 +-
lib/package-sync.ts | 16 +-
package-lock.json | 1284 +++++++++++++++++++++++++++++++
package.json | 8 +-
spec/helpers.coffee | 16 -
spec/helpers.ts | 22 +
spec/package-list.spec.ts | 116 +++
spec/package-list.test.coffee | 83 --
spec/package-sync.spec.ts | 26 +
spec/package-sync.test.coffee | 26 -
spec/runner.ts | 7 +
spec/status-message.test.coffee | 39 -
12 files changed, 1478 insertions(+), 182 deletions(-)
create mode 100644 package-lock.json
delete mode 100644 spec/helpers.coffee
create mode 100644 spec/helpers.ts
create mode 100644 spec/package-list.spec.ts
delete mode 100644 spec/package-list.test.coffee
create mode 100644 spec/package-sync.spec.ts
delete mode 100644 spec/package-sync.test.coffee
create mode 100644 spec/runner.ts
delete mode 100644 spec/status-message.test.coffee
diff --git a/lib/package-list.ts b/lib/package-list.ts
index ec68e77..cadbcab 100644
--- a/lib/package-list.ts
+++ b/lib/package-list.ts
@@ -10,21 +10,18 @@ interface PackagesFile {
* Represents the stored package list.
*/
export default class PackageList {
- static packageListPath = path.join(atom.getConfigDirPath(), 'packages.cson')
+ path: string
- /**
- * Gets the path to the stored package list.
- */
- static getPackageListPath(): string {
- return this.packageListPath
+ constructor(configDir = atom.getConfigDirPath()) {
+ this.path = path.join(configDir, 'packages.cson')
}
/**
* Gets the packages from the list.
*/
getPackages(): string[] {
- if (fs.existsSync(PackageList.getPackageListPath())) {
- let obj = CSON.readFileSync(PackageList.getPackageListPath()) as PackagesFile
+ if (fs.existsSync(this.path)) {
+ let obj = CSON.readFileSync(this.path) as PackagesFile
return obj.packages
}
@@ -36,11 +33,11 @@ export default class PackageList {
* the `forceOverwrite` configuration option is set to `true`.
*/
setPackages(): void {
- if (atom.config.get('package-sync.forceOverwrite') || !fs.existsSync(PackageList.getPackageListPath())) {
+ if (atom.config.get('package-sync.forceOverwrite') || !fs.existsSync(this.path)) {
let available = atom.packages.getAvailablePackageNames()
let names = available.filter((name: string) => { return !atom.packages.isBundledPackage(name) })
- CSON.writeFileSync(PackageList.getPackageListPath(), {packages: names})
+ CSON.writeFileSync(this.path, {packages: names})
}
}
}
diff --git a/lib/package-sync.ts b/lib/package-sync.ts
index 600cfe2..7688a7a 100644
--- a/lib/package-sync.ts
+++ b/lib/package-sync.ts
@@ -25,15 +25,17 @@ export default class PackageSync {
/**
* Creates the package list.
*/
- createPackageList(): void {
- new PackageList().setPackages()
+ createPackageList(configDir?: string): void {
+ let list = new PackageList(configDir)
+ list.setPackages()
}
/**
* Opens the package list in the workspace.
*/
- openPackageList(): void {
- atom.workspace.open(PackageList.getPackageListPath())
+ openPackageList(configDir?: string): void {
+ let list = new PackageList(configDir)
+ atom.workspace.open(list.path)
}
/**
@@ -97,12 +99,12 @@ export default class PackageSync {
/**
* Gets the list of missing package names by comparing against the current package list.
*/
- getMissingPackages(): string[] {
- let list = new PackageList()
+ getMissingPackages(configDir?: string): string[] {
+ let list = new PackageList(configDir)
let syncPackages = list.getPackages()
let availablePackages = atom.packages.getAvailablePackageNames()
- return syncPackages.filter((value) => { !(value in availablePackages) })
+ return syncPackages.filter((value) => { return !(value in availablePackages) })
}
/**
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..f21f74b
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,1284 @@
+{
+ "name": "package-sync",
+ "version": "1.1.0",
+ "lockfileVersion": 1,
+ "requires": true,
+ "dependencies": {
+ "@types/atom": {
+ "version": "1.23.0",
+ "resolved": "https://registry.npmjs.org/@types/atom/-/atom-1.23.0.tgz",
+ "integrity": "sha512-yJIXw3ITdV01JoQRXJAVngzGirmrNpGJPgVTSLkTAzCSMwePslPCuc5ryQlN1DF7yY92zYbvpdJ+spNSCe8odQ==",
+ "requires": {
+ "@types/jquery": "3.2.17",
+ "@types/node": "8.5.2"
+ }
+ },
+ "@types/atom-mocha-test-runner": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@types/atom-mocha-test-runner/-/atom-mocha-test-runner-1.0.2.tgz",
+ "integrity": "sha512-49cwl/SSvOEjPCToOv6KLpparFgmOy6iPFqIzLf+60dP1sIG7AR/Wi8uoICniu9WqCIH9cDnxBMRPOEuFyIxRA==",
+ "dev": true,
+ "requires": {
+ "@types/atom": "1.23.0",
+ "@types/mocha": "2.2.45"
+ }
+ },
+ "@types/chai": {
+ "version": "4.0.10",
+ "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.0.10.tgz",
+ "integrity": "sha512-Ejh1AXTY8lm+x91X/yar3G2z4x9RyKwdTVdyyu7Xj3dNB35fMNCnEWqTO9FgS3zjzlRNqk1MruYhgb8yhRN9rA==",
+ "dev": true
+ },
+ "@types/jquery": {
+ "version": "3.2.17",
+ "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.2.17.tgz",
+ "integrity": "sha512-lt8i2ZqymxxN1JnWSOTPU7Xc3ze32lhASkVdsMd6/SZnb/jtBsmFEoYCBSa0tzGDSyO7ZB+4r4aihj+KTlDs5w=="
+ },
+ "@types/mocha": {
+ "version": "2.2.45",
+ "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-2.2.45.tgz",
+ "integrity": "sha512-tE1SYtNG3I3atRVPELSGN2FJJJtPg3O/G0tycYSyzeDqdAbdLPRH089LhpWYA5M/iHeWHkVZq/b0OVKngcK0Eg==",
+ "dev": true,
+ "requires": {
+ "@types/node": "8.5.2"
+ }
+ },
+ "@types/node": {
+ "version": "8.5.2",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-8.5.2.tgz",
+ "integrity": "sha512-KA4GKOpgXnrqEH2eCVhiv2CsxgXGQJgV1X0vsGlh+WCnxbeAE1GT44ZsTU1IN5dEeV/gDupKa7gWo08V5IxWVQ=="
+ },
+ "ajv": {
+ "version": "4.11.8",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz",
+ "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "co": "4.6.0",
+ "json-stable-stringify": "1.0.1"
+ }
+ },
+ "ansi-styles": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz",
+ "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==",
+ "dev": true,
+ "requires": {
+ "color-convert": "1.9.1"
+ }
+ },
+ "asap": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
+ "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=",
+ "dev": true,
+ "optional": true
+ },
+ "asn1": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz",
+ "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=",
+ "dev": true,
+ "optional": true
+ },
+ "assert-plus": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz",
+ "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=",
+ "dev": true,
+ "optional": true
+ },
+ "assertion-error": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.0.2.tgz",
+ "integrity": "sha1-E8pRXYYgbaC6xm6DTdOX2HWBCUw=",
+ "dev": true
+ },
+ "async": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
+ "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo="
+ },
+ "asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
+ "dev": true,
+ "optional": true
+ },
+ "atom-mocha-test-runner": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/atom-mocha-test-runner/-/atom-mocha-test-runner-1.2.0.tgz",
+ "integrity": "sha512-HVbx7cAvySjVfVNKpb2go9RO890Xs6yigWWAwoISOz4l2X5oMTMs1rIw04geuEQeTTmW3ob3nj6YN1KWf2cBHg==",
+ "dev": true,
+ "requires": {
+ "etch": "0.8.0",
+ "grim": "2.0.2",
+ "less": "2.7.3",
+ "mocha": "3.5.3",
+ "tmp": "0.0.31"
+ }
+ },
+ "atom-transpiler-debug-tool": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/atom-transpiler-debug-tool/-/atom-transpiler-debug-tool-1.0.3.tgz",
+ "integrity": "sha512-lnfbrZDTKStt10dFG+ihtpyffrbBy2Z7/ePyLb3klsUel/a3oggVMKg1p5G9GxK3seYKVr/2/TZhsYhvonf8Ew==",
+ "dev": true,
+ "requires": {
+ "chalk": "2.3.0",
+ "glob": "7.1.2",
+ "resolve": "1.5.0"
+ }
+ },
+ "atom-ts-transpiler": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/atom-ts-transpiler/-/atom-ts-transpiler-1.4.0.tgz",
+ "integrity": "sha512-yL+/EquJIJwSG3xm357LT1X8QYYngEROXfxRo5yN5nrI1bgAUmvrBzx4ENZG0ufhr8BsBWjMFmMgHE3QNMm/+A=="
+ },
+ "aws-sign2": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz",
+ "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=",
+ "dev": true,
+ "optional": true
+ },
+ "aws4": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz",
+ "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=",
+ "dev": true,
+ "optional": true
+ },
+ "balanced-match": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
+ },
+ "bcrypt-pbkdf": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz",
+ "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "tweetnacl": "0.14.5"
+ }
+ },
+ "boom": {
+ "version": "2.10.1",
+ "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz",
+ "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=",
+ "dev": true,
+ "requires": {
+ "hoek": "2.16.3"
+ }
+ },
+ "brace-expansion": {
+ "version": "1.1.8",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz",
+ "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=",
+ "requires": {
+ "balanced-match": "1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "browser-split": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/browser-split/-/browser-split-0.0.1.tgz",
+ "integrity": "sha1-ewl1dPjj6tYG+0Zk5krf3aKYGpM=",
+ "dev": true
+ },
+ "browser-stdout": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz",
+ "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=",
+ "dev": true
+ },
+ "camelize": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz",
+ "integrity": "sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs=",
+ "dev": true
+ },
+ "caseless": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
+ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
+ "dev": true,
+ "optional": true
+ },
+ "chai": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chai/-/chai-4.1.2.tgz",
+ "integrity": "sha1-D2RYS6ZC8PKs4oBiefTwbKI61zw=",
+ "dev": true,
+ "requires": {
+ "assertion-error": "1.0.2",
+ "check-error": "1.0.2",
+ "deep-eql": "3.0.1",
+ "get-func-name": "2.0.0",
+ "pathval": "1.1.0",
+ "type-detect": "4.0.5"
+ }
+ },
+ "chalk": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz",
+ "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "3.2.0",
+ "escape-string-regexp": "1.0.5",
+ "supports-color": "4.5.0"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz",
+ "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=",
+ "dev": true
+ },
+ "supports-color": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz",
+ "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=",
+ "dev": true,
+ "requires": {
+ "has-flag": "2.0.0"
+ }
+ }
+ }
+ },
+ "check-error": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz",
+ "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=",
+ "dev": true
+ },
+ "co": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
+ "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=",
+ "dev": true,
+ "optional": true
+ },
+ "coffee-script": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.9.0.tgz",
+ "integrity": "sha1-dJLLvD8DYcxdiGWv9yN1Uv8z4fc="
+ },
+ "color-convert": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz",
+ "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "1.1.3"
+ }
+ },
+ "color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+ "dev": true
+ },
+ "combined-stream": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz",
+ "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=",
+ "dev": true,
+ "requires": {
+ "delayed-stream": "1.0.0"
+ }
+ },
+ "commander": {
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz",
+ "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=",
+ "dev": true,
+ "requires": {
+ "graceful-readlink": "1.0.1"
+ }
+ },
+ "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=",
+ "dev": true,
+ "optional": true
+ },
+ "cryptiles": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz",
+ "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "boom": "2.10.1"
+ }
+ },
+ "cson-parser": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/cson-parser/-/cson-parser-1.0.9.tgz",
+ "integrity": "sha1-t5/BuCp3V0NoDw7/uL+tMRNNrHQ=",
+ "requires": {
+ "coffee-script": "1.9.0"
+ }
+ },
+ "dashdash": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
+ "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "assert-plus": "1.0.0"
+ },
+ "dependencies": {
+ "assert-plus": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
+ "dev": true,
+ "optional": true
+ }
+ }
+ },
+ "debug": {
+ "version": "2.6.8",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
+ "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=",
+ "dev": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "deep-eql": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz",
+ "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==",
+ "dev": true,
+ "requires": {
+ "type-detect": "4.0.5"
+ }
+ },
+ "delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
+ "dev": true
+ },
+ "diff": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz",
+ "integrity": "sha1-yc45Okt8vQsFinJck98pkCeGj/k=",
+ "dev": true
+ },
+ "dom-walk": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.1.tgz",
+ "integrity": "sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg=",
+ "dev": true
+ },
+ "ecc-jsbn": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz",
+ "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "jsbn": "0.1.1"
+ }
+ },
+ "errno": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.6.tgz",
+ "integrity": "sha512-IsORQDpaaSwcDP4ZZnHxgE85werpo34VYn1Ud3mq+eUsF593faR8oCZNXrROVkpFu2TsbrNhHin0aUrTsQ9vNw==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "prr": "1.0.1"
+ }
+ },
+ "error": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/error/-/error-4.4.0.tgz",
+ "integrity": "sha1-v2n/JR+0onnBmtzNqmth6Q2b8So=",
+ "dev": true,
+ "requires": {
+ "camelize": "1.0.0",
+ "string-template": "0.2.1",
+ "xtend": "4.0.1"
+ }
+ },
+ "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=",
+ "dev": true
+ },
+ "etch": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/etch/-/etch-0.8.0.tgz",
+ "integrity": "sha1-VPYZV0NG+KPueXP1T7vQG1YnItY=",
+ "dev": true,
+ "requires": {
+ "virtual-dom": "2.1.1"
+ }
+ },
+ "ev-store": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/ev-store/-/ev-store-7.0.0.tgz",
+ "integrity": "sha1-GrDH+CE2UF3XSzHRdwHLK+bSZVg=",
+ "dev": true,
+ "requires": {
+ "individual": "3.0.0"
+ }
+ },
+ "event-kit": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/event-kit/-/event-kit-2.4.0.tgz",
+ "integrity": "sha512-ZXd9jxUoc/f/zdLdR3OUcCzT84WnpaNWefquLyE125akIC90sDs8S3T/qihliuVsaj7Osc0z8lLL2fjooE9Z4A==",
+ "dev": true
+ },
+ "extend": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz",
+ "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=",
+ "dev": true,
+ "optional": true
+ },
+ "extsprintf": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
+ "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
+ "dev": true
+ },
+ "forever-agent": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
+ "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=",
+ "dev": true,
+ "optional": true
+ },
+ "form-data": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz",
+ "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "asynckit": "0.4.0",
+ "combined-stream": "1.0.5",
+ "mime-types": "2.1.17"
+ }
+ },
+ "fs-plus": {
+ "version": "2.10.1",
+ "resolved": "https://registry.npmjs.org/fs-plus/-/fs-plus-2.10.1.tgz",
+ "integrity": "sha1-MgR4HXhAYR5jZOe2+wWMljJ8WqU=",
+ "requires": {
+ "async": "1.5.2",
+ "mkdirp": "0.5.1",
+ "rimraf": "2.6.2",
+ "underscore-plus": "1.6.6"
+ }
+ },
+ "fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
+ },
+ "get-func-name": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz",
+ "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=",
+ "dev": true
+ },
+ "getpass": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
+ "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "assert-plus": "1.0.0"
+ },
+ "dependencies": {
+ "assert-plus": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
+ "dev": true,
+ "optional": true
+ }
+ }
+ },
+ "glob": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
+ "integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=",
+ "requires": {
+ "fs.realpath": "1.0.0",
+ "inflight": "1.0.6",
+ "inherits": "2.0.3",
+ "minimatch": "3.0.4",
+ "once": "1.4.0",
+ "path-is-absolute": "1.0.1"
+ }
+ },
+ "global": {
+ "version": "4.3.2",
+ "resolved": "https://registry.npmjs.org/global/-/global-4.3.2.tgz",
+ "integrity": "sha1-52mJJopsdMOJCLEwWxD8DjlOnQ8=",
+ "dev": true,
+ "requires": {
+ "min-document": "2.19.0",
+ "process": "0.5.2"
+ }
+ },
+ "graceful-fs": {
+ "version": "4.1.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
+ "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
+ "dev": true,
+ "optional": true
+ },
+ "graceful-readlink": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz",
+ "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=",
+ "dev": true
+ },
+ "grim": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/grim/-/grim-2.0.2.tgz",
+ "integrity": "sha512-Qj7hTJRfd87E/gUgfvM0YIH/g2UA2SV6niv6BYXk1o6w4mhgv+QyYM1EjOJQljvzgEj4SqSsRWldXIeKHz3e3Q==",
+ "dev": true,
+ "requires": {
+ "event-kit": "2.4.0"
+ }
+ },
+ "growl": {
+ "version": "1.9.2",
+ "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz",
+ "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=",
+ "dev": true
+ },
+ "har-schema": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz",
+ "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=",
+ "dev": true,
+ "optional": true
+ },
+ "har-validator": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz",
+ "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "ajv": "4.11.8",
+ "har-schema": "1.0.5"
+ }
+ },
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+ "dev": true
+ },
+ "hawk": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz",
+ "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "boom": "2.10.1",
+ "cryptiles": "2.0.5",
+ "hoek": "2.16.3",
+ "sntp": "1.0.9"
+ }
+ },
+ "he": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz",
+ "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=",
+ "dev": true
+ },
+ "hoek": {
+ "version": "2.16.3",
+ "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz",
+ "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=",
+ "dev": true
+ },
+ "http-signature": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz",
+ "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "assert-plus": "0.2.0",
+ "jsprim": "1.4.1",
+ "sshpk": "1.13.1"
+ }
+ },
+ "image-size": {
+ "version": "0.5.5",
+ "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz",
+ "integrity": "sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=",
+ "dev": true,
+ "optional": true
+ },
+ "individual": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/individual/-/individual-3.0.0.tgz",
+ "integrity": "sha1-58pPhfiVewGHNPKFdQ3CLsL5hi0=",
+ "dev": true
+ },
+ "inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+ "requires": {
+ "once": "1.4.0",
+ "wrappy": "1.0.2"
+ }
+ },
+ "inherits": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
+ },
+ "is-object": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz",
+ "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=",
+ "dev": true
+ },
+ "is-typedarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
+ "dev": true,
+ "optional": true
+ },
+ "isstream": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
+ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
+ "dev": true,
+ "optional": true
+ },
+ "jsbn": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
+ "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
+ "dev": true,
+ "optional": true
+ },
+ "json-schema": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
+ "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=",
+ "dev": true,
+ "optional": true
+ },
+ "json-stable-stringify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz",
+ "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "jsonify": "0.0.0"
+ }
+ },
+ "json-stringify-safe": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
+ "dev": true,
+ "optional": true
+ },
+ "json3": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz",
+ "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=",
+ "dev": true
+ },
+ "jsonify": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
+ "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=",
+ "dev": true,
+ "optional": true
+ },
+ "jsprim": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
+ "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "assert-plus": "1.0.0",
+ "extsprintf": "1.3.0",
+ "json-schema": "0.2.3",
+ "verror": "1.10.0"
+ },
+ "dependencies": {
+ "assert-plus": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
+ "dev": true,
+ "optional": true
+ }
+ }
+ },
+ "less": {
+ "version": "2.7.3",
+ "resolved": "https://registry.npmjs.org/less/-/less-2.7.3.tgz",
+ "integrity": "sha512-KPdIJKWcEAb02TuJtaLrhue0krtRLoRoo7x6BNJIBelO00t/CCdJQUnHW5V34OnHMWzIktSalJxRO+FvytQlCQ==",
+ "dev": true,
+ "requires": {
+ "errno": "0.1.6",
+ "graceful-fs": "4.1.11",
+ "image-size": "0.5.5",
+ "mime": "1.6.0",
+ "mkdirp": "0.5.1",
+ "promise": "7.3.1",
+ "request": "2.81.0",
+ "source-map": "0.5.7"
+ }
+ },
+ "lodash._baseassign": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz",
+ "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=",
+ "dev": true,
+ "requires": {
+ "lodash._basecopy": "3.0.1",
+ "lodash.keys": "3.1.2"
+ }
+ },
+ "lodash._basecopy": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz",
+ "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=",
+ "dev": true
+ },
+ "lodash._basecreate": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz",
+ "integrity": "sha1-G8ZhYU2qf8MRt9A78WgGoCE8+CE=",
+ "dev": true
+ },
+ "lodash._getnative": {
+ "version": "3.9.1",
+ "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz",
+ "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=",
+ "dev": true
+ },
+ "lodash._isiterateecall": {
+ "version": "3.0.9",
+ "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz",
+ "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=",
+ "dev": true
+ },
+ "lodash.create": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/lodash.create/-/lodash.create-3.1.1.tgz",
+ "integrity": "sha1-1/KEnw29p+BGgruM1yqwIkYd6+c=",
+ "dev": true,
+ "requires": {
+ "lodash._baseassign": "3.2.0",
+ "lodash._basecreate": "3.0.3",
+ "lodash._isiterateecall": "3.0.9"
+ }
+ },
+ "lodash.isarguments": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
+ "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=",
+ "dev": true
+ },
+ "lodash.isarray": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz",
+ "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=",
+ "dev": true
+ },
+ "lodash.keys": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz",
+ "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=",
+ "dev": true,
+ "requires": {
+ "lodash._getnative": "3.9.1",
+ "lodash.isarguments": "3.1.0",
+ "lodash.isarray": "3.0.4"
+ }
+ },
+ "mime": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+ "dev": true,
+ "optional": true
+ },
+ "mime-db": {
+ "version": "1.30.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz",
+ "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=",
+ "dev": true
+ },
+ "mime-types": {
+ "version": "2.1.17",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz",
+ "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=",
+ "dev": true,
+ "requires": {
+ "mime-db": "1.30.0"
+ }
+ },
+ "min-document": {
+ "version": "2.19.0",
+ "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz",
+ "integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=",
+ "dev": true,
+ "requires": {
+ "dom-walk": "0.1.1"
+ }
+ },
+ "minimatch": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+ "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=",
+ "requires": {
+ "brace-expansion": "1.1.8"
+ }
+ },
+ "minimist": {
+ "version": "0.0.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+ "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
+ },
+ "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"
+ }
+ },
+ "mocha": {
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/mocha/-/mocha-3.5.3.tgz",
+ "integrity": "sha512-/6na001MJWEtYxHOV1WLfsmR4YIynkUEhBwzsb+fk2qmQ3iqsi258l/Q2MWHJMImAcNpZ8DEdYAK72NHoIQ9Eg==",
+ "dev": true,
+ "requires": {
+ "browser-stdout": "1.3.0",
+ "commander": "2.9.0",
+ "debug": "2.6.8",
+ "diff": "3.2.0",
+ "escape-string-regexp": "1.0.5",
+ "glob": "7.1.1",
+ "growl": "1.9.2",
+ "he": "1.1.1",
+ "json3": "3.3.2",
+ "lodash.create": "3.1.1",
+ "mkdirp": "0.5.1",
+ "supports-color": "3.1.2"
+ },
+ "dependencies": {
+ "glob": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz",
+ "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=",
+ "dev": true,
+ "requires": {
+ "fs.realpath": "1.0.0",
+ "inflight": "1.0.6",
+ "inherits": "2.0.3",
+ "minimatch": "3.0.4",
+ "once": "1.4.0",
+ "path-is-absolute": "1.0.1"
+ }
+ }
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ },
+ "next-tick": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-0.2.2.tgz",
+ "integrity": "sha1-ddpKkn7liH45BliABltzNkE7MQ0=",
+ "dev": true
+ },
+ "oauth-sign": {
+ "version": "0.8.2",
+ "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz",
+ "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=",
+ "dev": true,
+ "optional": true
+ },
+ "once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+ "requires": {
+ "wrappy": "1.0.2"
+ }
+ },
+ "optimist": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.4.0.tgz",
+ "integrity": "sha1-y47Dfy/jqphky2eidSUOfhliCiU=",
+ "requires": {
+ "wordwrap": "0.0.3"
+ }
+ },
+ "os-tmpdir": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+ "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
+ "dev": true
+ },
+ "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-parse": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz",
+ "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=",
+ "dev": true
+ },
+ "pathval": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz",
+ "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=",
+ "dev": true
+ },
+ "performance-now": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz",
+ "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=",
+ "dev": true,
+ "optional": true
+ },
+ "process": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/process/-/process-0.5.2.tgz",
+ "integrity": "sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8=",
+ "dev": true
+ },
+ "promise": {
+ "version": "7.3.1",
+ "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
+ "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "asap": "2.0.6"
+ }
+ },
+ "prr": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
+ "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=",
+ "dev": true,
+ "optional": true
+ },
+ "punycode": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+ "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
+ "dev": true,
+ "optional": true
+ },
+ "qs": {
+ "version": "6.4.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz",
+ "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=",
+ "dev": true,
+ "optional": true
+ },
+ "request": {
+ "version": "2.81.0",
+ "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz",
+ "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "aws-sign2": "0.6.0",
+ "aws4": "1.6.0",
+ "caseless": "0.12.0",
+ "combined-stream": "1.0.5",
+ "extend": "3.0.1",
+ "forever-agent": "0.6.1",
+ "form-data": "2.1.4",
+ "har-validator": "4.2.1",
+ "hawk": "3.1.3",
+ "http-signature": "1.1.1",
+ "is-typedarray": "1.0.0",
+ "isstream": "0.1.2",
+ "json-stringify-safe": "5.0.1",
+ "mime-types": "2.1.17",
+ "oauth-sign": "0.8.2",
+ "performance-now": "0.2.0",
+ "qs": "6.4.0",
+ "safe-buffer": "5.1.1",
+ "stringstream": "0.0.5",
+ "tough-cookie": "2.3.3",
+ "tunnel-agent": "0.6.0",
+ "uuid": "3.1.0"
+ }
+ },
+ "resolve": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.5.0.tgz",
+ "integrity": "sha512-hgoSGrc3pjzAPHNBg+KnFcK2HwlHTs/YrAGUr6qgTVUZmXv1UEXXl0bZNBKMA9fud6lRYFdPGz0xXxycPzmmiw==",
+ "dev": true,
+ "requires": {
+ "path-parse": "1.0.5"
+ }
+ },
+ "rimraf": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
+ "integrity": "sha1-LtgVDSShbqhlHm1u8PR8QVjOejY=",
+ "requires": {
+ "glob": "7.1.2"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
+ "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==",
+ "dev": true
+ },
+ "season": {
+ "version": "5.4.1",
+ "resolved": "https://registry.npmjs.org/season/-/season-5.4.1.tgz",
+ "integrity": "sha1-S9baYVKn8tbwixQzzi2SBmmFPQ0=",
+ "requires": {
+ "cson-parser": "1.0.9",
+ "fs-plus": "2.10.1",
+ "optimist": "0.4.0"
+ }
+ },
+ "sntp": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz",
+ "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "hoek": "2.16.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+ "dev": true,
+ "optional": true
+ },
+ "sshpk": {
+ "version": "1.13.1",
+ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz",
+ "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "asn1": "0.2.3",
+ "assert-plus": "1.0.0",
+ "bcrypt-pbkdf": "1.0.1",
+ "dashdash": "1.14.1",
+ "ecc-jsbn": "0.1.1",
+ "getpass": "0.1.7",
+ "jsbn": "0.1.1",
+ "tweetnacl": "0.14.5"
+ },
+ "dependencies": {
+ "assert-plus": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
+ "dev": true,
+ "optional": true
+ }
+ }
+ },
+ "string-template": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz",
+ "integrity": "sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0=",
+ "dev": true
+ },
+ "stringstream": {
+ "version": "0.0.5",
+ "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz",
+ "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=",
+ "dev": true,
+ "optional": true
+ },
+ "supports-color": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz",
+ "integrity": "sha1-cqJiiU2dQIuVbKBf83su2KbiotU=",
+ "dev": true,
+ "requires": {
+ "has-flag": "1.0.0"
+ }
+ },
+ "tmp": {
+ "version": "0.0.31",
+ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.31.tgz",
+ "integrity": "sha1-jzirlDjhcxXl29izZX6L+yd65Kc=",
+ "dev": true,
+ "requires": {
+ "os-tmpdir": "1.0.2"
+ }
+ },
+ "tough-cookie": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz",
+ "integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "punycode": "1.4.1"
+ }
+ },
+ "tunnel-agent": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+ "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "safe-buffer": "5.1.1"
+ }
+ },
+ "tweetnacl": {
+ "version": "0.14.5",
+ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
+ "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
+ "dev": true,
+ "optional": true
+ },
+ "type-detect": {
+ "version": "4.0.5",
+ "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.5.tgz",
+ "integrity": "sha512-N9IvkQslUGYGC24RkJk1ba99foK6TkwC2FHAEBlQFBP0RxQZS8ZpJuAZcwiY/w9ZJHFQb1aOXBI60OdxhTrwEQ==",
+ "dev": true
+ },
+ "typescript": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.6.2.tgz",
+ "integrity": "sha1-PFtv1/beCRQmkCfwPAlGdY92c6Q="
+ },
+ "underscore": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz",
+ "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag="
+ },
+ "underscore-plus": {
+ "version": "1.6.6",
+ "resolved": "https://registry.npmjs.org/underscore-plus/-/underscore-plus-1.6.6.tgz",
+ "integrity": "sha1-ZezeG9xEGjXYnmUP1w3PE65Dmn0=",
+ "requires": {
+ "underscore": "1.6.0"
+ }
+ },
+ "uuid": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz",
+ "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==",
+ "dev": true,
+ "optional": true
+ },
+ "verror": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
+ "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "assert-plus": "1.0.0",
+ "core-util-is": "1.0.2",
+ "extsprintf": "1.3.0"
+ },
+ "dependencies": {
+ "assert-plus": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
+ "dev": true,
+ "optional": true
+ }
+ }
+ },
+ "virtual-dom": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/virtual-dom/-/virtual-dom-2.1.1.tgz",
+ "integrity": "sha1-gO2i1IG57eDASRGM78tKBfIdE3U=",
+ "dev": true,
+ "requires": {
+ "browser-split": "0.0.1",
+ "error": "4.4.0",
+ "ev-store": "7.0.0",
+ "global": "4.3.2",
+ "is-object": "1.0.1",
+ "next-tick": "0.2.2",
+ "x-is-array": "0.1.0",
+ "x-is-string": "0.1.0"
+ }
+ },
+ "wordwrap": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
+ "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc="
+ },
+ "wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
+ },
+ "x-is-array": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/x-is-array/-/x-is-array-0.1.0.tgz",
+ "integrity": "sha1-3lIBcdR7P0FvVYfWKbidJrEtwp0=",
+ "dev": true
+ },
+ "x-is-string": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/x-is-string/-/x-is-string-0.1.0.tgz",
+ "integrity": "sha1-R0tQhlrzpJqcRlfwWs0UVFj3fYI=",
+ "dev": true
+ },
+ "xtend": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
+ "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=",
+ "dev": true
+ }
+ }
+}
diff --git a/package.json b/package.json
index 4dc087c..2c97aaa 100644
--- a/package.json
+++ b/package.json
@@ -22,10 +22,13 @@
"@types/node": "^8.5.2"
},
"devDependencies": {
+ "@types/atom-mocha-test-runner": "^1.0.2",
+ "@types/chai": "^4.0.10",
"atom-mocha-test-runner": "^1.2.0",
+ "atom-transpiler-debug-tool": "^1.0.3",
"chai": "^4.1.2"
},
- "atomTestRunner": "atom-mocha-test-runner",
+ "atomTestRunner": "./spec/runner",
"atomTranspilers": [
{
"transpiler": "atom-ts-transpiler",
@@ -55,5 +58,8 @@
"type": "boolean",
"default": false
}
+ },
+ "scripts": {
+ "debug": "atom-transpiler-debug-tool"
}
}
diff --git a/spec/helpers.coffee b/spec/helpers.coffee
deleted file mode 100644
index 90c2e33..0000000
--- a/spec/helpers.coffee
+++ /dev/null
@@ -1,16 +0,0 @@
-CSON = require 'season'
-fs = require 'fs'
-os = require 'os'
-path = require 'path'
-
-# Module of helper methods for tests.
-module.exports =
- createPackages: (packages, packagesPath = @getPackagesPath()) ->
- CSON.writeFileSync(packagesPath, packages)
-
- deletePackages: (packagesPath = @getPackagesPath()) ->
- if fs.existsSync(packagesPath)
- fs.unlinkSync(packagesPath)
-
- getPackagesPath: ->
- path.join(os.tmpdir(), 'packages.cson')
diff --git a/spec/helpers.ts b/spec/helpers.ts
new file mode 100644
index 0000000..0a8a64b
--- /dev/null
+++ b/spec/helpers.ts
@@ -0,0 +1,22 @@
+import * as CSON from 'season'
+import * as fs from 'fs'
+import * as os from 'os'
+import * as path from 'path'
+
+export function createList(list: string[]): void {
+ let packagesPath = getPackagesPath()
+
+ CSON.writeFileSync(packagesPath, {packages: list})
+}
+
+export function deleteList(): void {
+ let packagesPath = getPackagesPath()
+
+ if (fs.existsSync(packagesPath)) {
+ fs.unlinkSync(packagesPath)
+ }
+}
+
+export function getPackagesPath(): string {
+ return path.join(os.tmpdir(), 'packages.cson')
+}
diff --git a/spec/package-list.spec.ts b/spec/package-list.spec.ts
new file mode 100644
index 0000000..cf15ea5
--- /dev/null
+++ b/spec/package-list.spec.ts
@@ -0,0 +1,116 @@
+import * as chai from 'chai'
+import * as fs from 'fs'
+import * as os from 'os'
+
+import PackageList from '../lib/package-list'
+
+import {createList, deleteList, getPackagesPath} from './helpers'
+
+const expect = chai.expect
+
+describe('PackageList', () => {
+ let list: PackageList
+
+ beforeEach(() => {
+ list = new PackageList(os.tmpdir())
+ })
+
+ describe('getPackages', () => {
+ beforeEach(() => {
+ deleteList()
+ })
+
+ it('gives an empty array when there is no packages.cson', () => {
+ expect(list.getPackages()).to.be.empty
+ })
+
+ it('gives an empty array when the package list is empty', () => {
+ createList([])
+ expect(list.getPackages()).to.be.empty
+ })
+
+ it('gives the packages list when the list is non-empty', () => {
+ createList(['foo', 'bar', 'baz'])
+ expect(list.getPackages()).to.have.members(['foo', 'bar', 'baz'])
+ })
+ })
+
+ describe('setPackages', () => {
+ describe('when forceOverwrite is set to false', () => {
+ beforeEach(() => {
+ atom.config.set('package-sync.forceOverwrite', false)
+ })
+
+ describe('when the file does not exist', () => {
+ beforeEach(() => {
+ deleteList()
+ })
+
+ it('creates the packages file', () => {
+ list.setPackages()
+
+ expect(fs.existsSync(getPackagesPath())).to.be.true
+ })
+
+ it('includes all of the currently installed packages', () => {
+ let available = atom.packages.getAvailablePackageNames()
+ let installed = available.filter((name: string) => { return !atom.packages.isBundledPackage(name) })
+
+ expect(list.getPackages()).to.have.members(installed)
+ })
+ })
+
+ describe('when the file does exist', () => {
+ beforeEach(() => {
+ createList([])
+ })
+
+ it('does not change the file', () => {
+ list.setPackages()
+
+ expect(list.getPackages()).to.be.empty
+ })
+ })
+ })
+
+ describe('when forceOverwrite is set to true', () => {
+ beforeEach(() => {
+ atom.config.set('package-sync.forceOverwrite', true)
+ })
+
+ describe('when the file does not exist', () => {
+ beforeEach(() => {
+ deleteList()
+ })
+
+ it('creates the packages file', () => {
+ list.setPackages()
+
+ expect(fs.existsSync(getPackagesPath())).to.be.true
+ })
+
+ it('includes all of the currently installed packages', () => {
+ let available = atom.packages.getAvailablePackageNames()
+ let installed = available.filter((name: string) => { return !atom.packages.isBundledPackage(name) })
+
+ expect(list.getPackages()).to.have.members(installed)
+ })
+ })
+
+ describe('when the file does exist', () => {
+ beforeEach(() => {
+ createList([])
+ })
+
+ it('updates the contents of the file', () => {
+ list.setPackages()
+
+ let available = atom.packages.getAvailablePackageNames()
+ let installed = available.filter((name: string) => { return !atom.packages.isBundledPackage(name) })
+
+ expect(list.getPackages()).to.have.members(installed)
+ })
+ })
+ })
+ })
+})
diff --git a/spec/package-list.test.coffee b/spec/package-list.test.coffee
deleted file mode 100644
index 73bead1..0000000
--- a/spec/package-list.test.coffee
+++ /dev/null
@@ -1,83 +0,0 @@
-CSON = require 'season'
-fs = require 'fs'
-path = require 'path'
-os = require 'os'
-
-PackageList = require '../lib/package-list'
-
-h = require './helpers'
-
-expect = chai.expect
-
-describe 'PackageList', ->
- list = null
-
- beforeEach ->
- spyOn(atom, 'getConfigDirPath').andReturn(os.tmpdir())
- list = new PackageList
-
- afterEach ->
- h.deletePackages()
-
- describe 'getPackages', ->
- it 'gives an empty array when there is not a packages.cson', ->
- expect(list.getPackages()).toEqual([])
-
- it 'gives an empty array when there is an empty packages.cson', ->
- h.createPackages({'packages': []})
- expect(list.getPackages()).toEqual([])
-
- it 'gives the packages list when there is a non-zero packages.cson', ->
- h.createPackages({'packages': ['foo', 'bar', 'baz']})
- expect(list.getPackages()).toEqual(['foo', 'bar', 'baz'])
-
- describe 'setPackages', ->
- beforeEach ->
- spyOn(atom.packages, 'getAvailablePackageNames').andReturn(['foo', 'bar', 'baz'])
-
- describe 'when forceOverwrite is set to false', ->
- beforeEach ->
- atom.config.set('package-sync.forceOverwrite', false)
-
- it 'creates the packages.cson if it does not exist', ->
- list.setPackages()
- expect(fs.existsSync(h.getPackagesPath())).toBe(true)
-
- it 'creates the list of packages if packages.cson does not exist', ->
- list.setPackages()
-
- packages = list.getPackages()
- available = atom.packages.getAvailablePackageNames()
- for pkg in available when not atom.packages.isBundledPackage(pkg)
- expect(packages).toContain(pkg)
-
-
- it 'does not update the packages.cson if it does exist', ->
- h.createPackages({'packages': []})
-
- list.setPackages()
-
- expect(list.getPackages()).toEqual([])
-
- describe 'when forceOverwrite is set to true', ->
- beforeEach ->
- atom.config.set('package-sync.forceOverwrite', true)
-
- it 'creates the packages.cson if it does not exist', ->
- list.setPackages()
- expect(fs.existsSync(h.getPackagesPath())).toBe(true)
-
- it 'creates the list of packages if packages.cson does not exist', ->
- list.setPackages()
-
- packages = list.getPackages()
- available = atom.packages.getAvailablePackageNames()
- for pkg in available when not atom.packages.isBundledPackage(pkg)
- expect(packages).toContain(pkg)
-
- it 'updates the packages.cson if it does exist', ->
- h.createPackages({'packages': []})
-
- list.setPackages()
-
- expect(list.getPackages()).not.toEqual([])
diff --git a/spec/package-sync.spec.ts b/spec/package-sync.spec.ts
new file mode 100644
index 0000000..544e73c
--- /dev/null
+++ b/spec/package-sync.spec.ts
@@ -0,0 +1,26 @@
+import * as chai from 'chai'
+import * as os from 'os'
+
+import PackageSync from '../lib/package-sync'
+
+import {createList, deleteList} from './helpers'
+
+const expect = chai.expect
+
+describe('PackageSync', () => {
+ let sync: PackageSync
+
+ beforeEach(() => {
+ deleteList()
+
+ sync = new PackageSync()
+ })
+
+ describe('getMissingPackages', () => {
+ it('gets a list of missing packages', () => {
+ createList(['foo', 'bar', 'baz'])
+
+ expect(sync.getMissingPackages(os.tmpdir())).to.have.members(['foo', 'bar', 'baz'])
+ })
+ })
+})
diff --git a/spec/package-sync.test.coffee b/spec/package-sync.test.coffee
deleted file mode 100644
index 619e499..0000000
--- a/spec/package-sync.test.coffee
+++ /dev/null
@@ -1,26 +0,0 @@
-os = require 'os'
-
-PackageSync = require '../lib/package-sync'
-
-h = require './helpers'
-
-describe 'PackageSync', ->
- beforeEach ->
- @sync = new PackageSync()
-
- afterEach ->
- h.deletePackages()
-
- describe 'getMissingPackages', ->
- it 'gets a list of missing packages', ->
- h.createPackages({'packages': ['foo', 'bar', 'baz']})
- spyOn(atom, 'getConfigDirPath').andReturn(os.tmpdir())
-
- expect(@sync.getMissingPackages()).toEqual(['foo', 'bar', 'baz'])
-
- it 'gets a list of missing packages, excluding ones that are not missing', ->
- h.createPackages({'packages': ['foo', 'bar', 'baz']})
- spyOn(atom, 'getConfigDirPath').andReturn(os.tmpdir())
- spyOn(atom.packages, 'getAvailablePackageNames').andReturn(['foo'])
-
- expect(@sync.getMissingPackages()).toEqual(['bar', 'baz'])
diff --git a/spec/runner.ts b/spec/runner.ts
new file mode 100644
index 0000000..3c25152
--- /dev/null
+++ b/spec/runner.ts
@@ -0,0 +1,7 @@
+let createRunner = require('atom-mocha-test-runner').createRunner
+
+module.exports = createRunner({
+ testSuffixes: ['spec.ts', 'spec.js']
+}, (mocha: any) => {
+ mocha.timeout(parseInt(process.env.MOCHA_TIMEOUT || '5000', 10))
+})
diff --git a/spec/status-message.test.coffee b/spec/status-message.test.coffee
deleted file mode 100644
index 6b724d7..0000000
--- a/spec/status-message.test.coffee
+++ /dev/null
@@ -1,39 +0,0 @@
-StatusMessage = require '../lib/status-message'
-
-describe 'StatusMessage', ->
- [statusBar] = []
-
- beforeEach ->
- workspaceElement = atom.views.getView(atom.workspace)
- jasmine.attachToDOM(workspaceElement)
-
- waitsForPromise -> atom.packages.activatePackage('status-bar')
-
- runs ->
- statusBar = document.querySelector 'status-bar'
-
- it 'displays a message in the status bar', ->
- spyOn(statusBar, 'addLeftTile')
-
- message = new StatusMessage('Message')
-
- expect(statusBar.addLeftTile).toHaveBeenCalled()
-
- it 'does not throw if there is no status bar', ->
- atom.packages.deactivatePackage('status-bar')
-
- new StatusMessage('Message')
-
- it 'removes the message', ->
- message = new StatusMessage('Message')
- tile = message.tile
- spyOn(tile, 'destroy')
- message.remove()
-
- expect(tile.destroy).toHaveBeenCalled()
-
- it 'updates the message', ->
- message = new StatusMessage('Message')
- message.setText('Something else')
-
- expect(message.item.innerHTML).toEqual('Something else')
From 9e2e5549c72a0b6954674c0633f1a9e5d9d18ff4 Mon Sep 17 00:00:00 2001
From: Lee Dohm <1038121+lee-dohm@users.noreply.github.com>
Date: Mon, 1 Jan 2018 20:22:06 -0800
Subject: [PATCH 10/17] :fire: coffeelint.json
---
coffeelint.json | 114 ------------------------------------------------
1 file changed, 114 deletions(-)
delete mode 100644 coffeelint.json
diff --git a/coffeelint.json b/coffeelint.json
deleted file mode 100644
index 97b888e..0000000
--- a/coffeelint.json
+++ /dev/null
@@ -1,114 +0,0 @@
-{
- "coffeescript_error": {
- "level": "error"
- },
- "arrow_spacing": {
- "name": "arrow_spacing",
- "level": "ignore"
- },
- "no_tabs": {
- "name": "no_tabs",
- "level": "error"
- },
- "no_trailing_whitespace": {
- "name": "no_trailing_whitespace",
- "level": "error",
- "allowed_in_comments": false,
- "allowed_in_empty_lines": true
- },
- "max_line_length": {
- "name": "max_line_length",
- "value": 100,
- "level": "error",
- "limitComments": true
- },
- "line_endings": {
- "name": "line_endings",
- "level": "ignore",
- "value": "unix"
- },
- "no_trailing_semicolons": {
- "name": "no_trailing_semicolons",
- "level": "error"
- },
- "indentation": {
- "name": "indentation",
- "value": 2,
- "level": "error"
- },
- "camel_case_classes": {
- "name": "camel_case_classes",
- "level": "error"
- },
- "colon_assignment_spacing": {
- "name": "colon_assignment_spacing",
- "level": "ignore",
- "spacing": {
- "left": 0,
- "right": 0
- }
- },
- "no_implicit_braces": {
- "name": "no_implicit_braces",
- "level": "ignore",
- "strict": true
- },
- "no_plusplus": {
- "name": "no_plusplus",
- "level": "ignore"
- },
- "no_throwing_strings": {
- "name": "no_throwing_strings",
- "level": "error"
- },
- "no_backticks": {
- "name": "no_backticks",
- "level": "error"
- },
- "no_implicit_parens": {
- "name": "no_implicit_parens",
- "level": "ignore"
- },
- "no_empty_param_list": {
- "name": "no_empty_param_list",
- "level": "ignore"
- },
- "no_stand_alone_at": {
- "name": "no_stand_alone_at",
- "level": "ignore"
- },
- "space_operators": {
- "name": "space_operators",
- "level": "ignore"
- },
- "duplicate_key": {
- "name": "duplicate_key",
- "level": "error"
- },
- "empty_constructor_needs_parens": {
- "name": "empty_constructor_needs_parens",
- "level": "ignore"
- },
- "cyclomatic_complexity": {
- "name": "cyclomatic_complexity",
- "value": 10,
- "level": "ignore"
- },
- "newlines_after_classes": {
- "name": "newlines_after_classes",
- "value": 3,
- "level": "ignore"
- },
- "no_unnecessary_fat_arrows": {
- "name": "no_unnecessary_fat_arrows",
- "level": "warn"
- },
- "missing_fat_arrows": {
- "name": "missing_fat_arrows",
- "level": "ignore"
- },
- "non_empty_constructor_needs_parens": {
- "name": "non_empty_constructor_needs_parens",
- "level": "ignore"
- }
-}
From bc514994dc3aa9a1f22572fba6965699410aa610 Mon Sep 17 00:00:00 2001
From: Lee Dohm <1038121+lee-dohm@users.noreply.github.com>
Date: Mon, 1 Jan 2018 20:25:59 -0800
Subject: [PATCH 11/17] Properly clean up after myself
---
lib/index.ts | 37 +++++++++++++++++++++++++------------
1 file changed, 25 insertions(+), 12 deletions(-)
diff --git a/lib/index.ts b/lib/index.ts
index 7ccbc43..bacf558 100644
--- a/lib/index.ts
+++ b/lib/index.ts
@@ -1,34 +1,47 @@
+import {CompositeDisposable} from 'atom'
+
import PackageSync from './package-sync'
+let disposable: CompositeDisposable
+
/**
* Activates the package.
*/
export function activate(): void {
+ disposable = new CompositeDisposable()
+
let packageSync = new PackageSync()
- atom.commands.add('atom-workspace', 'package-sync:create-package-list', () => {
+ disposable.add(atom.commands.add('atom-workspace', 'package-sync:create-package-list', () => {
packageSync.createPackageList()
- })
+ }))
- atom.commands.add('atom-workspace', 'package-sync:open-package-list', () => {
+ disposable.add(atom.commands.add('atom-workspace', 'package-sync:open-package-list', () => {
packageSync.openPackageList()
- })
+ }))
- atom.commands.add('atom-workspace', 'package-sync:sync', () => {
+ disposable.add(atom.commands.add('atom-workspace', 'package-sync:sync', () => {
packageSync.sync()
- })
+ }))
- atom.packages.onDidActivateInitialPackages(() => {
- atom.packages.onDidLoadPackage(() => {
+ disposable.add(atom.packages.onDidActivateInitialPackages(() => {
+ disposable.add(atom.packages.onDidLoadPackage(() => {
if (atom.config.get('package-sync.createOnChange')) {
packageSync.createPackageList()
}
- })
+ }))
- atom.packages.onDidUnloadPackage(() => {
+ disposable.add(atom.packages.onDidUnloadPackage(() => {
if (atom.config.get('package-sync.createOnChange')) {
packageSync.createPackageList()
}
- })
- })
+ }))
+ }))
+}
+
+/**
+ * Deactivates the package.
+ */
+export function deactivate(): void {
+ disposable.dispose()
}
From aacdd1866c8010f0cb1ec0632efe0a29924d1f4b Mon Sep 17 00:00:00 2001
From: Lee Dohm <1038121+lee-dohm@users.noreply.github.com>
Date: Mon, 1 Jan 2018 20:42:24 -0800
Subject: [PATCH 12/17] Flesh out the season type documentation
---
lib/season.d.ts | 41 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 41 insertions(+)
diff --git a/lib/season.d.ts b/lib/season.d.ts
index 42642af..c253565 100644
--- a/lib/season.d.ts
+++ b/lib/season.d.ts
@@ -1,7 +1,48 @@
// Type definitions for atom/season
declare module 'season' {
+ /**
+ * Returns `true` if there is a `cson` or `json` file at the given path, minus extension; false
+ * otherwise.
+ */
+ export function isObjectPath(objectPath: string): boolean
+
+ /**
+ * Read the CSON or JSON object at the given path.
+ */
+ export function readFile(objectPath: string, callback: (err: Error, obj: object) => void): void
+
+ /**
+ * Read the CSON or JSON object at the given path synchronously.
+ */
export function readFileSync(objectPath: string): object
+ /**
+ * Resolve the path (minus extension) to a CSON or JSON object file.
+ *
+ * Returns `null` if neither was found.
+ */
+ export function resolve(objectPath: string): string | null
+
+ /**
+ * Sets the cache directory to use for storing compiled CSON files.
+ */
+ export function setCacheDir(cacheDirectory: string): void
+
+ /**
+ * Convert the object to a CSON string.
+ */
+ export function stringify(obj: object): string
+
+ /**
+ * Write the object to the given path as a CSON or JSON file depending on the path's extension.
+ *
+ * Callback is called in case of an error.
+ */
+ export function writeFile(objectPath: string, obj: object, callback: (err: Error) => void): void
+
+ /**
+ * Write the object to the given path as a CSON or JSON file depending on the path's extension.
+ */
export function writeFileSync(objectPath: string, obj: object): void
}
From 792b38bbb1fa3190f7361c129d2ed3fa4c64f375 Mon Sep 17 00:00:00 2001
From: Lee Dohm <1038121+lee-dohm@users.noreply.github.com>
Date: Mon, 1 Jan 2018 20:49:22 -0800
Subject: [PATCH 13/17] Add ConfigValues types
---
lib/config.d.ts | 9 +++++++++
1 file changed, 9 insertions(+)
create mode 100644 lib/config.d.ts
diff --git a/lib/config.d.ts b/lib/config.d.ts
new file mode 100644
index 0000000..053d8b8
--- /dev/null
+++ b/lib/config.d.ts
@@ -0,0 +1,9 @@
+declare module "atom" {
+ interface ConfigValues {
+ /** Create packages list when packages or themes are installed or removed */
+ 'package-sync.createOnChange': boolean
+
+ /** Overwrite packages list even when it is present */
+ 'package-sync.forceOverwrite': boolean
+ }
+}
From ad3131fbf2067419154fd88d95da0e330e21e1af Mon Sep 17 00:00:00 2001
From: Lee Dohm <1038121+lee-dohm@users.noreply.github.com>
Date: Mon, 1 Jan 2018 21:41:19 -0800
Subject: [PATCH 14/17] Convert to using atom-ide-ui's busy-signal service
---
lib/busy-signal.d.ts | 31 ++++++++++++++++++
lib/config.d.ts | 9 ------
lib/index.ts | 24 ++++++++++++--
lib/package-sync.ts | 74 ++++++++++++-------------------------------
lib/status-message.ts | 46 ---------------------------
package.json | 7 ++++
6 files changed, 80 insertions(+), 111 deletions(-)
create mode 100644 lib/busy-signal.d.ts
delete mode 100644 lib/config.d.ts
delete mode 100644 lib/status-message.ts
diff --git a/lib/busy-signal.d.ts b/lib/busy-signal.d.ts
new file mode 100644
index 0000000..e060202
--- /dev/null
+++ b/lib/busy-signal.d.ts
@@ -0,0 +1,31 @@
+declare module 'busy-signal' {
+ export interface BusyMessage {
+ /**
+ * Clears the busy message.
+ */
+ dispose(): void
+
+ /**
+ * Sets the title of the busy message.
+ */
+ setTitle(title: string): void
+ }
+
+ export interface BusySignalOptions {
+ /**
+ * If set to `true`, the busy signal tooltip will be immediately revealed
+ * when it first becomes visible (without explicit mouse interaction).
+ */
+ revealTooltip?: boolean
+ }
+
+ export interface BusySignalService {
+ /**
+ * Activates the busy signal.
+ *
+ * The title can be updated in the returned `BusyMessage` object and the signal can be
+ * deactivated by calling `dispose` on the `BusyMessage` object.
+ */
+ reportBusy(title: string, options?: BusySignalOptions): BusyMessage
+ }
+}
diff --git a/lib/config.d.ts b/lib/config.d.ts
deleted file mode 100644
index 053d8b8..0000000
--- a/lib/config.d.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-declare module "atom" {
- interface ConfigValues {
- /** Create packages list when packages or themes are installed or removed */
- 'package-sync.createOnChange': boolean
-
- /** Overwrite packages list even when it is present */
- 'package-sync.forceOverwrite': boolean
- }
-}
diff --git a/lib/index.ts b/lib/index.ts
index bacf558..adedaad 100644
--- a/lib/index.ts
+++ b/lib/index.ts
@@ -1,8 +1,19 @@
+///
+
import {CompositeDisposable} from 'atom'
+import {BusySignalService} from 'busy-signal'
import PackageSync from './package-sync'
+let busySignal: BusySignalService
let disposable: CompositeDisposable
+let packageSync: PackageSync
+
+function loadModule(): void {
+ if (!packageSync) {
+ packageSync = new PackageSync()
+ }
+}
/**
* Activates the package.
@@ -10,35 +21,42 @@ let disposable: CompositeDisposable
export function activate(): void {
disposable = new CompositeDisposable()
- let packageSync = new PackageSync()
-
disposable.add(atom.commands.add('atom-workspace', 'package-sync:create-package-list', () => {
+ loadModule()
packageSync.createPackageList()
}))
disposable.add(atom.commands.add('atom-workspace', 'package-sync:open-package-list', () => {
+ loadModule()
packageSync.openPackageList()
}))
disposable.add(atom.commands.add('atom-workspace', 'package-sync:sync', () => {
- packageSync.sync()
+ loadModule()
+ packageSync.sync(busySignal)
}))
disposable.add(atom.packages.onDidActivateInitialPackages(() => {
disposable.add(atom.packages.onDidLoadPackage(() => {
if (atom.config.get('package-sync.createOnChange')) {
+ loadModule()
packageSync.createPackageList()
}
}))
disposable.add(atom.packages.onDidUnloadPackage(() => {
if (atom.config.get('package-sync.createOnChange')) {
+ loadModule()
packageSync.createPackageList()
}
}))
}))
}
+export function consumeBusySignal(busySignalService: BusySignalService): void {
+ busySignal = busySignalService
+}
+
/**
* Deactivates the package.
*/
diff --git a/lib/package-sync.ts b/lib/package-sync.ts
index 7688a7a..f34a757 100644
--- a/lib/package-sync.ts
+++ b/lib/package-sync.ts
@@ -1,25 +1,24 @@
+///
+
import * as fs from 'fs'
import {BufferedProcess} from 'atom'
+import {BusyMessage, BusySignalService} from 'busy-signal'
import PackageList from './package-list'
-import StatusMessage from './status-message'
export default class PackageSync {
readonly apmPath = atom.packages.getApmPath()
- readonly longMessageTimeout = 15000
- readonly shortMessageTimeout = 1000
+ busyMessage: BusyMessage
+ busySignal: BusySignalService | null
currentInstall: BufferedProcess | null
- message: StatusMessage | null
packagesToInstall: string[]
- timeout: NodeJS.Timer | null
constructor() {
+ this.busySignal = null
this.currentInstall = null
- this.message = null
this.packagesToInstall = []
- this.timeout = null
}
/**
@@ -41,28 +40,14 @@ export default class PackageSync {
/**
* Syncs the package list by installing any missing packages.
*/
- sync(): void {
- let missing = this.getMissingPackages()
- this.installPackages(missing)
- }
-
- /**
- * Displays the `message` for the given `timeout` in milliseconds or indefinitely.
- */
- displayMessage(message: string, timeout?: number): void {
- if (this.timeout) {
- clearTimeout(this.timeout)
- }
-
- if (this.message) {
- this.message.setText(message)
- } else {
- this.message = new StatusMessage(message)
+ sync(busySignal: BusySignalService | null): void {
+ if (busySignal) {
+ this.busySignal = busySignal
+ this.busyMessage = this.busySignal.reportBusy('Starting package sync', {revealTooltip: true})
}
- if (timeout) {
- this.setMessageTimeout(timeout)
- }
+ let missing = this.getMissingPackages()
+ this.installPackages(missing)
}
/**
@@ -72,21 +57,13 @@ export default class PackageSync {
* `packagesToInstall` list.
*/
executeApm(pkg: string): void {
- this.displayMessage(`Installing ${pkg}`)
-
let command = this.apmPath
let args = ['install', pkg]
let stdout = (output: string) => {}
let stderr = (output: string) => {}
let exit = (exitCode: number) => {
- if (exitCode === 0) {
- if (this.packagesToInstall.length > 0) {
- this.displayMessage(`${pkg} installed!`, this.shortMessageTimeout)
- } else {
- this.displayMessage('Package sync complete!', this.longMessageTimeout)
- }
- } else {
- this.displayMessage(`An error occurred installing ${pkg}`, this.longMessageTimeout)
+ if (exitCode !== 0) {
+ this.busyMessage.setTitle(`An error occurred installing ${pkg}`)
}
this.currentInstall = null
@@ -118,7 +95,14 @@ export default class PackageSync {
let nextPackage = this.packagesToInstall.shift()
if (nextPackage) {
+ if (this.busyMessage) {
+ this.busyMessage.setTitle(`Installing ${nextPackage}`)
+ }
+
this.executeApm(nextPackage)
+ } else {
+ this.busyMessage.dispose()
+ this.busySignal = null
}
}
@@ -129,20 +113,4 @@ export default class PackageSync {
this.packagesToInstall.push(...packages)
this.installPackage()
}
-
- /**
- * Sets up a timeout for the currently displayed message.
- */
- setMessageTimeout(timeout: number): void {
- if (this.timeout) {
- clearTimeout(this.timeout)
- }
-
- this.timeout = setTimeout(() => {
- if (this.message) {
- this.message.remove()
- this.message = null
- }
- }, timeout)
- }
}
diff --git a/lib/status-message.ts b/lib/status-message.ts
deleted file mode 100644
index 64c58cc..0000000
--- a/lib/status-message.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-import {StatusBar, Tile} from 'atom/status-bar'
-
-/**
- * Displays a message in the status bar.
- */
-export default class StatusMessage {
- item: Element
- statusBar: StatusBar
- tile: Tile
-
- /**
- * Displays `message` in the status bar.
- *
- * If the status bar does not exist, no message is displayed and no error
- * occurs.
- */
- constructor(message: string) {
- this.statusBar = document.querySelector('status-bar') as StatusBar
-
- if (this.statusBar) {
- this.item = document.createElement('div')
- this.item.classList.add('inline-block')
- this.setText(message)
-
- this.tile = this.statusBar.addLeftTile({item: this.item})
- }
- }
-
- /**
- * Removes the message from the status bar.
- */
- remove(): void {
- if (this.tile) {
- this.tile.destroy()
- }
- }
-
- /**
- * Updates the text of the message.
- */
- setText(text: string): void {
- if (this.statusBar) {
- this.item.innerHTML = text
- }
- }
-}
diff --git a/package.json b/package.json
index 2c97aaa..4f2acec 100644
--- a/package.json
+++ b/package.json
@@ -59,6 +59,13 @@
"default": false
}
},
+ "consumedServices": {
+ "atom-ide-busy-signal": {
+ "versions": {
+ "0.1.0": "consumeBusySignal"
+ }
+ }
+ },
"scripts": {
"debug": "atom-transpiler-debug-tool"
}
From 652314a1fbe28507e3d44b1748f1c622550eaca3 Mon Sep 17 00:00:00 2001
From: Lee Dohm <1038121+lee-dohm@users.noreply.github.com>
Date: Tue, 2 Jan 2018 06:06:24 -0800
Subject: [PATCH 15/17] :art: Clean up busy signal code
---
lib/package-sync.ts | 29 ++++++++++++++++++++++-------
1 file changed, 22 insertions(+), 7 deletions(-)
diff --git a/lib/package-sync.ts b/lib/package-sync.ts
index f34a757..f521116 100644
--- a/lib/package-sync.ts
+++ b/lib/package-sync.ts
@@ -50,6 +50,16 @@ export default class PackageSync {
this.installPackages(missing)
}
+ /**
+ * Clears the busy message, if one is set.
+ */
+ clearBusyMessage(): void {
+ if (this.busySignal) {
+ this.busyMessage.dispose()
+ this.busySignal = null
+ }
+ }
+
/**
* Executes apm to install the given package by name.
*
@@ -63,7 +73,7 @@ export default class PackageSync {
let stderr = (output: string) => {}
let exit = (exitCode: number) => {
if (exitCode !== 0) {
- this.busyMessage.setTitle(`An error occurred installing ${pkg}`)
+ this.setBusyMessage(`An error occurred installing ${pkg}`)
}
this.currentInstall = null
@@ -95,14 +105,10 @@ export default class PackageSync {
let nextPackage = this.packagesToInstall.shift()
if (nextPackage) {
- if (this.busyMessage) {
- this.busyMessage.setTitle(`Installing ${nextPackage}`)
- }
-
+ this.setBusyMessage(`Installing ${nextPackage}`)
this.executeApm(nextPackage)
} else {
- this.busyMessage.dispose()
- this.busySignal = null
+ this.clearBusyMessage()
}
}
@@ -113,4 +119,13 @@ export default class PackageSync {
this.packagesToInstall.push(...packages)
this.installPackage()
}
+
+ /**
+ * Updates the busy message, if one is set.
+ */
+ setBusyMessage(message: string): void {
+ if (this.busySignal) {
+ this.busyMessage.setTitle(message)
+ }
+ }
}
From 10968d170691813c85f73ee65e0db46f432d2cea Mon Sep 17 00:00:00 2001
From: Lee Dohm <1038121+lee-dohm@users.noreply.github.com>
Date: Tue, 2 Jan 2018 16:09:41 -0800
Subject: [PATCH 16/17] :memo:
---
lib/package-list.ts | 3 +++
1 file changed, 3 insertions(+)
diff --git a/lib/package-list.ts b/lib/package-list.ts
index cadbcab..5799bae 100644
--- a/lib/package-list.ts
+++ b/lib/package-list.ts
@@ -2,6 +2,9 @@ import * as CSON from 'season'
import * as fs from 'fs'
import * as path from 'path'
+/**
+ * Information that gets stored in the `packages.cson` file.
+ */
interface PackagesFile {
packages: string[]
}
From fe40fbc228b6003cc18de60c688068e03bacdee5 Mon Sep 17 00:00:00 2001
From: lee-dohm <1038121+lee-dohm@users.noreply.github.com>
Date: Wed, 3 Jan 2018 11:57:19 -0800
Subject: [PATCH 17/17] Add visibility signifiers to class definitions
---
lib/package-list.ts | 17 ++++++++++-----
lib/package-sync.ts | 52 ++++++++++++++++++++++-----------------------
2 files changed, 38 insertions(+), 31 deletions(-)
diff --git a/lib/package-list.ts b/lib/package-list.ts
index 5799bae..6914a77 100644
--- a/lib/package-list.ts
+++ b/lib/package-list.ts
@@ -6,23 +6,23 @@ import * as path from 'path'
* Information that gets stored in the `packages.cson` file.
*/
interface PackagesFile {
- packages: string[]
+ readonly packages: string[]
}
/**
* Represents the stored package list.
*/
export default class PackageList {
- path: string
+ private path: string
- constructor(configDir = atom.getConfigDirPath()) {
+ public constructor(configDir = atom.getConfigDirPath()) {
this.path = path.join(configDir, 'packages.cson')
}
/**
* Gets the packages from the list.
*/
- getPackages(): string[] {
+ public getPackages(): string[] {
if (fs.existsSync(this.path)) {
let obj = CSON.readFileSync(this.path) as PackagesFile
return obj.packages
@@ -31,11 +31,18 @@ export default class PackageList {
return []
}
+ /**
+ * Get the path where the list is stored.
+ */
+ public getPath(): string {
+ return this.path
+ }
+
/**
* Updates the stored package list with what is currently installed if the list doesn't exist or
* the `forceOverwrite` configuration option is set to `true`.
*/
- setPackages(): void {
+ public setPackages(): void {
if (atom.config.get('package-sync.forceOverwrite') || !fs.existsSync(this.path)) {
let available = atom.packages.getAvailablePackageNames()
let names = available.filter((name: string) => { return !atom.packages.isBundledPackage(name) })
diff --git a/lib/package-sync.ts b/lib/package-sync.ts
index f521116..29667f3 100644
--- a/lib/package-sync.ts
+++ b/lib/package-sync.ts
@@ -8,14 +8,14 @@ import {BusyMessage, BusySignalService} from 'busy-signal'
import PackageList from './package-list'
export default class PackageSync {
- readonly apmPath = atom.packages.getApmPath()
+ private readonly apmPath = atom.packages.getApmPath()
- busyMessage: BusyMessage
- busySignal: BusySignalService | null
- currentInstall: BufferedProcess | null
- packagesToInstall: string[]
+ private busyMessage: BusyMessage
+ private busySignal: BusySignalService | null
+ private currentInstall: BufferedProcess | null
+ private packagesToInstall: string[]
- constructor() {
+ public constructor() {
this.busySignal = null
this.currentInstall = null
this.packagesToInstall = []
@@ -24,23 +24,34 @@ export default class PackageSync {
/**
* Creates the package list.
*/
- createPackageList(configDir?: string): void {
+ public createPackageList(configDir?: string): void {
let list = new PackageList(configDir)
list.setPackages()
}
+ /**
+ * Gets the list of missing package names by comparing against the current package list.
+ */
+ public getMissingPackages(configDir?: string): string[] {
+ let list = new PackageList(configDir)
+ let syncPackages = list.getPackages()
+ let availablePackages = atom.packages.getAvailablePackageNames()
+
+ return syncPackages.filter((value) => { return !(value in availablePackages) })
+ }
+
/**
* Opens the package list in the workspace.
*/
- openPackageList(configDir?: string): void {
+ public openPackageList(configDir?: string): void {
let list = new PackageList(configDir)
- atom.workspace.open(list.path)
+ atom.workspace.open(list.getPath())
}
/**
* Syncs the package list by installing any missing packages.
*/
- sync(busySignal: BusySignalService | null): void {
+ public sync(busySignal: BusySignalService | null): void {
if (busySignal) {
this.busySignal = busySignal
this.busyMessage = this.busySignal.reportBusy('Starting package sync', {revealTooltip: true})
@@ -53,7 +64,7 @@ export default class PackageSync {
/**
* Clears the busy message, if one is set.
*/
- clearBusyMessage(): void {
+ private clearBusyMessage(): void {
if (this.busySignal) {
this.busyMessage.dispose()
this.busySignal = null
@@ -66,7 +77,7 @@ export default class PackageSync {
* When the given package is done installing, it attempts to install the next package in the
* `packagesToInstall` list.
*/
- executeApm(pkg: string): void {
+ private executeApm(pkg: string): void {
let command = this.apmPath
let args = ['install', pkg]
let stdout = (output: string) => {}
@@ -83,21 +94,10 @@ export default class PackageSync {
this.currentInstall = new BufferedProcess({command, args, stdout, stderr, exit})
}
- /**
- * Gets the list of missing package names by comparing against the current package list.
- */
- getMissingPackages(configDir?: string): string[] {
- let list = new PackageList(configDir)
- let syncPackages = list.getPackages()
- let availablePackages = atom.packages.getAvailablePackageNames()
-
- return syncPackages.filter((value) => { return !(value in availablePackages) })
- }
-
/**
* Installs the next package in the list, if one exists.
*/
- installPackage(): void {
+ private installPackage(): void {
if (this.currentInstall) {
return
}
@@ -115,7 +115,7 @@ export default class PackageSync {
/**
* Queues up the given list of packages to be installed and starts the process.
*/
- installPackages(packages: string[]): void {
+ private installPackages(packages: string[]): void {
this.packagesToInstall.push(...packages)
this.installPackage()
}
@@ -123,7 +123,7 @@ export default class PackageSync {
/**
* Updates the busy message, if one is set.
*/
- setBusyMessage(message: string): void {
+ private setBusyMessage(message: string): void {
if (this.busySignal) {
this.busyMessage.setTitle(message)
}