Skip to content

Commit

Permalink
Bring back CmdArgs (#59)
Browse files Browse the repository at this point in the history
  • Loading branch information
asamuzaK committed May 14, 2024
1 parent 9d07496 commit 468c4db
Show file tree
Hide file tree
Showing 7 changed files with 461 additions and 10 deletions.
26 changes: 21 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,30 +142,46 @@ Output method:
* @param {Object} msg - message
* @returns {?Buffer} - buffered message, nullable

### Class ChildProcess
### Class ChildProcess / CmdArgs

Spawns child process.

Sample:
```javascript
import path from 'node:path';
import process from 'node:process';
import { ChildProcess } from 'web-ext-native-msg';
import { ChildProcess, CmdArgs } from 'web-ext-native-msg';

const arg = '-a -b -c';
const cmdArgs = (new CmdArgs(arg)).toArray();

const app = path.resolve(path.join('path', 'to', 'myApp.exe'));
const arg = ['-a, '-b', -c'];
const file = path.resolve(path.join('path', 'to', 'myFile.txt'));
const opt = {
cwd: null,
encoding: 'utf8',
env: process.env
};
const file = path.resolve(path.join('path', 'to', 'myFile.txt'));

const proc = (new ChildProcess(app, arg, opt)).spawn(file).catch(e => {
const proc = (new ChildProcess(app, cmdArgs, opt)).spawn(file).catch(e => {
throw e;
});
```

Construct:
* new CmdArgs(arg)
* @param {string|Array} arg - argument input
* new ChildProcess(app, args, opt)
* @param {string} app - application path
* @param {string|Array} [args] - command arguments
* @param {Object} [opt] - options. Defaults to `{cwd: null, env: process.env}`.

CmdArgs methods:
* toArray(): Arguments to array.
* @returns {Array} - arguments array or empty array
* toString(): Arguments array to string.
* @returns {string} - arguments string or empty string

ChildProcess method:
* spawn(file): Spawn child process. Async.
* @param {string} [file] - file path
Expand Down
2 changes: 1 addition & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* @see {@link https://github.com/asamuzaK/webExtNativeMsg/blob/master/LICENSE}
*/

export { ChildProcess } from './modules/child-process.js';
export { ChildProcess, CmdArgs } from './modules/child-process.js';
export { Input, Output } from './modules/native-message.js';
export { Setup } from './modules/setup.js';
export {
Expand Down
118 changes: 117 additions & 1 deletion modules/child-process.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,125 @@ import os from 'node:os';
import path from 'node:path';
import process from 'node:process';
import { parse, quote } from 'shell-quote';
import { getType, isString } from './common.js';
import { escapeChar, getType, isString } from './common.js';
import { isExecutable, isFile } from './file-util.js';

/**
* concat array
* @param {Array} arrA - array
* @param {Array} arrB - array
* @returns {Array} - array
*/
export const concatArray = (arrA, arrB) => {
if (!Array.isArray(arrA)) {
throw new TypeError(`Expected Array but got ${getType(arrA)}.`);
}
if (!Array.isArray(arrB)) {
throw new TypeError(`Expected Array but got ${getType(arrB)}.`);
}
return arrA.concat(arrB);
};

/**
* correct argument string
* @param {string} arg - argument
* @returns {string} - argument
*/
export const correctArg = arg => {
if (!isString(arg)) {
throw new TypeError(`Expected String but got ${getType(arg)}.`);
}
if (/^\s*(?:".*"|'.*')\s*$/.test(arg)) {
arg = arg.trim().replace(/^['"]/, '').replace(/["']$/, '');
if (/\\["\\]/.test(arg)) {
arg = arg.replace(/\\"/g, '"').replace(/\\\\/g, '\\');
}
} else {
if (/^.{0,4096}\\.{0,4096}$/.test(arg)) {
arg = arg.replace(/\\(?!\\)/g, '');
}
if (/"[^"]{0,16777216}"|'[^']{0,16777216}'/.test(arg)) {
arg = arg.replace(/"([^"]{1,4096}){0,4096}"|'([^']{1,4096}){0,4096}'/g, (m, c1, c2) => c1 || c2);
}
}
return arg;
};

/**
* extract argument
* @param {string} arg - argument
* @returns {Array.<string|undefined>} - arguments array
*/
export const extractArg = arg => {
if (!isString(arg)) {
throw new TypeError(`Expected String but got ${getType(arg)}.`);
}
let arr;
arg = escapeChar(arg, /(\\)/g);
if (arg) {
const reCmd = /(?:^|\s)(?:"(?:[^"\\]|\\[^"]|\\"){0,4096}"|'(?:[^'\\]|\\[^']|\\'){0,4096}')(?=\s|$)|(?:\\ |\S){1,4096}(?:"(?:[^"\\]|\\[^"]|\\"){0,4096}"|'(?:[^'\\]|\\[^']|\\'){0,4096}')(?:(?:\\ |\S){1,4096}(?:"(?:[^"\\]|\\[^"]|\\"){0,4096}"|'(?:[^'\\]|\\[^']|\\'){0,4096}')){0,4096}(?:\\ |\S){0,4096}|(?:[^"'\s\\]|\\\S|\\ ){1,4096}/g;
arr = arg.match(reCmd);
}
return Array.isArray(arr) ? arr.map(correctArg) : [];
};

/**
* stringify argument string
* @param {string} arg - argument
* @returns {string} - argument
*/
export const stringifyArg = arg => {
let str;
if (isString(arg)) {
if (/["'\\\s]/.test(arg)) {
str = `"${escapeChar(arg, /(["\\])/g)}"`.trim();
} else {
str = arg.trim();
}
} else {
str = '';
}
return str;
};

/* CmdArgs */
export class CmdArgs {
/* private fields */
#input;

/**
* argument input
* @param {string|Array} input - input
*/
constructor(input) {
this.#input = input;
}

/**
* arguments to array
* @returns {Array} - arguments array
*/
toArray() {
let arr;
if (Array.isArray(this.#input)) {
arr = this.#input;
} else if (isString(this.#input)) {
const args = [this.#input].map(extractArg);
arr = args.reduce(concatArray);
}
return arr || [];
}

/**
* arguments array to string
* @returns {string} - arguments string
*/
toString() {
const args = this.toArray().map(stringifyArg).join(' ');
return args.trim();
}
}

/* Child process */
export class ChildProcess {
/* private fields */
Expand Down

0 comments on commit 468c4db

Please sign in to comment.