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.
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"
- }
-}
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/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..adedaad
--- /dev/null
+++ b/lib/index.ts
@@ -0,0 +1,65 @@
+///
+
+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.
+ */
+export function activate(): void {
+ disposable = new CompositeDisposable()
+
+ 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', () => {
+ 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.
+ */
+export function deactivate(): void {
+ disposable.dispose()
+}
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..6914a77
--- /dev/null
+++ b/lib/package-list.ts
@@ -0,0 +1,53 @@
+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 {
+ readonly packages: string[]
+}
+
+/**
+ * Represents the stored package list.
+ */
+export default class PackageList {
+ private path: string
+
+ public constructor(configDir = atom.getConfigDirPath()) {
+ this.path = path.join(configDir, 'packages.cson')
+ }
+
+ /**
+ * Gets the packages from the list.
+ */
+ public getPackages(): string[] {
+ if (fs.existsSync(this.path)) {
+ let obj = CSON.readFileSync(this.path) as PackagesFile
+ return obj.packages
+ }
+
+ 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`.
+ */
+ 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) })
+
+ CSON.writeFileSync(this.path, {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..29667f3
--- /dev/null
+++ b/lib/package-sync.ts
@@ -0,0 +1,131 @@
+///
+
+import * as fs from 'fs'
+
+import {BufferedProcess} from 'atom'
+import {BusyMessage, BusySignalService} from 'busy-signal'
+
+import PackageList from './package-list'
+
+export default class PackageSync {
+ private readonly apmPath = atom.packages.getApmPath()
+
+ private busyMessage: BusyMessage
+ private busySignal: BusySignalService | null
+ private currentInstall: BufferedProcess | null
+ private packagesToInstall: string[]
+
+ public constructor() {
+ this.busySignal = null
+ this.currentInstall = null
+ this.packagesToInstall = []
+ }
+
+ /**
+ * Creates the package list.
+ */
+ 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.
+ */
+ public openPackageList(configDir?: string): void {
+ let list = new PackageList(configDir)
+ atom.workspace.open(list.getPath())
+ }
+
+ /**
+ * Syncs the package list by installing any missing packages.
+ */
+ public sync(busySignal: BusySignalService | null): void {
+ if (busySignal) {
+ this.busySignal = busySignal
+ this.busyMessage = this.busySignal.reportBusy('Starting package sync', {revealTooltip: true})
+ }
+
+ let missing = this.getMissingPackages()
+ this.installPackages(missing)
+ }
+
+ /**
+ * Clears the busy message, if one is set.
+ */
+ private clearBusyMessage(): void {
+ if (this.busySignal) {
+ this.busyMessage.dispose()
+ this.busySignal = null
+ }
+ }
+
+ /**
+ * 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.
+ */
+ private executeApm(pkg: string): void {
+ let command = this.apmPath
+ let args = ['install', pkg]
+ let stdout = (output: string) => {}
+ let stderr = (output: string) => {}
+ let exit = (exitCode: number) => {
+ if (exitCode !== 0) {
+ this.setBusyMessage(`An error occurred installing ${pkg}`)
+ }
+
+ this.currentInstall = null
+ this.installPackage()
+ }
+
+ this.currentInstall = new BufferedProcess({command, args, stdout, stderr, exit})
+ }
+
+ /**
+ * Installs the next package in the list, if one exists.
+ */
+ private installPackage(): void {
+ if (this.currentInstall) {
+ return
+ }
+
+ let nextPackage = this.packagesToInstall.shift()
+
+ if (nextPackage) {
+ this.setBusyMessage(`Installing ${nextPackage}`)
+ this.executeApm(nextPackage)
+ } else {
+ this.clearBusyMessage()
+ }
+ }
+
+ /**
+ * Queues up the given list of packages to be installed and starts the process.
+ */
+ private installPackages(packages: string[]): void {
+ this.packagesToInstall.push(...packages)
+ this.installPackage()
+ }
+
+ /**
+ * Updates the busy message, if one is set.
+ */
+ private setBusyMessage(message: string): void {
+ if (this.busySignal) {
+ this.busyMessage.setTitle(message)
+ }
+ }
+}
diff --git a/lib/season.d.ts b/lib/season.d.ts
new file mode 100644
index 0000000..c253565
--- /dev/null
+++ b/lib/season.d.ts
@@ -0,0 +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
+}
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/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 bf60c04..4f2acec 100644
--- a/package.json
+++ b/package.json
@@ -12,9 +12,61 @@
"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": {
+ "@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": "./spec/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
+ }
+ },
+ "consumedServices": {
+ "atom-ide-busy-signal": {
+ "versions": {
+ "0.1.0": "consumeBusySignal"
+ }
+ }
+ },
+ "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.coffee b/spec/package-list-spec.coffee
deleted file mode 100644
index a52d6f9..0000000
--- a/spec/package-list-spec.coffee
+++ /dev/null
@@ -1,81 +0,0 @@
-CSON = require 'season'
-fs = require 'fs'
-path = require 'path'
-os = require 'os'
-
-PackageList = require '../lib/package-list'
-
-h = require './helpers'
-
-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-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-sync-spec.coffee b/spec/package-sync-spec.coffee
deleted file mode 100644
index 619e499..0000000
--- a/spec/package-sync-spec.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/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/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-spec.coffee b/spec/status-message-spec.coffee
deleted file mode 100644
index 6b724d7..0000000
--- a/spec/status-message-spec.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')
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"
+ }
+}