[Pkg-javascript-commits] [node-external-editor] 01/10: Import Upstream version 2.0.1
Paolo Greppi
paolog-guest at moszumanska.debian.org
Mon Dec 19 11:44:48 UTC 2016
This is an automated email from the git hooks/post-receive script.
paolog-guest pushed a commit to branch master
in repository node-external-editor.
commit 7c936fbce613eab6c7282dd4395f3fcd457740b7
Author: Paolo Greppi <paolo.greppi at libpf.com>
Date: Fri Dec 16 18:08:14 2016 +0000
Import Upstream version 2.0.1
---
.coffeelint.json | 135 ++++++++++++++++++++
.editorconfig | 13 ++
.gitignore | 39 ++++++
.release.json | 8 ++
.travis.yml | 9 ++
LICENSE | 21 ++++
README.md | 143 ++++++++++++++++++++++
example_async.js | 40 ++++++
example_sync.js | 34 ++++++
main/errors/CreateFileError.js | 29 +++++
main/errors/LaunchEditorError.js | 29 +++++
main/errors/ReadFileError.js | 29 +++++
main/errors/RemoveFileError.js | 29 +++++
main/index.js | 208 +++++++++++++++++++++++++++++++
package.json | 45 +++++++
src/errors/CreateFileError.coffee | 11 ++
src/errors/LaunchEditorError.coffee | 11 ++
src/errors/ReadFileError.coffee | 11 ++
src/errors/RemoveFileError.coffee | 11 ++
src/index.coffee | 109 +++++++++++++++++
test/spec/main.coffee | 48 ++++++++
yarn.lock | 237 ++++++++++++++++++++++++++++++++++++
22 files changed, 1249 insertions(+)
diff --git a/.coffeelint.json b/.coffeelint.json
new file mode 100644
index 0000000..5aa4030
--- /dev/null
+++ b/.coffeelint.json
@@ -0,0 +1,135 @@
+{
+ "arrow_spacing": {
+ "level": "error"
+ },
+ "braces_spacing": {
+ "level": "error",
+ "spaces": 0,
+ "empty_object_spaces": 0
+ },
+ "camel_case_classes": {
+ "level": "error"
+ },
+ "coffeescript_error": {
+ "level": "error"
+ },
+ "colon_assignment_spacing": {
+ "level": "ignore",
+ "spacing": {
+ "left": 0,
+ "right": 0
+ }
+ },
+ "cyclomatic_complexity": {
+ "level": "ignore",
+ "value": 10
+ },
+ "duplicate_key": {
+ "level": "error"
+ },
+ "empty_constructor_needs_parens": {
+ "level": "ignore"
+ },
+ "ensure_comprehensions": {
+ "level": "warn"
+ },
+ "eol_last": {
+ "level": "error"
+ },
+ "indentation": {
+ "value": 2,
+ "level": "error"
+ },
+ "line_endings": {
+ "level": "error",
+ "value": "unix"
+ },
+ "max_line_length": {
+ "value": 80,
+ "level": "ignore",
+ "limitComments": true
+ },
+ "missing_fat_arrows": {
+ "level": "ignore",
+ "is_strict": false
+ },
+ "newlines_after_classes": {
+ "value": 3,
+ "level": "ignore"
+ },
+ "no_backticks": {
+ "level": "error"
+ },
+ "no_debugger": {
+ "level": "error",
+ "console": false
+ },
+ "no_empty_functions": {
+ "level": "ignore"
+ },
+ "no_empty_param_list": {
+ "level": "ignore"
+ },
+ "no_implicit_braces": {
+ "level": "ignore",
+ "strict": true
+ },
+ "no_implicit_parens": {
+ "level": "ignore",
+ "strict": true
+ },
+ "no_interpolation_in_single_quotes": {
+ "level": "error"
+ },
+ "no_nested_string_interpolation": {
+ "level": "warn"
+ },
+ "no_plusplus": {
+ "level": "ignore"
+ },
+ "no_private_function_fat_arrows": {
+ "level": "warn"
+ },
+ "no_stand_alone_at": {
+ "level": "ignore"
+ },
+ "no_tabs": {
+ "level": "error"
+ },
+ "no_this": {
+ "level": "error"
+ },
+ "no_throwing_strings": {
+ "level": "error"
+ },
+ "no_trailing_semicolons": {
+ "level": "error"
+ },
+ "no_trailing_whitespace": {
+ "level": "error",
+ "allowed_in_comments": false,
+ "allowed_in_empty_lines": true
+ },
+ "no_unnecessary_double_quotes": {
+ "level": "error"
+ },
+ "no_unnecessary_fat_arrows": {
+ "level": "warn"
+ },
+ "non_empty_constructor_needs_parens": {
+ "level": "ignore"
+ },
+ "prefer_english_operator": {
+ "level": "ignore",
+ "doubleNotLevel": "ignore"
+ },
+ "space_operators": {
+ "level": "error"
+ },
+ "spacing_after_comma": {
+ "level": "error"
+ },
+ "transform_messes_up_line_numbers": {
+ "level": "warn"
+ }
+}
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..6aea837
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,13 @@
+root = true
+
+[*]
+charset = utf-8
+end_of_line = lf
+indent_style = space
+indent_size = 2
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+[*.md]
+trim_trailing_whitespace = false
+indent_size = 4
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..edcf2d7
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,39 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+
+# Runtime data
+pids
+*.pid
+*.seed
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+
+# nyc test coverage
+.nyc_output
+
+# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons (http://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directories
+node_modules
+jspm_packages
+
+# Optional npm cache directory
+.npm
+
+# Optional REPL history
+.node_repl_history
+
+.idea
\ No newline at end of file
diff --git a/.release.json b/.release.json
new file mode 100644
index 0000000..65c302a
--- /dev/null
+++ b/.release.json
@@ -0,0 +1,8 @@
+{
+ "pre_commit_commands": [
+ "npm test"
+ ],
+ "post_complete_commands": [
+ "npm publish"
+ ]
+}
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..d4e22d3
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,9 @@
+sudo: false
+node_js:
+ - 7
+ - 6
+ - 5
+ - 4
+ - .12
+language: node_js
+script: npm test
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..f5f6185
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 Kevin Gravier
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..a85db22
--- /dev/null
+++ b/README.md
@@ -0,0 +1,143 @@
+# External Editor
+
+[![ExternalEditor on Travis CI](https://img.shields.io/travis/mrkmg/node-external-editor.svg?style=flat-square)](https://travis-ci.org/mrkmg/node-external-editor/branches)
+[![ExternalEditor on NPM](https://img.shields.io/npm/v/external-editor.svg?style=flat-square)](https://www.npmjs.com/package/external-editor)
+[![ExternalEditor uses the MIT](https://img.shields.io/npm/l/external-editor.svg?style=flat-square)](https://opensource.org/licenses/MIT)
+
+
+A node module to edit a string with a users preferred text editor using $VISUAL or $ENVIRONMENT.
+
+Version: 2.0.1
+
+As of version 2.0.0, node 0.10 is no longer support. Minimum node version is now 0.12.
+
+##Install
+
+`npm install external-editor --save`
+
+##Usage
+
+A simple example using the `.edit` convenience method
+
+ var ExternalEditor = require('external-editor')
+ var data = ExternalEditor.edit('\n\n# Please write your text above');
+ console.log(data);
+
+A full featured example
+
+ var ExternalEditor = require('external-editor');
+
+ try {
+ var editor = new ExternalEditor();
+ var text = editor.run()
+ // the text is also available in editor.text
+ } catch (err) {
+ if (err instanceOf ExternalEditor.CreateFileError) {
+ console.log('Failed to create the temporary file');
+ } else if (err instanceOf ExternalEditor.ReadFileError) {
+ console.log('Failed to read the temporary file');
+ } else if (err instanceOf ExternalEditor.LaunchEditorError) {
+ console.log('Failed to launch your editor');
+ } else {
+ throw err;
+ }
+ }
+
+ // Do things with the text
+
+ // Eventually call the cleanup to remove the temporary file
+ try {
+ editor.cleanup();
+ } catch (err) {
+ if (err instanceOf ExternalEditor.RemoveFileError) {
+ console.log('Failed to remove the temporary file');
+ } else {
+ throw err
+ }
+ }
+
+
+####API
+**Static Methods**
+- `edit(text)`
+ - `text` (string) *Optional* Defaults to empty string
+ - **Returns** (string) The contents of the file
+ - Could throw `CreateFileError`, `ReadFileError`, or `LaunchEditorError`, or `RemoveFileError`
+- `editAsync(text, callback)`
+ - `text` (string) *Optional* Defaults to empty string
+ - `callback` (function (error, text))
+ - `error` could be of type `CreateFileError`, `ReadFileError`, or `LaunchEditorError`, or `RemoveFileError`
+ - `text`(string) The contents of the file
+
+
+**Static Properties**
+- `CreateFileError` Error thrown if the temporary file could not be created.
+- `ReadFileError` Error thrown if the temporary file could not be read.
+- `RemoveFileError` Error thrown if the temporary file could not be removed during cleanup.
+- `LaunchEditorError` Error thrown if the editor could not be launched.
+
+**Public Methods**
+- `new ExternalEditor(text)`
+ - `text` (string) *Optional* Defaults to empty string
+ - Could throw `CreateFileError`
+- `run()` Launches the editor.
+ - **Returns** (string) The contents of the file
+ - Could throw `LaunchEditorError` or `ReadFileError`
+- `runAsync(callback)` Launches the editor in an async way
+ - `callback` (function (error, text))
+ - `error` could be of type `ReadFileError` or `LaunchEditorError`
+ - `text`(string) The contents of the file
+- `cleanup()` Removes the temporary file.
+ - Could throw `RemoveFileError`
+
+**Public Properties**
+- `text` (string) *readonly* The text in the temporary file.
+- `editor.bin` (string) The editor determined from the environment.
+- `editor.args` (array) Default arguments for the bin
+- `temp_file` (string) Path to temporary file. Can be changed, but be careful as the temporary file probably already
+ exists and would need be removed manually.
+
+##Errors
+
+All errors have a simple message explaining what went wrong. They all also have an `original_error` property containing
+the original error thrown for debugging purposes.
+
+##Why Synchronous?
+
+Everything is synchronous to make sure the editor has complete control of the stdin and stdout. Testing has shown
+async launching of the editor can lead to issues when using readline or other packages which try to read from stdin or
+write to stdout. Seeing as this will be used in an interactive CLI environment, I made the decision to force the package
+to be synchronous. If you know a reliable way to force all stdin and stdout to be limited only to the child_process,
+please submit a PR.
+
+If async is really needed, you can use `editAsync` or `runAsync`. If you are using readline or have anything else
+listening to the stdin or you write to stdout, you will most likely have problem, so make sure to remove any other
+listeners on stdin, stdout, or stdin.
+
+##Demo
+
+[![asciicast](https://asciinema.org/a/a1qh9lypbe65mj0ivfuoslz2s.png)](https://asciinema.org/a/a1qh9lypbe65mj0ivfuoslz2s)
+
+##License
+
+The MIT License (MIT)
+
+Copyright (c) 2016 Kevin Gravier
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/example_async.js b/example_async.js
new file mode 100644
index 0000000..025356c
--- /dev/null
+++ b/example_async.js
@@ -0,0 +1,40 @@
+var ExternalEditor = require('./main');
+var readline = require('readline');
+
+var rl = readline.createInterface({
+ input: process.stdin,
+ output: null
+});
+
+var message = '\n\n# Please Write a message\n# Any line starting with # is ignored';
+
+process.stdout.write('Please write a message. (press enter to launch your preferred editor)');
+
+editor = new ExternalEditor(message);
+
+rl.on('line', function () {
+ try {
+ rl.pause();
+ editor.runAsync(function (error, response)
+ {
+ if (error) {
+ process.stdout.write(error.message);
+ process.exit(1);
+ }
+ if (response.length === 0) {
+ readline.moveCursor(process.stdout, 0, -1);
+ process.stdout.write('Your message was empty, please try again. (press enter to launch your preferred editor)');
+ rl.resume();
+ } else {
+ process.stdout.write('Your Message:\n');
+ process.stdout.write(response);
+ process.stdout.write('\n');
+ rl.close();
+ }
+ });
+ } catch (err) {
+ process.stderr.write(err.message);
+ process.stdout.write('\n');
+ rl.close();
+ }
+});
diff --git a/example_sync.js b/example_sync.js
new file mode 100644
index 0000000..138f230
--- /dev/null
+++ b/example_sync.js
@@ -0,0 +1,34 @@
+var ExternalEditor = require('./main');
+var readline = require('readline');
+
+var rl = readline.createInterface({
+ input: process.stdin,
+ output: null
+});
+
+var message = '\n\n# Please Write a message\n# Any line starting with # is ignored';
+
+process.stdout.write('Please write a message. (press enter to launch your preferred editor)');
+
+editor = new ExternalEditor(message);
+
+rl.on('line', function () {
+ try {
+ // Get response, remove all lines starting with #, remove any trailing newlines.
+ var response = editor.run().replace(/^#.*\n?/gm, '').replace(/\n+$/g, '').trim();
+
+ if (response.length === 0) {
+ readline.moveCursor(process.stdout, 0, -1);
+ process.stdout.write('Your message was empty, please try again. (press enter to launch your preferred editor)');
+ } else {
+ process.stdout.write('Your Message:\n');
+ process.stdout.write(response);
+ process.stdout.write('\n');
+ rl.close();
+ }
+ } catch (err) {
+ process.stderr.write(err.message);
+ process.stdout.write('\n');
+ rl.close();
+ }
+});
diff --git a/main/errors/CreateFileError.js b/main/errors/CreateFileError.js
new file mode 100644
index 0000000..e13bec5
--- /dev/null
+++ b/main/errors/CreateFileError.js
@@ -0,0 +1,29 @@
+// Generated by CoffeeScript 1.12.0
+
+/*
+ ExternalEditor
+ Kevin Gravier <kevin at mrkmg.com>
+ MIT
+ */
+
+(function() {
+ var CreateFileError,
+ extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
+ hasProp = {}.hasOwnProperty;
+
+ CreateFileError = (function(superClass) {
+ extend(CreateFileError, superClass);
+
+ CreateFileError.prototype.message = 'Failed to create temporary file for editor';
+
+ function CreateFileError(original_error) {
+ this.original_error = original_error;
+ }
+
+ return CreateFileError;
+
+ })(Error);
+
+ module.exports = CreateFileError;
+
+}).call(this);
diff --git a/main/errors/LaunchEditorError.js b/main/errors/LaunchEditorError.js
new file mode 100644
index 0000000..731e4a4
--- /dev/null
+++ b/main/errors/LaunchEditorError.js
@@ -0,0 +1,29 @@
+// Generated by CoffeeScript 1.12.0
+
+/*
+ ExternalEditor
+ Kevin Gravier <kevin at mrkmg.com>
+ MIT
+ */
+
+(function() {
+ var LaunchEditorError,
+ extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
+ hasProp = {}.hasOwnProperty;
+
+ LaunchEditorError = (function(superClass) {
+ extend(LaunchEditorError, superClass);
+
+ LaunchEditorError.prototype.message = 'Failed launch editor';
+
+ function LaunchEditorError(original_error) {
+ this.original_error = original_error;
+ }
+
+ return LaunchEditorError;
+
+ })(Error);
+
+ module.exports = LaunchEditorError;
+
+}).call(this);
diff --git a/main/errors/ReadFileError.js b/main/errors/ReadFileError.js
new file mode 100644
index 0000000..af27934
--- /dev/null
+++ b/main/errors/ReadFileError.js
@@ -0,0 +1,29 @@
+// Generated by CoffeeScript 1.12.0
+
+/*
+ ExternalEditor
+ Kevin Gravier <kevin at mrkmg.com>
+ MIT
+ */
+
+(function() {
+ var ReadFileError,
+ extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
+ hasProp = {}.hasOwnProperty;
+
+ ReadFileError = (function(superClass) {
+ extend(ReadFileError, superClass);
+
+ ReadFileError.prototype.message = 'Failed to read temporary file';
+
+ function ReadFileError(original_error) {
+ this.original_error = original_error;
+ }
+
+ return ReadFileError;
+
+ })(Error);
+
+ module.exports = ReadFileError;
+
+}).call(this);
diff --git a/main/errors/RemoveFileError.js b/main/errors/RemoveFileError.js
new file mode 100644
index 0000000..80023ec
--- /dev/null
+++ b/main/errors/RemoveFileError.js
@@ -0,0 +1,29 @@
+// Generated by CoffeeScript 1.12.0
+
+/*
+ ExternalEditor
+ Kevin Gravier <kevin at mrkmg.com>
+ MIT
+ */
+
+(function() {
+ var RemoveFileError,
+ extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
+ hasProp = {}.hasOwnProperty;
+
+ RemoveFileError = (function(superClass) {
+ extend(RemoveFileError, superClass);
+
+ RemoveFileError.prototype.message = 'Failed to cleanup temporary file';
+
+ function RemoveFileError(original_error) {
+ this.original_error = original_error;
+ }
+
+ return RemoveFileError;
+
+ })(Error);
+
+ module.exports = RemoveFileError;
+
+}).call(this);
diff --git a/main/index.js b/main/index.js
new file mode 100644
index 0000000..d2c4c8d
--- /dev/null
+++ b/main/index.js
@@ -0,0 +1,208 @@
+// Generated by CoffeeScript 1.12.0
+
+/*
+ ExternalEditor
+ Kevin Gravier <kevin at mrkmg.com>
+ MIT
+ */
+
+(function() {
+ var CreateFileError, ExternalEditor, FS, LaunchEditorError, ReadFileError, RemoveFileError, Spawn, SpawnSync, Temp,
+ bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
+
+ FS = require('fs');
+
+ Temp = require('tmp');
+
+ SpawnSync = require('child_process').spawnSync;
+
+ Spawn = require('child_process').spawn;
+
+ CreateFileError = require('./errors/CreateFileError');
+
+ ReadFileError = require('./errors/ReadFileError');
+
+ RemoveFileError = require('./errors/RemoveFileError');
+
+ LaunchEditorError = require('./errors/LaunchEditorError');
+
+ ExternalEditor = (function() {
+ ExternalEditor.edit = function(text) {
+ var editor;
+ if (text == null) {
+ text = '';
+ }
+ editor = new ExternalEditor(text);
+ editor.run();
+ editor.cleanup();
+ return editor.text;
+ };
+
+ ExternalEditor.editAsync = function(text, callback) {
+ var editor;
+ if (text == null) {
+ text = '';
+ }
+ editor = new ExternalEditor(text);
+ return editor.runAsync(function(error_run, response) {
+ var error_cleanup;
+ if (!error_run) {
+ try {
+ editor.cleanup();
+ } catch (error) {
+ error_cleanup = error;
+ if (typeof callback === 'function') {
+ callback(error_cleanup);
+ }
+ }
+ return callback(null, response);
+ } else {
+ return callback(error_run) in typeof callback === 'function';
+ }
+ });
+ };
+
+ ExternalEditor.CreateFileError = CreateFileError;
+
+ ExternalEditor.ReadFileError = ReadFileError;
+
+ ExternalEditor.RemoveFileError = RemoveFileError;
+
+ ExternalEditor.LaunchEditorError = LaunchEditorError;
+
+ ExternalEditor.prototype.text = '';
+
+ ExternalEditor.prototype.temp_file = void 0;
+
+ ExternalEditor.prototype.editor = {
+ bin: void 0,
+ args: []
+ };
+
+ function ExternalEditor(text1) {
+ this.text = text1 != null ? text1 : '';
+ this.launchEditorAsync = bind(this.launchEditorAsync, this);
+ this.launchEditor = bind(this.launchEditor, this);
+ this.removeTemporaryFile = bind(this.removeTemporaryFile, this);
+ this.readTemporaryFile = bind(this.readTemporaryFile, this);
+ this.createTemporaryFile = bind(this.createTemporaryFile, this);
+ this.determineEditor = bind(this.determineEditor, this);
+ this.cleanup = bind(this.cleanup, this);
+ this.runAsync = bind(this.runAsync, this);
+ this.run = bind(this.run, this);
+ this.determineEditor();
+ this.createTemporaryFile();
+ }
+
+ ExternalEditor.prototype.run = function() {
+ this.launchEditor();
+ return this.readTemporaryFile();
+ };
+
+ ExternalEditor.prototype.runAsync = function(callback) {
+ var error_launch;
+ try {
+ return this.launchEditorAsync((function(_this) {
+ return function() {
+ var error_read;
+ try {
+ _this.readTemporaryFile();
+ if (typeof callback === 'function') {
+ return callback(null, _this.text);
+ }
+ } catch (error) {
+ error_read = error;
+ if (typeof callback === 'function') {
+ return callback(error_read);
+ }
+ }
+ };
+ })(this));
+ } catch (error) {
+ error_launch = error;
+ if (typeof callback === 'function') {
+ return callback(error_launch);
+ }
+ }
+ };
+
+ ExternalEditor.prototype.cleanup = function() {
+ return this.removeTemporaryFile();
+ };
+
+ ExternalEditor.prototype.determineEditor = function() {
+ var args, ed, editor;
+ ed = /^win/.test(process.platform) ? 'notepad' : 'vim';
+ editor = process.env.VISUAL || process.env.EDITOR || ed;
+ args = editor.split(/\s+/);
+ this.bin = args.shift();
+ return this.args = args;
+ };
+
+ ExternalEditor.prototype.createTemporaryFile = function() {
+ var e;
+ try {
+ this.temp_file = Temp.tmpNameSync({});
+ return FS.writeFileSync(this.temp_file, this.text);
+ } catch (error) {
+ e = error;
+ throw new CreateFileError(e);
+ }
+ };
+
+ ExternalEditor.prototype.readTemporaryFile = function() {
+ var e;
+ try {
+ return this.text = FS.readFileSync(this.temp_file).toString();
+ } catch (error) {
+ e = error;
+ throw new ReadFileError(e);
+ }
+ };
+
+ ExternalEditor.prototype.removeTemporaryFile = function() {
+ var e;
+ try {
+ return FS.unlinkSync(this.temp_file);
+ } catch (error) {
+ e = error;
+ throw new RemoveFileError(e);
+ }
+ };
+
+ ExternalEditor.prototype.launchEditor = function() {
+ var e;
+ try {
+ return SpawnSync(this.bin, this.args.concat([this.temp_file]), {
+ stdio: 'inherit'
+ });
+ } catch (error) {
+ e = error;
+ throw new LaunchEditorError(e);
+ }
+ };
+
+ ExternalEditor.prototype.launchEditorAsync = function(callback) {
+ var child_process, e;
+ try {
+ child_process = Spawn(this.bin, this.args.concat([this.temp_file]), {
+ stdio: 'inherit'
+ });
+ return child_process.on('exit', function() {
+ if (typeof callback === 'function') {
+ return callback();
+ }
+ });
+ } catch (error) {
+ e = error;
+ throw new LaunchEditorError(e);
+ }
+ };
+
+ return ExternalEditor;
+
+ })();
+
+ module.exports = ExternalEditor;
+
+}).call(this);
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..0c34af5
--- /dev/null
+++ b/package.json
@@ -0,0 +1,45 @@
+{
+ "name": "external-editor",
+ "version": "2.0.1",
+ "description": "Edit a string with the users preferred text editor using $VISUAL or $ENVIRONMENT",
+ "main": "main/index.js",
+ "scripts": {
+ "test": "npm run lint && npm run unit",
+ "unit": "mocha --recursive --compilers coffee:coffee-script/register --timeout 10000 ./test/spec",
+ "compile": "coffee --compile --output main/ src/",
+ "lint": "coffeelint -f .coffeelint.json src"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/mrkmg/node-external-editor.git"
+ },
+ "keywords": [
+ "editor",
+ "external",
+ "user",
+ "visual"
+ ],
+ "author": "Kevin Gravier <kevin at mrkmg.com> (https://mrkmg.com)",
+ "license": "MIT",
+ "bugs": {
+ "url": "https://github.com/mrkmg/node-external-editor/issues"
+ },
+ "homepage": "https://github.com/mrkmg/node-external-editor#readme",
+ "dependencies": {
+ "tmp": "^0.0.31"
+ },
+ "engines": {
+ "node": ">=0.12"
+ },
+ "devDependencies": {
+ "chai": "^3.5.0",
+ "coffee-script": "^1.10.0",
+ "coffeelint": "^1.14.2",
+ "mocha": "^2.5.3"
+ },
+ "files": [
+ "main",
+ "example_sync.js",
+ "example_async.js"
+ ]
+}
diff --git a/src/errors/CreateFileError.coffee b/src/errors/CreateFileError.coffee
new file mode 100644
index 0000000..ea895cc
--- /dev/null
+++ b/src/errors/CreateFileError.coffee
@@ -0,0 +1,11 @@
+###
+ ExternalEditor
+ Kevin Gravier <kevin at mrkmg.com>
+ MIT
+###
+
+class CreateFileError extends Error
+ message: 'Failed to create temporary file for editor'
+ constructor: (@original_error) ->
+
+module.exports = CreateFileError
diff --git a/src/errors/LaunchEditorError.coffee b/src/errors/LaunchEditorError.coffee
new file mode 100644
index 0000000..5e75366
--- /dev/null
+++ b/src/errors/LaunchEditorError.coffee
@@ -0,0 +1,11 @@
+###
+ ExternalEditor
+ Kevin Gravier <kevin at mrkmg.com>
+ MIT
+###
+
+class LaunchEditorError extends Error
+ message: 'Failed launch editor'
+ constructor: (@original_error) ->
+
+module.exports = LaunchEditorError
diff --git a/src/errors/ReadFileError.coffee b/src/errors/ReadFileError.coffee
new file mode 100644
index 0000000..d7646de
--- /dev/null
+++ b/src/errors/ReadFileError.coffee
@@ -0,0 +1,11 @@
+###
+ ExternalEditor
+ Kevin Gravier <kevin at mrkmg.com>
+ MIT
+###
+
+class ReadFileError extends Error
+ message: 'Failed to read temporary file'
+ constructor: (@original_error) ->
+
+module.exports = ReadFileError
diff --git a/src/errors/RemoveFileError.coffee b/src/errors/RemoveFileError.coffee
new file mode 100644
index 0000000..5527cf0
--- /dev/null
+++ b/src/errors/RemoveFileError.coffee
@@ -0,0 +1,11 @@
+###
+ ExternalEditor
+ Kevin Gravier <kevin at mrkmg.com>
+ MIT
+###
+
+class RemoveFileError extends Error
+ message: 'Failed to cleanup temporary file'
+ constructor: (@original_error) ->
+
+module.exports = RemoveFileError
diff --git a/src/index.coffee b/src/index.coffee
new file mode 100644
index 0000000..63013b3
--- /dev/null
+++ b/src/index.coffee
@@ -0,0 +1,109 @@
+###
+ ExternalEditor
+ Kevin Gravier <kevin at mrkmg.com>
+ MIT
+###
+
+FS = require 'fs'
+Temp = require 'tmp'
+SpawnSync = require('child_process').spawnSync
+Spawn = require('child_process').spawn
+
+CreateFileError = require './errors/CreateFileError'
+ReadFileError = require './errors/ReadFileError'
+RemoveFileError = require './errors/RemoveFileError'
+LaunchEditorError = require './errors/LaunchEditorError'
+
+class ExternalEditor
+ @edit: (text = '') ->
+ editor = new ExternalEditor(text)
+ editor.run()
+ editor.cleanup()
+ editor.text
+
+ @editAsync: (text = '', callback) ->
+ editor = new ExternalEditor(text)
+ editor.runAsync (error_run, response) ->
+ if not error_run
+ try
+ editor.cleanup()
+ catch error_cleanup
+ callback(error_cleanup) if typeof callback is 'function'
+ callback(null, response)
+ else
+ callback(error_run) of typeof callback is 'function'
+
+
+ @CreateFileError: CreateFileError
+ @ReadFileError: ReadFileError
+ @RemoveFileError: RemoveFileError
+ @LaunchEditorError: LaunchEditorError
+
+ text: ''
+ temp_file: undefined
+ editor:
+ bin: undefined
+ args: []
+
+ constructor: (@text = '') ->
+ @determineEditor()
+ @createTemporaryFile()
+
+ run: =>
+ @launchEditor()
+ @readTemporaryFile()
+
+ runAsync: (callback) =>
+ try
+ @launchEditorAsync =>
+ try
+ @readTemporaryFile()
+ callback(null, @text) if typeof callback is 'function'
+ catch error_read
+ callback(error_read) if typeof callback is 'function'
+ catch error_launch
+ callback(error_launch) if typeof callback is 'function'
+
+ cleanup: =>
+ @removeTemporaryFile()
+
+ determineEditor: =>
+ ed = if /^win/.test process.platform then 'notepad' else 'vim'
+ editor = process.env.VISUAL or process.env.EDITOR or ed
+ args = editor.split /\s+/
+ @bin = args.shift()
+ @args = args
+
+ createTemporaryFile: =>
+ try
+ @temp_file = Temp.tmpNameSync {}
+ FS.writeFileSync @temp_file, @text
+ catch e
+ throw new CreateFileError e
+
+ readTemporaryFile: =>
+ try
+ @text = FS.readFileSync(@temp_file).toString()
+ catch e
+ throw new ReadFileError e
+
+ removeTemporaryFile: =>
+ try
+ FS.unlinkSync(@temp_file)
+ catch e
+ throw new RemoveFileError e
+
+ launchEditor: =>
+ try
+ SpawnSync @bin, @args.concat([@temp_file]), stdio: 'inherit'
+ catch e
+ throw new LaunchEditorError e
+
+ launchEditorAsync: (callback) =>
+ try
+ child_process = Spawn @bin, @args.concat([@temp_file]), stdio: 'inherit'
+ child_process.on 'exit', -> callback() if typeof callback is 'function'
+ catch e
+ throw new LaunchEditorError e
+
+module.exports = ExternalEditor
diff --git a/test/spec/main.coffee b/test/spec/main.coffee
new file mode 100644
index 0000000..a2aadb6
--- /dev/null
+++ b/test/spec/main.coffee
@@ -0,0 +1,48 @@
+assert = require('chai').assert
+readFileSync = require('fs').readFileSync
+ExternalEditor = require('../../src')
+
+describe 'main', ->
+ before ->
+ @previous_visual = process.env.VISUAL
+ process.env.VISUAL = 'truncate --size 1'
+
+ beforeEach ->
+ @editor = new ExternalEditor 'XXX'
+
+ afterEach ->
+ @editor.cleanup()
+
+ after ->
+ process.env.VISUAL = @previous_visual
+
+ it 'convenience method ".edit"', ->
+ text = ExternalEditor.edit 'XXX'
+ assert.equal text, 'X'
+
+ it 'convenience method ".editAsync"', (cb) ->
+ ExternalEditor.editAsync 'XXX', (e, text) ->
+ assert.equal text, 'X'
+ cb()
+
+ it 'writes original text to file', ->
+ contents = readFileSync this.editor.temp_file
+ assert.equal contents, 'XXX'
+
+ it 'run() returns correctly', ->
+ text = @editor.run()
+ assert.equal text, 'X'
+
+ it 'runAsync() callbacks correctly', (cb) ->
+ @editor.runAsync (e, text) ->
+ assert.equal text, 'X'
+ cb()
+
+ it 'run() returns text same as editor.text', ->
+ text = @editor.run()
+ assert.equal text, @editor.text
+
+ it 'runAsync() callback text same as editor.text', (cb) ->
+ @editor.runAsync (e, text) =>
+ assert.equal text, @editor.text
+ cb()
diff --git a/yarn.lock b/yarn.lock
new file mode 100644
index 0000000..6cc9b30
--- /dev/null
+++ b/yarn.lock
@@ -0,0 +1,237 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+assertion-error@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.0.2.tgz#13ca515d86206da0bac66e834dd397d87581094c"
+
+balanced-match@^0.4.1:
+ version "0.4.2"
+ resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838"
+
+brace-expansion@^1.0.0:
+ version "1.1.6"
+ resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9"
+ dependencies:
+ balanced-match "^0.4.1"
+ concat-map "0.0.1"
+
+chai@^3.5.0:
+ version "3.5.0"
+ resolved "https://registry.yarnpkg.com/chai/-/chai-3.5.0.tgz#4d02637b067fe958bdbfdd3a40ec56fef7373247"
+ dependencies:
+ assertion-error "^1.0.1"
+ deep-eql "^0.1.3"
+ type-detect "^1.0.0"
+
+coffee-script@^1.10.0:
+ version "1.12.0"
+ resolved "https://registry.yarnpkg.com/coffee-script/-/coffee-script-1.12.0.tgz#8ae1181fb37ee9312c09cf2bf0b754dfa1525fba"
+
+coffee-script@~1.11.0:
+ version "1.11.1"
+ resolved "https://registry.yarnpkg.com/coffee-script/-/coffee-script-1.11.1.tgz#bf1c47ad64443a0d95d12df2b147cc0a4daad6e9"
+
+coffeelint@^1.14.2:
+ version "1.16.0"
+ resolved "https://registry.yarnpkg.com/coffeelint/-/coffeelint-1.16.0.tgz#83d8ed1dafde3a677de44e7b8a18be607761e6d8"
+ dependencies:
+ coffee-script "~1.11.0"
+ glob "^7.0.6"
+ ignore "^3.0.9"
+ optimist "^0.6.1"
+ resolve "^0.6.3"
+ strip-json-comments "^1.0.2"
+
+commander at 0.6.1:
+ version "0.6.1"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-0.6.1.tgz#fa68a14f6a945d54dbbe50d8cdb3320e9e3b1a06"
+
+commander at 2.3.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-2.3.0.tgz#fd430e889832ec353b9acd1de217c11cb3eef873"
+
+concat-map at 0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+
+debug at 2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da"
+ dependencies:
+ ms "0.7.1"
+
+deep-eql@^0.1.3:
+ version "0.1.3"
+ resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-0.1.3.tgz#ef558acab8de25206cd713906d74e56930eb69f2"
+ dependencies:
+ type-detect "0.1.1"
+
+diff at 1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/diff/-/diff-1.4.0.tgz#7f28d2eb9ee7b15a97efd89ce63dcfdaa3ccbabf"
+
+escape-string-regexp at 1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz#4dbc2fe674e71949caf3fb2695ce7f2dc1d9a8d1"
+
+fs.realpath@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
+
+glob@^7.0.6:
+ version "7.1.1"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8"
+ 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"
+
+glob at 3.2.11:
+ version "3.2.11"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-3.2.11.tgz#4a973f635b9190f715d10987d5c00fd2815ebe3d"
+ dependencies:
+ inherits "2"
+ minimatch "0.3"
+
+growl at 1.9.2:
+ version "1.9.2"
+ resolved "https://registry.yarnpkg.com/growl/-/growl-1.9.2.tgz#0ea7743715db8d8de2c5ede1775e1b45ac85c02f"
+
+ignore@^3.0.9:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.2.0.tgz#8d88f03c3002a0ac52114db25d2c673b0bf1e435"
+
+inflight@^1.0.4:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
+ dependencies:
+ once "^1.3.0"
+ wrappy "1"
+
+inherits at 2:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
+
+jade at 0.26.3:
+ version "0.26.3"
+ resolved "https://registry.yarnpkg.com/jade/-/jade-0.26.3.tgz#8f10d7977d8d79f2f6ff862a81b0513ccb25686c"
+ dependencies:
+ commander "0.6.1"
+ mkdirp "0.3.0"
+
+lru-cache at 2:
+ version "2.7.3"
+ resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952"
+
+minimatch@^3.0.2:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774"
+ dependencies:
+ brace-expansion "^1.0.0"
+
+minimatch at 0.3:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-0.3.0.tgz#275d8edaac4f1bb3326472089e7949c8394699dd"
+ dependencies:
+ lru-cache "2"
+ sigmund "~1.0.0"
+
+minimist@~0.0.1, minimist at 0.0.8:
+ version "0.0.8"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
+
+mkdirp at 0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.0.tgz#1bbf5ab1ba827af23575143490426455f481fe1e"
+
+mkdirp at 0.5.1:
+ version "0.5.1"
+ resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
+ dependencies:
+ minimist "0.0.8"
+
+mocha@^2.5.3:
+ version "2.5.3"
+ resolved "https://registry.yarnpkg.com/mocha/-/mocha-2.5.3.tgz#161be5bdeb496771eb9b35745050b622b5aefc58"
+ dependencies:
+ commander "2.3.0"
+ debug "2.2.0"
+ diff "1.4.0"
+ escape-string-regexp "1.0.2"
+ glob "3.2.11"
+ growl "1.9.2"
+ jade "0.26.3"
+ mkdirp "0.5.1"
+ supports-color "1.2.0"
+ to-iso-string "0.0.2"
+
+ms at 0.7.1:
+ version "0.7.1"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098"
+
+once@^1.3.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
+ dependencies:
+ wrappy "1"
+
+optimist@^0.6.1:
+ version "0.6.1"
+ resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686"
+ dependencies:
+ minimist "~0.0.1"
+ wordwrap "~0.0.2"
+
+os-tmpdir@~1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
+
+path-is-absolute@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
+
+resolve@^0.6.3:
+ version "0.6.3"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-0.6.3.tgz#dd957982e7e736debdf53b58a4dd91754575dd46"
+
+sigmund@~1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590"
+
+strip-json-comments@^1.0.2:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91"
+
+supports-color at 1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-1.2.0.tgz#ff1ed1e61169d06b3cf2d588e188b18d8847e17e"
+
+tmp@^0.0.31:
+ version "0.0.31"
+ resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.31.tgz#8f38ab9438e17315e5dbd8b3657e8bfb277ae4a7"
+ dependencies:
+ os-tmpdir "~1.0.1"
+
+to-iso-string at 0.0.2:
+ version "0.0.2"
+ resolved "https://registry.yarnpkg.com/to-iso-string/-/to-iso-string-0.0.2.tgz#4dc19e664dfccbe25bd8db508b00c6da158255d1"
+
+type-detect@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-1.0.0.tgz#762217cc06db258ec48908a1298e8b95121e8ea2"
+
+type-detect at 0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-0.1.1.tgz#0ba5ec2a885640e470ea4e8505971900dac58822"
+
+wordwrap@~0.0.2:
+ version "0.0.3"
+ resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107"
+
+wrappy at 1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-external-editor.git
More information about the Pkg-javascript-commits
mailing list