[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