Take a look at some of the awesome things {atom.branding.name} has changed:
+
Feel free to read our Full Change Log .
diff --git a/packages/welcome/lib/guide-view.js b/packages/welcome/lib/guide-view.js
index a28fc5d5c..2995d80fc 100644
--- a/packages/welcome/lib/guide-view.js
+++ b/packages/welcome/lib/guide-view.js
@@ -16,13 +16,10 @@ export default class GuideView {
this.didClickStylingButton = this.didClickStylingButton.bind(this);
this.didClickInitScriptButton = this.didClickInitScriptButton.bind(this);
this.didClickSnippetsButton = this.didClickSnippetsButton.bind(this);
- this.didExpandOrCollapseSection = this.didExpandOrCollapseSection.bind(
- this
- );
etch.initialize(this);
}
- update() {}
+ update() { }
render() {
return (
@@ -47,7 +44,7 @@ export default class GuideView {
In {this.brand} you can open individual files or a whole folder as a
- project. Opening a folder will ad a tree view, on the left side
+ project. Opening a folder will add a tree view, on the left side
(by default), listing all the files and folders belonging to your project.
@@ -257,8 +254,7 @@ export default class GuideView {
The init script is a bit of JavaScript or CoffeeScript run at
- startup. You can use it to quickly change the behaviour of
- {this.brand}.
+ startup. You can use it to quickly change the behaviour of {this.brand}.
{
- const link = event.target.closest('a');
- if (link && link.dataset.event) {
- this.props.reporterProxy.sendEvent(
- `clicked-welcome-${link.dataset.event}-link`
- );
- }
- });
}
didChangeShowOnStartup() {
diff --git a/packages/welcome/package-lock.json b/packages/welcome/package-lock.json
index 8c8ad9a20..2d37e808b 100644
--- a/packages/welcome/package-lock.json
+++ b/packages/welcome/package-lock.json
@@ -1,1281 +1,710 @@
{
"name": "welcome",
"version": "0.36.9",
- "lockfileVersion": 1,
+ "lockfileVersion": 3,
"requires": true,
- "dependencies": {
- "acorn": {
- "version": "5.7.1",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.1.tgz",
- "integrity": "sha512-d+nbxBUGKg7Arpsvbnlq61mc12ek3EY8EQldM3GPAhWJ1UVxC6TDGbIvUMNU6obBX3i1+ptCIzV4vq0gFPEGVQ==",
- "dev": true
- },
- "acorn-jsx": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz",
- "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=",
- "dev": true,
- "requires": {
- "acorn": "^3.0.4"
- },
+ "packages": {
+ "": {
+ "name": "welcome",
+ "version": "0.36.9",
+ "license": "MIT",
"dependencies": {
- "acorn": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz",
- "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=",
- "dev": true
- }
+ "etch": "0.9.0"
+ },
+ "devDependencies": {
+ "atom-mocha-test-runner": "^1.0.0"
+ },
+ "engines": {
+ "atom": ">0.50.0"
}
},
- "ajv": {
+ "node_modules/ajv": {
"version": "4.11.8",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz",
"integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=",
"dev": true,
- "requires": {
+ "optional": true,
+ "dependencies": {
"co": "^4.6.0",
"json-stable-stringify": "^1.0.1"
}
},
- "ajv-keywords": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz",
- "integrity": "sha1-MU3QpLM2j609/NxU7eYXG4htrzw=",
- "dev": true
- },
- "ansi-escapes": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz",
- "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=",
- "dev": true
- },
- "ansi-regex": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
- "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
- "dev": true
- },
- "ansi-styles": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
- "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
- "dev": true
- },
- "argparse": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
- "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
- "dev": true,
- "requires": {
- "sprintf-js": "~1.0.2"
- }
- },
- "array-union": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
- "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=",
- "dev": true,
- "requires": {
- "array-uniq": "^1.0.1"
- }
- },
- "array-uniq": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
- "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=",
- "dev": true
- },
- "arrify": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
- "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=",
- "dev": true
- },
- "asap": {
+ "node_modules/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": {
+ "node_modules/asn1": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
"integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
"dev": true,
"optional": true,
- "requires": {
+ "dependencies": {
"safer-buffer": "~2.1.0"
}
},
- "assert-plus": {
+ "node_modules/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
+ "optional": true,
+ "engines": {
+ "node": ">=0.8"
+ }
},
- "asynckit": {
+ "node_modules/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": {
+ "node_modules/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": {
+ "dependencies": {
"etch": "^0.8.0",
"grim": "^2.0.1",
"less": "^2.7.1",
"mocha": "^3.0.0",
"tmp": "0.0.31"
- },
- "dependencies": {
- "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.0.1"
- }
- }
}
},
- "aws-sign2": {
+ "node_modules/atom-mocha-test-runner/node_modules/etch": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/etch/-/etch-0.8.0.tgz",
+ "integrity": "sha1-VPYZV0NG+KPueXP1T7vQG1YnItY=",
+ "dev": true,
+ "dependencies": {
+ "virtual-dom": "^2.0.1"
+ }
+ },
+ "node_modules/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
+ "optional": true,
+ "engines": {
+ "node": "*"
+ }
},
- "aws4": {
+ "node_modules/aws4": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
"integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==",
"dev": true,
"optional": true
},
- "babel-code-frame": {
- "version": "6.26.0",
- "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
- "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=",
- "dev": true,
- "requires": {
- "chalk": "^1.1.3",
- "esutils": "^2.0.2",
- "js-tokens": "^3.0.2"
- }
- },
- "balanced-match": {
+ "node_modules/balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
"dev": true
},
- "bcrypt-pbkdf": {
+ "node_modules/bcrypt-pbkdf": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
"integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
"dev": true,
"optional": true,
- "requires": {
+ "dependencies": {
"tweetnacl": "^0.14.3"
}
},
- "boom": {
+ "node_modules/boom": {
"version": "2.10.1",
"resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz",
"integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=",
+ "deprecated": "This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial).",
"dev": true,
"optional": true,
- "requires": {
+ "dependencies": {
"hoek": "2.x.x"
+ },
+ "engines": {
+ "node": ">=0.10.40"
}
},
- "brace-expansion": {
+ "node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
- "requires": {
+ "dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
- "browser-split": {
+ "node_modules/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": {
+ "node_modules/browser-stdout": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz",
"integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=",
"dev": true
},
- "buffer-from": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
- "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
- "dev": true
- },
- "caller-path": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz",
- "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=",
- "dev": true,
- "requires": {
- "callsites": "^0.2.0"
- }
- },
- "callsites": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz",
- "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=",
- "dev": true
- },
- "camelize": {
+ "node_modules/camelize": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz",
"integrity": "sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs=",
"dev": true
},
- "caseless": {
+ "node_modules/caseless": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
"dev": true,
"optional": true
},
- "chalk": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
- "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
- "dev": true,
- "requires": {
- "ansi-styles": "^2.2.1",
- "escape-string-regexp": "^1.0.2",
- "has-ansi": "^2.0.0",
- "strip-ansi": "^3.0.0",
- "supports-color": "^2.0.0"
- },
- "dependencies": {
- "supports-color": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
- "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
- "dev": true
- }
- }
- },
- "circular-json": {
- "version": "0.3.3",
- "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz",
- "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==",
- "dev": true
- },
- "cli-cursor": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz",
- "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=",
- "dev": true,
- "requires": {
- "restore-cursor": "^1.0.1"
- }
- },
- "cli-width": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz",
- "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=",
- "dev": true
- },
- "co": {
+ "node_modules/co": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
"integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "engines": {
+ "iojs": ">= 1.0.0",
+ "node": ">= 0.12.0"
+ }
},
- "code-point-at": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
- "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
- "dev": true
- },
- "combined-stream": {
+ "node_modules/combined-stream": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz",
"integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=",
"dev": true,
"optional": true,
- "requires": {
+ "dependencies": {
"delayed-stream": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
}
},
- "commander": {
+ "node_modules/commander": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz",
"integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=",
"dev": true,
- "requires": {
+ "dependencies": {
"graceful-readlink": ">= 1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.6.x"
}
},
- "concat-map": {
+ "node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
"dev": true
},
- "concat-stream": {
- "version": "1.6.2",
- "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
- "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
- "dev": true,
- "requires": {
- "buffer-from": "^1.0.0",
- "inherits": "^2.0.3",
- "readable-stream": "^2.2.2",
- "typedarray": "^0.0.6"
- }
- },
- "core-util-is": {
+ "node_modules/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
+ "dev": true,
+ "optional": true
},
- "cryptiles": {
+ "node_modules/cryptiles": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz",
"integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=",
+ "deprecated": "This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial).",
"dev": true,
"optional": true,
- "requires": {
+ "dependencies": {
"boom": "2.x.x"
+ },
+ "engines": {
+ "node": ">=0.10.40"
}
},
- "d": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz",
- "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=",
- "dev": true,
- "requires": {
- "es5-ext": "^0.10.9"
- }
- },
- "dashdash": {
+ "node_modules/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": {
+ "dependencies": {
"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
- }
+ "engines": {
+ "node": ">=0.10"
}
},
- "debug": {
+ "node_modules/dashdash/node_modules/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,
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/debug": {
"version": "2.6.8",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
"integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=",
"dev": true,
- "requires": {
+ "dependencies": {
"ms": "2.0.0"
}
},
- "debug-log": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/debug-log/-/debug-log-1.0.1.tgz",
- "integrity": "sha1-IwdjLUwEOCuN+KMvcLiVBG1SdF8=",
- "dev": true
- },
- "deep-is": {
- "version": "0.1.3",
- "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
- "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=",
- "dev": true
- },
- "deglob": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/deglob/-/deglob-2.1.1.tgz",
- "integrity": "sha512-2kjwuGGonL7gWE1XU4Fv79+vVzpoQCl0V+boMwWtOQJV2AGDabCwez++nB1Nli/8BabAfZQ/UuHPlp6AymKdWw==",
- "dev": true,
- "requires": {
- "find-root": "^1.0.0",
- "glob": "^7.0.5",
- "ignore": "^3.0.9",
- "pkg-config": "^1.1.0",
- "run-parallel": "^1.1.2",
- "uniq": "^1.0.1"
- }
- },
- "del": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz",
- "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=",
- "dev": true,
- "requires": {
- "globby": "^5.0.0",
- "is-path-cwd": "^1.0.0",
- "is-path-in-cwd": "^1.0.0",
- "object-assign": "^4.0.1",
- "pify": "^2.0.0",
- "pinkie-promise": "^2.0.0",
- "rimraf": "^2.2.8"
- }
- },
- "delayed-stream": {
+ "node_modules/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,
- "optional": true
+ "optional": true,
+ "engines": {
+ "node": ">=0.4.0"
+ }
},
- "diff": {
+ "node_modules/diff": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz",
"integrity": "sha1-yc45Okt8vQsFinJck98pkCeGj/k=",
- "dev": true
- },
- "doctrine": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz",
- "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=",
"dev": true,
- "requires": {
- "esutils": "^2.0.2",
- "isarray": "^1.0.0"
+ "engines": {
+ "node": ">=0.3.1"
}
},
- "dom-walk": {
+ "node_modules/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": {
+ "node_modules/ecc-jsbn": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
"integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
"dev": true,
"optional": true,
- "requires": {
+ "dependencies": {
"jsbn": "~0.1.0",
"safer-buffer": "^2.1.0"
}
},
- "errno": {
+ "node_modules/errno": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz",
"integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==",
"dev": true,
"optional": true,
- "requires": {
+ "dependencies": {
"prr": "~1.0.1"
+ },
+ "bin": {
+ "errno": "cli.js"
}
},
- "error": {
+ "node_modules/error": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/error/-/error-4.4.0.tgz",
"integrity": "sha1-v2n/JR+0onnBmtzNqmth6Q2b8So=",
"dev": true,
- "requires": {
+ "dependencies": {
"camelize": "^1.0.0",
"string-template": "~0.2.0",
"xtend": "~4.0.0"
}
},
- "es5-ext": {
- "version": "0.10.46",
- "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.46.tgz",
- "integrity": "sha512-24XxRvJXNFwEMpJb3nOkiRJKRoupmjYmOPVlI65Qy2SrtxwOTB+g6ODjBKOtwEHbYrhWRty9xxOWLNdClT2djw==",
- "dev": true,
- "requires": {
- "es6-iterator": "~2.0.3",
- "es6-symbol": "~3.1.1",
- "next-tick": "1"
- },
- "dependencies": {
- "next-tick": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz",
- "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=",
- "dev": true
- }
- }
- },
- "es6-iterator": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
- "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=",
- "dev": true,
- "requires": {
- "d": "1",
- "es5-ext": "^0.10.35",
- "es6-symbol": "^3.1.1"
- }
- },
- "es6-map": {
- "version": "0.1.5",
- "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz",
- "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=",
- "dev": true,
- "requires": {
- "d": "1",
- "es5-ext": "~0.10.14",
- "es6-iterator": "~2.0.1",
- "es6-set": "~0.1.5",
- "es6-symbol": "~3.1.1",
- "event-emitter": "~0.3.5"
- }
- },
- "es6-set": {
- "version": "0.1.5",
- "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz",
- "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=",
- "dev": true,
- "requires": {
- "d": "1",
- "es5-ext": "~0.10.14",
- "es6-iterator": "~2.0.1",
- "es6-symbol": "3.1.1",
- "event-emitter": "~0.3.5"
- }
- },
- "es6-symbol": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz",
- "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=",
- "dev": true,
- "requires": {
- "d": "1",
- "es5-ext": "~0.10.14"
- }
- },
- "es6-weak-map": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz",
- "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=",
- "dev": true,
- "requires": {
- "d": "1",
- "es5-ext": "^0.10.14",
- "es6-iterator": "^2.0.1",
- "es6-symbol": "^3.1.1"
- }
- },
- "escape-string-regexp": {
+ "node_modules/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
- },
- "escope": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz",
- "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=",
"dev": true,
- "requires": {
- "es6-map": "^0.1.3",
- "es6-weak-map": "^2.0.1",
- "esrecurse": "^4.1.0",
- "estraverse": "^4.1.1"
+ "engines": {
+ "node": ">=0.8.0"
}
},
- "eslint": {
- "version": "3.10.2",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-3.10.2.tgz",
- "integrity": "sha1-yaEOi/bp1lZRIEd4xQM0Hx6sPOc=",
- "dev": true,
- "requires": {
- "babel-code-frame": "^6.16.0",
- "chalk": "^1.1.3",
- "concat-stream": "^1.4.6",
- "debug": "^2.1.1",
- "doctrine": "^1.2.2",
- "escope": "^3.6.0",
- "espree": "^3.3.1",
- "estraverse": "^4.2.0",
- "esutils": "^2.0.2",
- "file-entry-cache": "^2.0.0",
- "glob": "^7.0.3",
- "globals": "^9.2.0",
- "ignore": "^3.2.0",
- "imurmurhash": "^0.1.4",
- "inquirer": "^0.12.0",
- "is-my-json-valid": "^2.10.0",
- "is-resolvable": "^1.0.0",
- "js-yaml": "^3.5.1",
- "json-stable-stringify": "^1.0.0",
- "levn": "^0.3.0",
- "lodash": "^4.0.0",
- "mkdirp": "^0.5.0",
- "natural-compare": "^1.4.0",
- "optionator": "^0.8.2",
- "path-is-inside": "^1.0.1",
- "pluralize": "^1.2.1",
- "progress": "^1.1.8",
- "require-uncached": "^1.0.2",
- "shelljs": "^0.7.5",
- "strip-bom": "^3.0.0",
- "strip-json-comments": "~1.0.1",
- "table": "^3.7.8",
- "text-table": "~0.2.0",
- "user-home": "^2.0.0"
- }
- },
- "eslint-config-standard": {
- "version": "6.2.1",
- "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-6.2.1.tgz",
- "integrity": "sha1-06aKr8cZFjnn7kQec0hzkCY1QpI=",
- "dev": true
- },
- "eslint-config-standard-jsx": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/eslint-config-standard-jsx/-/eslint-config-standard-jsx-3.2.0.tgz",
- "integrity": "sha1-wkDibtkZoRpCqk3oBZRys4Jo1iA=",
- "dev": true
- },
- "eslint-plugin-promise": {
- "version": "3.4.2",
- "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-3.4.2.tgz",
- "integrity": "sha1-G+J5Pq/i0YtbEjuBNsJp+AT+cSI=",
- "dev": true
- },
- "eslint-plugin-react": {
- "version": "6.7.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-6.7.1.tgz",
- "integrity": "sha1-Gvlq6lRYVoJRV9l8G1DVqPtkpac=",
- "dev": true,
- "requires": {
- "doctrine": "^1.2.2",
- "jsx-ast-utils": "^1.3.3"
- }
- },
- "eslint-plugin-standard": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-2.0.1.tgz",
- "integrity": "sha1-NYlpn/nJF/LCX3apFmh/ZBw2n/M=",
- "dev": true
- },
- "espree": {
- "version": "3.5.4",
- "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz",
- "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==",
- "dev": true,
- "requires": {
- "acorn": "^5.5.0",
- "acorn-jsx": "^3.0.0"
- }
- },
- "esprima": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
- "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
- "dev": true
- },
- "esrecurse": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz",
- "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==",
- "dev": true,
- "requires": {
- "estraverse": "^4.1.0"
- }
- },
- "estraverse": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz",
- "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=",
- "dev": true
- },
- "esutils": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
- "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
- "dev": true
- },
- "etch": {
+ "node_modules/etch": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/etch/-/etch-0.9.0.tgz",
"integrity": "sha1-CSJpiPLO4GkL3yCMyyXkFNXfrV8="
},
- "ev-store": {
+ "node_modules/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": {
+ "dependencies": {
"individual": "^3.0.0"
}
},
- "event-emitter": {
- "version": "0.3.5",
- "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz",
- "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=",
- "dev": true,
- "requires": {
- "d": "1",
- "es5-ext": "~0.10.14"
- }
- },
- "event-kit": {
+ "node_modules/event-kit": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/event-kit/-/event-kit-2.5.0.tgz",
"integrity": "sha512-tUDxeNC9JzN2Tw/f8mLtksY34v1hHmaR7lV7X4p04XSjaeUhFMfzjF6Nwov9e0EKGEx63BaKcgXKxjpQaPo0wg==",
"dev": true
},
- "exit-hook": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz",
- "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=",
- "dev": true
- },
- "extend": {
+ "node_modules/extend": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
"dev": true,
"optional": true
},
- "extsprintf": {
+ "node_modules/extsprintf": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
"dev": true,
+ "engines": [
+ "node >=0.6.0"
+ ],
"optional": true
},
- "fast-levenshtein": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
- "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
- "dev": true
- },
- "figures": {
- "version": "1.7.0",
- "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz",
- "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=",
- "dev": true,
- "requires": {
- "escape-string-regexp": "^1.0.5",
- "object-assign": "^4.1.0"
- }
- },
- "file-entry-cache": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz",
- "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=",
- "dev": true,
- "requires": {
- "flat-cache": "^1.2.1",
- "object-assign": "^4.0.1"
- }
- },
- "find-root": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
- "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==",
- "dev": true
- },
- "flat-cache": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz",
- "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=",
- "dev": true,
- "requires": {
- "circular-json": "^0.3.1",
- "del": "^2.0.2",
- "graceful-fs": "^4.1.2",
- "write": "^0.2.1"
- }
- },
- "forever-agent": {
+ "node_modules/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
+ "optional": true,
+ "engines": {
+ "node": "*"
+ }
},
- "form-data": {
+ "node_modules/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": {
+ "dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.5",
"mime-types": "^2.1.12"
+ },
+ "engines": {
+ "node": ">= 0.12"
}
},
- "fs.realpath": {
+ "node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
"dev": true
},
- "generate-function": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz",
- "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=",
- "dev": true
- },
- "generate-object-property": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz",
- "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=",
- "dev": true,
- "requires": {
- "is-property": "^1.0.0"
- }
- },
- "get-stdin": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-5.0.1.tgz",
- "integrity": "sha1-Ei4WFZHiH/TFJTAwVpPyDmOTo5g=",
- "dev": true
- },
- "getpass": {
+ "node_modules/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
- }
+ "assert-plus": "^1.0.0"
}
},
- "glob": {
+ "node_modules/getpass/node_modules/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,
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/glob": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz",
"integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=",
"dev": true,
- "requires": {
+ "dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.2",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
}
},
- "global": {
+ "node_modules/global": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/global/-/global-4.3.2.tgz",
"integrity": "sha1-52mJJopsdMOJCLEwWxD8DjlOnQ8=",
"dev": true,
- "requires": {
+ "dependencies": {
"min-document": "^2.19.0",
"process": "~0.5.1"
}
},
- "globals": {
- "version": "9.18.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz",
- "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==",
- "dev": true
- },
- "globby": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz",
- "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=",
- "dev": true,
- "requires": {
- "array-union": "^1.0.1",
- "arrify": "^1.0.0",
- "glob": "^7.0.3",
- "object-assign": "^4.0.1",
- "pify": "^2.0.0",
- "pinkie-promise": "^2.0.0"
- }
- },
- "graceful-fs": {
+ "node_modules/graceful-fs": {
"version": "4.1.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
"integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "engines": {
+ "node": ">=0.4.0"
+ }
},
- "graceful-readlink": {
+ "node_modules/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": {
+ "node_modules/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": {
+ "dependencies": {
"event-kit": "^2.0.0"
}
},
- "growl": {
+ "node_modules/growl": {
"version": "1.9.2",
"resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz",
"integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=",
"dev": true
},
- "har-schema": {
+ "node_modules/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
+ "optional": true,
+ "engines": {
+ "node": ">=4"
+ }
},
- "har-validator": {
+ "node_modules/har-validator": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz",
"integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=",
+ "deprecated": "this library is no longer supported",
"dev": true,
"optional": true,
- "requires": {
+ "dependencies": {
"ajv": "^4.9.1",
"har-schema": "^1.0.5"
+ },
+ "engines": {
+ "node": ">=4"
}
},
- "has-ansi": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
- "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
- "dev": true,
- "requires": {
- "ansi-regex": "^2.0.0"
- }
- },
- "has-flag": {
+ "node_modules/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
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
},
- "hawk": {
+ "node_modules/hawk": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz",
"integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=",
+ "deprecated": "This module moved to @hapi/hawk. Please make sure to switch over as this distribution is no longer supported and may contain bugs and critical security issues.",
"dev": true,
"optional": true,
- "requires": {
+ "dependencies": {
"boom": "2.x.x",
"cryptiles": "2.x.x",
"hoek": "2.x.x",
"sntp": "1.x.x"
+ },
+ "engines": {
+ "node": ">=0.10.32"
}
},
- "he": {
+ "node_modules/he": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz",
"integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=",
- "dev": true
+ "dev": true,
+ "bin": {
+ "he": "bin/he"
+ }
},
- "hoek": {
+ "node_modules/hoek": {
"version": "2.16.3",
"resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz",
"integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=",
+ "deprecated": "This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial).",
"dev": true,
- "optional": true
- },
- "home-or-tmp": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz",
- "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=",
- "dev": true,
- "requires": {
- "os-homedir": "^1.0.0",
- "os-tmpdir": "^1.0.1"
+ "optional": true,
+ "engines": {
+ "node": ">=0.10.40"
}
},
- "http-signature": {
+ "node_modules/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": {
+ "dependencies": {
"assert-plus": "^0.2.0",
"jsprim": "^1.2.2",
"sshpk": "^1.7.0"
+ },
+ "engines": {
+ "node": ">=0.8",
+ "npm": ">=1.3.7"
}
},
- "ignore": {
- "version": "3.3.10",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz",
- "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==",
- "dev": true
- },
- "image-size": {
+ "node_modules/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
+ "optional": true,
+ "bin": {
+ "image-size": "bin/image-size.js"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
},
- "imurmurhash": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
- "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
- "dev": true
- },
- "individual": {
+ "node_modules/individual": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/individual/-/individual-3.0.0.tgz",
"integrity": "sha1-58pPhfiVewGHNPKFdQ3CLsL5hi0=",
"dev": true
},
- "inflight": {
+ "node_modules/inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"dev": true,
- "requires": {
+ "dependencies": {
"once": "^1.3.0",
"wrappy": "1"
}
},
- "inherits": {
+ "node_modules/inherits": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
"dev": true
},
- "inquirer": {
- "version": "0.12.0",
- "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz",
- "integrity": "sha1-HvK/1jUE3wvHV4X/+MLEHfEvB34=",
- "dev": true,
- "requires": {
- "ansi-escapes": "^1.1.0",
- "ansi-regex": "^2.0.0",
- "chalk": "^1.0.0",
- "cli-cursor": "^1.0.1",
- "cli-width": "^2.0.0",
- "figures": "^1.3.5",
- "lodash": "^4.3.0",
- "readline2": "^1.0.1",
- "run-async": "^0.1.0",
- "rx-lite": "^3.1.2",
- "string-width": "^1.0.1",
- "strip-ansi": "^3.0.0",
- "through": "^2.3.6"
- }
- },
- "interpret": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz",
- "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=",
- "dev": true
- },
- "is-fullwidth-code-point": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
- "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
- "dev": true,
- "requires": {
- "number-is-nan": "^1.0.0"
- }
- },
- "is-my-ip-valid": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz",
- "integrity": "sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ==",
- "dev": true
- },
- "is-my-json-valid": {
- "version": "2.19.0",
- "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.19.0.tgz",
- "integrity": "sha512-mG0f/unGX1HZ5ep4uhRaPOS8EkAY8/j6mDRMJrutq4CqhoJWYp7qAlonIPy3TV7p3ju4TK9fo/PbnoksWmsp5Q==",
- "dev": true,
- "requires": {
- "generate-function": "^2.0.0",
- "generate-object-property": "^1.1.0",
- "is-my-ip-valid": "^1.0.0",
- "jsonpointer": "^4.0.0",
- "xtend": "^4.0.0"
- }
- },
- "is-object": {
+ "node_modules/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-path-cwd": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz",
- "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=",
- "dev": true
- },
- "is-path-in-cwd": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz",
- "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==",
- "dev": true,
- "requires": {
- "is-path-inside": "^1.0.0"
- }
- },
- "is-path-inside": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz",
- "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=",
- "dev": true,
- "requires": {
- "path-is-inside": "^1.0.1"
- }
- },
- "is-property": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
- "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=",
- "dev": true
- },
- "is-resolvable": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz",
- "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==",
- "dev": true
- },
- "is-typedarray": {
+ "node_modules/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
},
- "isarray": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
- "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
- "dev": true
- },
- "isstream": {
+ "node_modules/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
},
- "js-tokens": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
- "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=",
- "dev": true
- },
- "js-yaml": {
- "version": "3.12.0",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz",
- "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==",
- "dev": true,
- "requires": {
- "argparse": "^1.0.7",
- "esprima": "^4.0.0"
- }
- },
- "jsbn": {
+ "node_modules/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": {
+ "node_modules/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": {
+ "node_modules/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,
- "requires": {
+ "optional": true,
+ "dependencies": {
"jsonify": "~0.0.0"
}
},
- "json-stringify-safe": {
+ "node_modules/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": {
+ "node_modules/json3": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz",
"integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=",
+ "deprecated": "Please use the native JSON object instead of JSON 3",
"dev": true
},
- "jsonify": {
+ "node_modules/jsonify": {
"version": "0.0.0",
"resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
"integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=",
- "dev": true
+ "dev": true,
+ "optional": true,
+ "engines": {
+ "node": "*"
+ }
},
- "jsonpointer": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz",
- "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=",
- "dev": true
- },
- "jsprim": {
+ "node_modules/jsprim": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
"integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
"dev": true,
+ "engines": [
+ "node >=0.6.0"
+ ],
"optional": true,
- "requires": {
+ "dependencies": {
"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
- }
}
},
- "jsx-ast-utils": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz",
- "integrity": "sha1-OGchPo3Xm/Ho8jAMDPwe+xgsDfE=",
- "dev": true
+ "node_modules/jsprim/node_modules/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,
+ "engines": {
+ "node": ">=0.8"
+ }
},
- "less": {
+ "node_modules/less": {
"version": "2.7.3",
"resolved": "https://registry.npmjs.org/less/-/less-2.7.3.tgz",
"integrity": "sha512-KPdIJKWcEAb02TuJtaLrhue0krtRLoRoo7x6BNJIBelO00t/CCdJQUnHW5V34OnHMWzIktSalJxRO+FvytQlCQ==",
"dev": true,
- "requires": {
+ "bin": {
+ "lessc": "bin/lessc"
+ },
+ "engines": {
+ "node": ">=0.12"
+ },
+ "optionalDependencies": {
"errno": "^0.1.1",
"graceful-fs": "^4.1.2",
"image-size": "~0.5.0",
@@ -1286,153 +715,156 @@
"source-map": "^0.5.3"
}
},
- "levn": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
- "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
- "dev": true,
- "requires": {
- "prelude-ls": "~1.1.2",
- "type-check": "~0.3.2"
- }
- },
- "lodash": {
- "version": "4.17.21",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
- "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
- "dev": true
- },
- "lodash._baseassign": {
+ "node_modules/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": {
+ "dependencies": {
"lodash._basecopy": "^3.0.0",
"lodash.keys": "^3.0.0"
}
},
- "lodash._basecopy": {
+ "node_modules/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": {
+ "node_modules/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": {
+ "node_modules/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": {
+ "node_modules/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": {
+ "node_modules/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": {
+ "dependencies": {
"lodash._baseassign": "^3.0.0",
"lodash._basecreate": "^3.0.0",
"lodash._isiterateecall": "^3.0.0"
}
},
- "lodash.isarguments": {
+ "node_modules/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": {
+ "node_modules/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": {
+ "node_modules/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": {
+ "dependencies": {
"lodash._getnative": "^3.0.0",
"lodash.isarguments": "^3.0.0",
"lodash.isarray": "^3.0.0"
}
},
- "mime": {
+ "node_modules/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
+ "optional": true,
+ "bin": {
+ "mime": "cli.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
},
- "mime-db": {
+ "node_modules/mime-db": {
"version": "1.35.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.35.0.tgz",
"integrity": "sha512-JWT/IcCTsB0Io3AhWUMjRqucrHSPsSf2xKLaRldJVULioggvkJvggZ3VXNNSRkCddE6D+BUI4HEIZIA2OjwIvg==",
"dev": true,
- "optional": true
+ "optional": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
},
- "mime-types": {
+ "node_modules/mime-types": {
"version": "2.1.19",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.19.tgz",
"integrity": "sha512-P1tKYHVSZ6uFo26mtnve4HQFE3koh1UWVkp8YUC+ESBHe945xWSoXuHHiGarDqcEZ+whpCDnlNw5LON0kLo+sw==",
"dev": true,
"optional": true,
- "requires": {
+ "dependencies": {
"mime-db": "~1.35.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
}
},
- "min-document": {
+ "node_modules/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": {
+ "dependencies": {
"dom-walk": "^0.1.0"
}
},
- "minimatch": {
+ "node_modules/minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dev": true,
- "requires": {
+ "dependencies": {
"brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
}
},
- "minimist": {
+ "node_modules/minimist": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
"dev": true
},
- "mkdirp": {
+ "node_modules/mkdirp": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+ "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)",
"dev": true,
- "requires": {
+ "dependencies": {
"minimist": "0.0.8"
+ },
+ "bin": {
+ "mkdirp": "bin/cmd.js"
}
},
- "mocha": {
+ "node_modules/mocha": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/mocha/-/mocha-3.5.3.tgz",
"integrity": "sha512-/6na001MJWEtYxHOV1WLfsmR4YIynkUEhBwzsb+fk2qmQ3iqsi258l/Q2MWHJMImAcNpZ8DEdYAK72NHoIQ9Eg==",
"dev": true,
- "requires": {
+ "dependencies": {
"browser-stdout": "1.3.0",
"commander": "2.9.0",
"debug": "2.6.8",
@@ -1445,252 +877,123 @@
"lodash.create": "3.1.1",
"mkdirp": "0.5.1",
"supports-color": "3.1.2"
+ },
+ "bin": {
+ "_mocha": "bin/_mocha",
+ "mocha": "bin/mocha"
+ },
+ "engines": {
+ "node": ">= 0.10.x",
+ "npm": ">= 1.4.x"
}
},
- "ms": {
+ "node_modules/ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
"dev": true
},
- "mute-stream": {
- "version": "0.0.5",
- "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz",
- "integrity": "sha1-j7+rsKmKJT0xhDMfno3rc3L6xsA=",
- "dev": true
- },
- "natural-compare": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
- "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
- "dev": true
- },
- "next-tick": {
+ "node_modules/next-tick": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/next-tick/-/next-tick-0.2.2.tgz",
"integrity": "sha1-ddpKkn7liH45BliABltzNkE7MQ0=",
"dev": true
},
- "number-is-nan": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
- "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
- "dev": true
- },
- "oauth-sign": {
+ "node_modules/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
+ "optional": true,
+ "engines": {
+ "node": "*"
+ }
},
- "object-assign": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
- "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
- "dev": true
- },
- "once": {
+ "node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"dev": true,
- "requires": {
+ "dependencies": {
"wrappy": "1"
}
},
- "onetime": {
- "version": "1.1.0",
- "resolved": "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz",
- "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=",
- "dev": true
- },
- "optionator": {
- "version": "0.8.2",
- "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz",
- "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=",
- "dev": true,
- "requires": {
- "deep-is": "~0.1.3",
- "fast-levenshtein": "~2.0.4",
- "levn": "~0.3.0",
- "prelude-ls": "~1.1.2",
- "type-check": "~0.3.2",
- "wordwrap": "~1.0.0"
- }
- },
- "os-homedir": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
- "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
- "dev": true
- },
- "os-tmpdir": {
+ "node_modules/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
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
},
- "path-is-absolute": {
+ "node_modules/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=",
- "dev": true
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
},
- "path-is-inside": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz",
- "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=",
- "dev": true
- },
- "path-parse": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
- "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
- "dev": true
- },
- "performance-now": {
+ "node_modules/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
},
- "pify": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
- "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
- "dev": true
- },
- "pinkie": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
- "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=",
- "dev": true
- },
- "pinkie-promise": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
- "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
- "dev": true,
- "requires": {
- "pinkie": "^2.0.0"
- }
- },
- "pkg-config": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/pkg-config/-/pkg-config-1.1.1.tgz",
- "integrity": "sha1-VX7yLXPaPIg3EHdmxS6tq94pj+Q=",
- "dev": true,
- "requires": {
- "debug-log": "^1.0.0",
- "find-root": "^1.0.0",
- "xtend": "^4.0.1"
- }
- },
- "pluralize": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz",
- "integrity": "sha1-0aIUg/0iu0HlihL6NCGCMUCJfEU=",
- "dev": true
- },
- "prelude-ls": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
- "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
- "dev": true
- },
- "process": {
+ "node_modules/process": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/process/-/process-0.5.2.tgz",
"integrity": "sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8=",
- "dev": true
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6.0"
+ }
},
- "process-nextick-args": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
- "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
- "dev": true
- },
- "progress": {
- "version": "1.1.8",
- "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz",
- "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=",
- "dev": true
- },
- "promise": {
+ "node_modules/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": {
+ "dependencies": {
"asap": "~2.0.3"
}
},
- "prr": {
+ "node_modules/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": {
+ "node_modules/punycode": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
"integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
"dev": true,
"optional": true
},
- "qs": {
+ "node_modules/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
- },
- "readable-stream": {
- "version": "2.3.6",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
- "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
- "dev": true,
- "requires": {
- "core-util-is": "~1.0.0",
- "inherits": "~2.0.3",
- "isarray": "~1.0.0",
- "process-nextick-args": "~2.0.0",
- "safe-buffer": "~5.1.1",
- "string_decoder": "~1.1.1",
- "util-deprecate": "~1.0.1"
+ "optional": true,
+ "engines": {
+ "node": ">=0.6"
}
},
- "readline2": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz",
- "integrity": "sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU=",
- "dev": true,
- "requires": {
- "code-point-at": "^1.0.0",
- "is-fullwidth-code-point": "^1.0.0",
- "mute-stream": "0.0.5"
- }
- },
- "rechoir": {
- "version": "0.6.2",
- "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
- "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=",
- "dev": true,
- "requires": {
- "resolve": "^1.1.6"
- }
- },
- "request": {
+ "node_modules/request": {
"version": "2.81.0",
"resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz",
"integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=",
+ "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142",
"dev": true,
"optional": true,
- "requires": {
+ "dependencies": {
"aws-sign2": "~0.6.0",
"aws4": "^1.2.1",
"caseless": "~0.12.0",
@@ -1713,418 +1016,199 @@
"tough-cookie": "~2.3.0",
"tunnel-agent": "^0.6.0",
"uuid": "^3.0.0"
+ },
+ "engines": {
+ "node": ">= 4"
}
},
- "require-uncached": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz",
- "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=",
- "dev": true,
- "requires": {
- "caller-path": "^0.1.0",
- "resolve-from": "^1.0.0"
- }
- },
- "resolve": {
- "version": "1.8.1",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz",
- "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==",
- "dev": true,
- "requires": {
- "path-parse": "^1.0.5"
- }
- },
- "resolve-from": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz",
- "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=",
- "dev": true
- },
- "restore-cursor": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz",
- "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=",
- "dev": true,
- "requires": {
- "exit-hook": "^1.0.0",
- "onetime": "^1.0.0"
- }
- },
- "rimraf": {
- "version": "2.6.2",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
- "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
- "dev": true,
- "requires": {
- "glob": "^7.0.5"
- }
- },
- "run-async": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz",
- "integrity": "sha1-yK1KXhEGYeQCp9IbUw4AnyX444k=",
- "dev": true,
- "requires": {
- "once": "^1.3.0"
- }
- },
- "run-parallel": {
- "version": "1.1.9",
- "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz",
- "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==",
- "dev": true
- },
- "rx-lite": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz",
- "integrity": "sha1-Gc5QLKVyZl87ZHsQk5+X/RYV8QI=",
- "dev": true
- },
- "safe-buffer": {
+ "node_modules/safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
- "dev": true
+ "dev": true,
+ "optional": true
},
- "safer-buffer": {
+ "node_modules/safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"dev": true,
"optional": true
},
- "shelljs": {
- "version": "0.7.8",
- "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.8.tgz",
- "integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=",
- "dev": true,
- "requires": {
- "glob": "^7.0.0",
- "interpret": "^1.0.0",
- "rechoir": "^0.6.2"
- }
- },
- "slice-ansi": {
- "version": "0.0.4",
- "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz",
- "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=",
- "dev": true
- },
- "sntp": {
+ "node_modules/sntp": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz",
"integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=",
+ "deprecated": "This module moved to @hapi/sntp. Please make sure to switch over as this distribution is no longer supported and may contain bugs and critical security issues.",
"dev": true,
"optional": true,
- "requires": {
+ "dependencies": {
"hoek": "2.x.x"
+ },
+ "engines": {
+ "node": ">=0.8.0"
}
},
- "source-map": {
+ "node_modules/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
+ "optional": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
},
- "sprintf-js": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
- "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
- "dev": true
- },
- "sshpk": {
+ "node_modules/sshpk": {
"version": "1.14.2",
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz",
"integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=",
"dev": true,
"optional": true,
- "requires": {
+ "dependencies": {
"asn1": "~0.2.3",
"assert-plus": "^1.0.0",
- "bcrypt-pbkdf": "^1.0.0",
"dashdash": "^1.12.0",
- "ecc-jsbn": "~0.1.1",
"getpass": "^0.1.1",
+ "safer-buffer": "^2.0.2"
+ },
+ "bin": {
+ "sshpk-conv": "bin/sshpk-conv",
+ "sshpk-sign": "bin/sshpk-sign",
+ "sshpk-verify": "bin/sshpk-verify"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ },
+ "optionalDependencies": {
+ "bcrypt-pbkdf": "^1.0.0",
+ "ecc-jsbn": "~0.1.1",
"jsbn": "~0.1.0",
- "safer-buffer": "^2.0.2",
"tweetnacl": "~0.14.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
- }
}
},
- "standard": {
- "version": "8.6.0",
- "resolved": "https://registry.npmjs.org/standard/-/standard-8.6.0.tgz",
- "integrity": "sha1-Y1Eyvnv7VnwpIQBfMPnjUOR1Kq0=",
+ "node_modules/sshpk/node_modules/assert-plus": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
"dev": true,
- "requires": {
- "eslint": "~3.10.2",
- "eslint-config-standard": "6.2.1",
- "eslint-config-standard-jsx": "3.2.0",
- "eslint-plugin-promise": "~3.4.0",
- "eslint-plugin-react": "~6.7.1",
- "eslint-plugin-standard": "~2.0.1",
- "standard-engine": "~5.2.0"
+ "optional": true,
+ "engines": {
+ "node": ">=0.8"
}
},
- "standard-engine": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/standard-engine/-/standard-engine-5.2.0.tgz",
- "integrity": "sha1-QAZgrlrM6K/U22D/IhSpGQrXkKM=",
- "dev": true,
- "requires": {
- "deglob": "^2.0.0",
- "find-root": "^1.0.0",
- "get-stdin": "^5.0.1",
- "home-or-tmp": "^2.0.0",
- "minimist": "^1.1.0",
- "pkg-config": "^1.0.1"
- },
- "dependencies": {
- "minimist": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
- "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
- "dev": true
- }
- }
- },
- "string-template": {
+ "node_modules/string-template": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz",
"integrity": "sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0=",
"dev": true
},
- "string-width": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
- "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
- "dev": true,
- "requires": {
- "code-point-at": "^1.0.0",
- "is-fullwidth-code-point": "^1.0.0",
- "strip-ansi": "^3.0.0"
- }
- },
- "string_decoder": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
- "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
- "dev": true,
- "requires": {
- "safe-buffer": "~5.1.0"
- }
- },
- "stringstream": {
+ "node_modules/stringstream": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.6.tgz",
"integrity": "sha512-87GEBAkegbBcweToUrdzf3eLhWNg06FJTebl4BVJz/JgWy8CvEr9dRtX5qWphiynMSQlxxi+QqN0z5T32SLlhA==",
"dev": true,
"optional": true
},
- "strip-ansi": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
- "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
- "dev": true,
- "requires": {
- "ansi-regex": "^2.0.0"
- }
- },
- "strip-bom": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
- "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
- "dev": true
- },
- "strip-json-comments": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz",
- "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=",
- "dev": true
- },
- "supports-color": {
+ "node_modules/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"
- }
- },
- "table": {
- "version": "3.8.3",
- "resolved": "https://registry.npmjs.org/table/-/table-3.8.3.tgz",
- "integrity": "sha1-K7xULw/amGGnVdOUf+/Ys/UThV8=",
- "dev": true,
- "requires": {
- "ajv": "^4.7.0",
- "ajv-keywords": "^1.0.0",
- "chalk": "^1.1.1",
- "lodash": "^4.0.0",
- "slice-ansi": "0.0.4",
- "string-width": "^2.0.0"
- },
"dependencies": {
- "ansi-regex": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
- "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
- "dev": true
- },
- "is-fullwidth-code-point": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
- "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
- "dev": true
- },
- "string-width": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
- "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
- "dev": true,
- "requires": {
- "is-fullwidth-code-point": "^2.0.0",
- "strip-ansi": "^4.0.0"
- }
- },
- "strip-ansi": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
- "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
- "dev": true,
- "requires": {
- "ansi-regex": "^3.0.0"
- }
- }
+ "has-flag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.8.0"
}
},
- "text-table": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
- "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
- "dev": true
- },
- "through": {
- "version": "2.3.8",
- "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
- "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
- "dev": true
- },
- "tmp": {
+ "node_modules/tmp": {
"version": "0.0.31",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.31.tgz",
"integrity": "sha1-jzirlDjhcxXl29izZX6L+yd65Kc=",
"dev": true,
- "requires": {
+ "dependencies": {
"os-tmpdir": "~1.0.1"
+ },
+ "engines": {
+ "node": ">=0.4.0"
}
},
- "tough-cookie": {
+ "node_modules/tough-cookie": {
"version": "2.3.4",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz",
"integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==",
"dev": true,
"optional": true,
- "requires": {
+ "dependencies": {
"punycode": "^1.4.1"
+ },
+ "engines": {
+ "node": ">=0.8"
}
},
- "tunnel-agent": {
+ "node_modules/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": {
+ "dependencies": {
"safe-buffer": "^5.0.1"
+ },
+ "engines": {
+ "node": "*"
}
},
- "tweetnacl": {
+ "node_modules/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-check": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
- "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
- "dev": true,
- "requires": {
- "prelude-ls": "~1.1.2"
- }
- },
- "typedarray": {
- "version": "0.0.6",
- "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
- "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
- "dev": true
- },
- "uniq": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz",
- "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=",
- "dev": true
- },
- "user-home": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz",
- "integrity": "sha1-nHC/2Babwdy/SGBODwS4tJzenp8=",
- "dev": true,
- "requires": {
- "os-homedir": "^1.0.0"
- }
- },
- "util-deprecate": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
- "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
- "dev": true
- },
- "uuid": {
+ "node_modules/uuid": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
"integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==",
+ "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
"dev": true,
- "optional": true
+ "optional": true,
+ "bin": {
+ "uuid": "bin/uuid"
+ }
},
- "verror": {
+ "node_modules/verror": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
"integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
"dev": true,
+ "engines": [
+ "node >=0.6.0"
+ ],
"optional": true,
- "requires": {
+ "dependencies": {
"assert-plus": "^1.0.0",
"core-util-is": "1.0.2",
"extsprintf": "^1.2.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": {
+ "node_modules/verror/node_modules/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,
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/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": {
+ "dependencies": {
"browser-split": "0.0.1",
"error": "^4.3.0",
"ev-store": "^7.0.0",
@@ -2135,44 +1219,32 @@
"x-is-string": "0.1.0"
}
},
- "wordwrap": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
- "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=",
- "dev": true
- },
- "wrappy": {
+ "node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
"dev": true
},
- "write": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz",
- "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=",
- "dev": true,
- "requires": {
- "mkdirp": "^0.5.1"
- }
- },
- "x-is-array": {
+ "node_modules/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": {
+ "node_modules/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": {
+ "node_modules/xtend": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
"integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=",
- "dev": true
+ "dev": true,
+ "engines": {
+ "node": ">=0.4"
+ }
}
}
}
diff --git a/packages/welcome/package.json b/packages/welcome/package.json
index 3e8af01ce..dba2f9a62 100644
--- a/packages/welcome/package.json
+++ b/packages/welcome/package.json
@@ -11,9 +11,6 @@
},
"scripts": {
"test": "atom --test test/*.test.js"
- },
- "consumedServices": {
-
},
"configSchema": {
"showOnStartup": {
diff --git a/packages/welcome/test/welcome.test.js b/packages/welcome/test/welcome.test.js
index 8c3c9221a..700a6c051 100644
--- a/packages/welcome/test/welcome.test.js
+++ b/packages/welcome/test/welcome.test.js
@@ -98,84 +98,5 @@ describe('Welcome', () => {
});
});
});
-
- describe('reporting events', () => {
- let panes, guideView, reportedEvents;
- beforeEach(() => {
- panes = atom.workspace.getCenter().getPanes();
- guideView = panes[1].getItems()[0];
- reportedEvents = [];
-
- welcomePackage.reporterProxy.sendEvent = (...event) => {
- reportedEvents.push(event);
- };
- });
-
- describe('GuideView events', () => {
- it('captures expand and collapse events', () => {
- guideView.element
- .querySelector('details[data-section="packages"] summary')
- .click();
- assert.deepEqual(reportedEvents, [['expand-packages-section']]);
-
- guideView.element
- .querySelector('details[data-section="packages"]')
- .setAttribute('open', 'open');
- guideView.element
- .querySelector('details[data-section="packages"] summary')
- .click();
- assert.deepEqual(reportedEvents, [
- ['expand-packages-section'],
- ['collapse-packages-section']
- ]);
- });
-
- it('captures button events', () => {
- for (const detailElement of Array.from(
- guideView.element.querySelector('details')
- )) {
- reportedEvents.length = 0;
-
- const sectionName = detailElement.dataset.section;
- const eventName = `clicked-${sectionName}-cta`;
- const primaryButton = detailElement.querySelector('.btn-primary');
- if (primaryButton) {
- primaryButton.click();
- assert.deepEqual(reportedEvents, [[eventName]]);
- }
- }
- });
- });
- });
-
- describe('when the reporter changes', () =>
- it('sends all queued events', () => {
- welcomePackage.reporterProxy.queue.length = 0;
-
- const reporter1 = {
- addCustomEvent(category, event) {
- this.reportedEvents.push({ category, ...event });
- },
- reportedEvents: []
- };
- const reporter2 = {
- addCustomEvent(category, event) {
- this.reportedEvents.push({ category, ...event });
- },
- reportedEvents: []
- };
-
- welcomePackage.reporterProxy.sendEvent('foo', 'bar', 10);
- welcomePackage.reporterProxy.sendEvent('foo2', 'bar2', 60);
- welcomePackage.reporterProxy.setReporter(reporter1);
-
- assert.deepEqual(reporter1.reportedEvents, [
- { category: 'welcome-v1', ea: 'foo', el: 'bar', ev: 10 },
- { category: 'welcome-v1', ea: 'foo2', el: 'bar2', ev: 60 }
- ]);
-
- welcomePackage.consumeReporter(reporter2);
- assert.deepEqual(reporter2.reportedEvents, []);
- }));
});
});
diff --git a/packages/whitespace/README.md b/packages/whitespace/README.md
new file mode 100644
index 000000000..356a97cac
--- /dev/null
+++ b/packages/whitespace/README.md
@@ -0,0 +1,15 @@
+# Whitespace package
+
+Strips trailing whitespace and adds a trailing newline when an editor is saved.
+
+To disable/enable features for a certain language package, you can use syntax-scoped properties in your `config.cson`. E.g.
+
+```coffee
+'.slim.text':
+ whitespace:
+ removeTrailingWhitespace: false
+```
+
+You find the `scope` on top of a grammar package's settings view.
+
+Note: for `.source.jade`, `.source.diff`, `.source.pug` and `.source.patch`, removing trailing whitespace is disabled by default.
diff --git a/packages/whitespace/lib/main.js b/packages/whitespace/lib/main.js
new file mode 100644
index 000000000..be4c7e0f1
--- /dev/null
+++ b/packages/whitespace/lib/main.js
@@ -0,0 +1,12 @@
+const Whitespace = require('./whitespace')
+
+module.exports = {
+ activate () {
+ this.whitespace = new Whitespace()
+ },
+
+ deactivate () {
+ if (this.whitespace) this.whitespace.destroy()
+ this.whitespace = null
+ }
+}
diff --git a/packages/whitespace/lib/whitespace.js b/packages/whitespace/lib/whitespace.js
new file mode 100644
index 000000000..e6bdac8a0
--- /dev/null
+++ b/packages/whitespace/lib/whitespace.js
@@ -0,0 +1,247 @@
+const {CompositeDisposable, Point, Range} = require('atom')
+
+const TRAILING_WHITESPACE_REGEX = /[ \t]+(?=\r?$)/g
+
+module.exports = class Whitespace {
+ constructor () {
+ this.watchedEditors = new WeakSet()
+ this.subscriptions = new CompositeDisposable()
+
+ this.subscriptions.add(atom.workspace.observeTextEditors(editor => {
+ return this.handleEvents(editor)
+ }))
+
+ this.subscriptions.add(atom.commands.add('atom-workspace', {
+ 'whitespace:remove-trailing-whitespace': () => {
+ let editor = atom.workspace.getActiveTextEditor()
+
+ if (editor) {
+ this.removeTrailingWhitespace(editor, editor.getGrammar().scopeName)
+ }
+ },
+
+ 'whitespace:save-with-trailing-whitespace': async () => {
+ let editor = atom.workspace.getActiveTextEditor()
+
+ if (editor) {
+ this.ignore = true
+ editor.getPath() ? await editor.save() : atom.workspace.getCenter().getActivePane().saveActiveItemAs()
+ this.ignore = false
+ }
+ },
+
+ 'whitespace:save-without-trailing-whitespace': async () => {
+ let editor = atom.workspace.getActiveTextEditor()
+
+ if (editor) {
+ this.removeTrailingWhitespace(editor, editor.getGrammar().scopeName)
+ console.log(editor.getPath())
+ editor.getPath() ? await editor.save() : atom.workspace.getCenter().getActivePane().saveActiveItemAs()
+ }
+ },
+
+ 'whitespace:convert-tabs-to-spaces': () => {
+ let editor = atom.workspace.getActiveTextEditor()
+
+ if (editor) {
+ this.convertTabsToSpaces(editor)
+ }
+ },
+
+ 'whitespace:convert-spaces-to-tabs': () => {
+ let editor = atom.workspace.getActiveTextEditor()
+
+ if (editor) {
+ return this.convertSpacesToTabs(editor)
+ }
+ },
+
+ 'whitespace:convert-all-tabs-to-spaces': () => {
+ let editor = atom.workspace.getActiveTextEditor()
+
+ if (editor) {
+ return this.convertTabsToSpaces(editor, true)
+ }
+ }
+ }))
+ }
+
+ destroy () {
+ return this.subscriptions.dispose()
+ }
+
+ handleEvents (editor) {
+ if (this.watchedEditors.has(editor)) return
+
+ let buffer = editor.getBuffer()
+
+ let bufferSavedSubscription = buffer.onWillSave(() => {
+ return buffer.transact(() => {
+ let scopeDescriptor = editor.getRootScopeDescriptor()
+
+ if (atom.config.get('whitespace.removeTrailingWhitespace', {
+ scope: scopeDescriptor
+ }) && !this.ignore) {
+ this.removeTrailingWhitespace(editor, editor.getGrammar().scopeName)
+ }
+
+ if (atom.config.get('whitespace.ensureSingleTrailingNewline', {scope: scopeDescriptor})) {
+ return this.ensureSingleTrailingNewline(editor)
+ }
+ })
+ })
+
+ let editorTextInsertedSubscription = editor.onDidInsertText(function (event) {
+ if (event.text !== '\n') {
+ return
+ }
+
+ if (!buffer.isRowBlank(event.range.start.row)) {
+ return
+ }
+
+ let scopeDescriptor = editor.getRootScopeDescriptor()
+
+ if (atom.config.get('whitespace.removeTrailingWhitespace', {
+ scope: scopeDescriptor
+ })) {
+ if (!atom.config.get('whitespace.ignoreWhitespaceOnlyLines', {
+ scope: scopeDescriptor
+ })) {
+ return editor.setIndentationForBufferRow(event.range.start.row, 0)
+ }
+ }
+ })
+
+ let editorDestroyedSubscription = editor.onDidDestroy(() => {
+ bufferSavedSubscription.dispose()
+ editorTextInsertedSubscription.dispose()
+ editorDestroyedSubscription.dispose()
+ this.subscriptions.remove(bufferSavedSubscription)
+ this.subscriptions.remove(editorTextInsertedSubscription)
+ this.subscriptions.remove(editorDestroyedSubscription)
+ this.watchedEditors.delete(editor)
+ })
+
+ this.subscriptions.add(bufferSavedSubscription)
+ this.subscriptions.add(editorTextInsertedSubscription)
+ this.subscriptions.add(editorDestroyedSubscription)
+ this.watchedEditors.add(editor)
+ }
+
+ removeTrailingWhitespace (editor, grammarScopeName) {
+ const buffer = editor.getBuffer()
+ const scopeDescriptor = editor.getRootScopeDescriptor()
+
+ // When buffer is same buffer of activeEditor's buffer, don't remove
+ // trailing WS at activeEditor's cursor line.
+ const activeEditor = atom.workspace.getActiveTextEditor()
+ const cursorRows =
+ activeEditor && activeEditor.getBuffer() === buffer
+ ? new Set(activeEditor.getCursors().map(cursor => cursor.getBufferRow()))
+ : new Set()
+
+ const ignoreCurrentLine = atom.config.get('whitespace.ignoreWhitespaceOnCurrentLine', {
+ scope: scopeDescriptor
+ })
+
+ const ignoreWhitespaceOnlyLines = atom.config.get('whitespace.ignoreWhitespaceOnlyLines', {
+ scope: scopeDescriptor
+ })
+
+ const keepMarkdownLineBreakWhitespace =
+ grammarScopeName === ('source.gfm' || 'text.md') &&
+ atom.config.get('whitespace.keepMarkdownLineBreakWhitespace')
+
+ buffer.transact(() => {
+ // TODO - remove this conditional after Atom 1.19 stable is released.
+ if (buffer.findAllSync) {
+ const ranges = buffer.findAllSync(TRAILING_WHITESPACE_REGEX)
+ for (let i = 0, n = ranges.length; i < n; i++) {
+ const range = ranges[i]
+ const row = range.start.row
+ const trailingWhitespaceStart = ranges[i].start.column
+ if (ignoreCurrentLine && cursorRows.has(row)) continue
+ if (ignoreWhitespaceOnlyLines && trailingWhitespaceStart === 0) continue
+ if (keepMarkdownLineBreakWhitespace) {
+ const whitespaceLength = range.end.column - range.start.column
+ if (trailingWhitespaceStart > 0 && whitespaceLength >= 2) continue
+ }
+ buffer.delete(ranges[i])
+ }
+ } else {
+ for (let row = 0, lineCount = buffer.getLineCount(); row < lineCount; row++) {
+ const line = buffer.lineForRow(row)
+ const lastCharacter = line[line.length - 1]
+ if (lastCharacter === ' ' || lastCharacter === '\t') {
+ const trailingWhitespaceStart = line.search(TRAILING_WHITESPACE_REGEX)
+ if (ignoreCurrentLine && cursorRows.has(row)) continue
+ if (ignoreWhitespaceOnlyLines && trailingWhitespaceStart === 0) continue
+ if (keepMarkdownLineBreakWhitespace) {
+ const whitespaceLength = line.length - trailingWhitespaceStart
+ if (trailingWhitespaceStart > 0 && whitespaceLength >= 2) continue
+ }
+ buffer.delete(Range(Point(row, trailingWhitespaceStart), Point(row, line.length)))
+ }
+ }
+ }
+ })
+ }
+
+ ensureSingleTrailingNewline (editor) {
+ let selectedBufferRanges
+ let row
+ let buffer = editor.getBuffer()
+ let lastRow = buffer.getLastRow()
+
+ if (buffer.lineForRow(lastRow) === '') {
+ row = lastRow - 1
+
+ while (row && buffer.lineForRow(row) === '') {
+ buffer.deleteRow(row--)
+ }
+ } else {
+ selectedBufferRanges = editor.getSelectedBufferRanges()
+ buffer.append('\n')
+ editor.setSelectedBufferRanges(selectedBufferRanges)
+ }
+ }
+
+ convertTabsToSpaces (editor, convertAllTabs) {
+ let buffer = editor.getBuffer()
+ let spacesText = new Array(editor.getTabLength() + 1).join(' ')
+ let regex = (convertAllTabs ? /\t/g : /^\t+/g)
+
+ buffer.transact(function () {
+ return buffer.scan(regex, function ({replace}) {
+ return replace(spacesText)
+ })
+ })
+
+ return editor.setSoftTabs(true)
+ }
+
+ convertSpacesToTabs (editor) {
+ let buffer = editor.getBuffer()
+ let scope = editor.getRootScopeDescriptor()
+ let fileTabSize = editor.getTabLength()
+
+ let userTabSize = atom.config.get('editor.tabLength', {
+ scope: scope
+ })
+
+ let regex = new RegExp(' '.repeat(fileTabSize), 'g')
+
+ buffer.transact(function () {
+ return buffer.scan(/^[ \t]+/g, function ({matchText, replace}) {
+ return replace(matchText.replace(regex, '\t').replace(/[ ]+\t/g, '\t'))
+ })
+ })
+
+ editor.setSoftTabs(false)
+
+ if (fileTabSize !== userTabSize) {
+ return editor.setTabLength(userTabSize)
+ }
+ }
+}
diff --git a/packages/whitespace/menus/whitespace.cson b/packages/whitespace/menus/whitespace.cson
new file mode 100644
index 000000000..5ed8b0efe
--- /dev/null
+++ b/packages/whitespace/menus/whitespace.cson
@@ -0,0 +1,16 @@
+'menu': [
+ {
+ 'label': 'Packages'
+ 'submenu': [
+ 'label': 'Whitespace'
+ 'submenu': [
+ { 'label': 'Remove Trailing Whitespace', 'command': 'whitespace:remove-trailing-whitespace' }
+ { 'label': 'Save With Trailing Whitespace', 'command': 'whitespace:save-with-trailing-whitespace' }
+ { 'label': 'Save Without Trailing Whitespace', 'command': 'whitespace:save-without-trailing-whitespace' }
+ { 'label': 'Convert Tabs To Spaces', 'command': 'whitespace:convert-tabs-to-spaces' }
+ { 'label': 'Convert Spaces To Tabs', 'command': 'whitespace:convert-spaces-to-tabs' }
+ { 'label': 'Convert All Tabs To Spaces', 'command': 'whitespace:convert-all-tabs-to-spaces' }
+ ]
+ ]
+ }
+]
diff --git a/packages/whitespace/package-lock.json b/packages/whitespace/package-lock.json
new file mode 100644
index 000000000..b3cf862b6
--- /dev/null
+++ b/packages/whitespace/package-lock.json
@@ -0,0 +1,210 @@
+{
+ "name": "whitespace",
+ "version": "0.37.8",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "whitespace",
+ "version": "0.37.8",
+ "license": "MIT",
+ "devDependencies": {
+ "fs-plus": "2.x",
+ "temp": "~0.8.1"
+ },
+ "engines": {
+ "atom": "*"
+ }
+ },
+ "node_modules/async": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
+ "integrity": "sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==",
+ "dev": true
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true
+ },
+ "node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+ "dev": true
+ },
+ "node_modules/fs-plus": {
+ "version": "2.10.1",
+ "resolved": "https://registry.npmjs.org/fs-plus/-/fs-plus-2.10.1.tgz",
+ "integrity": "sha512-AaKbqqBM2p+Z5NSFhW/LU0sPD3cOnXwQ4kfM/JRX47ehwx+pxz0LuYYdpA/SeHV2i7lMQp+tA9OWBYBC/BYcfw==",
+ "dev": true,
+ "dependencies": {
+ "async": "^1.5.2",
+ "mkdirp": "^0.5.1",
+ "rimraf": "^2.5.2",
+ "underscore-plus": "1.x"
+ }
+ },
+ "node_modules/fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+ "dev": true
+ },
+ "node_modules/glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "dev": true,
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+ "dev": true,
+ "dependencies": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true
+ },
+ "node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/minimist": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz",
+ "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==",
+ "dev": true,
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/mkdirp": {
+ "version": "0.5.6",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
+ "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
+ "dev": true,
+ "dependencies": {
+ "minimist": "^1.2.6"
+ },
+ "bin": {
+ "mkdirp": "bin/cmd.js"
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "dev": true,
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rimraf": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
+ "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
+ "dev": true,
+ "dependencies": {
+ "glob": "^7.1.3"
+ },
+ "bin": {
+ "rimraf": "bin.js"
+ }
+ },
+ "node_modules/temp": {
+ "version": "0.8.4",
+ "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.4.tgz",
+ "integrity": "sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg==",
+ "dev": true,
+ "dependencies": {
+ "rimraf": "~2.6.2"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/temp/node_modules/rimraf": {
+ "version": "2.6.3",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
+ "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
+ "dev": true,
+ "dependencies": {
+ "glob": "^7.1.3"
+ },
+ "bin": {
+ "rimraf": "bin.js"
+ }
+ },
+ "node_modules/underscore": {
+ "version": "1.13.6",
+ "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz",
+ "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==",
+ "dev": true
+ },
+ "node_modules/underscore-plus": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/underscore-plus/-/underscore-plus-1.7.0.tgz",
+ "integrity": "sha512-A3BEzkeicFLnr+U/Q3EyWwJAQPbA19mtZZ4h+lLq3ttm9kn8WC4R3YpuJZEXmWdLjYP47Zc8aLZm9kwdv+zzvA==",
+ "dev": true,
+ "dependencies": {
+ "underscore": "^1.9.1"
+ }
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "dev": true
+ }
+ }
+}
diff --git a/packages/whitespace/package.json b/packages/whitespace/package.json
new file mode 100644
index 000000000..5d7f1dd39
--- /dev/null
+++ b/packages/whitespace/package.json
@@ -0,0 +1,56 @@
+{
+ "name": "whitespace",
+ "version": "0.37.8",
+ "main": "./lib/main",
+ "description": "Strips trailing whitespace and adds a trailing newline when an editor is saved.",
+ "repository": "https://github.com/pulsar-edit/pulsar",
+ "license": "MIT",
+ "engines": {
+ "atom": "*"
+ },
+ "devDependencies": {
+ "fs-plus": "2.x",
+ "temp": "~0.8.1"
+ },
+ "configSchema": {
+ "removeTrailingWhitespace": {
+ "type": "boolean",
+ "default": true,
+ "scopes": {
+ ".source.diff": {
+ "default": false
+ },
+ ".source.jade": {
+ "default": false
+ },
+ ".source.patch": {
+ "default": false
+ },
+ ".source.pug": {
+ "default": false
+ }
+ },
+ "description": "Automatically remove whitespace characters at ends of lines when the buffer is saved. To disable/enable for a certain language, use [syntax-scoped properties](https://github.com/pulsar-edit/whitespace#readme) in your `config.cson`."
+ },
+ "keepMarkdownLineBreakWhitespace": {
+ "type": "boolean",
+ "default": true,
+ "description": "Markdown uses two or more spaces at the end of a line to signify a line break. Enable this option to keep this whitespace in Markdown files, even if other settings would remove it."
+ },
+ "ignoreWhitespaceOnCurrentLine": {
+ "type": "boolean",
+ "default": true,
+ "description": "Skip removing trailing whitespace on the line which the cursor is positioned on when the buffer is saved. To disable/enable for a certain language, use [syntax-scoped properties](https://github.com/pulsar-edit/pulsar/tree/master/packages/whitespace#readme) in your `config.cson`."
+ },
+ "ignoreWhitespaceOnlyLines": {
+ "type": "boolean",
+ "default": false,
+ "description": "Skip removing trailing whitespace on lines which consist only of whitespace characters. To disable/enable for a certain language, use [syntax-scoped properties](https://github.com/pulsar-edit/pulsar/tree/master/packages/whitespace#readme) in your `config.cson`."
+ },
+ "ensureSingleTrailingNewline": {
+ "type": "boolean",
+ "default": true,
+ "description": "If the buffer doesn't end with a newline character when it's saved, then append one. If it ends with more than one newline, remove all but one. To disable/enable for a certain language, use [syntax-scoped properties](https://github.com/pulsar-edit/pulsar/tree/master/packages/whitespace#readme) in your `config.cson`."
+ }
+ }
+}
diff --git a/packages/whitespace/spec/async-spec-helpers.js b/packages/whitespace/spec/async-spec-helpers.js
new file mode 100644
index 000000000..0783c64fd
--- /dev/null
+++ b/packages/whitespace/spec/async-spec-helpers.js
@@ -0,0 +1,43 @@
+exports.beforeEach = function beforeEach (fn) {
+ global.beforeEach(function () {
+ const result = fn()
+ if (result instanceof Promise) {
+ waitsForPromise(() => result)
+ }
+ })
+}
+
+exports.afterEach = function afterEach (fn) {
+ global.afterEach(function () {
+ const result = fn()
+ if (result instanceof Promise) {
+ waitsForPromise(() => result)
+ }
+ })
+}
+
+;['it', 'fit', 'ffit', 'fffit'].forEach(function (name) {
+ exports[name] = function (description, fn) {
+ if (fn === undefined) {
+ global[name](description)
+ return
+ }
+
+ global[name](description, function () {
+ const result = fn()
+ if (result instanceof Promise) {
+ waitsForPromise(() => result)
+ }
+ })
+ }
+})
+
+function waitsForPromise (fn) {
+ const promise = fn()
+ global.waitsFor('spec promise to resolve', function (done) {
+ promise.then(done, function (error) {
+ jasmine.getEnv().currentSpec.fail(error)
+ done()
+ })
+ })
+}
diff --git a/packages/whitespace/spec/whitespace-spec.js b/packages/whitespace/spec/whitespace-spec.js
new file mode 100644
index 000000000..7020376f9
--- /dev/null
+++ b/packages/whitespace/spec/whitespace-spec.js
@@ -0,0 +1,531 @@
+const path = require('path')
+const fs = require('fs-plus')
+const temp = require('temp')
+const {it, fit, ffit, beforeEach} = require('./async-spec-helpers') // eslint-disable-line
+
+describe('Whitespace', () => {
+ let editor, buffer, workspaceElement
+
+ beforeEach(async () => {
+ const directory = temp.mkdirSync()
+ atom.project.setPaths([directory])
+ workspaceElement = atom.views.getView(atom.workspace)
+ const filePath = path.join(directory, 'atom-whitespace.txt')
+ fs.writeFileSync(filePath, '')
+ fs.writeFileSync(path.join(directory, 'sample.txt'), 'Some text.\n')
+
+ editor = await atom.workspace.open(filePath)
+ buffer = editor.getBuffer()
+ await atom.packages.activatePackage('whitespace')
+ })
+
+ describe('when the editor is destroyed', () => {
+ beforeEach(() => editor.destroy())
+
+ it('does not leak subscriptions', async () => {
+ const {whitespace} = atom.packages.getActivePackage('whitespace').mainModule
+ expect(whitespace.subscriptions.disposables.size).toBe(2)
+
+ await atom.packages.deactivatePackage('whitespace')
+ expect(whitespace.subscriptions.disposables).toBeNull()
+ })
+ })
+
+ describe("when 'whitespace.removeTrailingWhitespace' is true", () => {
+ beforeEach(() => atom.config.set('whitespace.removeTrailingWhitespace', true))
+
+ it('strips trailing whitespace before an editor saves a buffer', async () => {
+ // works for buffers that are already open when package is initialized
+ editor.insertText('foo \nbar\t \n\nbaz\n')
+ await editor.save()
+ expect(editor.getText()).toBe('foo\nbar\n\nbaz\n')
+
+ editor = await atom.workspace.open('sample.txt')
+
+ editor.moveToEndOfLine()
+ editor.insertText(' ')
+
+ // move cursor to next line to avoid ignoreWhitespaceOnCurrentLine
+ editor.moveToBottom()
+
+ await editor.save()
+ expect(editor.getText()).toBe('Some text.\n')
+ })
+
+ it('works for files with CRLF line endings', async () => {
+ editor.insertText('foo \r\nbar\t \r\n\r\nbaz\r\n')
+ await editor.save()
+ expect(editor.getText()).toBe('foo\r\nbar\r\n\r\nbaz\r\n')
+ })
+
+ it('clears blank lines when the editor inserts a newline', () => {
+ // Need autoIndent to be true
+ editor.update({autoIndent: true})
+
+ // Create an indent level and insert a newline
+ editor.setIndentationForBufferRow(0, 1)
+ editor.insertText('\n')
+ expect(editor.getText()).toBe('\n ')
+
+ // Undo the newline insert and redo it
+ editor.undo()
+ expect(editor.getText()).toBe(' ')
+ editor.redo()
+ expect(editor.getText()).toBe('\n ')
+
+ // Test for multiple cursors, possibly without blank lines
+ editor.insertText('foo')
+ editor.insertText('\n')
+ editor.setCursorBufferPosition([1, 5]) // Cursor after 'foo'
+ editor.addCursorAtBufferPosition([2, 2]) // Cursor on the next line (blank)
+ editor.insertText('\n')
+ expect(editor.getText()).toBe('\n foo\n \n\n ')
+ })
+ })
+
+ describe("when 'whitespace.removeTrailingWhitespace' is false", () => {
+ beforeEach(() => atom.config.set('whitespace.removeTrailingWhitespace', false))
+
+ it('does not trim trailing whitespace', async () => {
+ editor.insertText("don't trim me \n\n")
+ await editor.save()
+ expect(editor.getText()).toBe("don't trim me \n")
+ })
+
+ describe('when the setting is set scoped to the grammar', () => {
+ beforeEach(() => {
+ atom.config.set('whitespace.removeTrailingWhitespace', true)
+ atom.config.set('whitespace.removeTrailingWhitespace', false, {scopeSelector: '.text.plain'})
+ })
+
+ it('does not trim trailing whitespace', async () => {
+ editor.insertText("don't trim me \n\n")
+ await editor.save()
+ expect(editor.getText()).toBe("don't trim me \n")
+ })
+ })
+ })
+
+ describe("when 'whitespace.ignoreWhitespaceOnCurrentLine' is true", () => {
+ beforeEach(() => atom.config.set('whitespace.ignoreWhitespaceOnCurrentLine', true))
+
+ describe('respects multiple cursors', () => {
+ it('removes the whitespace from all lines, excluding the current lines', async () => {
+ editor.insertText('1 \n2 \n3 \n')
+ editor.setCursorBufferPosition([1, 3])
+ editor.addCursorAtBufferPosition([2, 3])
+ await editor.save()
+ expect(editor.getText()).toBe('1\n2 \n3 \n')
+ })
+ })
+
+ describe('when buffer is opened in multiple editors', () => {
+ let editor2
+ beforeEach(async () => {
+ editor2 = atom.workspace.buildTextEditor({buffer: editor.buffer})
+ await atom.workspace.open(editor2)
+ })
+
+ it('[editor is activeEditor] remove WS with excluding active editor\'s cursor line', async () => {
+ editor.insertText('1 \n2 \n3 \n')
+ editor.setCursorBufferPosition([1, 3])
+ editor2.setCursorBufferPosition([2, 3])
+
+ atom.workspace.getActivePane().activateItem(editor)
+ expect(atom.workspace.getActiveTextEditor()).toBe(editor)
+ await editor.save()
+ expect(editor.getText()).toBe('1\n2 \n3\n')
+ })
+
+ it('[editor2 is activeEditor] remove WS with excluding active editor\'s cursor line', async () => {
+ editor.insertText('1 \n2 \n3 \n')
+ editor.setCursorBufferPosition([1, 3])
+ editor2.setCursorBufferPosition([2, 3])
+
+ atom.workspace.getActivePane().activateItem(editor2)
+ expect(atom.workspace.getActiveTextEditor()).toBe(editor2)
+ await editor2.save()
+ expect(editor.getText()).toBe('1\n2\n3 \n')
+ })
+
+ it('[either editor nor editor2 is activeEditor] remove WS but doesn\'t exclude cursor line for non active editor', async () => {
+ editor.insertText('1 \n2 \n3 \n')
+ editor.setCursorBufferPosition([1, 3])
+ editor2.setCursorBufferPosition([1, 3])
+
+ const editor3 = await atom.workspace.open()
+ expect(atom.workspace.getActiveTextEditor()).toBe(editor3)
+ await editor.save()
+ expect(editor.getText()).toBe('1\n2\n3\n') // all trainling-WS were removed
+ })
+ })
+ })
+
+ describe("when 'whitespace.ignoreWhitespaceOnCurrentLine' is false", () => {
+ beforeEach(() => atom.config.set('whitespace.ignoreWhitespaceOnCurrentLine', false))
+
+ it('removes the whitespace from all lines, including the current lines', async () => {
+ editor.insertText('1 \n2 \n3 \n')
+ editor.setCursorBufferPosition([1, 3])
+ editor.addCursorAtBufferPosition([2, 3])
+ await editor.save()
+ expect(editor.getText()).toBe('1\n2\n3\n')
+ })
+ })
+
+ describe("when 'whitespace.ignoreWhitespaceOnlyLines' is false", () => {
+ beforeEach(() => atom.config.set('whitespace.ignoreWhitespaceOnlyLines', false))
+
+ it('removes the whitespace from all lines, including the whitespace-only lines', async () => {
+ editor.insertText('1 \n2\t \n\t \n3\n')
+
+ // move cursor to bottom for preventing effect of whitespace.ignoreWhitespaceOnCurrentLine
+ editor.moveToBottom()
+ await editor.save()
+ expect(editor.getText()).toBe('1\n2\n\n3\n')
+ })
+ })
+
+ describe("when 'whitespace.ignoreWhitespaceOnlyLines' is true", () => {
+ beforeEach(() => atom.config.set('whitespace.ignoreWhitespaceOnlyLines', true))
+
+ it('removes the whitespace from all lines, excluding the whitespace-only lines', async () => {
+ editor.insertText('1 \n2\t \n\t \n3\n')
+
+ // move cursor to bottom for preventing effect of whitespace.ignoreWhitespaceOnCurrentLine
+ editor.moveToBottom()
+ await editor.save()
+ expect(editor.getText()).toBe('1\n2\n\t \n3\n')
+ })
+ })
+
+ describe("when 'whitespace.ensureSingleTrailingNewline' is true", () => {
+ beforeEach(() => atom.config.set('whitespace.ensureSingleTrailingNewline', true))
+
+ it('adds a trailing newline when there is no trailing newline', async () => {
+ editor.insertText('foo')
+ await editor.save()
+ expect(editor.getText()).toBe('foo\n')
+ })
+
+ it('removes extra trailing newlines and only keeps one', async () => {
+ editor.insertText('foo\n\n\n\n')
+ await editor.save()
+ expect(editor.getText()).toBe('foo\n')
+ })
+
+ it('leaves a buffer with a single trailing newline untouched', async () => {
+ editor.insertText('foo\nbar\n')
+ await editor.save()
+ expect(editor.getText()).toBe('foo\nbar\n')
+ })
+
+ it('leaves an empty buffer untouched', () => {
+ editor.insertText('')
+ editor.save()
+ expect(editor.getText()).toBe('')
+ })
+
+ it('leaves a buffer that is a single newline untouched', () => {
+ editor.insertText('\n')
+ editor.save()
+ expect(editor.getText()).toBe('\n')
+ })
+
+ it('does not move the cursor when the new line is added', async () => {
+ editor.insertText('foo\nboo')
+ editor.setCursorBufferPosition([0, 3])
+ await editor.save()
+ expect(editor.getText()).toBe('foo\nboo\n')
+ expect(editor.getCursorBufferPosition()).toEqual([0, 3])
+ })
+
+ it('preserves selections when saving on last line', async () => {
+ editor.insertText('foo')
+ editor.setCursorBufferPosition([0, 0])
+ editor.selectToEndOfLine()
+ const originalSelectionRange = editor.getLastSelection().getBufferRange()
+ await editor.save()
+ const newSelectionRange = editor.getLastSelection().getBufferRange()
+ expect(originalSelectionRange).toEqual(newSelectionRange)
+ })
+ })
+
+ describe("when 'whitespace.ensureSingleTrailingNewline' is false", () => {
+ beforeEach(() => atom.config.set('whitespace.ensureSingleTrailingNewline', false))
+
+ it('does not add trailing newline if ensureSingleTrailingNewline is false', () => {
+ editor.insertText('no trailing newline')
+ editor.save()
+ expect(editor.getText()).toBe('no trailing newline')
+ })
+ })
+
+ describe('GFM whitespace trimming', () => {
+ describe('when keepMarkdownLineBreakWhitespace is true', () => {
+ beforeEach(() => {
+ atom.config.set('whitespace.removeTrailingWhitespace', true)
+ atom.config.set('whitespace.ignoreWhitespaceOnCurrentLine', false)
+ atom.config.set('whitespace.keepMarkdownLineBreakWhitespace', true)
+
+ waitsForPromise(() => atom.packages.activatePackage('language-gfm'))
+
+ runs(() => editor.setGrammar(atom.grammars.grammarForScopeName('source.gfm')))
+ })
+
+ it('trims GFM text with a single space', async () => {
+ editor.insertText('foo \nline break!')
+ await editor.save()
+ expect(editor.getText()).toBe('foo\nline break!\n')
+ })
+
+ it('leaves GFM text with double spaces alone', async () => {
+ editor.insertText('foo \nline break!')
+ await editor.save()
+ expect(editor.getText()).toBe('foo \nline break!\n')
+ })
+
+ it('leaves GFM text with a more than two spaces', async () => {
+ editor.insertText('foo \nline break!')
+ await editor.save()
+ expect(editor.getText()).toBe('foo \nline break!\n')
+ })
+
+ it('trims empty lines', async () => {
+ editor.insertText('foo\n ')
+ await editor.save()
+ expect(editor.getText()).toBe('foo\n')
+
+ editor.setText('foo\n ')
+ await editor.save()
+ expect(editor.getText()).toBe('foo\n')
+ })
+
+ it("respects 'whitespace.ignoreWhitespaceOnCurrentLine' setting", async () => {
+ atom.config.set('whitespace.ignoreWhitespaceOnCurrentLine', true)
+
+ editor.insertText('foo \nline break!')
+ editor.setCursorBufferPosition([0, 4])
+ await editor.save()
+ expect(editor.getText()).toBe('foo \nline break!\n')
+ })
+
+ it("respects 'whitespace.ignoreWhitespaceOnlyLines' setting", async () => {
+ atom.config.set('whitespace.ignoreWhitespaceOnlyLines', true)
+
+ editor.insertText('\t \nline break!')
+ await editor.save()
+ expect(editor.getText()).toBe('\t \nline break!\n')
+ })
+ })
+
+ describe('when keepMarkdownLineBreakWhitespace is false', () => {
+ beforeEach(() => {
+ atom.config.set('whitespace.ignoreWhitespaceOnCurrentLine', false)
+ atom.config.set('whitespace.keepMarkdownLineBreakWhitespace', false)
+
+ waitsForPromise(() => atom.packages.activatePackage('language-gfm'))
+
+ runs(() => editor.setGrammar(atom.grammars.grammarForScopeName('source.gfm')))
+ })
+
+ it('trims GFM text with a single space', async () => {
+ editor.insertText('foo \nline break!')
+ await editor.save()
+ expect(editor.getText()).toBe('foo\nline break!\n')
+ })
+
+ it('trims GFM text with two spaces', async () => {
+ editor.insertText('foo \nline break!')
+ await editor.save()
+ expect(editor.getText()).toBe('foo\nline break!\n')
+ })
+
+ it('trims GFM text with a more than two spaces', async () => {
+ editor.insertText('foo \nline break!')
+ await editor.save()
+ expect(editor.getText()).toBe('foo\nline break!\n')
+ })
+
+ it('trims empty lines', async () => {
+ editor.insertText('foo\n ')
+ await editor.save()
+ expect(editor.getText()).toBe('foo\n')
+
+ editor.setText('foo\n ')
+ await editor.save()
+ expect(editor.getText()).toBe('foo\n')
+ })
+
+ it("respects 'whitespace.ignoreWhitespaceOnCurrentLine' setting", async () => {
+ atom.config.set('whitespace.ignoreWhitespaceOnCurrentLine', true)
+
+ editor.insertText('foo \nline break!')
+ editor.setCursorBufferPosition([0, 4])
+ await editor.save()
+ expect(editor.getText()).toBe('foo \nline break!\n')
+ })
+
+ it("respects 'whitespace.ignoreWhitespaceOnlyLines' setting", async () => {
+ atom.config.set('whitespace.ignoreWhitespaceOnlyLines', true)
+
+ editor.insertText('\t \nline break!')
+ await editor.save()
+ expect(editor.getText()).toBe('\t \nline break!\n')
+ })
+ })
+ })
+
+ describe('when the editor is split', () =>
+ it('does not throw exceptions when the editor is saved after the split is closed (regression)', async () => {
+ atom.workspace.getActivePane().splitRight({copyActiveItem: true})
+ atom.workspace.getPanes()[0].destroyItems()
+
+ editor = atom.workspace.getActivePaneItem()
+ editor.setText('test')
+ await editor.save()
+ expect(editor.getText()).toBe('test\n')
+ })
+ )
+
+ describe('when deactivated', () =>
+ it('does not remove trailing whitespace from editors opened after deactivation', async () => {
+ atom.config.set('whitespace.removeTrailingWhitespace', true)
+ await atom.packages.deactivatePackage('whitespace')
+
+ editor.setText('foo \n')
+ await editor.save()
+ expect(editor.getText()).toBe('foo \n')
+
+ await atom.workspace.open('sample2.txt')
+
+ editor = atom.workspace.getActiveTextEditor()
+ editor.setText('foo \n')
+ await editor.save()
+ expect(editor.getText()).toBe('foo \n')
+ })
+ )
+
+ describe("when the 'whitespace:remove-trailing-whitespace' command is run", () => {
+ beforeEach(() => buffer.setText('foo \nbar\t \n\nbaz'))
+
+ it('removes the trailing whitespace in the active editor', () => {
+ atom.commands.dispatch(workspaceElement, 'whitespace:remove-trailing-whitespace')
+ expect(buffer.getText()).toBe('foo\nbar\n\nbaz')
+ })
+
+ it('does not attempt to remove whitespace when the package is deactivated', async () => {
+ await atom.packages.deactivatePackage('whitespace')
+ expect(buffer.getText()).toBe('foo \nbar\t \n\nbaz')
+ })
+ })
+
+ describe("when the 'whitespace:save-with-trailing-whitespace' command is run", () => {
+ beforeEach(() => {
+ atom.config.set('whitespace.removeTrailingWhitespace', true)
+ atom.config.set('whitespace.ensureSingleTrailingNewline', false)
+ buffer.setText('foo \nbar\t \n\nbaz')
+ })
+
+ it('saves the file without removing any trailing whitespace', () =>
+ waitsFor((done) => {
+ buffer.onDidSave(() => {
+ expect(buffer.getText()).toBe('foo \nbar\t \n\nbaz')
+ expect(buffer.isModified()).toBe(false)
+ done()
+ })
+ atom.commands.dispatch(workspaceElement, 'whitespace:save-with-trailing-whitespace')
+ })
+ )
+ })
+
+ describe("when the 'whitespace:save-without-trailing-whitespace' command is run", () => {
+ beforeEach(() => {
+ atom.config.set('whitespace.removeTrailingWhitespace', false)
+ atom.config.set('whitespace.ensureSingleTrailingNewline', false)
+ buffer.setText('foo \nbar\t \n\nbaz')
+ })
+
+ it('saves the file and removes any trailing whitespace', () =>
+ waitsFor(function (done) {
+ buffer.onDidSave(() => {
+ expect(buffer.getText()).toBe('foo\nbar\n\nbaz')
+ expect(buffer.isModified()).toBe(false)
+ done()
+ })
+ atom.commands.dispatch(workspaceElement, 'whitespace:save-without-trailing-whitespace')
+ })
+ )
+ })
+
+ describe("when the 'whitespace:convert-tabs-to-spaces' command is run", () => {
+ it('removes leading \\t characters and replaces them with spaces using the configured tab length', () => {
+ editor.setTabLength(2)
+ buffer.setText('\ta\n\t\nb\t\nc\t\td')
+ atom.commands.dispatch(workspaceElement, 'whitespace:convert-tabs-to-spaces')
+ expect(buffer.getText()).toBe(' a\n \nb\t\nc\t\td')
+
+ editor.setTabLength(3)
+ buffer.setText('\ta\n\t\nb\t\nc\t\td')
+ atom.commands.dispatch(workspaceElement, 'whitespace:convert-tabs-to-spaces')
+ expect(buffer.getText()).toBe(' a\n \nb\t\nc\t\td')
+ })
+
+ it('changes the tab type to soft tabs', () => {
+ atom.commands.dispatch(workspaceElement, 'whitespace:convert-tabs-to-spaces')
+ expect(editor.getSoftTabs()).toBe(true)
+ })
+ })
+
+ describe("when the 'whitespace:convert-spaces-to-tabs' command is run", () => {
+ it('removes leading space characters and replaces them with hard tabs', () => {
+ editor.setTabLength(2)
+ buffer.setText(' a\n \nb \nc d')
+ atom.commands.dispatch(workspaceElement, 'whitespace:convert-spaces-to-tabs')
+ expect(buffer.getText()).toBe('\t a\n\t\nb \nc d')
+
+ editor.setTabLength(3)
+ buffer.setText(' a\n \nb \nc d')
+ atom.commands.dispatch(workspaceElement, 'whitespace:convert-spaces-to-tabs')
+ expect(buffer.getText()).toBe('\t a\n\t\nb \nc d')
+ })
+
+ it('handles mixed runs of tabs and spaces correctly', () => {
+ editor.setTabLength(4)
+ buffer.setText(' \t \t\ta ')
+ atom.commands.dispatch(workspaceElement, 'whitespace:convert-spaces-to-tabs')
+ expect(buffer.getText()).toBe('\t\t\t\t\ta ')
+ })
+
+ it('changes the tab type to hard tabs', () => {
+ atom.commands.dispatch(workspaceElement, 'whitespace:convert-spaces-to-tabs')
+ expect(editor.getSoftTabs()).toBe(false)
+ })
+
+ it("changes the tab length to user's tab-size", () => {
+ editor.setTabLength(4)
+ buffer.setText(' ')
+ atom.commands.dispatch(workspaceElement, 'whitespace:convert-spaces-to-tabs')
+ expect(editor.getTabLength()).toBe(2)
+ })
+ })
+
+ describe("when the 'whitespace:convert-all-tabs-to-spaces' command is run", () => {
+ it('removes all \\t characters and replaces them with spaces using the configured tab length', () => {
+ editor.setTabLength(2)
+ buffer.setText('\ta\n\t\nb\t\nc\t\td')
+ atom.commands.dispatch(workspaceElement, 'whitespace:convert-all-tabs-to-spaces')
+ expect(buffer.getText()).toBe(' a\n \nb \nc d')
+
+ editor.setTabLength(3)
+ buffer.setText('\ta\n\t\nb\t\nc\t\td')
+ atom.commands.dispatch(workspaceElement, 'whitespace:convert-all-tabs-to-spaces')
+ expect(buffer.getText()).toBe(' a\n \nb \nc d')
+ })
+
+ it('changes the tab type to soft tabs', () => {
+ atom.commands.dispatch(workspaceElement, 'whitespace:convert-all-tabs-to-spaces')
+ expect(editor.getSoftTabs()).toBe(true)
+ })
+ })
+})
diff --git a/packages/wrap-guide/.gitignore b/packages/wrap-guide/.gitignore
new file mode 100644
index 000000000..3c3629e64
--- /dev/null
+++ b/packages/wrap-guide/.gitignore
@@ -0,0 +1 @@
+node_modules
diff --git a/packages/wrap-guide/README.md b/packages/wrap-guide/README.md
new file mode 100644
index 000000000..1bfa87017
--- /dev/null
+++ b/packages/wrap-guide/README.md
@@ -0,0 +1,35 @@
+# Wrap Guide package
+
+The `wrap-guide` package places a vertical line in each editor at a certain column to guide your formatting, so lines do not exceed a certain width.
+
+By default, the wrap-guide is placed at the value of `editor.preferredLineLength` config setting. The 80th column is used as the fallback if the config value is unset.
+
+![](https://f.cloud.github.com/assets/671378/2241976/dbf6a8f6-9ced-11e3-8fef-d8a226301530.png)
+
+## Configuration
+
+You can customize where the column is placed for different file types by opening the Settings View and configuring the "Preferred Line Length" value. If you do not want the guide to show for a particular language, that can be set using scoped configuration. For example, to turn off the guide for GitHub-Flavored Markdown, you can add the following to your `config.cson`:
+
+```coffeescript
+'.source.gfm':
+ 'wrap-guide':
+ 'enabled': false
+```
+
+It is possible to configure the color and/or width of the line by adding the following CSS/LESS to your `styles.less`:
+
+```css
+atom-text-editor .wrap-guide {
+ width: 10px;
+ background-color: red;
+}
+```
+
+Multiple guide lines are also supported. For example, add the following to your `config.cson` to create four columns at the indicated positions:
+
+```coffeescript
+'wrap-guide':
+ 'columns': [72, 80, 100, 120]
+```
+
+> Note: When using multiple guide lines, the right-most guide line functions as your `editor.preferredLineLength` setting.
diff --git a/packages/wrap-guide/lib/main.coffee b/packages/wrap-guide/lib/main.coffee
new file mode 100644
index 000000000..e2beff8d7
--- /dev/null
+++ b/packages/wrap-guide/lib/main.coffee
@@ -0,0 +1,26 @@
+{CompositeDisposable} = require 'atom'
+WrapGuideElement = require './wrap-guide-element'
+
+module.exports =
+ activate: ->
+ @subscriptions = new CompositeDisposable()
+ @wrapGuides = new Map()
+
+ @subscriptions.add atom.workspace.observeTextEditors (editor) =>
+ return if @wrapGuides.has(editor)
+
+ editorElement = atom.views.getView(editor)
+ wrapGuideElement = new WrapGuideElement(editor, editorElement)
+
+ @wrapGuides.set(editor, wrapGuideElement)
+ @subscriptions.add editor.onDidDestroy =>
+ @wrapGuides.get(editor).destroy()
+ @wrapGuides.delete(editor)
+
+ deactivate: ->
+ @subscriptions.dispose()
+ @wrapGuides.forEach (wrapGuide, editor) -> wrapGuide.destroy()
+ @wrapGuides.clear()
+
+ uniqueAscending: (list) ->
+ (list.filter((item, index) -> list.indexOf(item) is index)).sort((a, b) -> a - b)
diff --git a/packages/wrap-guide/lib/wrap-guide-element.coffee b/packages/wrap-guide/lib/wrap-guide-element.coffee
new file mode 100644
index 000000000..46f86362b
--- /dev/null
+++ b/packages/wrap-guide/lib/wrap-guide-element.coffee
@@ -0,0 +1,137 @@
+{CompositeDisposable} = require 'atom'
+
+module.exports =
+class WrapGuideElement
+ constructor: (@editor, @editorElement) ->
+ @subscriptions = new CompositeDisposable()
+ @configSubscriptions = new CompositeDisposable()
+ @element = document.createElement('div')
+ @element.setAttribute('is', 'wrap-guide')
+ @element.classList.add('wrap-guide-container')
+ @attachToLines()
+ @handleEvents()
+ @updateGuide()
+
+ @element.updateGuide = @updateGuide.bind(this)
+ @element.getDefaultColumn = @getDefaultColumn.bind(this)
+
+ attachToLines: ->
+ scrollView = @editorElement.querySelector('.scroll-view')
+ scrollView?.appendChild(@element)
+
+ handleEvents: ->
+ updateGuideCallback = => @updateGuide()
+
+ @handleConfigEvents()
+
+ @subscriptions.add atom.config.onDidChange 'editor.fontSize', =>
+ # Wait for editor to finish updating before updating wrap guide
+ # TODO: Use async/await once this file is converted to JS
+ @editorElement.getComponent().getNextUpdatePromise().then -> updateGuideCallback()
+
+ @subscriptions.add @editorElement.onDidChangeScrollLeft(updateGuideCallback)
+ @subscriptions.add @editor.onDidChangePath(updateGuideCallback)
+ @subscriptions.add @editor.onDidChangeGrammar =>
+ @configSubscriptions.dispose()
+ @handleConfigEvents()
+ updateGuideCallback()
+
+ @subscriptions.add @editor.onDidDestroy =>
+ @subscriptions.dispose()
+ @configSubscriptions.dispose()
+
+ @subscriptions.add @editorElement.onDidAttach =>
+ @attachToLines()
+ updateGuideCallback()
+
+ handleConfigEvents: ->
+ {uniqueAscending} = require './main'
+
+ updatePreferredLineLengthCallback = (args) =>
+ # ensure that the right-most wrap guide is the preferredLineLength
+ columns = atom.config.get('wrap-guide.columns', scope: @editor.getRootScopeDescriptor())
+ if columns.length > 0
+ columns[columns.length - 1] = args.newValue
+ columns = uniqueAscending(i for i in columns when i <= args.newValue)
+ atom.config.set 'wrap-guide.columns', columns,
+ scopeSelector: ".#{@editor.getGrammar().scopeName}"
+ @updateGuide()
+ @configSubscriptions.add atom.config.onDidChange(
+ 'editor.preferredLineLength',
+ scope: @editor.getRootScopeDescriptor(),
+ updatePreferredLineLengthCallback
+ )
+
+ updateGuideCallback = => @updateGuide()
+ @configSubscriptions.add atom.config.onDidChange(
+ 'wrap-guide.enabled',
+ scope: @editor.getRootScopeDescriptor(),
+ updateGuideCallback
+ )
+
+ updateGuidesCallback = (args) =>
+ # ensure that multiple guides stay sorted in ascending order
+ columns = uniqueAscending(args.newValue)
+ if columns?.length
+ atom.config.set('wrap-guide.columns', columns)
+ atom.config.set 'editor.preferredLineLength', columns[columns.length - 1],
+ scopeSelector: ".#{@editor.getGrammar().scopeName}"
+ @updateGuide()
+ @configSubscriptions.add atom.config.onDidChange(
+ 'wrap-guide.columns',
+ scope: @editor.getRootScopeDescriptor(),
+ updateGuidesCallback
+ )
+
+ getDefaultColumn: ->
+ atom.config.get('editor.preferredLineLength', scope: @editor.getRootScopeDescriptor())
+
+ getGuidesColumns: (path, scopeName) ->
+ columns = atom.config.get('wrap-guide.columns', scope: @editor.getRootScopeDescriptor()) ? []
+ return columns if columns.length > 0
+ return [@getDefaultColumn()]
+
+ isEnabled: ->
+ atom.config.get('wrap-guide.enabled', scope: @editor.getRootScopeDescriptor()) ? true
+
+ hide: ->
+ @element.style.display = 'none'
+
+ show: ->
+ @element.style.display = 'block'
+
+ updateGuide: ->
+ if @isEnabled()
+ @updateGuides()
+ else
+ @hide()
+
+ updateGuides: ->
+ @removeGuides()
+ @appendGuides()
+ if @element.children.length
+ @show()
+ else
+ @hide()
+
+ destroy: ->
+ @element.remove()
+ @subscriptions.dispose()
+ @configSubscriptions.dispose()
+
+ removeGuides: ->
+ while @element.firstChild
+ @element.removeChild(@element.firstChild)
+
+ appendGuides: ->
+ columns = @getGuidesColumns(@editor.getPath(), @editor.getGrammar().scopeName)
+ for column in columns
+ @appendGuide(column) unless column < 0
+
+ appendGuide: (column) ->
+ columnWidth = @editorElement.getDefaultCharacterWidth() * column
+ columnWidth -= @editorElement.getScrollLeft()
+ guide = document.createElement('div')
+ guide.classList.add('wrap-guide')
+ guide.style.left = "#{Math.round(columnWidth)}px"
+ @element.appendChild(guide)
diff --git a/packages/wrap-guide/package-lock.json b/packages/wrap-guide/package-lock.json
new file mode 100644
index 000000000..88840000a
--- /dev/null
+++ b/packages/wrap-guide/package-lock.json
@@ -0,0 +1,16 @@
+{
+ "name": "wrap-guide",
+ "version": "0.41.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "wrap-guide",
+ "version": "0.41.0",
+ "license": "MIT",
+ "engines": {
+ "atom": "*"
+ }
+ }
+ }
+}
diff --git a/packages/wrap-guide/package.json b/packages/wrap-guide/package.json
new file mode 100644
index 000000000..642a205c7
--- /dev/null
+++ b/packages/wrap-guide/package.json
@@ -0,0 +1,25 @@
+{
+ "name": "wrap-guide",
+ "version": "0.41.0",
+ "main": "./lib/main",
+ "description": "Displays a vertical line at the 80th character in the editor.\nThis packages uses the config value of `editor.preferredLineLength` when set.",
+ "license": "MIT",
+ "repository": "https://github.com/pulsar-edit/pulsar",
+ "engines": {
+ "atom": "*"
+ },
+ "configSchema": {
+ "columns": {
+ "default": [],
+ "type": "array",
+ "items": {
+ "type": "integer"
+ },
+ "description": "Display guides at each of the listed character widths. Leave blank for one guide at your `editor.preferredLineLength`."
+ },
+ "enabled": {
+ "default": true,
+ "type": "boolean"
+ }
+ }
+}
diff --git a/packages/wrap-guide/spec/async-spec-helpers.js b/packages/wrap-guide/spec/async-spec-helpers.js
new file mode 100644
index 000000000..73002c049
--- /dev/null
+++ b/packages/wrap-guide/spec/async-spec-helpers.js
@@ -0,0 +1,103 @@
+/** @babel */
+
+export function beforeEach (fn) {
+ global.beforeEach(function () {
+ const result = fn()
+ if (result instanceof Promise) {
+ waitsForPromise(() => result)
+ }
+ })
+}
+
+export function afterEach (fn) {
+ global.afterEach(function () {
+ const result = fn()
+ if (result instanceof Promise) {
+ waitsForPromise(() => result)
+ }
+ })
+}
+
+['it', 'fit', 'ffit', 'fffit'].forEach(function (name) {
+ module.exports[name] = function (description, fn) {
+ if (fn === undefined) {
+ global[name](description)
+ return
+ }
+
+ global[name](description, function () {
+ const result = fn()
+ if (result instanceof Promise) {
+ waitsForPromise(() => result)
+ }
+ })
+ }
+})
+
+export async function conditionPromise (condition, description = 'anonymous condition') {
+ const startTime = Date.now()
+
+ while (true) {
+ await timeoutPromise(100)
+
+ if (await condition()) {
+ return
+ }
+
+ if (Date.now() - startTime > 5000) {
+ throw new Error('Timed out waiting on ' + description)
+ }
+ }
+}
+
+export function timeoutPromise (timeout) {
+ return new Promise(function (resolve) {
+ global.setTimeout(resolve, timeout)
+ })
+}
+
+function waitsForPromise (fn) {
+ const promise = fn()
+ global.waitsFor('spec promise to resolve', function (done) {
+ promise.then(done, function (error) {
+ jasmine.getEnv().currentSpec.fail(error)
+ done()
+ })
+ })
+}
+
+export function emitterEventPromise (emitter, event, timeout = 15000) {
+ return new Promise((resolve, reject) => {
+ const timeoutHandle = setTimeout(() => {
+ reject(new Error(`Timed out waiting for '${event}' event`))
+ }, timeout)
+ emitter.once(event, () => {
+ clearTimeout(timeoutHandle)
+ resolve()
+ })
+ })
+}
+
+export function promisify (original) {
+ return function (...args) {
+ return new Promise((resolve, reject) => {
+ args.push((err, ...results) => {
+ if (err) {
+ reject(err)
+ } else {
+ resolve(...results)
+ }
+ })
+
+ return original(...args)
+ })
+ }
+}
+
+export function promisifySome (obj, fnNames) {
+ const result = {}
+ for (const fnName of fnNames) {
+ result[fnName] = promisify(obj[fnName])
+ }
+ return result
+}
diff --git a/packages/wrap-guide/spec/helpers.js b/packages/wrap-guide/spec/helpers.js
new file mode 100644
index 000000000..3bdb2e963
--- /dev/null
+++ b/packages/wrap-guide/spec/helpers.js
@@ -0,0 +1,20 @@
+const helpers = {
+ getWrapGuides () {
+ wrapGuides = []
+ for (const editor of atom.workspace.getTextEditors()) {
+ const guide = editor.getElement().querySelector('.wrap-guide')
+ if (guide) wrapGuides.push(guide)
+ }
+ return wrapGuides
+ },
+
+ getLeftPosition (element) {
+ return parseInt(element.style.left)
+ },
+
+ getLeftPositions (elements) {
+ return Array.prototype.map.call(elements, element => helpers.getLeftPosition(element))
+ }
+}
+
+module.exports = helpers
diff --git a/packages/wrap-guide/spec/wrap-guide-element-spec.coffee b/packages/wrap-guide/spec/wrap-guide-element-spec.coffee
new file mode 100644
index 000000000..c112fa56f
--- /dev/null
+++ b/packages/wrap-guide/spec/wrap-guide-element-spec.coffee
@@ -0,0 +1,275 @@
+{getLeftPosition, getLeftPositions} = require './helpers'
+{uniqueAscending} = require '../lib/main'
+
+describe "WrapGuideElement", ->
+ [editor, editorElement, wrapGuide, workspaceElement] = []
+
+ beforeEach ->
+ workspaceElement = atom.views.getView(atom.workspace)
+ workspaceElement.style.height = "200px"
+ workspaceElement.style.width = "1500px"
+
+ jasmine.attachToDOM(workspaceElement)
+
+ waitsForPromise ->
+ atom.packages.activatePackage('wrap-guide')
+
+ waitsForPromise ->
+ atom.packages.activatePackage('language-javascript')
+
+ waitsForPromise ->
+ atom.packages.activatePackage('language-coffee-script')
+
+ waitsForPromise ->
+ atom.workspace.open('sample.js')
+
+ runs ->
+ editor = atom.workspace.getActiveTextEditor()
+ editorElement = editor.getElement()
+ wrapGuide = editorElement.querySelector(".wrap-guide-container")
+
+ describe ".activate", ->
+ getWrapGuides = ->
+ wrapGuides = []
+ atom.workspace.getTextEditors().forEach (editor) ->
+ guides = editor.getElement().querySelectorAll(".wrap-guide")
+ wrapGuides.push(guides) if guides
+ wrapGuides
+
+ it "appends a wrap guide to all existing and new editors", ->
+ expect(atom.workspace.getTextEditors().length).toBe 1
+
+ expect(getWrapGuides().length).toBe 1
+ expect(getLeftPosition(getWrapGuides()[0][0])).toBeGreaterThan(0)
+
+ atom.workspace.getActivePane().splitRight(copyActiveItem: true)
+ expect(atom.workspace.getTextEditors().length).toBe 2
+ expect(getWrapGuides().length).toBe 2
+ expect(getLeftPosition(getWrapGuides()[0][0])).toBeGreaterThan(0)
+ expect(getLeftPosition(getWrapGuides()[1][0])).toBeGreaterThan(0)
+
+ it "positions the guide at the configured column", ->
+ width = editor.getDefaultCharWidth() * wrapGuide.getDefaultColumn()
+ expect(width).toBeGreaterThan(0)
+ expect(Math.abs(getLeftPosition(wrapGuide.firstChild) - width)).toBeLessThan 1
+ expect(wrapGuide).toBeVisible()
+
+ it "appends multiple wrap guides to all existing and new editors", ->
+ columns = [10, 20, 30]
+ atom.config.set("wrap-guide.columns", columns)
+
+ waitsForPromise ->
+ editorElement.getComponent().getNextUpdatePromise()
+
+ runs ->
+ expect(atom.workspace.getTextEditors().length).toBe 1
+ expect(getWrapGuides().length).toBe 1
+ positions = getLeftPositions(getWrapGuides()[0])
+ expect(positions.length).toBe(columns.length)
+ expect(positions[0]).toBeGreaterThan(0)
+ expect(positions[1]).toBeGreaterThan(positions[0])
+ expect(positions[2]).toBeGreaterThan(positions[1])
+
+ atom.workspace.getActivePane().splitRight(copyActiveItem: true)
+ expect(atom.workspace.getTextEditors().length).toBe 2
+ expect(getWrapGuides().length).toBe 2
+ pane1_positions = getLeftPositions(getWrapGuides()[0])
+ expect(pane1_positions.length).toBe(columns.length)
+ expect(pane1_positions[0]).toBeGreaterThan(0)
+ expect(pane1_positions[1]).toBeGreaterThan(pane1_positions[0])
+ expect(pane1_positions[2]).toBeGreaterThan(pane1_positions[1])
+ pane2_positions = getLeftPositions(getWrapGuides()[1])
+ expect(pane2_positions.length).toBe(pane1_positions.length)
+ expect(pane2_positions[0]).toBe(pane1_positions[0])
+ expect(pane2_positions[1]).toBe(pane1_positions[1])
+ expect(pane2_positions[2]).toBe(pane1_positions[2])
+
+ it "positions multiple guides at the configured columns", ->
+ columnCount = 5
+ columns = (c * 10 for c in [1..columnCount])
+ atom.config.set("wrap-guide.columns", columns)
+ waitsForPromise ->
+ editorElement.getComponent().getNextUpdatePromise()
+
+ runs ->
+ positions = getLeftPositions(getWrapGuides()[0])
+ expect(positions.length).toBe(columnCount)
+ expect(wrapGuide.children.length).toBe(columnCount)
+
+ for i in columnCount - 1
+ width = editor.getDefaultCharWidth() * columns[i]
+ expect(width).toBeGreaterThan(0)
+ expect(Math.abs(getLeftPosition(wrapGuide.children[i]) - width)).toBeLessThan 1
+ expect(wrapGuide).toBeVisible()
+
+ describe "when the font size changes", ->
+ it "updates the wrap guide position", ->
+ initial = getLeftPosition(wrapGuide.firstChild)
+ expect(initial).toBeGreaterThan(0)
+ fontSize = atom.config.get("editor.fontSize")
+ atom.config.set("editor.fontSize", fontSize + 10)
+
+ waitsForPromise ->
+ editorElement.getComponent().getNextUpdatePromise()
+
+ runs ->
+ expect(getLeftPosition(wrapGuide.firstChild)).toBeGreaterThan(initial)
+ expect(wrapGuide.firstChild).toBeVisible()
+
+ it "updates the wrap guide position for hidden editors when they become visible", ->
+ initial = getLeftPosition(wrapGuide.firstChild)
+ expect(initial).toBeGreaterThan(0)
+
+ waitsForPromise ->
+ atom.workspace.open()
+
+ runs ->
+ fontSize = atom.config.get("editor.fontSize")
+ atom.config.set("editor.fontSize", fontSize + 10)
+ atom.workspace.getActivePane().activatePreviousItem()
+
+ waitsForPromise ->
+ editorElement.getComponent().getNextUpdatePromise()
+
+ runs ->
+ expect(getLeftPosition(wrapGuide.firstChild)).toBeGreaterThan(initial)
+ expect(wrapGuide.firstChild).toBeVisible()
+
+ describe "when the column config changes", ->
+ it "updates the wrap guide position", ->
+ initial = getLeftPosition(wrapGuide.firstChild)
+ expect(initial).toBeGreaterThan(0)
+ column = atom.config.get("editor.preferredLineLength")
+ atom.config.set("editor.preferredLineLength", column + 10)
+ expect(getLeftPosition(wrapGuide.firstChild)).toBeGreaterThan(initial)
+ expect(wrapGuide).toBeVisible()
+
+ describe "when the preferredLineLength changes", ->
+ it "updates the wrap guide positions", ->
+ initial = [10, 15, 20, 30]
+ atom.config.set 'wrap-guide.columns', initial,
+ scopeSelector: ".#{editor.getGrammar().scopeName}"
+ waitsForPromise ->
+ editorElement.getComponent().getNextUpdatePromise()
+
+ runs ->
+ atom.config.set 'editor.preferredLineLength', 15,
+ scopeSelector: ".#{editor.getGrammar().scopeName}"
+ waitsForPromise ->
+ editorElement.getComponent().getNextUpdatePromise()
+
+ runs ->
+ columns = atom.config.get('wrap-guide.columns', scope: editor.getRootScopeDescriptor())
+ expect(columns.length).toBe(2)
+ expect(columns[0]).toBe(10)
+ expect(columns[1]).toBe(15)
+
+ describe "when the columns config changes", ->
+ it "updates the wrap guide positions", ->
+ initial = getLeftPositions(wrapGuide.children)
+ expect(initial.length).toBe(1)
+ expect(initial[0]).toBeGreaterThan(0)
+
+ columns = [10, 20, 30]
+ atom.config.set("wrap-guide.columns", columns)
+ waitsForPromise ->
+ editorElement.getComponent().getNextUpdatePromise()
+
+ runs ->
+ positions = getLeftPositions(wrapGuide.children)
+ expect(positions.length).toBe(columns.length)
+ expect(positions[0]).toBeGreaterThan(0)
+ expect(positions[1]).toBeGreaterThan(positions[0])
+ expect(positions[2]).toBeGreaterThan(positions[1])
+ expect(wrapGuide).toBeVisible()
+
+ it "updates the preferredLineLength", ->
+ initial = atom.config.get('editor.preferredLineLength', scope: editor.getRootScopeDescriptor())
+ atom.config.set("wrap-guide.columns", [initial, initial + 10])
+ waitsForPromise ->
+ editorElement.getComponent().getNextUpdatePromise()
+
+ runs ->
+ length = atom.config.get('editor.preferredLineLength', scope: editor.getRootScopeDescriptor())
+ expect(length).toBe(initial + 10)
+
+ it "keeps guide positions unique and in ascending order", ->
+ initial = getLeftPositions(wrapGuide.children)
+ expect(initial.length).toBe(1)
+ expect(initial[0]).toBeGreaterThan(0)
+
+ reverseColumns = [30, 20, 10]
+ columns = [reverseColumns[reverseColumns.length - 1], reverseColumns..., reverseColumns[0]]
+ uniqueColumns = uniqueAscending(columns)
+ expect(uniqueColumns.length).toBe(3)
+ expect(uniqueColumns[0]).toBeGreaterThan(0)
+ expect(uniqueColumns[1]).toBeGreaterThan(uniqueColumns[0])
+ expect(uniqueColumns[2]).toBeGreaterThan(uniqueColumns[1])
+
+ atom.config.set("wrap-guide.columns", columns)
+ waitsForPromise ->
+ editorElement.getComponent().getNextUpdatePromise()
+
+ runs ->
+ positions = getLeftPositions(wrapGuide.children)
+ expect(positions.length).toBe(uniqueColumns.length)
+ expect(positions[0]).toBeGreaterThan(0)
+ expect(positions[1]).toBeGreaterThan(positions[0])
+ expect(positions[2]).toBeGreaterThan(positions[1])
+ expect(wrapGuide).toBeVisible()
+
+ describe "when the editor's scroll left changes", ->
+ it "updates the wrap guide position to a relative position on screen", ->
+ editor.setText("a long line which causes the editor to scroll")
+ editorElement.style.width = "100px"
+
+ waitsFor -> editorElement.component.getMaxScrollLeft() > 10
+
+ runs ->
+ initial = getLeftPosition(wrapGuide.firstChild)
+ expect(initial).toBeGreaterThan(0)
+ editorElement.setScrollLeft(10)
+ expect(getLeftPosition(wrapGuide.firstChild)).toBe(initial - 10)
+ expect(wrapGuide.firstChild).toBeVisible()
+
+ describe "when the editor's grammar changes", ->
+ it "updates the wrap guide position", ->
+ atom.config.set('editor.preferredLineLength', 20, scopeSelector: '.source.js')
+ initial = getLeftPosition(wrapGuide.firstChild)
+ expect(initial).toBeGreaterThan(0)
+ expect(wrapGuide).toBeVisible()
+
+ editor.setGrammar(atom.grammars.grammarForScopeName('text.plain.null-grammar'))
+ expect(getLeftPosition(wrapGuide.firstChild)).toBeGreaterThan(initial)
+ expect(wrapGuide).toBeVisible()
+
+ it 'listens for preferredLineLength updates for the new grammar', ->
+ editor.setGrammar(atom.grammars.grammarForScopeName('source.coffee'))
+ initial = getLeftPosition(wrapGuide.firstChild)
+ atom.config.set('editor.preferredLineLength', 20, scopeSelector: '.source.coffee')
+ expect(getLeftPosition(wrapGuide.firstChild)).toBeLessThan(initial)
+
+ it 'listens for wrap-guide.enabled updates for the new grammar', ->
+ editor.setGrammar(atom.grammars.grammarForScopeName('source.coffee'))
+ expect(wrapGuide).toBeVisible()
+ atom.config.set('wrap-guide.enabled', false, scopeSelector: '.source.coffee')
+ expect(wrapGuide).not.toBeVisible()
+
+ describe 'scoped config', ->
+ it '::getDefaultColumn returns the scope-specific column value', ->
+ atom.config.set('editor.preferredLineLength', 132, scopeSelector: '.source.js')
+
+ expect(wrapGuide.getDefaultColumn()).toBe 132
+
+ it 'updates the guide when the scope-specific column changes', ->
+ initial = getLeftPosition(wrapGuide.firstChild)
+ column = atom.config.get('editor.preferredLineLength', scope: editor.getRootScopeDescriptor())
+ atom.config.set('editor.preferredLineLength', column + 10, scope: '.source.js')
+ expect(getLeftPosition(wrapGuide.firstChild)).toBeGreaterThan(initial)
+
+ it 'updates the guide when wrap-guide.enabled is set to false', ->
+ expect(wrapGuide).toBeVisible()
+
+ atom.config.set('wrap-guide.enabled', false, scopeSelector: '.source.js')
+
+ expect(wrapGuide).not.toBeVisible()
diff --git a/packages/wrap-guide/spec/wrap-guide-spec.js b/packages/wrap-guide/spec/wrap-guide-spec.js
new file mode 100644
index 000000000..92d6f7c6b
--- /dev/null
+++ b/packages/wrap-guide/spec/wrap-guide-spec.js
@@ -0,0 +1,48 @@
+const {getWrapGuides, getLeftPosition} = require('./helpers')
+
+const {it, fit, ffit, afterEach, beforeEach} = require('./async-spec-helpers') // eslint-disable-line no-unused-vars
+
+describe('Wrap Guide', () => {
+ let editor, editorElement, wrapGuide = []
+
+ beforeEach(async () => {
+ await atom.packages.activatePackage('wrap-guide')
+
+ editor = await atom.workspace.open('sample.js')
+ editorElement = editor.getElement()
+ wrapGuide = editorElement.querySelector('.wrap-guide-container')
+
+ jasmine.attachToDOM(atom.views.getView(atom.workspace))
+ })
+
+ describe('package activation', () => {
+ it('appends a wrap guide to all existing and new editors', () => {
+ expect(atom.workspace.getTextEditors().length).toBe(1)
+ expect(getWrapGuides().length).toBe(1)
+ expect(getLeftPosition(getWrapGuides()[0])).toBeGreaterThan(0)
+
+ atom.workspace.getActivePane().splitRight({copyActiveItem: true})
+ expect(atom.workspace.getTextEditors().length).toBe(2)
+ expect(getWrapGuides().length).toBe(2)
+ expect(getLeftPosition(getWrapGuides()[0])).toBeGreaterThan(0)
+ expect(getLeftPosition(getWrapGuides()[1])).toBeGreaterThan(0)
+ })
+
+ it('positions the guide at the configured column', () => {
+ width = editor.getDefaultCharWidth() * wrapGuide.getDefaultColumn()
+ expect(width).toBeGreaterThan(0)
+ expect(Math.abs(getLeftPosition(wrapGuide.firstChild) - width)).toBeLessThan(1)
+ expect(wrapGuide.firstChild).toBeVisible()
+ })
+ })
+
+ describe('package deactivation', () => {
+ beforeEach(async () => {
+ await atom.packages.deactivatePackage('wrap-guide')
+ })
+
+ it('disposes of all wrap guides', () => {
+ expect(getWrapGuides().length).toBe(0)
+ })
+ })
+})
diff --git a/packages/wrap-guide/styles/wrap-guide.less b/packages/wrap-guide/styles/wrap-guide.less
new file mode 100644
index 000000000..554753d66
--- /dev/null
+++ b/packages/wrap-guide/styles/wrap-guide.less
@@ -0,0 +1,14 @@
+@import "syntax-variables";
+
+atom-text-editor {
+ .wrap-guide {
+ height: 100%;
+ width: 1px;
+ z-index: 3;
+ position: absolute;
+ top: 0;
+ background-color: @syntax-wrap-guide-color;
+ -webkit-transform: translateZ(0);
+ pointer-events: none;
+ }
+}
diff --git a/ppm b/ppm
index e09cc63b8..915cbf6e5 160000
--- a/ppm
+++ b/ppm
@@ -1 +1 @@
-Subproject commit e09cc63b85616d19a95a10b02a632ecf48741056
+Subproject commit 915cbf6e5f9ea1141ef5dcaf86343237e17bf380
diff --git a/pulsar.sh b/pulsar.sh
index 88b5153ec..7f501f542 100755
--- a/pulsar.sh
+++ b/pulsar.sh
@@ -16,7 +16,7 @@ ATOM_ADD=false
ATOM_NEW_WINDOW=false
EXIT_CODE_OVERRIDE=
-while getopts ":anwtfvh-:" opt; do
+while getopts ":anwtfvhp-:" opt; do
case "$opt" in
-)
case "${OPTARG}" in
@@ -30,10 +30,9 @@ while getopts ":anwtfvh-:" opt; do
WAIT=1
;;
help|version)
- REDIRECT_STDERR=1
EXPECT_OUTPUT=1
;;
- foreground|benchmark|benchmark-test|test)
+ foreground|benchmark|benchmark-test|test|package)
EXPECT_OUTPUT=1
;;
enable-electron-logging)
@@ -50,11 +49,7 @@ while getopts ":anwtfvh-:" opt; do
w)
WAIT=1
;;
- h|v)
- REDIRECT_STDERR=1
- EXPECT_OUTPUT=1
- ;;
- f|t)
+ f|t|h|v|p)
EXPECT_OUTPUT=1
;;
esac
@@ -78,7 +73,9 @@ if [ $OS == 'Mac' ]; then
else
SCRIPT="$0"
fi
- ATOM_APP="$(dirname "$(dirname "$(dirname "$(dirname "$SCRIPT")")")")"
+
+ ATOM_APP="$(dirname "$(dirname "$(dirname "$SCRIPT")")")"
+
if [ "$ATOM_APP" == . ]; then
unset ATOM_APP
else
@@ -121,7 +118,7 @@ if [ $OS == 'Mac' ]; then
exit ${ATOM_EXIT}
fi
else
- open -a "$PULSAR_PATH/$ATOM_APP_NAME" -n --args --executed-from="$(pwd)" --pid=$$ --path-environment="$PATH" "$@"
+ open -a "$PULSAR_PATH/$ATOM_APP_NAME" -n -g --args --executed-from="$(pwd)" --pid=$$ --path-environment="$PATH" "$@"
fi
elif [ $OS == 'Linux' ]; then
SCRIPT=$(readlink -f "$0")
@@ -149,7 +146,7 @@ elif [ $OS == 'Linux' ]; then
[ -x "$PULSAR_PATH" ] || PULSAR_PATH="$TMPDIR/pulsar-build/Pulsar/pulsar"
if [ $EXPECT_OUTPUT ]; then
- "$PULSAR_PATH" --executed-from="$(pwd)" --pid=$$ "$@"
+ "$PULSAR_PATH" --executed-from="$(pwd)" --pid=$$ "$@" --no-sandbox
ATOM_EXIT=$?
if [ ${ATOM_EXIT} -eq 0 ] && [ -n "${EXIT_CODE_OVERRIDE}" ]; then
exit "${EXIT_CODE_OVERRIDE}"
@@ -158,7 +155,7 @@ elif [ $OS == 'Linux' ]; then
fi
else
(
- nohup "$PULSAR_PATH" --executed-from="$(pwd)" --pid=$$ "$@" > "$ATOM_HOME/nohup.out" 2>&1
+ nohup "$PULSAR_PATH" --executed-from="$(pwd)" --pid=$$ "$@" --no-sandbox > "$ATOM_HOME/nohup.out" 2>&1
if [ $? -ne 0 ]; then
cat "$ATOM_HOME/nohup.out"
exit $?
diff --git a/resources/app-icons/beta.icns b/resources/app-icons/beta.icns
new file mode 100644
index 000000000..9492efdd0
Binary files /dev/null and b/resources/app-icons/beta.icns differ
diff --git a/resources/app-icons/beta.ico b/resources/app-icons/beta.ico
index 7ba53236f..e25a62f34 100644
Binary files a/resources/app-icons/beta.ico and b/resources/app-icons/beta.ico differ
diff --git a/resources/app-icons/beta.svg b/resources/app-icons/beta.svg
new file mode 100644
index 000000000..64f0bb492
--- /dev/null
+++ b/resources/app-icons/beta.svg
@@ -0,0 +1,16 @@
+
diff --git a/resources/icons/128x128.png b/resources/icons/128x128.png
new file mode 100644
index 000000000..e9802618e
Binary files /dev/null and b/resources/icons/128x128.png differ
diff --git a/resources/icons/16x16.png b/resources/icons/16x16.png
new file mode 100644
index 000000000..35e34b0ae
Binary files /dev/null and b/resources/icons/16x16.png differ
diff --git a/resources/icons/22x22.png b/resources/icons/22x22.png
new file mode 100644
index 000000000..f8cfb1516
Binary files /dev/null and b/resources/icons/22x22.png differ
diff --git a/resources/icons/24x24.png b/resources/icons/24x24.png
new file mode 100644
index 000000000..66ac5ef42
Binary files /dev/null and b/resources/icons/24x24.png differ
diff --git a/resources/icons/256x256.png b/resources/icons/256x256.png
new file mode 100644
index 000000000..22a44b648
Binary files /dev/null and b/resources/icons/256x256.png differ
diff --git a/resources/icons/32x32.png b/resources/icons/32x32.png
new file mode 100644
index 000000000..276438d6b
Binary files /dev/null and b/resources/icons/32x32.png differ
diff --git a/resources/icons/384x384.png b/resources/icons/384x384.png
new file mode 100644
index 000000000..4e7a55ec2
Binary files /dev/null and b/resources/icons/384x384.png differ
diff --git a/resources/icons/48x48.png b/resources/icons/48x48.png
new file mode 100644
index 000000000..d2984bbf1
Binary files /dev/null and b/resources/icons/48x48.png differ
diff --git a/resources/icons/64x64.png b/resources/icons/64x64.png
new file mode 100644
index 000000000..1b9d544a7
Binary files /dev/null and b/resources/icons/64x64.png differ
diff --git a/resources/linux/dev.pulsar_edit.Pulsar.metainfo.xml b/resources/linux/dev.pulsar_edit.Pulsar.metainfo.xml
new file mode 100644
index 000000000..b57ea99aa
--- /dev/null
+++ b/resources/linux/dev.pulsar_edit.Pulsar.metainfo.xml
@@ -0,0 +1,24 @@
+
+
+ dev.pulsar_edit.Pulsar
+ Pulsar
+ Pulsar Edit
+ A Community-led Hyper-Hackable Text Editor
+ MIT
+ MIT
+ https://pulsar-edit.dev
+ https://github.com/pulsar-edit/pulsar/issues/
+ admin@pulsar-edit.dev
+
+ Pulsar aims to not only reach feature parity with the original Atom, but to bring Pulsar into the 21st century by updating the underlying architecture, and supporting modern features.
+
+
+
+ https://raw.githubusercontent.com/pulsar-edit/pulsar/master/resources/readme.png
+
+
+
+ HiDpiIcon
+
+
+
diff --git a/resources/pulsar.png b/resources/pulsar.png
index e2db9a40d..e8009462b 100644
Binary files a/resources/pulsar.png and b/resources/pulsar.png differ
diff --git a/resources/readme.png b/resources/readme.png
new file mode 100644
index 000000000..8e821932b
Binary files /dev/null and b/resources/readme.png differ
diff --git a/resources/win/pulsar.cmd b/resources/win/pulsar.cmd
index 0f055f883..8776fa2de 100644
--- a/resources/win/pulsar.cmd
+++ b/resources/win/pulsar.cmd
@@ -16,6 +16,8 @@ FOR %%a IN (%*) DO (
IF /I "%%a"=="--test" SET EXPECT_OUTPUT=YES
IF /I "%%a"=="--benchmark" SET EXPECT_OUTPUT=YES
IF /I "%%a"=="--benchmark-test" SET EXPECT_OUTPUT=YES
+ IF /I "%%a"=="-p" SET EXPECT_OUTPUT=YES
+ IF /I "%%a"=="--package" SET EXPECT_OUTPUT=YES
IF /I "%%a"=="-v" SET EXPECT_OUTPUT=YES
IF /I "%%a"=="--version" SET EXPECT_OUTPUT=YES
IF /I "%%a"=="--enable-electron-logging" SET ELECTRON_ENABLE_LOGGING=YES
@@ -41,11 +43,11 @@ IF "%ATOM_ADD%"=="YES" (
IF "%EXPECT_OUTPUT%"=="YES" (
IF "%WAIT%"=="YES" (
- powershell -noexit "Start-Process -FilePath \"%~dp0\..\..\<%= atomExeName %>\" -ArgumentList \"--pid=$pid $env:PSARGS\" ; wait-event"
+ powershell -noexit "Start-Process -FilePath \"%~dp0\..\Pulsar.exe\" -ArgumentList \"--pid=$pid $env:PSARGS\" ; wait-event"
exit 0
) ELSE (
- "%~dp0\..\..\<%= atomExeName %>" %*
+ "%~dp0\..\Pulsar.exe" %*
)
) ELSE (
- "%~dp0\..\app\apm\bin\node.exe" "%~dp0\pulsar.js" "<%= atomExeName %>" %*
+ "%~dp0\app\ppm\bin\node.exe" "%~dp0\pulsar.js" "Pulsar.exe" %*
)
diff --git a/resources/win/pulsar.js b/resources/win/pulsar.js
index 4c4a099e9..97bd131bf 100644
--- a/resources/win/pulsar.js
+++ b/resources/win/pulsar.js
@@ -1,7 +1,7 @@
var path = require('path');
var spawn = require('child_process').spawn;
-var atomCommandPath = path.resolve(__dirname, '..', '..', process.argv[2]);
+var atomCommandPath = path.resolve(__dirname, '..', process.argv[2]);
var args = process.argv.slice(3);
args.unshift('--executed-from', process.cwd());
var options = { detached: true, stdio: 'ignore' };
diff --git a/script/electron-builder.js b/script/electron-builder.js
index 67200df09..0c3d194fb 100644
--- a/script/electron-builder.js
+++ b/script/electron-builder.js
@@ -2,6 +2,7 @@ const path = require('path')
const normalizePackageData = require('normalize-package-data');
const fs = require("fs/promises");
const generateMetadata = require('./generate-metadata-for-builder')
+const macBundleDocumentTypes = require("./mac-bundle-document-types.js");
// Monkey-patch to not remove things I explicitly didn't say so
// See: https://github.com/electron-userland/electron-builder/issues/6957
@@ -41,35 +42,26 @@ const Platform = builder.Platform
const pngIcon = 'resources/app-icons/beta.png'
const icoIcon = 'resources/app-icons/beta.ico'
+const svgIcon = 'resources/app-icons/beta.svg'
+const icnsIcon = 'resources/app-icons/beta.icns'
let options = {
- "appId": "com.pulsar-edit.pulsar",
+ "appId": "dev.pulsar-edit.pulsar",
"npmRebuild": false,
"publish": null,
files: [
+ // --- Inclusions ---
+ // Core Repo Inclusions
"package.json",
- "!docs/",
"dot-atom/**/*",
"exports/**/*",
- "!keymaps/",
- "!menus/",
- "node_modules/**/*",
"resources/**/*",
- "!script/",
"src/**/*",
"static/**/*",
"vendor/**/*",
- "!**/node_modules/*/{test,__tests__,tests,powered-test,example,examples}",
- "!**/node_modules/*.d.ts",
- "!**/node_modules/.bin",
- "!**/*.{iml,o,hprof,orig,pyc,pyo,rbc,swp,csproj,sln,xproj}",
- "!.editorconfig",
- "!**/._*",
- "!**/{.DS_Store,.git,.hg,.svn,CVS,RCS,SCCS,.gitignore,.gitattributes}",
- "!**/{__pycache__,thumbs.db,.flowconfig,.idea,.vs,.nyc_output}",
- "!**/{appveyor.yml,.travis.yml,circle.yml}",
- "!**/{npm-debug.log,yarn.lock,.yarn-integrity,.yarn-metadata.json}",
+ "node_modules/**/*",
+ // Core Repo Test Inclusions
"spec/jasmine-test-runner.js",
"spec/spec-helper.js",
"spec/jasmine-junit-reporter.js",
@@ -77,41 +69,65 @@ let options = {
"spec/atom-reporter.js",
"spec/jasmine-list-reporter.js",
- // The following are taken directly from Atom (Hoping they still apply)
- "!**/{.jshintrc,.npmignore,.pairs,.lint,.lintignore,.eslintrc,.jshintignore}",
- "!**/{.coffeelintignore,.git-keep}",
+ // --- Exclusions ---
+ // Core Repo Exclusions
+ "!docs/",
+ "!keymaps/",
+ "!menus/",
+ "!script/",
+ "!integration/",
+ "!hooks/",
+
+ // Git Related Exclusions
+ "!**/{.git,.gitignore,.gitattributes,.git-keep,.github}",
+ "!**/{.eslintignore,PULL_REQUEST_TEMPLATE.md,ISSUE_TEMPLATE.md,CONTRIBUTING.md,SECURITY.md}",
+
+ // Development Tools Exclusions
+ "!**/{npm-debug.log,yarn.lock,.yarn-integrity,.yarn-metadata.json,.npmignore}",
+ "!**/npm/{doc,html,man}",
+ "!.editorconfig",
+ "!**/{appveyor.yml,.travis.yml,circle.yml}",
+ "!**/{__pycache__,thumbs.db,.flowconfig,.idea,.vs,.nyc_output}",
+ "!**/*.{iml,o,hprof,orig,pyc,pyo,rbc,swp,csproj,sln,xproj}",
+ "!**/{.jshintrc,.pairs,.lint,.lintignore,.eslintrc,.jshintignore}",
+ "!**/{.coffeelintignore,.editorconfig,.nycrc,.coffeelint.json,.vscode,coffeelint.json}",
+
+ // Common File Exclusions
+ "!**/{.DS_Store,.hg,.svn,CVS,RCS,SCCS}",
+
+ // Build Chain Exclusions
+ "!**/*.{cc,h}", // Ignore *.cc and *.h files from native modules
+ "!**/*.js.map",
+ "!**/{Makefile}",
+ "!**/build/{binding.Makefile,config.gypi,gyp-mac-tool,Makefile}",
+ "!**/build/Release/{obj.target,obj,.deps}",
+
+ // Test Exclusions
+ "!**/pegjs/examples",
+ "!**/node_modules/*/{test,__tests__,tests,powered-test,example,examples}",
+ "!**/node_modules/babel-core/lib/transformation/transforers/spec", // Ignore babel-core spec
+ "!**/{oniguruma,dev-live-reload,deprecation-cop,one-dark-ui,incompatible-packages,git-diff,line-ending-selector}/spec",
+ "!**/{link,grammar-selector,json-schema-traverse,exception-reporting,one-light-ui,autoflow,about,go-to-line,sylvester,apparatus}/spec",
+ "!**/{archive-view,autocomplete-plus,autocomplete-atom-api,autocomplete-css,autosave}/spec",
+
+ // Other Exclusions
+ "!**/._*",
+ "!**/node_modules/*.d.ts",
+ "!**/node_modules/.bin",
+ "!**/node_modules/native-mate",
+ "!node_modules/fuzzy-native/node_modules", // node_modules of the fuzzy-native package are only required for building it
+ "!**/node_modules/spellchecker/vendor/hunspell/.*",
"!**/git-utils/deps",
"!**/oniguruma/deps",
"!**/less/dist",
- "!**/npm/{doc,html,man}",
- "!**/pegjs/examples",
"!**/get-parameter-names/node_modules/testla",
"!**/get-parameter-names/node_modules/.bin/testla",
"!**/jasmine-reporters/ext",
- "!**/node_modules/native-mate",
- "!**/build/{binding.Makefile,config.gypi,gyp-mac-tool,Makefile}",
- "!**/build/Release/{obj.target,obj,.deps}",
"!**/deps/libgit2",
- "!**/node_modules/spellchecker/vendor/hunspell/.*",
// These are only required in dev-mode, when pegjs grammars aren't precompiled
// "!node_modules/loophole", // Note: We do need these packages. Because our PegJS files _aren't_ all pre-compiled.
// "!node_modules/pegjs", // Note: if these files are excluded, 'snippets' package breaks.
- // "!node_modules/.bin/pegjs",
- // node_modules of the fuzzy-native package are only required for building it
- "!node_modules/fuzzy-native/node_modules",
- // Ignore *.cc and *.h files from native modules
- "!**/*.{cc,h}",
- // Handpicked spec folders
- "!**/{oniguruma,dev-live-reload,deprecation-cop,one-dark-ui,incompatible-packages,git-diff,line-ending-selector}/spec",
- "!**/{link,grammar-selector,json-schema-traverse,exception-reporting,one-light-ui,autoflow,about,go-to-line,sylvester,apparatus}/spec",
- // Ignore babel-core spec
- "!**/node_modules/babel-core/lib/transformation/transforers/spec",
-
- // The following are cherry-picked for Pulsar
- "!**/{archive-view,autocomplete-plus,autocomplete-atom-api,autocomplete-css,autosave}/spec",
- "!**/{.eslintignore,PULL_REQUEST_TEMPLATE.md,ISSUE_TEMPLATE.md,CONTRIBUTING.md,SECURITY.md}",
- "!**/{Makefile,.editorconfig,.nycrc,.coffeelint.json,.github,.vscode,coffeelint.json}",
- "!**/*.js.map",
+ // "!node_modules/.bin/pegjs", // Note: https://github.com/pulsar-edit/pulsar/pull/206
],
"extraResources": [
{
@@ -123,16 +139,26 @@ let options = {
}, {
"from": pngIcon,
"to": "pulsar.png"
+ }, {
+ "from": "LICENSE.md",
+ "to": "LICENSE.md"
},
],
compression: "normal",
- deb: { afterInstall: "script/post-install.sh" },
+ deb: {
+ afterInstall: "script/post-install.sh",
+ afterRemove: "script/post-uninstall.sh",
+ },
rpm: {
afterInstall: "script/post-install.sh",
+ afterRemove: "script/post-uninstall.sh",
compression: 'xz'
},
"linux": {
- "icon": pngIcon,
+ // Giving a single PNG icon to electron-builder prevents the correct
+ // construction of the icon path, so we have to specify a folder containing
+ // multiple icons named each with its size.
+ "icon": "resources/icons",
"category": "Development",
"synopsis": "A Community-led Hyper-Hackable Text Editor",
"target": [
@@ -141,20 +167,73 @@ let options = {
{ target: "rpm" },
{ target: "tar.gz" }
],
+ "extraResources": [
+ {
+ // Extra SVG icon included in the resources folder to give a chance to
+ // Linux packagers to add a scalable desktop icon under
+ // /usr/share/icons/hicolor/scalable
+ // (used only by desktops to show it on bar/switcher and app menus).
+ "from": svgIcon,
+ "to": "pulsar.svg"
+ },
+ ],
},
"mac": {
- "icon": pngIcon,
- "category": "Development"
+ "icon": icnsIcon,
+ "category": "public.app-category.developer-tools",
+ "minimumSystemVersion": "10.8",
+ "hardenedRuntime": true,
+ "entitlements": "resources/mac/entitlements.plist",
+ "entitlementsInherit": "resources/mac/entitlements.plist",
+ "extendInfo": {
+ // This contains extra values that will be inserted into the App's plist
+ "CFBundleExecutable": "Pulsar",
+ "NSAppleScriptEnabled": "YES",
+ "NSMainNibFile": "MainMenu",
+ "NSRequiresAquaSystemAppearance": "NO",
+ "CFBundleDocumentTypes": macBundleDocumentTypes.create(),
+ "CFBundleURLTypes": [
+ { "CFBundleURLSchemes": [ "atom" ] },
+ { "CFBundleURLName": "Atom Shared Session Protocol" }
+ ]
+ },
+ },
+ "dmg": {
+ "sign": false
},
"win": {
"icon": icoIcon,
+ "extraResources": [
+ {
+ "from": icoIcon,
+ "to": "pulsar.ico"
+ },
+ {
+ "from": "resources/win/pulsar.cmd",
+ "to": "pulsar.cmd"
+ },
+ {
+ "from": "resources/win/pulsar.js",
+ "to": "pulsar.js"
+ },
+ ],
"target": [
{ "target": "nsis" },
- { "target": "portable" }
- ]
+ { "target": "portable" },
+ ],
+ },
+ // Windows NSIS Configuration
+ "nsis": {
+ "oneClick": false,
+ "allowToChangeInstallationDirectory": true,
+ "uninstallDisplayName": "Pulsar",
+ "runAfterFinish": true,
+ "createDesktopShortcut": true,
+ "createStartMenuShortcut": true,
},
"extraMetadata": {
},
+ "afterSign": "script/mac-notarise.js",
"asarUnpack": [
"node_modules/github/bin/*",
"node_modules/github/lib/*", // Resolves Error in console
diff --git a/script/mac-bundle-document-types.js b/script/mac-bundle-document-types.js
new file mode 100644
index 000000000..0215f1d7a
--- /dev/null
+++ b/script/mac-bundle-document-types.js
@@ -0,0 +1,474 @@
+/**
+ The macOS configuration MUST be passed this exact object structure in order to
+ build the plist file as expected and accepted.
+ mac.extendInfo.CFBundleDocumentTypes is a plist entry that MUST receive an array.
+
+ This array then accepts objects of the below values, with the required configuration.
+ Since the majority of the file repeats itself we can use the below create() builder
+ to minimize file size, and changes that must occur if we ever want to add additional
+ values or replace existing values.
+
+ But I do not recommend changing the structure of the object without careful testing.
+
+ The Extensions and Names of the files have all been taken from a Known working
+ configuration of Atom's plist that was included with the macOS build.
+
+ But as we now build this for ourselves we will take advantage of our new methods
+ and ensure we use the wins electron-builder provides by staying on platform.
+
+ @see https://github.com/atom/atom/blob/master/resources/mac/atom-Info.plist
+*/
+
+/**
+ When creating this document the syntax is as follows:
+
+ `ext` - An array of file extensions to identify, each being a string
+ This value is optional, but in most cases will be needed.
+
+ `name` - A string of the friendly file name.
+ This value is optional, but generally should have a name unless relating to bundles or folders.
+
+ Then if needed some additional types are available:
+ * "CFBundleTypeMIMETypes" - An array of strings, containing the MIME type of the file.
+ * "CFBundleTypeOSTypes" - An array of Strings, for the OS types of the file.
+ * "LSItemContentTypes" - An array of Strings
+*/
+
+const docs = [
+ {
+ "ext": [ "adb", "ads" ],
+ "name": "ADA source"
+ },
+ {
+ "ext": [ "scpt" ],
+ "name": "Compile AppleScript"
+ },
+ {
+ "ext": [ "applescript" ],
+ "name": "AppleScript source"
+ },
+ {
+ "ext": [ "as" ],
+ "name": "ActionScript source"
+ },
+ {
+ "ext": [ "asp", "asa" ],
+ "name": "ASP document"
+ },
+ {
+ "ext": [ "aspx", "ascx", "asmx", "ashx" ],
+ "name": "ASP.NET document"
+ },
+ {
+ "ext": [ "bib" ],
+ "name": "BibTeX bibliography"
+ },
+ {
+ "ext": [ "c" ],
+ "name": "C source"
+ },
+ {
+ "ext": [ "cc", "cp", "cpp", "cxx", "c++" ],
+ "name": "C++ source"
+ },
+ {
+ "ext": [ "cs" ],
+ "name": "C# source"
+ },
+ {
+ "ext": [ "coffee" ],
+ "name": "CoffeeScript source"
+ },
+ {
+ "ext": [ "COMMIT_EDITMSG" ],
+ "name": "Commit message"
+ },
+ {
+ "ext": [ "cfdg" ],
+ "name": "Context Free Design Grammar"
+ },
+ {
+ "ext": [ "clj", "cljs" ],
+ "name": "Clojure source"
+ },
+ {
+ "ext": [ "csv" ],
+ "name": "Comma separated values"
+ },
+ {
+ "ext": [ "tsv" ],
+ "name": "Tab separated values"
+ },
+ {
+ "ext": [ "cgi", "fcgi" ],
+ "name": "CGI script"
+ },
+ {
+ "ext": [ "cfg", "conf", "config", "htaccess" ],
+ "name": "Configuration file"
+ },
+ {
+ "ext": [ "css" ],
+ "name": "Cascading style sheet"
+ },
+ {
+ "ext": [ "diff" ],
+ "name": "Differences file"
+ },
+ {
+ "ext": [ "dtd" ],
+ "name": "Document Type Definition"
+ },
+ {
+ "ext": [ "dylan" ],
+ "name": "Dylan source"
+ },
+ {
+ "ext": [ "erl", "hrl" ],
+ "name": "Erlang source"
+ },
+ {
+ "ext": [ "fscript" ],
+ "name": "F-Script source"
+ },
+ {
+ "ext": [ "f", "for", "fpp", "f77", "f90", "f95" ],
+ "name": "Fortran source"
+ },
+ {
+ "ext": [ "h", "pch" ],
+ "name": "Header"
+ },
+ {
+ "ext": [ "hh", "hpp", "hxx", "h++" ],
+ "name": "C++ header"
+ },
+ {
+ "ext": [ "go" ],
+ "name": "Go source"
+ },
+ {
+ "ext": [ "gtd", "gtdlog" ],
+ "name": "GTD document"
+ },
+ {
+ "ext": [ "h", "hls" ],
+ "name": "Haskell source"
+ },
+ {
+ "ext": [ "htm", "html", "phtml", "shtml" ],
+ "name": "HTML document"
+ },
+ {
+ "ext": [ "inc" ],
+ "name": "Include file"
+ },
+ {
+ "ext": [ "ics" ],
+ "name": "iCalendar schedule"
+ },
+ {
+ "ext": [ "ini" ],
+ "name": "MS Windows initialization file"
+ },
+ {
+ "ext": [ "io" ],
+ "name": "Io source"
+ },
+ {
+ "ext": [ "java" ],
+ "name": "Java source"
+ },
+ {
+ "ext": [ "bsh" ],
+ "name": "BeanShell script"
+ },
+ {
+ "ext": [ "properties" ],
+ "name": "Java properties file"
+ },
+ {
+ "ext": [ "js", "htc" ],
+ "name": "JavaScript source"
+ },
+ {
+ "ext": [ "jsp" ],
+ "name": "Java Server Page"
+ },
+ {
+ "ext": [ "json" ],
+ "name": "JSON file"
+ },
+ {
+ "ext": [ "ldif" ],
+ "name": "LDAP Data Interchange Format"
+ },
+ {
+ "ext": [ "less" ],
+ "name": "Less source"
+ },
+ {
+ "ext": [ "lisp", "cl", "l", "lsp", "mud", "el" ],
+ "name": "Lisp source"
+ },
+ {
+ "ext": [ "log" ],
+ "name": "Log file"
+ },
+ {
+ "ext": [ "logo" ],
+ "name": "Logo source"
+ },
+ {
+ "ext": [ "lua" ],
+ "name": "Lua source"
+ },
+ {
+ "ext": [ "markdown", "mdown", "markdn", "md" ],
+ "name": "Markdown document"
+ },
+ {
+ "ext": [ "mk" ],
+ "name": "Makefile source"
+ },
+ {
+ "ext": [ "wiki", "wikipedia", "mediawiki" ],
+ "name": "Mediawiki document"
+ },
+ {
+ "ext": [ "s", "mips", "spim", "asm" ],
+ "name": "MIPS assembler source"
+ },
+ {
+ "ext": [ "m3", "cm3" ],
+ "name": "Modula-3 source"
+ },
+ {
+ "ext": [ "moinmoin" ],
+ "name": "MoinMoin document"
+ },
+ {
+ "ext": [ "m" ],
+ "name": "Objective-C source"
+ },
+ {
+ "ext": [ "mm" ],
+ "name": "Objective-C++ source"
+ },
+ {
+ "ext": [ "ml", "mli", "mll", "mly" ],
+ "name": "OCaml source"
+ },
+ {
+ "ext": [ "mustache", "hbs" ],
+ "name": "Mustache document"
+ },
+ {
+ "ext": [ "pas", "p" ],
+ "name": "Pascal source"
+ },
+ {
+ "ext": [ "patch" ],
+ "name": "Patch file"
+ },
+ {
+ "ext": [ "pl", "pod", "perl" ],
+ "name": "Perl source"
+ },
+ {
+ "ext": [ "pm" ],
+ "name": "Perl module"
+ },
+ {
+ "ext": [ "php", "php3", "php4", "php5" ],
+ "name": "PHP source"
+ },
+ {
+ "ext": [ "ps", "eps" ],
+ "name": "PostScript source"
+ },
+ {
+ "ext": [ "dict", "plist", "scriptSuite", "scriptTerminology" ],
+ "name": "Property list"
+ },
+ {
+ "ext": [ "py", "rpy", "cpy", "python" ],
+ "name": "Python source"
+ },
+ {
+ "ext": [ "r", "s" ],
+ "name": "R source"
+ },
+ {
+ "ext": [ "rl", "ragel" ],
+ "name": "Ragel source"
+ },
+ {
+ "ext": [ "rem", "remind" ],
+ "name": "Remind document"
+ },
+ {
+ "ext": [ "rst", "rest" ],
+ "name": "reStructuredText document"
+ },
+ {
+ "ext": [ "rhtml", "erb" ],
+ "name": "HTML with embedded Ruby"
+ },
+ {
+ "ext": [ "erbsql" ],
+ "name": "SQL with embedded Ruby"
+ },
+ {
+ "ext": [ "rb", "rbx", "rjs", "rxml" ],
+ "name": "Ruby source"
+ },
+ {
+ "ext": [ "sass", "scss" ],
+ "name": "Sass source"
+ },
+ {
+ "ext": [ "scm", "sch" ],
+ "name": "Scheme source"
+ },
+ {
+ "ext": [ "ext" ],
+ "name": "Setext document"
+ },
+ {
+ "ext": [ "sh", "ss", "bashrc", "bash_profile", "bash_login", "profile", "bash_logout" ],
+ "name": "Shell script"
+ },
+ {
+ "ext": [ "slate" ],
+ "name": "Slate source"
+ },
+ {
+ "ext": [ "sql" ],
+ "name": "SQL source"
+ },
+ {
+ "ext": [ "sml" ],
+ "name": "Standard ML source"
+ },
+ {
+ "ext": [ "strings" ],
+ "name": "Strings document"
+ },
+ {
+ "ext": [ "svg" ],
+ "name": "Scalable vector graphics"
+ },
+ {
+ "ext": [ "i", "swg" ],
+ "name": "SWIG source"
+ },
+ {
+ "ext": [ "tcl" ],
+ "name": "Tcl source"
+ },
+ {
+ "ext": [ "tex", "sty", "cls" ],
+ "name": "TeX document"
+ },
+ {
+ "ext": [ "text", "txt", "utf8" ],
+ "name": "Plain text document",
+ "CFBundleTypeMIMETypes": [ "text/plain" ],
+ "CFBundleTypeOSTypes": [ "TEXT", "sEXT", "ttro" ]
+ },
+ {
+ "ext": [ "textile" ],
+ "name": "Textile document"
+ },
+ {
+ "ext": [ "toml" ],
+ "name": "TOML file"
+ },
+ {
+ "ext": [ "xhtml" ],
+ "name": "XHTML document"
+ },
+ {
+ "ext": [ "xml", "xsd", "xib", "rss", "tld", "pt", "cpt", "dtml" ],
+ "name": "XML document"
+ },
+ {
+ "ext": [ "xsl", "xslt" ],
+ "name": "XSL stylesheet"
+ },
+ {
+ "ext": [ "vcf", "vcard" ],
+ "name": "Electronic business card"
+ },
+ {
+ "ext": [ "vb" ],
+ "name": "Visual Basic source"
+ },
+ {
+ "ext": [ "yaml", "yml" ],
+ "name": "YAML document"
+ },
+ {
+ "ext": [ "nfo" ],
+ "name": "Text document"
+ },
+ {
+ "ext": [ "g", "vss", "d", "e", "gri", "inf", "mel", "build", "re", "textmate", "fxscript", "lgt" ],
+ "name": "Source"
+ },
+ {
+ "ext": [ "cfm", "cfml", "dbm", "dist", "dot", "ics", "ifb", "dwt", "g", "in", "l", "m4", "mp", "mtml", "orig", "pde", "rej", "servlet", "s5", "tmp", "tpl", "tt", "xql", "yy", "*" ],
+ "name": "Document"
+ },
+ {
+ "name": "Document",
+ "CFBundleTypeOSTypes": [ "****" ],
+ "LSItemContentTypes": [ "public.data" ]
+ },
+ {
+ // Adds Folder Support
+ "LSItemContentTypes": [ "public.directory", "com.apple.bundle", "com.apple.resolvable" ]
+ }
+];
+
+function create() {
+ let obj = [];
+
+ for (let i = 0; i < docs.length; i++) {
+ let tmp = {
+ "CFBundleTypeIconFile": "file.icns",
+ "CFBundleTypeRole": "Editor",
+ "LSHandlerRank": "Alternate"
+ };
+
+ if (docs[i].name) {
+ tmp["CFBundleTypeName"] = docs[i].name;
+ }
+
+ if (docs[i].ext) {
+ tmp["CFBundleTypeExtensions"] = docs[i].ext;
+ }
+
+ if (docs[i]["CFBundleTypeMIMETypes"]) {
+ // If this type is specified
+ tmp["CFBundleTypeMIMETypes"] = docs[i]["CFBundleTypeMIMETypes"];
+ }
+
+ if (docs[i]["CFBundleTypeOSTypes"]) {
+ tmp["CFBundleTypeOSTypes"] = docs[i]["CFBundleTypeOSTypes"];
+ }
+
+ if (docs[i]["LSItemContentTypes"]) {
+ tmp["LSItemContentTypes"] = docs[i]["LSItemContentTypes"];
+ }
+
+ obj.push(tmp);
+ }
+
+ return obj;
+}
+
+module.exports = {
+ create,
+};
diff --git a/script/mac-notarise.js b/script/mac-notarise.js
new file mode 100644
index 000000000..349f0ad6e
--- /dev/null
+++ b/script/mac-notarise.js
@@ -0,0 +1,48 @@
+const { notarize } = require("@electron/notarize");
+
+// https://kilianvalkhof.com/2019/electron/notarizing-your-electron-application/
+
+/**
+ * @param {import("electron-builder").AfterPackContext} ctx
+ */
+exports.default = async function notarizing(ctx) {
+ if (ctx.electronPlatformName !== "darwin") return;
+
+ const appleId = process.env.APPLEID;
+ const appleIdPassword = process.env.APPLEID_PASSWORD;
+ const teamId = process.env.TEAM_ID;
+ const appname = ctx.packager.appInfo.productFilename;
+
+ if (!appleId || !appleIdPassword) {
+ console.error("environment variables APPLEID and APPLEID_PASSWORD are not both present, skipping notarisation");
+ return;
+ }
+
+ /** @type {Parameters[0]} */
+ let notarise_args = {
+ appBundleId: "dev.pulsar-edit.pulsar",
+ appPath: `${ctx.appOutDir}/${appname}.app`,
+ appleId,
+ appleIdPassword
+ };
+
+ if (!teamId) {
+ console.log("no TEAM_ID, using (legacy) altool");
+ notarise_args = {
+ ...notarise_args,
+ tool: "legacy"
+ }
+ } else {
+ console.log("using notarytool");
+
+ notarise_args = {
+ ...notarise_args,
+ tool: "notarytool",
+ teamId
+ };
+ }
+
+ require("debug").enable("electron-notarize");
+
+ return await notarize(notarise_args);
+}
diff --git a/script/package.json b/script/package.json
deleted file mode 100644
index e424fbe30..000000000
--- a/script/package.json
+++ /dev/null
@@ -1,60 +0,0 @@
-{
- "name": "atom-build-scripts",
- "description": "Atom build scripts",
- "dependencies": {
- "7zip-bin": "^4.0.2",
- "@atom/electron-winstaller": "0.0.1",
- "@octokit/request": "^5.4.5",
- "async": "^3.2.0",
- "babel-core": "5.8.38",
- "babel-eslint": "^10.0.1",
- "cheerio": "1.0.0-rc.2",
- "coffeelint": "1.15.7",
- "colors": "1.1.2",
- "donna": "1.0.16",
- "electron-chromedriver": "^11.0.0",
- "electron-link": "^0.6.0",
- "electron-mksnapshot": "^11.0.1",
- "electron-packager": "^15.1.0",
- "eslint": "^5.16.0",
- "eslint-config-prettier": "^4.2.0",
- "eslint-config-standard": "^12.0.0",
- "eslint-plugin-import": "^2.17.2",
- "eslint-plugin-node": "^9.0.1",
- "eslint-plugin-prettier": "^3.0.1",
- "eslint-plugin-promise": "^4.1.1",
- "eslint-plugin-standard": "^4.0.0",
- "fs-admin": "0.19.0",
- "fs-extra": "9.0.1",
- "glob": "7.0.3",
- "joanna": "0.0.10",
- "klaw-sync": "^1.1.2",
- "legal-eagle": "0.14.0",
- "lodash.startcase": "4.4.0",
- "lodash.template": "4.5.0",
- "minidump": "^0.22.0",
- "mkdirp": "0.5.1",
- "nock": "^13.0.2",
- "node-fetch": "^2.6.7",
- "normalize-package-data": "2.3.5",
- "npm": "^6.14.16",
- "npm-check": "^5.9.2",
- "passwd-user": "2.1.0",
- "pegjs": "0.9.0",
- "prettier": "^1.17.0",
- "random-seed": "^0.3.0",
- "season": "5.3.0",
- "semver": "5.3.0",
- "simple-git": "^2.7.0",
- "stylelint": "^9.0.0",
- "stylelint-config-standard": "^18.1.0",
- "sync-request": "3.0.1",
- "tello": "1.2.0",
- "terser": "^3.8.1",
- "webdriverio": "^5.9.2",
- "yargs": "4.8.1"
- },
- "scripts": {
- "postinstall": "node ./redownload-electron-bins.js"
- }
-}
diff --git a/script/post-install.sh b/script/post-install.sh
index 2c3564b09..ffe2c5332 100644
--- a/script/post-install.sh
+++ b/script/post-install.sh
@@ -1,4 +1,19 @@
#!/bin/sh
-rm /usr/bin/pulsar
-cp /opt/Pulsar/resources/pulsar.sh /usr/bin/pulsar
+FILESOURCE='/opt/Pulsar/resources/pulsar.sh'
+FILEDEST='/usr/bin/pulsar'
+
+if [ -f "$FILEDEST" ]
+then
+ rm "$FILEDEST"
+fi
+cp "$FILESOURCE" "$FILEDEST"
+
+SYMLINK_TARGET='/opt/Pulsar/resources/app/ppm/bin/apm'
+SYMLINK_PATH='/usr/bin/ppm'
+
+if [ -L "$SYMLINK_PATH" ]
+then
+ rm "$SYMLINK_PATH"
+fi
+ln -s "$SYMLINK_TARGET" "$SYMLINK_PATH"
diff --git a/script/post-uninstall.sh b/script/post-uninstall.sh
new file mode 100644
index 000000000..cba294dba
--- /dev/null
+++ b/script/post-uninstall.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+PULSAR_SCRIPT_PATH='/usr/bin/pulsar'
+
+if [ -f "$PULSAR_SCRIPT_PATH" ]
+then
+ rm "$PULSAR_SCRIPT_PATH"
+fi
+
+PPM_SYMLINK_PATH='/usr/bin/ppm'
+
+if [ -L "$PPM_SYMLINK_PATH" ]
+then
+ rm "$PPM_SYMLINK_PATH"
+fi
diff --git a/script/run-package-tests.js b/script/run-package-tests.js
index 73620f480..558332ccb 100644
--- a/script/run-package-tests.js
+++ b/script/run-package-tests.js
@@ -1,7 +1,7 @@
-const cp = require('child_process')
const fs = require('fs')
const path = require('path')
const packJson = require('../package.json')
+const runAllSpecs = require('./run-tests')
module.exports = function(filter) {
let packagePath = []
@@ -16,12 +16,5 @@ module.exports = function(filter) {
}
}
- // console.log('yarn', 'start', '--test', ...packagePath)
- const res = cp.spawnSync('yarn', ['start', '--test', ...packagePath], {
- cwd: process.cwd(),
- detached: true,
- stdio: "inherit"
- })
-
- process.exit(res.status)
+ runAllSpecs(packagePath)
}
diff --git a/script/run-tests.js b/script/run-tests.js
new file mode 100644
index 000000000..f6fff0c3c
--- /dev/null
+++ b/script/run-tests.js
@@ -0,0 +1,76 @@
+const cp = require('child_process')
+
+function runAllSpecs(files) {
+ runSpecs(files, [])
+}
+
+function runSpecs(files, retries) {
+ let env = process.env
+ env.ATOM_JASMINE_REPORTER='list'
+ if(retries.length > 0) {
+ // Escape possible tests that can generate a regexp that will not match...
+ const escaped = retries.map(str => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'));
+ env.SPEC_FILTER = escaped.join("|")
+ }
+ const res = cp.spawn('yarn', ['start', '--test', ...files], {
+ cwd: process.cwd(),
+ env: env
+ })
+
+ let out;
+ res.stdout.on('data', data => {
+ process.stdout.write(data.toString());
+ });
+
+ res.stderr.on('data', data => {
+ const strData = data.toString();
+ process.stderr.write(strData);
+
+ if(strData.match(/ALL TESTS THAT FAILED:/)) {
+ out = '';
+ } else if(out !== undefined) {
+ out += strData;
+ }
+ });
+
+ res.on('close', code => {
+ if(code !== 0 && retries.length === 0) {
+ const failed = filterSpecs(out)
+
+ console.log(`*********************
+Tests failed. Retrying failed tests...
+*********************
+
+`)
+ runSpecs(files, failed)
+ } else {
+ process.exit(code)
+ }
+ });
+}
+
+function filterSpecs(output) {
+ if(!output) return ''
+ let descriptions = []
+ let start = true
+ for(let out of output.split("\n")) {
+ if(start) {
+ if(out !== '') {
+ start = false
+ descriptions.push(out)
+ }
+ } else if(out !== '') {
+ descriptions.push(out)
+ } else {
+ return descriptions
+ }
+ }
+}
+
+if(process.argv[0] === __filename) {
+ runAllSpecs(process.argv.splice(1))
+} else if(process.argv[1] === __filename) {
+ runAllSpecs(process.argv.splice(2))
+} else {
+ module.exports = runAllSpecs
+}
diff --git a/spec/command-installer-spec.js b/spec/command-installer-spec.js
index 81efd4550..059ebcd77 100644
--- a/spec/command-installer-spec.js
+++ b/spec/command-installer-spec.js
@@ -3,231 +3,228 @@ const fs = require('fs-plus');
const temp = require('temp').track();
const CommandInstaller = require('../src/command-installer');
-describe('CommandInstaller on #darwin', () => {
- let installer, resourcesPath, installationPath, atomBinPath, apmBinPath;
-
- beforeEach(() => {
- installationPath = temp.mkdirSync('atom-bin');
-
- resourcesPath = temp.mkdirSync('atom-app');
- atomBinPath = path.join(resourcesPath, 'app', 'atom.sh');
- apmBinPath = path.join(
- resourcesPath,
- 'app',
- 'apm',
- 'node_modules',
- '.bin',
- 'apm'
- );
- fs.writeFileSync(atomBinPath, '');
- fs.writeFileSync(apmBinPath, '');
- fs.chmodSync(atomBinPath, '755');
- fs.chmodSync(apmBinPath, '755');
-
- spyOn(CommandInstaller.prototype, 'getResourcesDirectory').andReturn(
- resourcesPath
- );
- spyOn(CommandInstaller.prototype, 'getInstallDirectory').andReturn(
- installationPath
- );
- });
-
- afterEach(() => {
- try {
- temp.cleanupSync();
- } catch (error) {}
- });
-
- it('shows an error dialog when installing commands interactively fails', () => {
- const appDelegate = jasmine.createSpyObj('appDelegate', ['confirm']);
- installer = new CommandInstaller(appDelegate);
- installer.initialize('2.0.2');
- spyOn(installer, 'installAtomCommand').andCallFake((__, callback) =>
- callback(new Error('an error'))
- );
-
- installer.installShellCommandsInteractively();
-
- expect(appDelegate.confirm.mostRecentCall.args[0]).toEqual({
- message: 'Failed to install shell commands',
- detail: 'an error'
- });
-
- appDelegate.confirm.reset();
- installer.installAtomCommand.andCallFake((__, callback) => callback());
- spyOn(installer, 'installApmCommand').andCallFake((__, callback) =>
- callback(new Error('another error'))
- );
-
- installer.installShellCommandsInteractively();
-
- expect(appDelegate.confirm.mostRecentCall.args[0]).toEqual({
- message: 'Failed to install shell commands',
- detail: 'another error'
- });
- });
-
- it('shows a success dialog when installing commands interactively succeeds', () => {
- const appDelegate = jasmine.createSpyObj('appDelegate', ['confirm']);
- installer = new CommandInstaller(appDelegate);
- installer.initialize('2.0.2');
- spyOn(installer, 'installAtomCommand').andCallFake((__, callback) =>
- callback(undefined, 'atom')
- );
- spyOn(installer, 'installApmCommand').andCallFake((__, callback) =>
- callback(undefined, 'apm')
- );
-
- installer.installShellCommandsInteractively();
-
- expect(appDelegate.confirm.mostRecentCall.args[0]).toEqual({
- message: 'Commands installed.',
- detail: 'The shell commands `atom` and `apm` are installed.'
- });
- });
-
- describe('when using a stable version of atom', () => {
- beforeEach(() => {
- installer = new CommandInstaller();
- installer.initialize('2.0.2');
- });
-
- /**
- * TODO: FAILING TEST - This test fails with the following output: (macos only)
- * timeout: timed out after 120000 msec waiting for condition
- */
- xit("symlinks the atom command as 'atom'", () => {
- const installedAtomPath = path.join(installationPath, 'atom');
- expect(fs.isFileSync(installedAtomPath)).toBeFalsy();
-
- waitsFor(done => {
- installer.installAtomCommand(false, error => {
- expect(error).toBeNull();
- expect(fs.realpathSync(installedAtomPath)).toBe(
- fs.realpathSync(atomBinPath)
- );
- expect(fs.isExecutableSync(installedAtomPath)).toBe(true);
- expect(fs.isFileSync(path.join(installationPath, 'atom-beta'))).toBe(
- false
- );
- done();
- });
- });
- });
-
- it("symlinks the apm command as 'apm'", () => {
- const installedApmPath = path.join(installationPath, 'apm');
- expect(fs.isFileSync(installedApmPath)).toBeFalsy();
-
- waitsFor(done => {
- installer.installApmCommand(false, error => {
- expect(error).toBeNull();
- expect(fs.realpathSync(installedApmPath)).toBe(
- fs.realpathSync(apmBinPath)
- );
- expect(fs.isExecutableSync(installedApmPath)).toBeTruthy();
- expect(fs.isFileSync(path.join(installationPath, 'apm-beta'))).toBe(
- false
- );
- done();
- });
- });
- });
- });
-
- describe('when using a beta version of atom', () => {
- beforeEach(() => {
- installer = new CommandInstaller();
- installer.initialize('2.2.0-beta.0');
- });
-
- /**
- * TODO: FAILING TEST - This test fails with the following output: (macos only)
- * timeout: timed out after 120000 msec waiting for condition
- */
- xit("symlinks the atom command as 'atom-beta'", () => {
- const installedAtomPath = path.join(installationPath, 'atom-beta');
- expect(fs.isFileSync(installedAtomPath)).toBeFalsy();
-
- waitsFor(done => {
- installer.installAtomCommand(false, error => {
- expect(error).toBeNull();
- expect(fs.realpathSync(installedAtomPath)).toBe(
- fs.realpathSync(atomBinPath)
- );
- expect(fs.isExecutableSync(installedAtomPath)).toBe(true);
- expect(fs.isFileSync(path.join(installationPath, 'atom'))).toBe(
- false
- );
- done();
- });
- });
- });
-
- it("symlinks the apm command as 'apm-beta'", () => {
- const installedApmPath = path.join(installationPath, 'apm-beta');
- expect(fs.isFileSync(installedApmPath)).toBeFalsy();
-
- waitsFor(done => {
- installer.installApmCommand(false, error => {
- expect(error).toBeNull();
- expect(fs.realpathSync(installedApmPath)).toBe(
- fs.realpathSync(apmBinPath)
- );
- expect(fs.isExecutableSync(installedApmPath)).toBeTruthy();
- expect(fs.isFileSync(path.join(installationPath, 'apm'))).toBe(false);
- done();
- });
- });
- });
- });
-
- describe('when using a nightly version of atom', () => {
- beforeEach(() => {
- installer = new CommandInstaller();
- installer.initialize('2.2.0-nightly0');
- });
-
- /**
- * TODO: FAILING TEST - This test fails with the following output: (macos only)
- * timeout: timed out after 120000 msec waiting for condition
- */
- xit("symlinks the atom command as 'atom-nightly'", () => {
- const installedAtomPath = path.join(installationPath, 'atom-nightly');
- expect(fs.isFileSync(installedAtomPath)).toBeFalsy();
-
- waitsFor(done => {
- installer.installAtomCommand(false, error => {
- expect(error).toBeNull();
- expect(fs.realpathSync(installedAtomPath)).toBe(
- fs.realpathSync(atomBinPath)
- );
- expect(fs.isExecutableSync(installedAtomPath)).toBe(true);
- expect(fs.isFileSync(path.join(installationPath, 'atom'))).toBe(
- false
- );
- done();
- });
- });
- });
-
- it("symlinks the apm command as 'apm-nightly'", () => {
- const installedApmPath = path.join(installationPath, 'apm-nightly');
- expect(fs.isFileSync(installedApmPath)).toBeFalsy();
-
- waitsFor(done => {
- installer.installApmCommand(false, error => {
- expect(error).toBeNull();
- expect(fs.realpathSync(installedApmPath)).toBe(
- fs.realpathSync(apmBinPath)
- );
- expect(fs.isExecutableSync(installedApmPath)).toBeTruthy();
- expect(fs.isFileSync(path.join(installationPath, 'nightly'))).toBe(
- false
- );
- done();
- });
- });
- });
- });
-});
+// describe('CommandInstaller on #darwin', () => {
+// let installer, resourcesPath, installationPath, atomBinPath, apmBinPath;
+//
+// beforeEach(() => {
+// installationPath = temp.mkdirSync('atom-bin');
+//
+// resourcesPath = temp.mkdirSync('atom-app');
+// atomBinPath = path.join(resourcesPath, 'app', 'atom.sh');
+// apmBinPath = path.join(
+// resourcesPath,
+// 'app',
+// 'apm',
+// 'node_modules',
+// '.bin',
+// 'apm'
+// );
+// fs.writeFileSync(atomBinPath, '');
+// fs.writeFileSync(apmBinPath, '');
+// fs.chmodSync(atomBinPath, '755');
+// fs.chmodSync(apmBinPath, '755');
+//
+// spyOn(CommandInstaller.prototype, 'getResourcesDirectory').andReturn(
+// resourcesPath
+// );
+// spyOn(CommandInstaller.prototype, 'getInstallDirectory').andReturn(
+// installationPath
+// );
+// });
+//
+// afterEach(() => {
+// try {
+// temp.cleanupSync();
+// } catch (error) {}
+// });
+//
+// it('shows an error dialog when installing commands interactively fails', () => {
+// const appDelegate = jasmine.createSpyObj('appDelegate', ['confirm']);
+// installer = new CommandInstaller(appDelegate);
+// installer.initialize('2.0.2');
+// spyOn(installer, 'installAtomCommand').andCallFake((__, callback) =>
+// callback(new Error('an error'))
+// );
+//
+// installer.installShellCommandsInteractively();
+//
+// expect(appDelegate.confirm.mostRecentCall.args[0]).toEqual({
+// message: 'Failed to install shell commands',
+// detail: 'an error'
+// });
+//
+// appDelegate.confirm.reset();
+// installer.installAtomCommand.andCallFake((__, callback) => callback());
+// spyOn(installer, 'installApmCommand').andCallFake((__, callback) =>
+// callback(new Error('another error'))
+// );
+//
+// installer.installShellCommandsInteractively();
+//
+// expect(appDelegate.confirm.mostRecentCall.args[0]).toEqual({
+// message: 'Failed to install shell commands',
+// detail: 'another error'
+// });
+// });
+//
+// it('shows a success dialog when installing commands interactively succeeds', () => {
+// const appDelegate = jasmine.createSpyObj('appDelegate', ['confirm']);
+// installer = new CommandInstaller(appDelegate);
+// installer.initialize('2.0.2');
+// spyOn(installer, 'installAtomCommand').andCallFake((__, callback) =>
+// callback(undefined, 'atom')
+// );
+// spyOn(installer, 'installApmCommand').andCallFake((__, callback) =>
+// callback(undefined, 'apm')
+// );
+//
+// installer.installShellCommandsInteractively();
+//
+// expect(appDelegate.confirm.mostRecentCall.args[0]).toEqual({
+// message: 'Commands installed.',
+// detail: 'The shell commands `atom` and `apm` are installed.'
+// });
+// });
+//
+// describe('when installing command line tools for Pulsar', () => {
+// beforeEach(() => {
+// installer = new CommandInstaller();
+// installer.initialize('2.0.2');
+// });
+//
+// /**
+// * TODO: FAILING TEST - This test fails with the following output: (macos only)
+// * timeout: timed out after 120000 msec waiting for condition
+// */
+// it("symlinks the atom command as 'pulsar'", () => {
+// const installedAtomPath = path.join(installationPath, 'pulsar');
+// expect(fs.isFileSync(installedAtomPath)).toBeFalsy();
+//
+// waitsFor(done => {
+// installer.installAtomCommand(false, error => {
+// expect(error).toBeNull();
+// expect(fs.realpathSync(installedAtomPath)).toBe(
+// fs.realpathSync(atomBinPath)
+// );
+// expect(fs.isExecutableSync(installedAtomPath)).toBe(true);
+// expect(fs.isFileSync(path.join(installationPath, 'pulsar'))).toBe(
+// false
+// );
+// done();
+// });
+// });
+// });
+//
+// it("symlinks the package command as 'ppm'", () => {
+// const installedPpmPath = path.join(installationPath, 'ppm');
+// expect(fs.isFileSync(installedPpmPath)).toBeFalsy();
+//
+// waitsFor(done => {
+// installer.installApmCommand(false, error => {
+// expect(error).toBeNull();
+// expect(fs.realpathSync(installedPpmPath)).toBe(
+// fs.realpathSync(apmBinPath)
+// );
+// expect(fs.isExecutableSync(installedPpmPath)).toBeTruthy();
+// done();
+// });
+// });
+// });
+// });
+//
+// describe('when using a beta version of atom', () => {
+// beforeEach(() => {
+// installer = new CommandInstaller();
+// installer.initialize('2.2.0-beta.0');
+// });
+//
+// /**
+// * TODO: FAILING TEST - This test fails with the following output: (macos only)
+// * timeout: timed out after 120000 msec waiting for condition
+// */
+// xit("symlinks the atom command as 'atom-beta'", () => {
+// const installedAtomPath = path.join(installationPath, 'atom-beta');
+// expect(fs.isFileSync(installedAtomPath)).toBeFalsy();
+//
+// waitsFor(done => {
+// installer.installAtomCommand(false, error => {
+// expect(error).toBeNull();
+// expect(fs.realpathSync(installedAtomPath)).toBe(
+// fs.realpathSync(atomBinPath)
+// );
+// expect(fs.isExecutableSync(installedAtomPath)).toBe(true);
+// expect(fs.isFileSync(path.join(installationPath, 'atom'))).toBe(
+// false
+// );
+// done();
+// });
+// });
+// });
+//
+// it("symlinks the apm command as 'apm-beta'", () => {
+// const installedApmPath = path.join(installationPath, 'apm-beta');
+// expect(fs.isFileSync(installedApmPath)).toBeFalsy();
+//
+// waitsFor(done => {
+// installer.installApmCommand(false, error => {
+// expect(error).toBeNull();
+// expect(fs.realpathSync(installedApmPath)).toBe(
+// fs.realpathSync(apmBinPath)
+// );
+// expect(fs.isExecutableSync(installedApmPath)).toBeTruthy();
+// expect(fs.isFileSync(path.join(installationPath, 'apm'))).toBe(false);
+// done();
+// });
+// });
+// });
+// });
+//
+// describe('when using a nightly version of atom', () => {
+// beforeEach(() => {
+// installer = new CommandInstaller();
+// installer.initialize('2.2.0-nightly0');
+// });
+//
+// /**
+// * TODO: FAILING TEST - This test fails with the following output: (macos only)
+// * timeout: timed out after 120000 msec waiting for condition
+// */
+// xit("symlinks the atom command as 'atom-nightly'", () => {
+// const installedAtomPath = path.join(installationPath, 'atom-nightly');
+// expect(fs.isFileSync(installedAtomPath)).toBeFalsy();
+//
+// waitsFor(done => {
+// installer.installAtomCommand(false, error => {
+// expect(error).toBeNull();
+// expect(fs.realpathSync(installedAtomPath)).toBe(
+// fs.realpathSync(atomBinPath)
+// );
+// expect(fs.isExecutableSync(installedAtomPath)).toBe(true);
+// expect(fs.isFileSync(path.join(installationPath, 'atom'))).toBe(
+// false
+// );
+// done();
+// });
+// });
+// });
+//
+// it("symlinks the apm command as 'apm-nightly'", () => {
+// const installedApmPath = path.join(installationPath, 'apm-nightly');
+// expect(fs.isFileSync(installedApmPath)).toBeFalsy();
+//
+// waitsFor(done => {
+// installer.installApmCommand(false, error => {
+// expect(error).toBeNull();
+// expect(fs.realpathSync(installedApmPath)).toBe(
+// fs.realpathSync(apmBinPath)
+// );
+// expect(fs.isExecutableSync(installedApmPath)).toBeTruthy();
+// expect(fs.isFileSync(path.join(installationPath, 'nightly'))).toBe(
+// false
+// );
+// done();
+// });
+// });
+// });
+// });
+// });
diff --git a/spec/compile-cache-spec.js b/spec/compile-cache-spec.js
index 9689b7601..c550ce11c 100644
--- a/spec/compile-cache-spec.js
+++ b/spec/compile-cache-spec.js
@@ -8,7 +8,7 @@
const path = require('path');
const temp = require('temp').track();
const babelCompiler = require('../src/babel');
-const CoffeeScript = require('coffee-script');
+const CoffeeScript = require('coffeescript');
const {TypeScriptSimple} = require('typescript-simple');
const CSON = require('season');
const CompileCache = require('../src/compile-cache');
diff --git a/spec/integration/helpers/atom-launcher.sh b/spec/integration/helpers/atom-launcher.sh
deleted file mode 100755
index f104dbfbf..000000000
--- a/spec/integration/helpers/atom-launcher.sh
+++ /dev/null
@@ -1,47 +0,0 @@
-#!/bin/bash
-
-# This script wraps the `Atom` binary, allowing the `chromedriver` server to
-# execute it with positional arguments and environment variables. `chromedriver`
-# only allows 'switches' to be specified when starting a browser, not positional
-# arguments, so this script accepts the following special switches:
-#
-# * `atom-path`: The path to the `Atom` binary.
-# * `atom-args`: A space-separated list of positional arguments to pass to Atom.
-# * `atom-env`: A space-separated list of key=value pairs representing environment
-# variables to set for Atom.
-#
-# Any other switches will be passed through to `Atom`.
-
-atom_path=""
-atom_switches=()
-atom_args=()
-
-for arg in "$@"; do
- case $arg in
- --atom-path=*)
- atom_path="${arg#*=}"
- ;;
-
- --atom-args=*)
- atom_arg_string="${arg#*=}"
- for atom_arg in $atom_arg_string; do
- atom_args+=($atom_arg)
- done
- ;;
-
- --atom-env=*)
- atom_env_string="${arg#*=}"
- for atom_env_pair in $atom_env_string; do
- export $atom_env_pair
- done
- ;;
-
- *)
- atom_switches+=($arg)
- ;;
- esac
-done
-
-echo "Launching Atom" >&2
-echo "${atom_path}" ${atom_args[@]} ${atom_switches[@]} >&2
-exec "${atom_path}" ${atom_args[@]} ${atom_switches[@]}
diff --git a/spec/integration/helpers/start-atom.js b/spec/integration/helpers/start-atom.js
deleted file mode 100644
index f8807aa5d..000000000
--- a/spec/integration/helpers/start-atom.js
+++ /dev/null
@@ -1,195 +0,0 @@
-const path = require('path');
-const http = require('http');
-const temp = require('temp').track();
-const { remote } = require('electron');
-const { once } = require('underscore-plus');
-const { spawn } = require('child_process');
-const webdriverio = require('webdriverio');
-
-const AtomPath = remote.process.argv[0];
-const AtomLauncherPath = path.join(
- __dirname,
- '..',
- 'helpers',
- 'atom-launcher.sh'
-);
-const ChromedriverPath = path.resolve(
- __dirname,
- '..',
- '..',
- '..',
- 'script',
- 'node_modules',
- 'electron-chromedriver',
- 'bin',
- 'chromedriver'
-);
-const ChromedriverPort = 8082;
-const ChromedriverURLBase = '/wd/hub';
-const ChromedriverStatusURL = `http://localhost:${ChromedriverPort}${ChromedriverURLBase}/status`;
-
-const chromeDriverUp = done => {
- const checkStatus = () =>
- http
- .get(ChromedriverStatusURL, response => {
- if (response.statusCode === 200) {
- done();
- } else {
- chromeDriverUp(done);
- }
- })
- .on('error', () => chromeDriverUp(done));
-
- setTimeout(checkStatus, 100);
-};
-
-const chromeDriverDown = done => {
- const checkStatus = () =>
- http
- .get(ChromedriverStatusURL, response => chromeDriverDown(done))
- .on('error', done);
-
- setTimeout(checkStatus, 100);
-};
-
-const buildAtomClient = async (args, env) => {
- const userDataDir = temp.mkdirSync('atom-user-data-dir');
- const client = await webdriverio.remote({
- host: 'localhost',
- port: ChromedriverPort,
- capabilities: {
- browserName: 'chrome', // Webdriverio will figure it out on it's own, but I will leave it in case it's helpful in the future https://webdriver.io/docs/configurationfile.html
- 'goog:chromeOptions': {
- binary: AtomLauncherPath,
- args: [
- `atom-path=${AtomPath}`,
- `atom-args=${args.join(' ')}`,
- `atom-env=${Object.entries(env)
- .map(([key, value]) => `${key}=${value}`)
- .join(' ')}`,
- 'dev',
- 'safe',
- `user-data-dir=${userDataDir}`
- ]
- }
- }
- });
-
- client.addCommand('waitForPaneItemCount', async function(count, timeout) {
- await this.waitUntil(
- () =>
- this.execute(() => atom.workspace.getActivePane().getItems().length),
- timeout
- );
- });
- client.addCommand('treeViewRootDirectories', async function() {
- const treeViewElement = await this.$('.tree-view');
- await treeViewElement.waitForExist(10000);
- return this.execute(() =>
- Array.from(
- document.querySelectorAll('.tree-view .project-root > .header .name')
- ).map(element => element.dataset.path)
- );
- });
- client.addCommand('dispatchCommand', async function(command) {
- return this.execute(
- command => atom.commands.dispatch(document.activeElement, command),
- command
- );
- });
-
- return client;
-};
-
-module.exports = function(args, env, fn) {
- let chromedriver, chromedriverLogs, chromedriverExit;
-
- runs(() => {
- chromedriver = spawn(ChromedriverPath, [
- '--verbose',
- `--port=${ChromedriverPort}`,
- `--url-base=${ChromedriverURLBase}`
- ]);
-
- chromedriverLogs = [];
- chromedriverExit = new Promise(resolve => {
- let errorCode = null;
- chromedriver.on('exit', (code, signal) => {
- if (signal == null) {
- errorCode = code;
- }
- });
- chromedriver.stderr.on('data', log =>
- chromedriverLogs.push(log.toString())
- );
- chromedriver.stderr.on('close', () => resolve(errorCode));
- });
- });
-
- waitsFor('webdriver to start', chromeDriverUp, 15000);
-
- waitsFor(
- 'tests to run',
- async done => {
- const finish = once(async () => {
- await client.deleteSession();
- chromedriver.kill();
-
- const errorCode = await chromedriverExit;
- if (errorCode != null) {
- jasmine.getEnv().currentSpec
- .fail(`Chromedriver exited with code ${errorCode}.
-Logs:\n${chromedriverLogs.join('\n')}`);
- }
- done();
- });
-
- let client;
- try {
- client = await buildAtomClient(args, env);
- } catch (error) {
- jasmine
- .getEnv()
- .currentSpec.fail(`Unable to build Atom client.\n${error}`);
- finish();
- return;
- }
-
- try {
- await client.waitUntil(async function() {
- const handles = await this.getWindowHandles();
- return handles.length > 0;
- }, 10000);
- } catch (error) {
- jasmine
- .getEnv()
- .currentSpec.fail(`Unable to locate windows.\n\n${error}`);
- finish();
- return;
- }
-
- try {
- const workspaceElement = await client.$('atom-workspace');
- await workspaceElement.waitForExist(10000);
- } catch (error) {
- jasmine
- .getEnv()
- .currentSpec.fail(`Unable to find workspace element.\n\n${error}`);
- finish();
- return;
- }
-
- try {
- await fn(client);
- } catch (error) {
- jasmine.getEnv().currentSpec.fail(error);
- finish();
- return;
- }
- finish();
- },
- 60000
- );
-
- waitsFor('webdriver to stop', chromeDriverDown, 15000);
-};
diff --git a/spec/integration/smoke-spec.js b/spec/integration/smoke-spec.js
deleted file mode 100644
index f7b0d490d..000000000
--- a/spec/integration/smoke-spec.js
+++ /dev/null
@@ -1,65 +0,0 @@
-const fs = require('fs-plus');
-const path = require('path');
-const season = require('season');
-const temp = require('temp').track();
-const runAtom = require('./helpers/start-atom');
-
-describe('Smoke Test', () => {
- // Fails on win32
- if (process.platform !== 'darwin') {
- return;
- }
-
- const atomHome = temp.mkdirSync('atom-home');
-
- beforeEach(() => {
- jasmine.useRealClock();
- season.writeFileSync(path.join(atomHome, 'config.cson'), {
- '*': {
- welcome: { showOnStartup: false },
- core: {
- disabledPackages: ['github']
- }
- }
- });
- });
-
- /**
- * TODO: FAILING TEST - This test fails with the following output: (macos only)
- * timeout: timed out after 15000 msec waiting for webdriver to start
- */
- xit('can open a file in Atom and perform basic operations on it', async () => {
- const tempDirPath = temp.mkdirSync('empty-dir');
- const filePath = path.join(tempDirPath, 'new-file');
-
- fs.writeFileSync(filePath, '', { encoding: 'utf8' });
-
- runAtom([tempDirPath], { ATOM_HOME: atomHome }, async client => {
- const roots = await client.treeViewRootDirectories();
- expect(roots).toEqual([tempDirPath]);
-
- await client.execute(filePath => atom.workspace.open(filePath), filePath);
-
- const textEditorElement = await client.$('atom-text-editor');
- await textEditorElement.waitForExist(5000);
-
- await client.waitForPaneItemCount(1, 1000);
-
- await textEditorElement.click();
-
- const closestElement = await client.execute(() =>
- document.activeElement.closest('atom-text-editor')
- );
- expect(closestElement).not.toBeNull();
-
- await client.keys('Hello!');
-
- const text = await client.execute(() =>
- atom.workspace.getActiveTextEditor().getText()
- );
- expect(text).toBe('Hello!');
-
- await client.dispatchCommand('editor:delete-line');
- });
- });
-});
diff --git a/spec/jasmine-list-reporter.js b/spec/jasmine-list-reporter.js
index 0928a13f1..6e3fe5bc9 100644
--- a/spec/jasmine-list-reporter.js
+++ b/spec/jasmine-list-reporter.js
@@ -2,13 +2,7 @@ const { TerminalReporter } = require('jasmine-tagged');
class JasmineListReporter extends TerminalReporter {
fullDescription(spec) {
- let fullDescription = 'it ' + spec.description;
- let currentSuite = spec.suite;
- while (currentSuite) {
- fullDescription = currentSuite.description + ' > ' + fullDescription;
- currentSuite = currentSuite.parentSuite;
- }
- return fullDescription;
+ return getFullDescription(spec, true);
}
reportSpecStarting(spec) {
@@ -23,13 +17,44 @@ class JasmineListReporter extends TerminalReporter {
let msg = '';
if (result.passed()) {
- msg = this.stringWithColor_('[pass]', this.color_.pass());
+ msg = "\u001b[34m[pass]\u001b[0m";
} else {
- msg = this.stringWithColor_('[FAIL]', this.color_.fail());
+ msg = "\u001b[1m\u001b[31m[FAIL]\u001b[0m";
+
+ this.flatFailures ||= [];
+ this.flatFailures.push(getFullDescription(spec, false))
+
this.addFailureToFailures_(spec);
}
this.printLine_(msg);
}
+
+ reportFailures_(spec) {
+ super.reportFailures_(spec);
+
+ if(this.flatFailures && this.flatFailures.length > 0) {
+ this.printLine_("\n\nALL TESTS THAT FAILED:")
+ for(let failure of this.flatFailures) {
+ this.printLine_(failure)
+ }
+ }
+ }
}
-module.exports = { JasmineListReporter };
+function getFullDescription(spec, tokens) {
+ let fullDescription = spec.description;
+ if(tokens) fullDescription = `it ${fullDescription}`;
+
+ let currentSuite = spec.suite;
+ while (currentSuite) {
+ if(tokens) {
+ fullDescription = `${currentSuite.description} > ${fullDescription}`;
+ } else {
+ fullDescription = `${currentSuite.description} ${fullDescription}`;
+ }
+ currentSuite = currentSuite.parentSuite;
+ }
+ return fullDescription;
+}
+
+module.exports = { JasmineListReporter, getFullDescription };
diff --git a/spec/jasmine-test-runner.js b/spec/jasmine-test-runner.js
index 585bd6e86..5c91fb7c8 100644
--- a/spec/jasmine-test-runner.js
+++ b/spec/jasmine-test-runner.js
@@ -77,6 +77,12 @@ module.exports = function({logFile, headless, testPaths, buildAtomEnvironment})
const jasmineEnv = jasmine.getEnv();
jasmineEnv.addReporter(buildReporter({logFile, headless, resolveWithExitCode}));
+ if(process.env.SPEC_FILTER) {
+ const {getFullDescription} = require('./jasmine-list-reporter');
+ const regex = new RegExp(process.env.SPEC_FILTER)
+ jasmineEnv.specFilter = (spec) => getFullDescription(spec, false).match(regex)
+ }
+
if (process.env.TEST_JUNIT_XML_PATH) {
const {JasmineJUnitReporter} = require('./jasmine-junit-reporter');
process.stdout.write(`Outputting JUnit XML to <${process.env.TEST_JUNIT_XML_PATH}>\n`);
diff --git a/src/atom-environment.js b/src/atom-environment.js
index 4b7825c94..6fd920822 100644
--- a/src/atom-environment.js
+++ b/src/atom-environment.js
@@ -53,18 +53,18 @@ const stat = util.promisify(fs.stat);
let nextId = 0;
-// Essential: Pulsar global for dealing with packages, themes, menus, and the window.
-//
-// An instance of this class is always available as the `atom` global.
+/**
+ * @class AtomEnvironment
+ * @classdesc Pulsar global for dealing with packages, themes, menus, and the window.
+ *
+ * An instance of this class is always available as the `atom` global.
+ */
class AtomEnvironment {
- /*
- Section: Properties
- */
constructor(params = {}) {
this.id = params.id != null ? params.id : nextId++;
- // Public: A {Clipboard} instance
+ /** @type {Clipboard} */
this.clipboard = params.clipboard;
this.updateProcessEnv = params.updateProcessEnv || updateProcessEnv;
this.enablePersistence = params.enablePersistence;
@@ -77,19 +77,19 @@ class AtomEnvironment {
this.disposables = new CompositeDisposable();
this.pathsWithWaitSessions = new Set();
- // Public: A {DeserializerManager} instance
+ /** @type {DeserializerManager} */
this.deserializers = new DeserializerManager(this);
this.deserializeTimings = {};
- // Public: A {ViewRegistry} instance
+ /** @type {ViewRegistry} */
this.views = new ViewRegistry(this);
- // Public: A {NotificationManager} instance
+ /** @type {NotificationManager} */
this.notifications = new NotificationManager();
this.stateStore = new StateStore('AtomEnvironments', 1);
- // Public: A {Config} instance
+ /** @type {Config} */
this.config = new Config({
saveCallback: settings => {
if (this.enablePersistence) {
@@ -105,28 +105,28 @@ class AtomEnvironment {
properties: _.clone(ConfigSchema)
});
- // Public: A {KeymapManager} instance
+ /** @type {KeymapManager} */
this.keymaps = new KeymapManager({
notificationManager: this.notifications
});
- // Public: A {TooltipManager} instance
+ /** @type {TooltipManager} */
this.tooltips = new TooltipManager({
keymapManager: this.keymaps,
viewRegistry: this.views
});
- // Public: A {CommandRegistry} instance
+ /** @type {CommandRegistry} */
this.commands = new CommandRegistry();
this.uriHandlerRegistry = new URIHandlerRegistry();
- // Public: A {GrammarRegistry} instance
+ /** @type {GrammarRegistry} */
this.grammars = new GrammarRegistry({ config: this.config });
- // Public: A {StyleManager} instance
+ /** @type {StyleManager} */
this.styles = new StyleManager();
- // Public: A {PackageManager} instance
+ /** @type {PackageManager} */
this.packages = new PackageManager({
config: this.config,
styleManager: this.styles,
@@ -139,7 +139,7 @@ class AtomEnvironment {
uriHandlerRegistry: this.uriHandlerRegistry
});
- // Public: A {ThemeManager} instance
+ /** @type {ThemeManager} */
this.themes = new ThemeManager({
packageManager: this.packages,
config: this.config,
@@ -148,20 +148,20 @@ class AtomEnvironment {
viewRegistry: this.views
});
- // Public: A {MenuManager} instance
+ /** @type {MenuManager} */
this.menu = new MenuManager({
keymapManager: this.keymaps,
packageManager: this.packages
});
- // Public: A {ContextMenuManager} instance
+ /** @type {ContextMenuManager} */
this.contextMenu = new ContextMenuManager({ keymapManager: this.keymaps });
this.packages.setMenuManager(this.menu);
this.packages.setContextMenuManager(this.contextMenu);
this.packages.setThemeManager(this.themes);
- // Public: A {Project} instance
+ /** @type {Project} */
this.project = new Project({
notificationManager: this.notifications,
packageManager: this.packages,
@@ -172,7 +172,7 @@ class AtomEnvironment {
this.commandInstaller = new CommandInstaller(this.applicationDelegate);
this.protocolHandlerInstaller = new ProtocolHandlerInstaller();
- // Public: A {TextEditorRegistry} instance
+ /** @type {TextEditorRegistry} */
this.textEditors = new TextEditorRegistry({
config: this.config,
grammarRegistry: this.grammars,
@@ -180,7 +180,7 @@ class AtomEnvironment {
packageManager: this.packages
});
- // Public: A {Workspace} instance
+ /** @type {Workspace} */
this.workspace = new Workspace({
config: this.config,
project: this.project,
@@ -215,7 +215,7 @@ class AtomEnvironment {
applicationDelegate: this.applicationDelegate
});
- // Public: A {HistoryManager} instance
+ /** @type {HistoryManager} */
this.history = new HistoryManager({
project: this.project,
commands: this.commands,
@@ -340,6 +340,12 @@ class AtomEnvironment {
);
}
+ /**
+ * @name preloadPackages
+ * @private
+ * @memberof AtomEnvironment
+ * @desc Returns output of `preloadPackages()` for this Classes Instance of `Packages`.
+ */
preloadPackages() {
return this.packages.preloadPackages();
}
@@ -470,15 +476,15 @@ class AtomEnvironment {
this.uninstallWindowEventHandler();
}
- /*
- Section: Event Subscription
- */
-
- // Extended: Invoke the given callback whenever {::beep} is called.
- //
- // * `callback` {Function} to be called whenever {::beep} is called.
- //
- // Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
+ /**
+ * @memberof AtomEnvironment
+ * @function onDidBeep
+ * @desc Invoke the given callback whenever {@link ::beep} is called.
+ * @listens ::beep
+ * @param {function} callback - Function to be called whenever {@link ::beep} is called.
+ * @returns {Disposable} on which `.dispose()` can be called to unsubscribe.
+ * @category Event Subscription
+ */
onDidBeep(callback) {
return this.emitter.on('did-beep', callback);
}
@@ -1189,11 +1195,11 @@ class AtomEnvironment {
this.packages.triggerActivationHook('core:loaded-shell-environment');
}
- /*
- Section: Messaging the User
- */
-
- // Essential: Visually and audibly trigger a beep.
+ /**
+ * Visually and audibly trigger a beep.
+ * @fires beep
+ * @category Messaging the User
+ */
beep() {
if (this.config.get('core.audioBeep'))
this.applicationDelegate.playBeepSound();
diff --git a/src/clipboard.js b/src/clipboard.js
index 9b047d7e0..2dd58ff8b 100644
--- a/src/clipboard.js
+++ b/src/clipboard.js
@@ -12,6 +12,17 @@ const { clipboard } = require('electron');
//
// console.log(atom.clipboard.read()) // 'hello'
// ```
+/**
+ * @class Clipboard
+ * @desc Represents the clipboard used for copying and pasting in Pulsar.
+ *
+ * An instance of this class is always available as the `atom.clipboard` global.
+ * @example
+ * // returns 'hello'
+ * atom.clipboard.write('hello');
+ *
+ * console.log(atom.clipboard.read());
+ */
module.exports = class Clipboard {
constructor() {
this.reset();
diff --git a/src/coffee-script.js b/src/coffee-script.js
index dcd93ca2e..508c1e244 100644
--- a/src/coffee-script.js
+++ b/src/coffee-script.js
@@ -21,9 +21,9 @@ exports.getCachePath = function(sourceCode) {
exports.compile = function(sourceCode, filePath) {
if (!CoffeeScript) {
const previousPrepareStackTrace = Error.prepareStackTrace;
- CoffeeScript = require('coffee-script');
+ CoffeeScript = require('coffeescript');
- // When it loads, coffee-script reassigns Error.prepareStackTrace. We have
+ // When it loads, coffeescript reassigns Error.prepareStackTrace. We have
// already reassigned it via the 'source-map-support' module, so we need
// to set it back.
Error.prepareStackTrace = previousPrepareStackTrace;
diff --git a/src/command-installer.js b/src/command-installer.js
index a00747a94..384e54324 100644
--- a/src/command-installer.js
+++ b/src/command-installer.js
@@ -60,8 +60,8 @@ module.exports = class CommandInstaller {
installAtomCommand(askForPrivilege, callback) {
this.installCommand(
- path.join(this.getResourcesDirectory(), 'app', 'pulsar.sh'),
- this.getCommandNameForChannel('pulsar'),
+ path.join(this.getResourcesDirectory(), 'pulsar.sh'),
+ 'pulsar',
askForPrivilege,
callback
);
@@ -72,12 +72,11 @@ module.exports = class CommandInstaller {
path.join(
this.getResourcesDirectory(),
'app',
- 'apm',
- 'node_modules',
- '.bin',
+ 'ppm',
+ 'bin',
'apm'
),
- this.getCommandNameForChannel('apm'),
+ 'ppm',
askForPrivilege,
callback
);
diff --git a/src/config-file.js b/src/config-file.js
index 6b4a53d3e..cee35b442 100644
--- a/src/config-file.js
+++ b/src/config-file.js
@@ -92,8 +92,8 @@ module.exports = class ConfigFile {
On linux there are currently problems with watch sizes.
See [this document][watches] for more info.
- [watches]:https://github.com/atom/atom/blob/master/docs/build-instructions/linux.md#typeerror-unable-to-watch-path\
- `
+ [watches]:https://pulsar-edit.dev/docs/atom-archive/hacking-atom/#typeerror-unable-to-watch-path
+ `//TODO: Update the above to the pulsar docs if we choose to add this
);
return new Disposable();
}
diff --git a/src/config-schema.js b/src/config-schema.js
index e814c81bc..10ebc690b 100644
--- a/src/config-schema.js
+++ b/src/config-schema.js
@@ -1,5 +1,5 @@
// This is loaded by atom-environment.coffee. See
-// https://atom.io/docs/api/latest/Config for more information about config
+// https://atom.io/docs/api/latest/Config for more information about config TODO: Link to Pulsar API site when documented
// schemas.
const configSchema = {
core: {
@@ -312,7 +312,7 @@ const configSchema = {
enum: ['no', 'yes', 'always'],
default: 'yes',
description:
- "When selected 'no', a blank environment is loaded. When selected 'yes' and Pulsar is started from the icon or `atom` by itself from the command line, restores the last state of all Pulsar windows; otherwise a blank environment is loaded. When selected 'always', restores the last state of all Pulsar windows always, no matter how Pulsar is started."
+ "When selected 'no', a blank environment is loaded. When selected 'yes' and Pulsar is started from the icon or `pulsar` by itself from the command line, restores the last state of all Pulsar windows; otherwise a blank environment is loaded. When selected 'always', restores the last state of all Pulsar windows always, no matter how Pulsar is started."
},
reopenProjectMenuCount: {
description:
@@ -322,14 +322,14 @@ const configSchema = {
},
automaticallyUpdate: {
description:
- 'Automatically update Pulsar when a new release is available.',
+ 'Automatically update Pulsar when a new release is available. **Note**: Currently not functional, please download new releases from [pulsar-edit.dev](https://pulsar-edit.dev/download.html)',
type: 'boolean',
- default: true
+ default: false
},
useProxySettingsWhenCallingApm: {
- title: 'Use Proxy Settings When Calling APM',
+ title: 'Use Proxy Settings When Calling PPM',
description:
- 'Use detected proxy settings when calling the `apm` command-line tool.',
+ 'Use detected proxy settings when calling the `pulsar -p` or `ppm` command-line tool.',
type: 'boolean',
default: true
},
@@ -594,7 +594,7 @@ const configSchema = {
type: 'boolean',
default: true,
description:
- 'Add multiple cursors when pressing the Ctrl key (Command key on MacOS) and clicking the editor.'
+ 'Add multiple cursors when pressing the Ctrl key (Command key on macOS) and clicking the editor.'
}
}
}
@@ -621,7 +621,7 @@ if (process.platform === 'darwin') {
type: 'boolean',
default: false,
description:
- 'Use pre-Lion fullscreen on macOS. This does not create a new desktop space for the atom on fullscreen mode.'
+ 'Use pre-Lion fullscreen on macOS. This does not create a new desktop space for Pulsar on fullscreen mode.'
};
}
diff --git a/src/config.js b/src/config.js
index 596398e47..2e6f98841 100644
--- a/src/config.js
+++ b/src/config.js
@@ -79,7 +79,7 @@ const schemaEnforcers = {};
// # ...
// ```
//
-// See [package docs](http://flight-manual.atom.io/hacking-atom/sections/package-word-count/) for
+// See [package docs](https://pulsar-edit.dev/docs/launch-manual/sections/core-hacking/#package-word-count) for
// more info.
//
// ## Config Schemas
@@ -329,7 +329,7 @@ const schemaEnforcers = {};
//
// * **bold** - `**bold**`
// * *italics* - `*italics*`
-// * [links](https://atom.io) - `[links](https://atom.io)`
+// * [links](https://pulsar-edit.dev) - `[links](https://pulsar-edit.dev)`
// * `code spans` - `` `code spans` ``
// * line breaks - `line breaks `
// * ~~strikethrough~~ - `~~strikethrough~~`
@@ -487,7 +487,7 @@ class Config {
// * `scope` (optional) {ScopeDescriptor} describing a path from
// the root of the syntax tree to a token. Get one by calling
// {editor.getLastCursor().getScopeDescriptor()}. See {::get} for examples.
- // See [the scopes docs](http://flight-manual.atom.io/behind-atom/sections/scoped-settings-scopes-and-scope-descriptors/)
+ // See [the scopes docs](https://pulsar-edit.dev/docs/launch-manual/sections/behind-pulsar#scoped-settings-scopes-and-scope-descriptors)
// for more information.
// * `callback` {Function} to call when the value of the key changes.
// * `value` the new value of the key
@@ -531,7 +531,7 @@ class Config {
// * `scope` (optional) {ScopeDescriptor} describing a path from
// the root of the syntax tree to a token. Get one by calling
// {editor.getLastCursor().getScopeDescriptor()}. See {::get} for examples.
- // See [the scopes docs](http://flight-manual.atom.io/behind-atom/sections/scoped-settings-scopes-and-scope-descriptors/)
+ // See [the scopes docs](https://pulsar-edit.dev/docs/launch-manual/sections/behind-pulsar#scoped-settings-scopes-and-scope-descriptors)
// for more information.
// * `callback` {Function} to call when the value of the key changes.
// * `event` {Object}
@@ -613,7 +613,7 @@ class Config {
// * `scope` (optional) {ScopeDescriptor} describing a path from
// the root of the syntax tree to a token. Get one by calling
// {editor.getLastCursor().getScopeDescriptor()}
- // See [the scopes docs](http://flight-manual.atom.io/behind-atom/sections/scoped-settings-scopes-and-scope-descriptors/)
+ // See [the scopes docs](https://pulsar-edit.dev/docs/launch-manual/sections/behind-pulsar#scoped-settings-scopes-and-scope-descriptors)
// for more information.
//
// Returns the value from Pulsar's default settings, the user's configuration
@@ -720,7 +720,7 @@ class Config {
// setting to the default value.
// * `options` (optional) {Object}
// * `scopeSelector` (optional) {String}. eg. '.source.ruby'
- // See [the scopes docs](http://flight-manual.atom.io/behind-atom/sections/scoped-settings-scopes-and-scope-descriptors/)
+ // See [the scopes docs](https://pulsar-edit.dev/docs/launch-manual/sections/behind-pulsar#scoped-settings-scopes-and-scope-descriptors)
// for more information.
// * `source` (optional) {String} The name of a file with which the setting
// is associated. Defaults to the user's config file.
diff --git a/src/keymap-extensions.js b/src/keymap-extensions.js
index 36fcd190e..9fdbe2b21 100644
--- a/src/keymap-extensions.js
+++ b/src/keymap-extensions.js
@@ -61,7 +61,7 @@ KeymapManager.prototype.loadUserKeymap = function() {
On linux there are currently problems with watch sizes. See \
[this document][watches] for more info. \
- [watches]:https://github.com/atom/atom/blob/master/docs/build-instructions/linux.md#typeerror-unable-to-watch-path`;
+ [watches]:https://pulsar-edit.dev/docs/atom-archive/hacking-atom/#typeerror-unable-to-watch-path`; //TODO: Update the above to Pulsar docs if we choose to add this
this.notificationManager.addError(message, {dismissable: true});
}
else {
diff --git a/src/main-process/atom-application.js b/src/main-process/atom-application.js
index 3c25c7a06..e9ff0df4d 100644
--- a/src/main-process/atom-application.js
+++ b/src/main-process/atom-application.js
@@ -39,17 +39,6 @@ const LocationSuffixRegExp = /(:\d+)(:\d+)?$/;
// incompatible way.
const APPLICATION_STATE_VERSION = '1';
-const getDefaultPath = () => {
- const editor = atom.workspace.getActiveTextEditor();
- if (!editor || !editor.getPath()) {
- return;
- }
- const paths = atom.project.getPaths();
- if (paths) {
- return paths[0];
- }
-};
-
const getSocketSecretPath = applicationVersion => {
const { username } = os.userInfo();
const atomHome = path.resolve(process.env.ATOM_HOME);
@@ -599,7 +588,7 @@ module.exports = class AtomApplication extends EventEmitter {
shell.openExternal('https://pulsar-edit.dev/docs/launch-manual/sections/faq/')
);
this.on('application:open-terms-of-use', () =>
- shell.openExternal('https://atom.io/terms')
+ shell.openExternal('https://atom.io/terms') //TODO: This needs to be updated for when we have our own published on the site
);
this.on('application:report-issue', () =>
shell.openExternal(
@@ -632,25 +621,37 @@ module.exports = class AtomApplication extends EventEmitter {
});
this.on('application:open', () => {
- this.promptForPathToOpen(
- 'all',
- createOpenSettings({ sameWindow: true }),
- getDefaultPath()
- );
+ const win = this.focusedWindow();
+ if(win) {
+ win.sendCommand('application:open')
+ } else {
+ this.promptForPathToOpen(
+ 'all',
+ createOpenSettings({ sameWindow: true })
+ );
+ }
});
this.on('application:open-file', () => {
- this.promptForPathToOpen(
- 'file',
- createOpenSettings({ sameWindow: true }),
- getDefaultPath()
- );
+ const win = this.focusedWindow();
+ if(win) {
+ win.sendCommand('application:open-file')
+ } else {
+ this.promptForPathToOpen(
+ 'file',
+ createOpenSettings({ sameWindow: true })
+ );
+ }
});
this.on('application:open-folder', () => {
- this.promptForPathToOpen(
- 'folder',
- createOpenSettings({ sameWindow: true }),
- getDefaultPath()
- );
+ const win = this.focusedWindow();
+ if(win) {
+ win.sendCommand('application:open-folder')
+ } else {
+ this.promptForPathToOpen(
+ 'folder',
+ createOpenSettings({ sameWindow: true })
+ );
+ }
});
this.on('application:bring-all-windows-to-front', () =>
diff --git a/src/main-process/atom-window.js b/src/main-process/atom-window.js
index 39d49d8e8..cf180e3b4 100644
--- a/src/main-process/atom-window.js
+++ b/src/main-process/atom-window.js
@@ -263,7 +263,7 @@ module.exports = class AtomWindow extends EventEmitter {
buttons: ['Close Window', 'Reload', 'Keep It Open'],
cancelId: 2, // Canceling should be the least destructive action
message: 'The editor has crashed',
- detail: 'Please report this issue to https://github.com/atom/atom'
+ detail: 'Please report this issue to https://github.com/pulsar-edit/pulsar'
});
switch (result.response) {
diff --git a/src/main-process/main.js b/src/main-process/main.js
index cc195d102..95d88329d 100644
--- a/src/main-process/main.js
+++ b/src/main-process/main.js
@@ -39,9 +39,10 @@ if (args.resourcePath) {
} else {
const stableResourcePath = path.dirname(path.dirname(__dirname));
const defaultRepositoryPath = path.join(
+ // Setting the path for the app
app.getPath('home'),
'github',
- 'atom'
+ 'pulsar'
);
if (process.env.ATOM_DEV_RESOURCE_PATH) {
diff --git a/src/main-process/parse-command-line.js b/src/main-process/parse-command-line.js
index 80d7f8197..6eace2f15 100644
--- a/src/main-process/parse-command-line.js
+++ b/src/main-process/parse-command-line.js
@@ -149,7 +149,12 @@ module.exports = function parseCommandLine(processArgs) {
const PackageManager = require('../package-manager');
const cp = require('child_process');
const ppmPath = PackageManager.possibleApmPaths();
- const ppmArgs = args['_'];
+
+ let ppmArgs = [...processArgs]
+ while(true) {
+ const arg = ppmArgs.shift()
+ if(arg === '-p' || arg === '--package' || ppmArgs.length === 0) break;
+ }
const exitCode = cp.spawnSync(ppmPath, ppmArgs, {stdio: 'inherit'}).status;
process.exit(exitCode);
return;
@@ -190,7 +195,7 @@ module.exports = function parseCommandLine(processArgs) {
`Only one of the --add and --new-window options may be specified at the same time.\n\n${options.help()}`
);
- // Exiting the main process with a nonzero exit code on MacOS causes the app open to fail with the mysterious
+ // Exiting the main process with a nonzero exit code on macOS causes the app open to fail with the mysterious
// message "LSOpenURLsWithRole() failed for the application /Applications/Pulsar Dev.app with error -10810."
process.exit(0);
}
diff --git a/src/main-process/start.js b/src/main-process/start.js
index cad16904e..303c7a5ab 100644
--- a/src/main-process/start.js
+++ b/src/main-process/start.js
@@ -75,7 +75,7 @@ module.exports = function start(resourcePath, devResourcePath, startTime) {
}
const releaseChannel = getReleaseChannel(app.getVersion());
- let appUserModelId = 'com.squirrel.atom.' + process.arch;
+ let appUserModelId = 'dev.pulsar-edit.pulsar.' + process.arch;
// If the release channel is not stable, we append it to the app user model id.
// This allows having the different release channels as separate items in the taskbar.
diff --git a/src/overlay-manager.js b/src/overlay-manager.js
deleted file mode 100644
index 4e669a051..000000000
--- a/src/overlay-manager.js
+++ /dev/null
@@ -1,85 +0,0 @@
-const ElementResizeDetector = require('element-resize-detector');
-
-var elementResizeDetector = null;
-
-module.exports = class OverlayManager {
-
- constructor(presenter, container, views) {
- this.presenter = presenter;
- this.container = container;
- this.views = views;
- this.overlaysById = {};
- }
-
- render(state) {
- for (let decorationId in state.content.overlays) {
- const overlay = state.content.overlays[decorationId];
- if (this.shouldUpdateOverlay(decorationId, overlay)) {
- this.renderOverlay(state, decorationId, overlay);
- }
- }
- for (let id in this.overlaysById) {
- const {overlayNode} = this.overlaysById[id];
- if (!state.content.overlays.hasOwnProperty(id)) {
- delete this.overlaysById[id];
- overlayNode.remove();
- }
- }
- }
-
- shouldUpdateOverlay(decorationId, overlay) {
- const cachedOverlay = this.overlaysById[decorationId];
- if (cachedOverlay == null || cachedOverlay.pixelPosition == null) {
- return true;
- }
- let cacheTop, cacheLeft, top, left;
- if (cachedOverlay.pixelPosition != null) {
- cacheTop = cachedOverlay.pixelPosition.top;
- cacheLeft = cachedOverlay.pixelPosition.left;
- }
- if (overlay.pixelPosition == null) {
- {top, left} = overlay.pixelPosition;
- }
- return cacheTop != top || cacheLeft != left;
- }
-
- measureOverlay(decorationId, itemView) {
- const contentMargin = parseInt(getComputedStyle(itemView)['margin-left']) || 0;
- this.presenter.setOverlayDimensions(decorationId, itemView.offsetWidth, itemView.offsetHeight, contentMargin);
- }
-
- renderOverlay(state, decorationId, { item, pixelPosition, class: klass}) {
- let overlayNode;
- const itemView = this.views.getView(item);
- let cachedOverlay = this.overlaysById[decorationId];
- if (cachedOverlay != null && cachedOverlay.overlayNode != null) {
- overlayNode = cachedOverlay.overlayNode
- }
- else {
- overlayNode = document.createElement('atom-overlay');
- if (klass != null) {
- overlayNode.classList.add(klass);
- }
- if (elementResizeDetector == null) {
- elementResizeDetector = ElementResizeDetector({strategy: 'scroll'});
- }
- elementResizeDetector.listenTo(overlayNode, () => {
- if (overlayNode.parentElement != null) {
- this.measureOverlay(decorationId, itemView);
- }
- });
- this.container.appendChild(overlayNode);
- this.overlaysById[decorationId] = cachedOverlay = {overlayNode, itemView};
- }
- if (!overlayNode.contains(itemView)) {
- // The same node may be used in more than one overlay. This steals the node
- // back if it has been displayed in another overlay.
- overlayNode.appendChild(itemView);
- }
- cachedOverlay.pixelPosition = pixelPosition;
- overlayNode.style.top = pixelPosition.top + 'px';
- overlayNode.style.left = pixelPosition.left + 'px';
- this.measureOverlay(decorationId, itemView);
- }
-
-};
diff --git a/src/package.js b/src/package.js
index c567a4573..24b4fbfa3 100644
--- a/src/package.js
+++ b/src/package.js
@@ -897,7 +897,7 @@ module.exports = class Package {
Failed to require the main module of '${
this.name
}' because it requires one or more incompatible native modules (${nativeModuleNames}).
- Run \`apm rebuild\` in the package directory and restart Pulsar to resolve.\
+ Run \`pulsar -p rebuild\` in the package directory and restart Pulsar to resolve.\
`);
} else {
const mainModulePath = this.getMainModulePath();
@@ -1252,7 +1252,7 @@ module.exports = class Package {
//
// Returns a {Promise} that resolves with an object containing `code`,
// `stdout`, and `stderr` properties based on the results of running
- // `apm rebuild` on the package.
+ // `pulsar -p rebuild` on the package.
rebuild() {
return new Promise(resolve =>
this.runRebuildProcess(result => {
diff --git a/src/scope-descriptor.js b/src/scope-descriptor.js
index 111ce5676..6dcfed402 100644
--- a/src/scope-descriptor.js
+++ b/src/scope-descriptor.js
@@ -15,7 +15,7 @@
// specific position in the buffer.
// * {Cursor::getScopeDescriptor} to get a cursor's descriptor based on position.
//
-// See the [scopes and scope descriptor guide](http://flight-manual.atom.io/behind-atom/sections/scoped-settings-scopes-and-scope-descriptors/)
+// See the [scopes and scope descriptor guide](https://pulsar-edit.dev/docs/launch-manual/sections/behind-pulsar#scoped-settings-scopes-and-scope-descriptors)
// for more information.
module.exports = class ScopeDescriptor {
static fromObject(scopes) {
diff --git a/src/special-token-symbols.js b/src/special-token-symbols.js
deleted file mode 100644
index 06884b85f..000000000
--- a/src/special-token-symbols.js
+++ /dev/null
@@ -1,6 +0,0 @@
-module.exports = {
- SoftTab: Symbol('SoftTab')
- HardTab: Symbol('HardTab')
- PairedCharacter: Symbol('PairedCharacter')
- SoftWrapIndent: Symbol('SoftWrapIndent')
-}
diff --git a/src/test.ejs b/src/test.ejs
deleted file mode 100644
index 7b93c31b3..000000000
--- a/src/test.ejs
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-<% if something() { %>
-
- <%= html `ok how about this ` %>
-
-<% } %>
-
-
diff --git a/src/theme-manager.js b/src/theme-manager.js
index a25d08937..c520f1bc8 100644
--- a/src/theme-manager.js
+++ b/src/theme-manager.js
@@ -244,8 +244,8 @@ you have permissions to \`${userStylesheetPath}\`.
On linux there are currently problems with watch sizes. See
[this document][watches] for more info.
-[watches]:https://github.com/atom/atom/blob/master/docs/build-instructions/linux.md#typeerror-unable-to-watch-path\
-`;
+[watches]:https://pulsar-edit.dev/docs/atom-archive/hacking-atom/#typeerror-unable-to-watch-path
+`; //TODO: Update the above to Pulsar docs if we choose to add this
this.notificationManager.addError(message, { dismissable: true });
}
diff --git a/static/core-ui/text-editor.less b/static/core-ui/text-editor.less
index 8106db9eb..d1b25729d 100644
--- a/static/core-ui/text-editor.less
+++ b/static/core-ui/text-editor.less
@@ -98,6 +98,10 @@ atom-text-editor {
z-index: -1;
}
+ .selection .region {
+ background-color: @syntax-selection-color;
+ }
+
.line {
white-space: pre;
contain: @contain_except_size;