first commit
This commit is contained in:
22
node_modules/@inquirer/external-editor/LICENSE
generated
vendored
Normal file
22
node_modules/@inquirer/external-editor/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
Copyright (c) 2025 Simon Boudrias
|
||||
|
||||
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.
|
||||
164
node_modules/@inquirer/external-editor/README.md
generated
vendored
Normal file
164
node_modules/@inquirer/external-editor/README.md
generated
vendored
Normal file
@@ -0,0 +1,164 @@
|
||||
# `@inquirer/external-editor`
|
||||
|
||||
A Node.js module to edit a string with the user's preferred text editor using $VISUAL or $EDITOR.
|
||||
|
||||
> [!NOTE]
|
||||
> This package is a replacement for the unmaintained `external-editor`. It includes security fixes.
|
||||
|
||||
# Special Thanks
|
||||
|
||||
<div align="center" markdown="1">
|
||||
|
||||
[](https://graphite.dev/?utm_source=npmjs&utm_medium=repo&utm_campaign=inquirerjs)<br>
|
||||
|
||||
### [Graphite is the AI developer productivity platform helping teams on GitHub ship higher quality software, faster](https://graphite.dev/?utm_source=npmjs&utm_medium=repo&utm_campaign=inquirerjs)
|
||||
|
||||
</div>
|
||||
|
||||
# Installation
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>npm</th>
|
||||
<th>yarn</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
```sh
|
||||
npm install @inquirer/external-editor
|
||||
```
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
```sh
|
||||
yarn add @inquirer/external-editor
|
||||
```
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
## Usage
|
||||
|
||||
A simple example using the `edit` function
|
||||
|
||||
```ts
|
||||
import { edit } from '@inquirer/external-editor';
|
||||
|
||||
const data = edit('\n\n# Please write your text above');
|
||||
console.log(data);
|
||||
```
|
||||
|
||||
Example relying on the class construct
|
||||
|
||||
```ts
|
||||
import {
|
||||
ExternalEditor,
|
||||
CreateFileError,
|
||||
ReadFileError,
|
||||
RemoveFileError,
|
||||
LaunchEditorError,
|
||||
} from '@inquirer/external-editor';
|
||||
|
||||
try {
|
||||
const editor = new ExternalEditor();
|
||||
const text = editor.run(); // the text is also available in editor.text
|
||||
|
||||
if (editor.lastExitStatus !== 0) {
|
||||
console.log('The editor exited with a non-zero code');
|
||||
}
|
||||
|
||||
// Do things with the text
|
||||
editor.cleanup();
|
||||
} catch (err) {
|
||||
if (err instanceof CreateFileError) {
|
||||
console.log('Failed to create the temporary file');
|
||||
} else if (err instanceof ReadFileError) {
|
||||
console.log('Failed to read the temporary file');
|
||||
} else if (err instanceof LaunchEditorError) {
|
||||
console.log('Failed to launch your editor');
|
||||
} else if (err instanceof RemoveFileError) {
|
||||
console.log('Failed to remove the temporary file');
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### API
|
||||
|
||||
**Convenience Functions**
|
||||
|
||||
- `edit(text, config)`
|
||||
- `text` (string) _Optional_ Defaults to empty string
|
||||
- `config` (Config) _Optional_ Options for temporary file creation
|
||||
- **Returns** (string) The contents of the file
|
||||
- Could throw `CreateFileError`, `ReadFileError`, or `LaunchEditorError`, or `RemoveFileError`
|
||||
- `editAsync(text, callback, config)`
|
||||
- `text` (string) _Optional_ Defaults to empty string
|
||||
- `callback` (function (error?, text?))
|
||||
- `error` could be of type `CreateFileError`, `ReadFileError`, `LaunchEditorError`, or `RemoveFileError`
|
||||
- `text` (string) The contents of the file
|
||||
- `config` (Config) _Optional_ Options for temporary file creation
|
||||
|
||||
**Errors**
|
||||
|
||||
- `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.
|
||||
|
||||
**External Editor Public Methods**
|
||||
|
||||
- `new ExternalEditor(text, config)`
|
||||
- `text` (string) _Optional_ Defaults to empty string
|
||||
- `config` (Config) _Optional_ Options for temporary file creation
|
||||
- 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`
|
||||
|
||||
**External Editor 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
|
||||
- `tempFile` (string) Path to temporary file. Can be changed, but be careful as the temporary file probably already
|
||||
exists and would need be removed manually.
|
||||
- `lastExitStatus` (number) The last exit code emitted from the editor.
|
||||
|
||||
**Config Options**
|
||||
|
||||
- `prefix` (string) _Optional_ A prefix for the file name.
|
||||
- `postfix` (string) _Optional_ A postfix for the file name. Useful if you want to provide an extension.
|
||||
- `mode` (number) _Optional_ Which mode to create the file with. e.g. 644
|
||||
- `dir` (string) _Optional_ Which path to store the file.
|
||||
|
||||
## 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 stderr.
|
||||
|
||||
## Demo
|
||||
|
||||
[](https://asciinema.org/a/a1qh9lypbe65mj0ivfuoslz2s)
|
||||
|
||||
# License
|
||||
|
||||
Copyright (c) 2025 Simon Boudrias (twitter: [@vaxilart](https://twitter.com/Vaxilart))<br/>
|
||||
Licensed under the MIT license.
|
||||
10
node_modules/@inquirer/external-editor/dist/commonjs/errors/CreateFileError.d.ts
generated
vendored
Normal file
10
node_modules/@inquirer/external-editor/dist/commonjs/errors/CreateFileError.d.ts
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
/***
|
||||
* Node External Editor
|
||||
*
|
||||
* Kevin Gravier <kevin@mrkmg.com>
|
||||
* MIT 2018
|
||||
*/
|
||||
export declare class CreateFileError extends Error {
|
||||
originalError: Error;
|
||||
constructor(originalError: Error);
|
||||
}
|
||||
17
node_modules/@inquirer/external-editor/dist/commonjs/errors/CreateFileError.js
generated
vendored
Normal file
17
node_modules/@inquirer/external-editor/dist/commonjs/errors/CreateFileError.js
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
"use strict";
|
||||
/***
|
||||
* Node External Editor
|
||||
*
|
||||
* Kevin Gravier <kevin@mrkmg.com>
|
||||
* MIT 2018
|
||||
*/
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.CreateFileError = void 0;
|
||||
class CreateFileError extends Error {
|
||||
originalError;
|
||||
constructor(originalError) {
|
||||
super(`Failed to create temporary file. ${originalError.message}`);
|
||||
this.originalError = originalError;
|
||||
}
|
||||
}
|
||||
exports.CreateFileError = CreateFileError;
|
||||
10
node_modules/@inquirer/external-editor/dist/commonjs/errors/LaunchEditorError.d.ts
generated
vendored
Normal file
10
node_modules/@inquirer/external-editor/dist/commonjs/errors/LaunchEditorError.d.ts
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
/***
|
||||
* Node External Editor
|
||||
*
|
||||
* Kevin Gravier <kevin@mrkmg.com>
|
||||
* MIT 2018
|
||||
*/
|
||||
export declare class LaunchEditorError extends Error {
|
||||
originalError: Error;
|
||||
constructor(originalError: Error);
|
||||
}
|
||||
17
node_modules/@inquirer/external-editor/dist/commonjs/errors/LaunchEditorError.js
generated
vendored
Normal file
17
node_modules/@inquirer/external-editor/dist/commonjs/errors/LaunchEditorError.js
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
"use strict";
|
||||
/***
|
||||
* Node External Editor
|
||||
*
|
||||
* Kevin Gravier <kevin@mrkmg.com>
|
||||
* MIT 2018
|
||||
*/
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.LaunchEditorError = void 0;
|
||||
class LaunchEditorError extends Error {
|
||||
originalError;
|
||||
constructor(originalError) {
|
||||
super(`Failed to launch editor. ${originalError.message}`);
|
||||
this.originalError = originalError;
|
||||
}
|
||||
}
|
||||
exports.LaunchEditorError = LaunchEditorError;
|
||||
10
node_modules/@inquirer/external-editor/dist/commonjs/errors/ReadFileError.d.ts
generated
vendored
Normal file
10
node_modules/@inquirer/external-editor/dist/commonjs/errors/ReadFileError.d.ts
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
/***
|
||||
* Node External Editor
|
||||
*
|
||||
* Kevin Gravier <kevin@mrkmg.com>
|
||||
* MIT 2018
|
||||
*/
|
||||
export declare class ReadFileError extends Error {
|
||||
originalError: Error;
|
||||
constructor(originalError: Error);
|
||||
}
|
||||
17
node_modules/@inquirer/external-editor/dist/commonjs/errors/ReadFileError.js
generated
vendored
Normal file
17
node_modules/@inquirer/external-editor/dist/commonjs/errors/ReadFileError.js
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
"use strict";
|
||||
/***
|
||||
* Node External Editor
|
||||
*
|
||||
* Kevin Gravier <kevin@mrkmg.com>
|
||||
* MIT 2018
|
||||
*/
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.ReadFileError = void 0;
|
||||
class ReadFileError extends Error {
|
||||
originalError;
|
||||
constructor(originalError) {
|
||||
super(`Failed to read temporary file. ${originalError.message}`);
|
||||
this.originalError = originalError;
|
||||
}
|
||||
}
|
||||
exports.ReadFileError = ReadFileError;
|
||||
10
node_modules/@inquirer/external-editor/dist/commonjs/errors/RemoveFileError.d.ts
generated
vendored
Normal file
10
node_modules/@inquirer/external-editor/dist/commonjs/errors/RemoveFileError.d.ts
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
/***
|
||||
* Node External Editor
|
||||
*
|
||||
* Kevin Gravier <kevin@mrkmg.com>
|
||||
* MIT 2018
|
||||
*/
|
||||
export declare class RemoveFileError extends Error {
|
||||
originalError: Error;
|
||||
constructor(originalError: Error);
|
||||
}
|
||||
17
node_modules/@inquirer/external-editor/dist/commonjs/errors/RemoveFileError.js
generated
vendored
Normal file
17
node_modules/@inquirer/external-editor/dist/commonjs/errors/RemoveFileError.js
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
"use strict";
|
||||
/***
|
||||
* Node External Editor
|
||||
*
|
||||
* Kevin Gravier <kevin@mrkmg.com>
|
||||
* MIT 2018
|
||||
*/
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.RemoveFileError = void 0;
|
||||
class RemoveFileError extends Error {
|
||||
originalError;
|
||||
constructor(originalError) {
|
||||
super(`Failed to remove temporary file. ${originalError.message}`);
|
||||
this.originalError = originalError;
|
||||
}
|
||||
}
|
||||
exports.RemoveFileError = RemoveFileError;
|
||||
39
node_modules/@inquirer/external-editor/dist/commonjs/index.d.ts
generated
vendored
Normal file
39
node_modules/@inquirer/external-editor/dist/commonjs/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
import { CreateFileError } from './errors/CreateFileError.js';
|
||||
import { LaunchEditorError } from './errors/LaunchEditorError.js';
|
||||
import { ReadFileError } from './errors/ReadFileError.js';
|
||||
import { RemoveFileError } from './errors/RemoveFileError.js';
|
||||
export interface IEditorParams {
|
||||
args: string[];
|
||||
bin: string;
|
||||
}
|
||||
export interface IFileOptions {
|
||||
prefix?: string;
|
||||
postfix?: string;
|
||||
mode?: number;
|
||||
template?: string;
|
||||
dir?: string;
|
||||
}
|
||||
export type StringCallback = (err: Error | undefined, result: string | undefined) => void;
|
||||
export type VoidCallback = () => void;
|
||||
export { CreateFileError, LaunchEditorError, ReadFileError, RemoveFileError };
|
||||
export declare function edit(text?: string, fileOptions?: IFileOptions): string;
|
||||
export declare function editAsync(text: string | undefined, callback: StringCallback, fileOptions?: IFileOptions): void;
|
||||
export declare class ExternalEditor {
|
||||
text: string;
|
||||
tempFile: string;
|
||||
editor: IEditorParams;
|
||||
lastExitStatus: number;
|
||||
private fileOptions;
|
||||
get temp_file(): string;
|
||||
get last_exit_status(): number;
|
||||
constructor(text?: string, fileOptions?: IFileOptions);
|
||||
run(): string;
|
||||
runAsync(callback: StringCallback): void;
|
||||
cleanup(): void;
|
||||
private determineEditor;
|
||||
private createTemporaryFile;
|
||||
private readTemporaryFile;
|
||||
private removeTemporaryFile;
|
||||
private launchEditor;
|
||||
private launchEditorAsync;
|
||||
}
|
||||
203
node_modules/@inquirer/external-editor/dist/commonjs/index.js
generated
vendored
Normal file
203
node_modules/@inquirer/external-editor/dist/commonjs/index.js
generated
vendored
Normal file
@@ -0,0 +1,203 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.ExternalEditor = exports.RemoveFileError = exports.ReadFileError = exports.LaunchEditorError = exports.CreateFileError = void 0;
|
||||
exports.edit = edit;
|
||||
exports.editAsync = editAsync;
|
||||
const chardet_1 = require("chardet");
|
||||
const child_process_1 = require("child_process");
|
||||
const fs_1 = require("fs");
|
||||
const node_path_1 = __importDefault(require("node:path"));
|
||||
const node_os_1 = __importDefault(require("node:os"));
|
||||
const node_crypto_1 = require("node:crypto");
|
||||
const iconv_lite_1 = __importDefault(require("iconv-lite"));
|
||||
const CreateFileError_js_1 = require("./errors/CreateFileError.js");
|
||||
Object.defineProperty(exports, "CreateFileError", { enumerable: true, get: function () { return CreateFileError_js_1.CreateFileError; } });
|
||||
const LaunchEditorError_js_1 = require("./errors/LaunchEditorError.js");
|
||||
Object.defineProperty(exports, "LaunchEditorError", { enumerable: true, get: function () { return LaunchEditorError_js_1.LaunchEditorError; } });
|
||||
const ReadFileError_js_1 = require("./errors/ReadFileError.js");
|
||||
Object.defineProperty(exports, "ReadFileError", { enumerable: true, get: function () { return ReadFileError_js_1.ReadFileError; } });
|
||||
const RemoveFileError_js_1 = require("./errors/RemoveFileError.js");
|
||||
Object.defineProperty(exports, "RemoveFileError", { enumerable: true, get: function () { return RemoveFileError_js_1.RemoveFileError; } });
|
||||
function edit(text = '', fileOptions) {
|
||||
const editor = new ExternalEditor(text, fileOptions);
|
||||
editor.run();
|
||||
editor.cleanup();
|
||||
return editor.text;
|
||||
}
|
||||
function editAsync(text = '', callback, fileOptions) {
|
||||
const editor = new ExternalEditor(text, fileOptions);
|
||||
editor.runAsync((err, result) => {
|
||||
if (err) {
|
||||
setImmediate(callback, err, undefined);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
editor.cleanup();
|
||||
setImmediate(callback, undefined, result);
|
||||
}
|
||||
catch (cleanupError) {
|
||||
setImmediate(callback, cleanupError, undefined);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
function sanitizeAffix(affix) {
|
||||
if (!affix)
|
||||
return '';
|
||||
return affix.replace(/[^a-zA-Z0-9_.-]/g, '_');
|
||||
}
|
||||
function splitStringBySpace(str) {
|
||||
const pieces = [];
|
||||
let currentString = '';
|
||||
for (let strIndex = 0; strIndex < str.length; strIndex++) {
|
||||
const currentLetter = str.charAt(strIndex);
|
||||
if (strIndex > 0 &&
|
||||
currentLetter === ' ' &&
|
||||
str[strIndex - 1] !== '\\' &&
|
||||
currentString.length > 0) {
|
||||
pieces.push(currentString);
|
||||
currentString = '';
|
||||
}
|
||||
else {
|
||||
currentString = `${currentString}${currentLetter}`;
|
||||
}
|
||||
}
|
||||
if (currentString.length > 0) {
|
||||
pieces.push(currentString);
|
||||
}
|
||||
return pieces;
|
||||
}
|
||||
class ExternalEditor {
|
||||
text = '';
|
||||
tempFile;
|
||||
editor;
|
||||
lastExitStatus = 0;
|
||||
fileOptions = {};
|
||||
get temp_file() {
|
||||
console.log('DEPRECATED: temp_file. Use tempFile moving forward.');
|
||||
return this.tempFile;
|
||||
}
|
||||
get last_exit_status() {
|
||||
console.log('DEPRECATED: last_exit_status. Use lastExitStatus moving forward.');
|
||||
return this.lastExitStatus;
|
||||
}
|
||||
constructor(text = '', fileOptions) {
|
||||
this.text = text;
|
||||
if (fileOptions) {
|
||||
this.fileOptions = fileOptions;
|
||||
}
|
||||
this.determineEditor();
|
||||
this.createTemporaryFile();
|
||||
}
|
||||
run() {
|
||||
this.launchEditor();
|
||||
this.readTemporaryFile();
|
||||
return this.text;
|
||||
}
|
||||
runAsync(callback) {
|
||||
try {
|
||||
this.launchEditorAsync(() => {
|
||||
try {
|
||||
this.readTemporaryFile();
|
||||
setImmediate(callback, undefined, this.text);
|
||||
}
|
||||
catch (readError) {
|
||||
setImmediate(callback, readError, undefined);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (launchError) {
|
||||
setImmediate(callback, launchError, undefined);
|
||||
}
|
||||
}
|
||||
cleanup() {
|
||||
this.removeTemporaryFile();
|
||||
}
|
||||
determineEditor() {
|
||||
const editor = process.env['VISUAL']
|
||||
? process.env['VISUAL']
|
||||
: process.env['EDITOR']
|
||||
? process.env['EDITOR']
|
||||
: process.platform.startsWith('win')
|
||||
? 'notepad'
|
||||
: 'vim';
|
||||
const editorOpts = splitStringBySpace(editor).map((piece) => piece.replace('\\ ', ' '));
|
||||
const bin = editorOpts.shift();
|
||||
this.editor = { args: editorOpts, bin };
|
||||
}
|
||||
createTemporaryFile() {
|
||||
try {
|
||||
const baseDir = this.fileOptions.dir ?? node_os_1.default.tmpdir();
|
||||
const id = (0, node_crypto_1.randomUUID)();
|
||||
const prefix = sanitizeAffix(this.fileOptions.prefix);
|
||||
const postfix = sanitizeAffix(this.fileOptions.postfix);
|
||||
const filename = `${prefix}${id}${postfix}`;
|
||||
const candidate = node_path_1.default.resolve(baseDir, filename);
|
||||
const baseResolved = node_path_1.default.resolve(baseDir) + node_path_1.default.sep;
|
||||
if (!candidate.startsWith(baseResolved)) {
|
||||
throw new Error('Resolved temporary file escaped the base directory');
|
||||
}
|
||||
this.tempFile = candidate;
|
||||
const opt = { encoding: 'utf8', flag: 'wx' };
|
||||
if (Object.prototype.hasOwnProperty.call(this.fileOptions, 'mode')) {
|
||||
opt.mode = this.fileOptions.mode;
|
||||
}
|
||||
(0, fs_1.writeFileSync)(this.tempFile, this.text, opt);
|
||||
}
|
||||
catch (createFileError) {
|
||||
throw new CreateFileError_js_1.CreateFileError(createFileError);
|
||||
}
|
||||
}
|
||||
readTemporaryFile() {
|
||||
try {
|
||||
const tempFileBuffer = (0, fs_1.readFileSync)(this.tempFile);
|
||||
if (tempFileBuffer.length === 0) {
|
||||
this.text = '';
|
||||
}
|
||||
else {
|
||||
let encoding = (0, chardet_1.detect)(tempFileBuffer) ?? 'utf8';
|
||||
if (!iconv_lite_1.default.encodingExists(encoding)) {
|
||||
// Probably a bad idea, but will at least prevent crashing
|
||||
encoding = 'utf8';
|
||||
}
|
||||
this.text = iconv_lite_1.default.decode(tempFileBuffer, encoding);
|
||||
}
|
||||
}
|
||||
catch (readFileError) {
|
||||
throw new ReadFileError_js_1.ReadFileError(readFileError);
|
||||
}
|
||||
}
|
||||
removeTemporaryFile() {
|
||||
try {
|
||||
(0, fs_1.unlinkSync)(this.tempFile);
|
||||
}
|
||||
catch (removeFileError) {
|
||||
throw new RemoveFileError_js_1.RemoveFileError(removeFileError);
|
||||
}
|
||||
}
|
||||
launchEditor() {
|
||||
try {
|
||||
const editorProcess = (0, child_process_1.spawnSync)(this.editor.bin, this.editor.args.concat([this.tempFile]), { stdio: 'inherit' });
|
||||
this.lastExitStatus = editorProcess.status ?? 0;
|
||||
}
|
||||
catch (launchError) {
|
||||
throw new LaunchEditorError_js_1.LaunchEditorError(launchError);
|
||||
}
|
||||
}
|
||||
launchEditorAsync(callback) {
|
||||
try {
|
||||
const editorProcess = (0, child_process_1.spawn)(this.editor.bin, this.editor.args.concat([this.tempFile]), { stdio: 'inherit' });
|
||||
editorProcess.on('exit', (code) => {
|
||||
this.lastExitStatus = code;
|
||||
setImmediate(callback);
|
||||
});
|
||||
}
|
||||
catch (launchError) {
|
||||
throw new LaunchEditorError_js_1.LaunchEditorError(launchError);
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.ExternalEditor = ExternalEditor;
|
||||
3
node_modules/@inquirer/external-editor/dist/commonjs/package.json
generated
vendored
Normal file
3
node_modules/@inquirer/external-editor/dist/commonjs/package.json
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"type": "commonjs"
|
||||
}
|
||||
10
node_modules/@inquirer/external-editor/dist/esm/errors/CreateFileError.d.ts
generated
vendored
Normal file
10
node_modules/@inquirer/external-editor/dist/esm/errors/CreateFileError.d.ts
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
/***
|
||||
* Node External Editor
|
||||
*
|
||||
* Kevin Gravier <kevin@mrkmg.com>
|
||||
* MIT 2018
|
||||
*/
|
||||
export declare class CreateFileError extends Error {
|
||||
originalError: Error;
|
||||
constructor(originalError: Error);
|
||||
}
|
||||
13
node_modules/@inquirer/external-editor/dist/esm/errors/CreateFileError.js
generated
vendored
Normal file
13
node_modules/@inquirer/external-editor/dist/esm/errors/CreateFileError.js
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
/***
|
||||
* Node External Editor
|
||||
*
|
||||
* Kevin Gravier <kevin@mrkmg.com>
|
||||
* MIT 2018
|
||||
*/
|
||||
export class CreateFileError extends Error {
|
||||
originalError;
|
||||
constructor(originalError) {
|
||||
super(`Failed to create temporary file. ${originalError.message}`);
|
||||
this.originalError = originalError;
|
||||
}
|
||||
}
|
||||
10
node_modules/@inquirer/external-editor/dist/esm/errors/LaunchEditorError.d.ts
generated
vendored
Normal file
10
node_modules/@inquirer/external-editor/dist/esm/errors/LaunchEditorError.d.ts
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
/***
|
||||
* Node External Editor
|
||||
*
|
||||
* Kevin Gravier <kevin@mrkmg.com>
|
||||
* MIT 2018
|
||||
*/
|
||||
export declare class LaunchEditorError extends Error {
|
||||
originalError: Error;
|
||||
constructor(originalError: Error);
|
||||
}
|
||||
13
node_modules/@inquirer/external-editor/dist/esm/errors/LaunchEditorError.js
generated
vendored
Normal file
13
node_modules/@inquirer/external-editor/dist/esm/errors/LaunchEditorError.js
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
/***
|
||||
* Node External Editor
|
||||
*
|
||||
* Kevin Gravier <kevin@mrkmg.com>
|
||||
* MIT 2018
|
||||
*/
|
||||
export class LaunchEditorError extends Error {
|
||||
originalError;
|
||||
constructor(originalError) {
|
||||
super(`Failed to launch editor. ${originalError.message}`);
|
||||
this.originalError = originalError;
|
||||
}
|
||||
}
|
||||
10
node_modules/@inquirer/external-editor/dist/esm/errors/ReadFileError.d.ts
generated
vendored
Normal file
10
node_modules/@inquirer/external-editor/dist/esm/errors/ReadFileError.d.ts
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
/***
|
||||
* Node External Editor
|
||||
*
|
||||
* Kevin Gravier <kevin@mrkmg.com>
|
||||
* MIT 2018
|
||||
*/
|
||||
export declare class ReadFileError extends Error {
|
||||
originalError: Error;
|
||||
constructor(originalError: Error);
|
||||
}
|
||||
13
node_modules/@inquirer/external-editor/dist/esm/errors/ReadFileError.js
generated
vendored
Normal file
13
node_modules/@inquirer/external-editor/dist/esm/errors/ReadFileError.js
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
/***
|
||||
* Node External Editor
|
||||
*
|
||||
* Kevin Gravier <kevin@mrkmg.com>
|
||||
* MIT 2018
|
||||
*/
|
||||
export class ReadFileError extends Error {
|
||||
originalError;
|
||||
constructor(originalError) {
|
||||
super(`Failed to read temporary file. ${originalError.message}`);
|
||||
this.originalError = originalError;
|
||||
}
|
||||
}
|
||||
10
node_modules/@inquirer/external-editor/dist/esm/errors/RemoveFileError.d.ts
generated
vendored
Normal file
10
node_modules/@inquirer/external-editor/dist/esm/errors/RemoveFileError.d.ts
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
/***
|
||||
* Node External Editor
|
||||
*
|
||||
* Kevin Gravier <kevin@mrkmg.com>
|
||||
* MIT 2018
|
||||
*/
|
||||
export declare class RemoveFileError extends Error {
|
||||
originalError: Error;
|
||||
constructor(originalError: Error);
|
||||
}
|
||||
13
node_modules/@inquirer/external-editor/dist/esm/errors/RemoveFileError.js
generated
vendored
Normal file
13
node_modules/@inquirer/external-editor/dist/esm/errors/RemoveFileError.js
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
/***
|
||||
* Node External Editor
|
||||
*
|
||||
* Kevin Gravier <kevin@mrkmg.com>
|
||||
* MIT 2018
|
||||
*/
|
||||
export class RemoveFileError extends Error {
|
||||
originalError;
|
||||
constructor(originalError) {
|
||||
super(`Failed to remove temporary file. ${originalError.message}`);
|
||||
this.originalError = originalError;
|
||||
}
|
||||
}
|
||||
39
node_modules/@inquirer/external-editor/dist/esm/index.d.ts
generated
vendored
Normal file
39
node_modules/@inquirer/external-editor/dist/esm/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
import { CreateFileError } from './errors/CreateFileError.js';
|
||||
import { LaunchEditorError } from './errors/LaunchEditorError.js';
|
||||
import { ReadFileError } from './errors/ReadFileError.js';
|
||||
import { RemoveFileError } from './errors/RemoveFileError.js';
|
||||
export interface IEditorParams {
|
||||
args: string[];
|
||||
bin: string;
|
||||
}
|
||||
export interface IFileOptions {
|
||||
prefix?: string;
|
||||
postfix?: string;
|
||||
mode?: number;
|
||||
template?: string;
|
||||
dir?: string;
|
||||
}
|
||||
export type StringCallback = (err: Error | undefined, result: string | undefined) => void;
|
||||
export type VoidCallback = () => void;
|
||||
export { CreateFileError, LaunchEditorError, ReadFileError, RemoveFileError };
|
||||
export declare function edit(text?: string, fileOptions?: IFileOptions): string;
|
||||
export declare function editAsync(text: string | undefined, callback: StringCallback, fileOptions?: IFileOptions): void;
|
||||
export declare class ExternalEditor {
|
||||
text: string;
|
||||
tempFile: string;
|
||||
editor: IEditorParams;
|
||||
lastExitStatus: number;
|
||||
private fileOptions;
|
||||
get temp_file(): string;
|
||||
get last_exit_status(): number;
|
||||
constructor(text?: string, fileOptions?: IFileOptions);
|
||||
run(): string;
|
||||
runAsync(callback: StringCallback): void;
|
||||
cleanup(): void;
|
||||
private determineEditor;
|
||||
private createTemporaryFile;
|
||||
private readTemporaryFile;
|
||||
private removeTemporaryFile;
|
||||
private launchEditor;
|
||||
private launchEditorAsync;
|
||||
}
|
||||
191
node_modules/@inquirer/external-editor/dist/esm/index.js
generated
vendored
Normal file
191
node_modules/@inquirer/external-editor/dist/esm/index.js
generated
vendored
Normal file
@@ -0,0 +1,191 @@
|
||||
import { detect } from 'chardet';
|
||||
import { spawn, spawnSync } from 'child_process';
|
||||
import { readFileSync, unlinkSync, writeFileSync } from 'fs';
|
||||
import path from 'node:path';
|
||||
import os from 'node:os';
|
||||
import { randomUUID } from 'node:crypto';
|
||||
import iconv from 'iconv-lite';
|
||||
import { CreateFileError } from './errors/CreateFileError.js';
|
||||
import { LaunchEditorError } from './errors/LaunchEditorError.js';
|
||||
import { ReadFileError } from './errors/ReadFileError.js';
|
||||
import { RemoveFileError } from './errors/RemoveFileError.js';
|
||||
export { CreateFileError, LaunchEditorError, ReadFileError, RemoveFileError };
|
||||
export function edit(text = '', fileOptions) {
|
||||
const editor = new ExternalEditor(text, fileOptions);
|
||||
editor.run();
|
||||
editor.cleanup();
|
||||
return editor.text;
|
||||
}
|
||||
export function editAsync(text = '', callback, fileOptions) {
|
||||
const editor = new ExternalEditor(text, fileOptions);
|
||||
editor.runAsync((err, result) => {
|
||||
if (err) {
|
||||
setImmediate(callback, err, undefined);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
editor.cleanup();
|
||||
setImmediate(callback, undefined, result);
|
||||
}
|
||||
catch (cleanupError) {
|
||||
setImmediate(callback, cleanupError, undefined);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
function sanitizeAffix(affix) {
|
||||
if (!affix)
|
||||
return '';
|
||||
return affix.replace(/[^a-zA-Z0-9_.-]/g, '_');
|
||||
}
|
||||
function splitStringBySpace(str) {
|
||||
const pieces = [];
|
||||
let currentString = '';
|
||||
for (let strIndex = 0; strIndex < str.length; strIndex++) {
|
||||
const currentLetter = str.charAt(strIndex);
|
||||
if (strIndex > 0 &&
|
||||
currentLetter === ' ' &&
|
||||
str[strIndex - 1] !== '\\' &&
|
||||
currentString.length > 0) {
|
||||
pieces.push(currentString);
|
||||
currentString = '';
|
||||
}
|
||||
else {
|
||||
currentString = `${currentString}${currentLetter}`;
|
||||
}
|
||||
}
|
||||
if (currentString.length > 0) {
|
||||
pieces.push(currentString);
|
||||
}
|
||||
return pieces;
|
||||
}
|
||||
export class ExternalEditor {
|
||||
text = '';
|
||||
tempFile;
|
||||
editor;
|
||||
lastExitStatus = 0;
|
||||
fileOptions = {};
|
||||
get temp_file() {
|
||||
console.log('DEPRECATED: temp_file. Use tempFile moving forward.');
|
||||
return this.tempFile;
|
||||
}
|
||||
get last_exit_status() {
|
||||
console.log('DEPRECATED: last_exit_status. Use lastExitStatus moving forward.');
|
||||
return this.lastExitStatus;
|
||||
}
|
||||
constructor(text = '', fileOptions) {
|
||||
this.text = text;
|
||||
if (fileOptions) {
|
||||
this.fileOptions = fileOptions;
|
||||
}
|
||||
this.determineEditor();
|
||||
this.createTemporaryFile();
|
||||
}
|
||||
run() {
|
||||
this.launchEditor();
|
||||
this.readTemporaryFile();
|
||||
return this.text;
|
||||
}
|
||||
runAsync(callback) {
|
||||
try {
|
||||
this.launchEditorAsync(() => {
|
||||
try {
|
||||
this.readTemporaryFile();
|
||||
setImmediate(callback, undefined, this.text);
|
||||
}
|
||||
catch (readError) {
|
||||
setImmediate(callback, readError, undefined);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (launchError) {
|
||||
setImmediate(callback, launchError, undefined);
|
||||
}
|
||||
}
|
||||
cleanup() {
|
||||
this.removeTemporaryFile();
|
||||
}
|
||||
determineEditor() {
|
||||
const editor = process.env['VISUAL']
|
||||
? process.env['VISUAL']
|
||||
: process.env['EDITOR']
|
||||
? process.env['EDITOR']
|
||||
: process.platform.startsWith('win')
|
||||
? 'notepad'
|
||||
: 'vim';
|
||||
const editorOpts = splitStringBySpace(editor).map((piece) => piece.replace('\\ ', ' '));
|
||||
const bin = editorOpts.shift();
|
||||
this.editor = { args: editorOpts, bin };
|
||||
}
|
||||
createTemporaryFile() {
|
||||
try {
|
||||
const baseDir = this.fileOptions.dir ?? os.tmpdir();
|
||||
const id = randomUUID();
|
||||
const prefix = sanitizeAffix(this.fileOptions.prefix);
|
||||
const postfix = sanitizeAffix(this.fileOptions.postfix);
|
||||
const filename = `${prefix}${id}${postfix}`;
|
||||
const candidate = path.resolve(baseDir, filename);
|
||||
const baseResolved = path.resolve(baseDir) + path.sep;
|
||||
if (!candidate.startsWith(baseResolved)) {
|
||||
throw new Error('Resolved temporary file escaped the base directory');
|
||||
}
|
||||
this.tempFile = candidate;
|
||||
const opt = { encoding: 'utf8', flag: 'wx' };
|
||||
if (Object.prototype.hasOwnProperty.call(this.fileOptions, 'mode')) {
|
||||
opt.mode = this.fileOptions.mode;
|
||||
}
|
||||
writeFileSync(this.tempFile, this.text, opt);
|
||||
}
|
||||
catch (createFileError) {
|
||||
throw new CreateFileError(createFileError);
|
||||
}
|
||||
}
|
||||
readTemporaryFile() {
|
||||
try {
|
||||
const tempFileBuffer = readFileSync(this.tempFile);
|
||||
if (tempFileBuffer.length === 0) {
|
||||
this.text = '';
|
||||
}
|
||||
else {
|
||||
let encoding = detect(tempFileBuffer) ?? 'utf8';
|
||||
if (!iconv.encodingExists(encoding)) {
|
||||
// Probably a bad idea, but will at least prevent crashing
|
||||
encoding = 'utf8';
|
||||
}
|
||||
this.text = iconv.decode(tempFileBuffer, encoding);
|
||||
}
|
||||
}
|
||||
catch (readFileError) {
|
||||
throw new ReadFileError(readFileError);
|
||||
}
|
||||
}
|
||||
removeTemporaryFile() {
|
||||
try {
|
||||
unlinkSync(this.tempFile);
|
||||
}
|
||||
catch (removeFileError) {
|
||||
throw new RemoveFileError(removeFileError);
|
||||
}
|
||||
}
|
||||
launchEditor() {
|
||||
try {
|
||||
const editorProcess = spawnSync(this.editor.bin, this.editor.args.concat([this.tempFile]), { stdio: 'inherit' });
|
||||
this.lastExitStatus = editorProcess.status ?? 0;
|
||||
}
|
||||
catch (launchError) {
|
||||
throw new LaunchEditorError(launchError);
|
||||
}
|
||||
}
|
||||
launchEditorAsync(callback) {
|
||||
try {
|
||||
const editorProcess = spawn(this.editor.bin, this.editor.args.concat([this.tempFile]), { stdio: 'inherit' });
|
||||
editorProcess.on('exit', (code) => {
|
||||
this.lastExitStatus = code;
|
||||
setImmediate(callback);
|
||||
});
|
||||
}
|
||||
catch (launchError) {
|
||||
throw new LaunchEditorError(launchError);
|
||||
}
|
||||
}
|
||||
}
|
||||
3
node_modules/@inquirer/external-editor/dist/esm/package.json
generated
vendored
Normal file
3
node_modules/@inquirer/external-editor/dist/esm/package.json
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"type": "module"
|
||||
}
|
||||
114
node_modules/@inquirer/external-editor/package.json
generated
vendored
Normal file
114
node_modules/@inquirer/external-editor/package.json
generated
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
{
|
||||
"name": "@inquirer/external-editor",
|
||||
"version": "1.0.2",
|
||||
"description": "Edit a string with the users preferred text editor using $VISUAL or $ENVIRONMENT",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
"./package.json": "./package.json",
|
||||
".": {
|
||||
"import": {
|
||||
"types": "./dist/esm/index.d.ts",
|
||||
"default": "./dist/esm/index.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/commonjs/index.d.ts",
|
||||
"default": "./dist/commonjs/index.js"
|
||||
}
|
||||
}
|
||||
},
|
||||
"module": "./dist/esm/index.js",
|
||||
"main": "./dist/commonjs/index.js",
|
||||
"types": "./dist/commonjs/index.d.ts",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/SBoudrias/Inquirer.js.git"
|
||||
},
|
||||
"keywords": [
|
||||
"answer",
|
||||
"answers",
|
||||
"ask",
|
||||
"base",
|
||||
"cli",
|
||||
"command",
|
||||
"command-line",
|
||||
"confirm",
|
||||
"enquirer",
|
||||
"generate",
|
||||
"generator",
|
||||
"hyper",
|
||||
"input",
|
||||
"inquire",
|
||||
"inquirer",
|
||||
"interface",
|
||||
"iterm",
|
||||
"javascript",
|
||||
"menu",
|
||||
"node",
|
||||
"nodejs",
|
||||
"prompt",
|
||||
"promptly",
|
||||
"prompts",
|
||||
"question",
|
||||
"readline",
|
||||
"scaffold",
|
||||
"scaffolder",
|
||||
"scaffolding",
|
||||
"stdin",
|
||||
"stdout",
|
||||
"terminal",
|
||||
"tty",
|
||||
"ui",
|
||||
"yeoman",
|
||||
"yo",
|
||||
"zsh",
|
||||
"editor",
|
||||
"external",
|
||||
"external-editor",
|
||||
"user",
|
||||
"visual"
|
||||
],
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"author": "Simon Boudrias <admin@simonboudrias.com>",
|
||||
"license": "MIT",
|
||||
"sideEffects": false,
|
||||
"homepage": "https://github.com/SBoudrias/Inquirer.js/blob/main/packages/external-editor/README.md",
|
||||
"dependencies": {
|
||||
"chardet": "^2.1.0",
|
||||
"iconv-lite": "^0.7.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@arethetypeswrong/cli": "^0.18.2",
|
||||
"@types/chardet": "^1.0.0",
|
||||
"tshy": "^3.0.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/node": ">=18"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/node": {
|
||||
"optional": true
|
||||
}
|
||||
},
|
||||
"tshy": {
|
||||
"exclude": [
|
||||
"src/**/*.test.ts"
|
||||
],
|
||||
"exports": {
|
||||
"./package.json": "./package.json",
|
||||
".": "./src/index.ts"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"tsc": "tshy",
|
||||
"attw": "attw --pack"
|
||||
},
|
||||
"gitHead": "62045dc4a4cd6f31ba0f77b20874be2409570957"
|
||||
}
|
||||
Reference in New Issue
Block a user