🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

@inquirer/external-editor

Package Overview
Dependencies
Maintainers
2
Versions
13
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@inquirer/external-editor - npm Package Compare versions

Comparing version
2.0.4
to
3.0.0
+20
dist/errors.d.ts
export declare class CreateFileError extends Error {
name: string;
originalError: unknown;
constructor(originalError: unknown);
}
export declare class LaunchEditorError extends Error {
name: string;
originalError: unknown;
constructor(originalError: unknown);
}
export declare class ReadFileError extends Error {
name: string;
originalError: unknown;
constructor(originalError: unknown);
}
export declare class RemoveFileError extends Error {
name: string;
originalError: unknown;
constructor(originalError: unknown);
}
export class CreateFileError extends Error {
name = 'CreateFileError';
originalError;
constructor(originalError) {
super(`Failed to create temporary file.${originalError instanceof Error ? ` ${originalError.message}` : ''}`, { cause: originalError });
this.originalError = originalError;
}
}
export class LaunchEditorError extends Error {
name = 'LaunchEditorError';
originalError;
constructor(originalError) {
super(`Failed to launch editor.${originalError instanceof Error ? ` ${originalError.message}` : ''}`, { cause: originalError });
this.originalError = originalError;
}
}
export class ReadFileError extends Error {
name = 'ReadFileError';
originalError;
constructor(originalError) {
super(`Failed to read temporary file.${originalError instanceof Error ? ` ${originalError.message}` : ''}`, { cause: originalError });
this.originalError = originalError;
}
}
export class RemoveFileError extends Error {
name = 'RemoveFileError';
originalError;
constructor(originalError) {
super(`Failed to remove temporary file.${originalError instanceof Error ? ` ${originalError.message}` : ''}`, { cause: originalError });
this.originalError = originalError;
}
}
export type EditorParams = {
args: string[];
bin: string;
};
export declare function parseEditorCommand(editor: string): EditorParams;
export function parseEditorCommand(editor) {
let bin;
let rest;
if (editor.startsWith('"')) {
const closeQuote = editor.indexOf('"', 1);
if (closeQuote === -1) {
// Unmatched quote — treat the whole string as the binary
bin = editor.slice(1);
rest = '';
}
else {
bin = editor.substring(1, closeQuote);
rest = editor.substring(closeQuote + 1).trim();
}
}
else {
const firstSpace = editor.indexOf(' ');
if (firstSpace === -1) {
bin = editor;
rest = '';
}
else {
bin = editor.substring(0, firstSpace);
rest = editor.substring(firstSpace + 1).trim();
}
}
return { bin, args: rest ? rest.split(/\s+/) : [] };
}
+21
-27

@@ -1,10 +0,5 @@

import { CreateFileError } from './errors/CreateFileError.ts';
import { LaunchEditorError } from './errors/LaunchEditorError.ts';
import { ReadFileError } from './errors/ReadFileError.ts';
import { RemoveFileError } from './errors/RemoveFileError.ts';
export interface IEditorParams {
args: string[];
bin: string;
}
export interface IFileOptions {
import { CreateFileError, LaunchEditorError, ReadFileError, RemoveFileError } from './errors.ts';
import { type EditorParams } from './parse-editor-command.ts';
type StringCallback = (err: Error | undefined, result: string | undefined) => void;
export type FileOptions = {
prefix?: string;

@@ -15,26 +10,25 @@ postfix?: string;

dir?: string;
}
export type StringCallback = (err: Error | undefined, result: string | undefined) => void;
export type VoidCallback = () => void;
};
/** @deprecated Use FileOptions */
export type IFileOptions = FileOptions;
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 function edit(text?: string, fileOptions?: FileOptions): string;
type EditAsync = {
/** @deprecated Use editAsync(text, options) returning a Promise instead */
(text: string, callback: StringCallback, fileOptions?: FileOptions): Promise<string>;
(text?: string, fileOptions?: FileOptions): Promise<string>;
};
export declare const editAsync: EditAsync;
export declare class ExternalEditor {
text: string;
tempFile: string;
editor: IEditorParams;
editor: EditorParams;
lastExitStatus: number;
private text;
private tempFile;
private fileOptions;
get temp_file(): string;
get last_exit_status(): number;
constructor(text?: string, fileOptions?: IFileOptions);
constructor(text?: string, fileOptions?: FileOptions);
run(): string;
runAsync(callback: StringCallback): void;
cleanup(): void;
private determineEditor;
private createTemporaryFile;
runAsync(callback?: StringCallback): Promise<string>;
private cleanup;
private createTempFile;
private readTemporaryFile;
private removeTemporaryFile;
private launchEditor;
private launchEditorAsync;
}
import { detect } from 'chardet';
import { spawn, spawnSync } from 'child_process';
import { readFileSync, unlinkSync, writeFileSync } from 'fs';
import { spawn, spawnSync } from 'node:child_process';
import { readFileSync, unlinkSync, writeFileSync } from 'node:fs';
import path from 'node:path';

@@ -8,30 +8,13 @@ import os from 'node:os';

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";
import { CreateFileError, LaunchEditorError, ReadFileError, RemoveFileError, } from "./errors.js";
import { parseEditorCommand } from "./parse-editor-command.js";
export { CreateFileError, LaunchEditorError, ReadFileError, RemoveFileError };
export function edit(text = '', fileOptions) {
const editor = new ExternalEditor(text, fileOptions);
editor.run();
editor.cleanup();
return editor.text;
return new ExternalEditor(text, fileOptions).run();
}
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);
}
}
});
}
export const editAsync = (text, callbackOrOptions, fileOptions) => {
const callback = typeof callbackOrOptions === 'function' ? callbackOrOptions : undefined;
const options = typeof callbackOrOptions === 'function' ? fileOptions : callbackOrOptions;
return new ExternalEditor(text, options).runAsync(callback);
};
function sanitizeAffix(affix) {

@@ -42,82 +25,70 @@ if (!affix)

}
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;
text = '';
tempFile = '';
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) {
constructor(text = '', fileOptions = {}) {
this.text = text;
if (fileOptions) {
this.fileOptions = fileOptions;
}
this.determineEditor();
this.createTemporaryFile();
this.fileOptions = fileOptions;
this.editor = parseEditorCommand(process.env['VISUAL'] ??
process.env['EDITOR'] ??
(process.platform.startsWith('win') ? 'notepad' : 'vim'));
}
run() {
this.launchEditor();
this.readTemporaryFile();
return this.text;
this.createTempFile();
try {
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);
}
this.readTemporaryFile();
return this.text;
}
finally {
this.cleanup();
}
}
runAsync(callback) {
this.createTempFile();
const promise = new Promise((resolve, reject) => {
try {
const editorProcess = spawn(this.editor.bin, this.editor.args.concat([this.tempFile]), { stdio: 'inherit' });
editorProcess.on('exit', (code) => {
this.lastExitStatus = code;
resolve();
});
}
catch (launchError) {
reject(new LaunchEditorError(launchError));
}
})
.then(() => {
this.readTemporaryFile();
return this.text;
})
.finally(() => {
this.cleanup();
});
if (callback) {
promise.then((text) => callback(undefined, text), (err) => callback(err instanceof Error ? err : new Error(String(err)), undefined));
}
return promise;
}
cleanup() {
if (!this.tempFile)
return;
try {
this.launchEditorAsync(() => {
try {
this.readTemporaryFile();
setImmediate(callback, undefined, this.text);
}
catch (readError) {
setImmediate(callback, readError, undefined);
}
});
unlinkSync(this.tempFile);
this.tempFile = '';
}
catch (launchError) {
setImmediate(callback, launchError, undefined);
catch (removeFileError) {
throw new RemoveFileError(removeFileError);
}
}
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() {
createTempFile() {
try {

@@ -164,31 +135,2 @@ const baseDir = this.fileOptions.dir ?? os.tmpdir();

}
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);
}
}
}
{
"name": "@inquirer/external-editor",
"version": "2.0.4",
"version": "3.0.0",
"description": "Edit a string with the users preferred text editor using $VISUAL or $ENVIRONMENT",

@@ -80,3 +80,4 @@ "keywords": [

"@types/chardet": "^1.0.0",
"typescript": "^5.9.3"
"@types/node": "^25.5.2",
"typescript": "^6.0.2"
},

@@ -96,3 +97,3 @@ "peerDependencies": {

"types": "./dist/index.d.ts",
"gitHead": "b218fcc4afe888a58957aa78c9a032f9bd2d60cb"
"gitHead": "e68fe01d65359e083581c48c4a18cd8f97d88842"
}