Compare commits

..

34 Commits

Author SHA1 Message Date
a6f164602c 2.0.16 2019-05-22 15:45:09 +02:00
f8457ad58d fix(core): update 2019-05-22 15:45:08 +02:00
8ceac74a1f 2.0.15 2019-05-19 22:41:20 +02:00
f63c4456bf fix(core): update 2019-05-19 22:41:20 +02:00
32c33cad5b 2.0.14 2019-05-14 17:28:38 +02:00
0758e58fa4 fix(core): update 2019-05-14 17:28:38 +02:00
e981ca6bdd 2.0.13 2018-12-14 18:36:23 +01:00
2853a48708 fix(core): update 2018-12-14 18:36:23 +01:00
389f8f4a52 2.0.12 2018-12-14 18:35:31 +01:00
c1a537f052 fix(core): update 2018-12-14 18:35:31 +01:00
4701341c0c ensure WSL compatibility 2018-12-13 16:50:32 +01:00
d5d347721a 2.0.11 2018-11-26 17:55:16 +01:00
6a047d6333 fix(core): update 2018-11-26 17:55:15 +01:00
6e7b4dd18e 2.0.10 2018-11-26 17:46:32 +01:00
debc5f1524 fix(core): update 2018-11-26 17:46:31 +01:00
8d03561762 2.0.9 2018-11-26 17:45:59 +01:00
f516a6e753 fix(core): update 2018-11-26 17:45:58 +01:00
1c4f6a8bf9 2.0.8 2018-10-28 19:18:42 +01:00
4fe3775904 fix(child processes): now run detached 2018-10-28 19:18:42 +01:00
dcee2d6233 2.0.7 2018-10-28 19:12:16 +01:00
39d457382f fix(exec): processes now run detached 2018-10-28 19:12:15 +01:00
e6ed457501 2.0.6 2018-08-05 23:27:38 +02:00
0a6484762c fix(ci): update testing framework 2018-08-05 23:27:37 +02:00
baa3e4e6e9 2.0.5 2018-08-04 16:43:02 +02:00
0d68361381 fix(PATH): add proper PATH handling for child processes 2018-08-04 16:43:02 +02:00
286d80328c 2.0.4 2018-07-30 16:34:45 +02:00
2a71f00ab0 2.0.3 2018-07-30 16:19:38 +02:00
80a44a43cb fix(ci): update build step to be faster 2018-07-30 16:19:38 +02:00
5ea780acda 2.0.2 2018-07-30 16:08:14 +02:00
7c9cf6e70d fix(structure): clean up 2018-07-30 16:08:14 +02:00
697f789b55 2.0.1 2018-07-30 16:06:43 +02:00
f452964779 fix(test): add test for environment 2018-07-30 16:06:43 +02:00
f2db8dc41f 2.0.0 2018-07-30 16:03:48 +02:00
2ca593297c BREAKING CHANGE(update the API): update 2018-07-30 16:03:48 +02:00
13 changed files with 1382 additions and 621 deletions

View File

@ -26,6 +26,7 @@ mirror:
snyk:
stage: security
script:
- npmci npm prepare
- npmci command npm install -g snyk
- npmci command npm install --ignore-scripts
- npmci command snyk test
@ -36,21 +37,11 @@ snyk:
# ====================
# test stage
# ====================
testLEGACY:
stage: test
script:
- npmci node install legacy
- npmci npm install
- npmci npm test
coverage: /\d+.?\d+?\%\s*coverage/
tags:
- docker
- notpriv
allow_failure: true
testLTS:
stage: test
script:
- npmci npm prepare
- npmci node install lts
- npmci npm install
- npmci npm test
@ -62,6 +53,7 @@ testLTS:
testSTABLE:
stage: test
script:
- npmci npm prepare
- npmci node install stable
- npmci npm install
- npmci npm test
@ -117,8 +109,10 @@ pages:
image: hosttoday/ht-docker-node:npmci
stage: metadata
script:
- npmci command npm install -g npmpage
- npmci command npmpage
- npmci command npm install -g typedoc typescript
- npmci npm prepare
- npmci npm install
- npmci command typedoc --module "commonjs" --target "ES2016" --out public/ ts/
tags:
- docker
- notpriv
@ -129,13 +123,3 @@ pages:
paths:
- public
allow_failure: true
windowsCompatibility:
image: stefanscherer/node-windows:10-build-tools
stage: metadata
script:
- npm install & npm test
coverage: /\d+.?\d+?\%\s*coverage/
tags:
- windows
allow_failure: true

View File

@ -1,32 +0,0 @@
# smartshell
shell actions designed as promises
## Availabililty
[![npm](https://pushrocks.gitlab.io/assets/repo-button-npm.svg)](https://www.npmjs.com/package/smartshell)
[![git](https://pushrocks.gitlab.io/assets/repo-button-git.svg)](https://GitLab.com/pushrocks/smartshell)
[![git](https://pushrocks.gitlab.io/assets/repo-button-mirror.svg)](https://github.com/pushrocks/smartshell)
[![docs](https://pushrocks.gitlab.io/assets/repo-button-docs.svg)](https://pushrocks.gitlab.io/smartshell/)
## Status for master
[![build status](https://GitLab.com/pushrocks/smartshell/badges/master/build.svg)](https://GitLab.com/pushrocks/smartshell/commits/master)
[![coverage report](https://GitLab.com/pushrocks/smartshell/badges/master/coverage.svg)](https://GitLab.com/pushrocks/smartshell/commits/master)
[![npm downloads per month](https://img.shields.io/npm/dm/smartshell.svg)](https://www.npmjs.com/package/smartshell)
[![Dependency Status](https://david-dm.org/pushrocks/smartshell.svg)](https://david-dm.org/pushrocks/smartshell)
[![bitHound Dependencies](https://www.bithound.io/github/pushrocks/smartshell/badges/dependencies.svg)](https://www.bithound.io/github/pushrocks/smartshell/master/dependencies/npm)
[![bitHound Code](https://www.bithound.io/github/pushrocks/smartshell/badges/code.svg)](https://www.bithound.io/github/pushrocks/smartshell)
[![TypeScript](https://img.shields.io/badge/TypeScript-2.x-blue.svg)](https://nodejs.org/dist/latest-v6.x/docs/api/)
[![node](https://img.shields.io/badge/node->=%206.x.x-blue.svg)](https://nodejs.org/dist/latest-v6.x/docs/api/)
[![JavaScript Style Guide](https://img.shields.io/badge/code%20style-standard-brightgreen.svg)](http://standardjs.com/)
## Usage
Use TypeScript for best in class instellisense.
For further information read the linked docs at the top of this README.
> MIT licensed | **©** [Lossless GmbH](https://lossless.gmbh)
[![repo-footer](https://pushrocks.gitlab.io/assets/repo-footer.svg)](https://push.rocks)

View File

@ -1,9 +1,7 @@
{
"npmci": {
"npmGlobalTools": [
"npmts",
"ts-node"
],
"npmAccessLevel": "public"
"npmGlobalTools": [],
"npmAccessLevel": "public",
"npmRegistryUrl": "registry.npmjs.org"
}
}

1303
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +1,13 @@
{
"name": "@pushrocks/smartshell",
"private": false,
"version": "1.0.21",
"version": "2.0.16",
"description": "shell actions designed as promises",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
"scripts": {
"test": "(tsrun test/test.ts)",
"build": "(npmts)"
"test": "(tstest test/)",
"build": "(tsbuild)"
},
"repository": {
"type": "git",
@ -24,12 +24,17 @@
},
"homepage": "https://gitlab.com/pushrocks/smartshell#README",
"devDependencies": {
"@gitzone/tsrun": "^1.1.9",
"@pushrocks/tapbundle": "^3.0.1",
"@types/node": "^10.5.2"
"@gitzone/tsbuild": "^2.1.11",
"@gitzone/tsrun": "^1.2.6",
"@gitzone/tstest": "^1.0.20",
"@pushrocks/tapbundle": "^3.0.9",
"@types/node": "^12.0.2",
"tslint": "^5.16.0",
"tslint-config-prettier": "^1.18.0"
},
"dependencies": {
"@pushrocks/smartpromise": "^2.0.5",
"@pushrocks/smartexit": "^1.0.8",
"@pushrocks/smartpromise": "^3.0.2",
"@types/which": "^1.3.1",
"which": "^1.3.1"
}

View File

@ -1,37 +1,10 @@
import { expect, tap } from '@pushrocks/tapbundle';
import * as smartshell from '../ts/index';
import * as smartshell from '../ts';
import * as smartpromise from '@pushrocks/smartpromise';
let testSmartshell: smartshell.Smartshell;
tap.test('smartshell should run async', async () => {
let execResult = await smartshell.exec('npm -v');
expect(execResult.stdout).to.match(/[0-9\.]*/);
});
tap.test('smartshell should run async and silent', async () => {
let execResult = await smartshell.execSilent('npm -v');
expect(execResult.stdout).to.match(/[0-9\.]*/);
});
tap.test('smartshell should stream a shell execution', async () => {
let done = smartpromise.defer();
let execStreamingResponse = smartshell.execStreaming('npm -v');
execStreamingResponse.childProcess.stdout.on('data', data => {
done.resolve(data);
});
let data = await done.promise;
expect(data).to.match(/[0-9\.]*/);
await execStreamingResponse.finalPromise;
});
tap.test('it should execute and wait for a line in the output', async () => {
await smartshell.execAndWaitForLine('echo "5.0.4"', /5.0.4/);
});
// Smartshell class
tap.test('smartshell should create a Smartshell instance', async () => {
testSmartshell = new smartshell.Smartshell({
executor: 'bash',
@ -40,12 +13,41 @@ tap.test('smartshell should create a Smartshell instance', async () => {
expect(testSmartshell).to.be.instanceof(smartshell.Smartshell);
});
tap.test('smartshell should run async', async () => {
let execResult = await testSmartshell.exec('npm -v');
expect(execResult.stdout).to.match(/[0-9\.]*/);
});
tap.test('smartshell should run async and silent', async () => {
let execResult = await testSmartshell.execSilent('npm -v');
expect(execResult.stdout).to.match(/[0-9\.]*/);
});
tap.test('smartshell should stream a shell execution', async () => {
let done = smartpromise.defer();
let execStreamingResponse = await testSmartshell.execStreaming('npm -v');
execStreamingResponse.childProcess.stdout.on('data', data => {
done.resolve(data);
});
let data = await done.promise;
expect(data).to.match(/[0-9\.]*/);
await execStreamingResponse.finalPromise;
});
tap.test('it should execute and wait for a line in the output', async () => {
await testSmartshell.execAndWaitForLine('echo "5.0.4"', /5.0.4/);
});
tap.test('smartshell should run async', async () => {
return testSmartshell.execSilent('sleep 1 && npm -v').then(async execResult => {
console.log(execResult.stdout);
});
});
tap.test('should be able to find git', async () => {
testSmartshell.exec('git --version');
});
tap.start({
throwOnError: true
});

View File

@ -1,2 +1 @@
export * from './smartshell.wrap';
export * from './smartshell.classes.smartshell';

View File

@ -0,0 +1,103 @@
export type TExecutor = 'sh' | 'bash';
export interface IShellEnvContructorOptions {
executor: TExecutor;
sourceFilePaths?: string[];
pathDirectories?: string[];
}
export class ShellEnv {
executor: TExecutor;
sourceFileArray: string[] = [];
pathDirArray: string[] = [];
/**
* constructor for the shellenv
*/
constructor(optionsArg: IShellEnvContructorOptions) {
this.executor = optionsArg.executor;
// add sourcefiles
if (optionsArg.sourceFilePaths) {
this.sourceFileArray = this.sourceFileArray.concat(optionsArg.sourceFilePaths);
}
// add pathDirectories
if (optionsArg.pathDirectories) {
this.pathDirArray = this.pathDirArray.concat(optionsArg.pathDirectories);
}
}
/**
* imports path into the shell from env if available and returns it with
*/
private _setPath(commandStringArg): string {
let commandResult = commandStringArg;
let commandPaths: string[] = [];
commandPaths = commandPaths.concat(process.env.PATH.split(':'));
if (process.env.SMARTSHELL_PATH) {
commandPaths = commandPaths.concat(process.env.SMARTSHELL_PATH.split(':'));
}
// lets filter for unwanted paths
// Windows WSL
commandPaths = commandPaths.filter(commandPathArg => {
const filterResult =
!commandPathArg.startsWith('/mnt/c/') &&
!commandPathArg.startsWith('Files/1E') &&
!commandPathArg.includes(' ');
if (!filterResult) {
// console.log(`${commandPathArg} will be filtered!`);
}
return filterResult;
});
commandResult = `PATH=${commandPaths.join(':')} && ${commandStringArg}`;
return commandResult;
}
/**
* add files that are going to be sourced when running a command
* @param sourceFilePathsArray
*/
addSourceFiles(sourceFilePathsArray: string[]) {
for (let sourceFilePath of sourceFilePathsArray) {
this.sourceFileArray.push(sourceFilePath);
}
}
/**
* cleans the source files array
*/
cleanSourceFiles() {
this.sourceFileArray = [];
}
public createEnvExecString(commandArg: string): string {
let commandResult = '';
let sourceString = '';
// deal with sourcestring
for (const sourceFilePath of this.sourceFileArray) {
sourceString = sourceString + `source ${sourceFilePath} && `;
}
// deal with avaiable path
let pathString = 'PATH=$PATH';
for (const pathDir of this.pathDirArray) {
pathString += `:${pathDir}`;
}
pathString += ` && `;
switch (this.executor) {
case 'bash':
commandResult = `bash -c '${pathString}${sourceString}${commandArg}'`;
break;
case 'sh':
commandResult = `${pathString}${sourceString}${commandArg}`;
break;
}
commandResult = this._setPath(commandResult);
return commandResult;
}
}

View File

@ -0,0 +1,38 @@
import * as plugins from './smartshell.plugins';
/**
* a log handler for spawned logs
* making sure the process doesn't run out of memory
*/
export class ShellLog {
logStore = Buffer.from('');
/**
* log data to console
* @param dataArg
*/
logToConsole(dataArg: string | Buffer): void {
// make sure we have the data as string
process.stdout.write(dataArg);
}
/**
* add data to Buffer for later consumption
* @param dataArg
*/
addToBuffer(dataArg: string | Buffer): void {
// make sure we have the data as Buffer
const dataBuffer: Buffer = (() => {
if (!Buffer.isBuffer(dataArg)) {
return Buffer.from(dataArg);
}
return dataArg;
})();
this.logStore = Buffer.concat([this.logStore, dataBuffer]);
}
logAndAdd(dataArg: string | Buffer): void {
this.logToConsole(dataArg);
this.addToBuffer(dataArg);
}
}

View File

@ -1,64 +1,158 @@
// -- imports --
import * as plugins from './smartshell.plugins';
import * as smartshellWrap from './smartshell.wrap';
import { ShellEnv, IShellEnvContructorOptions, TExecutor } from './smartshell.classes.shellenv';
import { ShellLog } from './smartshell.classes.shelllog';
export type TExecutor = 'sh' | 'bash';
import * as cp from 'child_process';
import { Deferred } from '@pushrocks/smartpromise';
export interface ISmartshellContructorOptions {
executor: TExecutor;
sourceFilePaths: string[];
// -- interfaces --
/**
* interface for ExecResult
*/
export interface IExecResult {
exitCode: number;
stdout: string;
}
/**
* interface for streaming ExecResult
*/
export interface IExecResultStreaming {
childProcess: cp.ChildProcess;
finalPromise: Promise<IExecResult>;
kill: () => void;
}
// -- SmartShell --
export class Smartshell {
executor: TExecutor;
sourceFileArray: string[] = [];
constructor(optionsArg: ISmartshellContructorOptions) {
this.executor = optionsArg.executor;
for (let sourceFilePath of optionsArg.sourceFilePaths) {
this.sourceFileArray.push(sourceFilePath);
}
}
public shellEnv: ShellEnv;
public smartexit = new plugins.smartexit.SmartExit();
addSourceFiles(sourceFilePathsArray: string[]) {
for (let sourceFilePath of sourceFilePathsArray) {
this.sourceFileArray.push(sourceFilePath);
}
}
cleanSourceFiles() {
this.sourceFileArray = [];
constructor(optionsArg: IShellEnvContructorOptions) {
this.shellEnv = new ShellEnv(optionsArg);
}
/**
* executes silently and returns IExecResult
* @param commandArg
* executes a given command async
* @param commandStringArg
*/
async execSilent(commandArg: string) {
let execCommand = this.createExecString(commandArg);
return await smartshellWrap.execSilent(execCommand);
}
private async _exec(
commandStringArg: string,
silentArg: boolean = false,
strictArg = false,
streamingArg = false
): Promise<IExecResult | IExecResultStreaming> {
// flow control promises
const done = plugins.smartpromise.defer<IExecResult | IExecResultStreaming>();
const childProcessEnded = plugins.smartpromise.defer<IExecResult>();
// build commandToExecute
let commandToExecute = commandStringArg;
commandToExecute = this.shellEnv.createEnvExecString(commandStringArg);
const spawnlogInstance = new ShellLog();
const execChildProcess = cp.spawn(commandToExecute, [], {
shell: true,
env: process.env,
detached: true
});
/**
* executes and returns IExecResult
* @param commandArg
*/
async exec(commandArg: string) {
let execCommand = this.createExecString(commandArg);
return await smartshellWrap.exec(execCommand);
}
this.smartexit.addProcess(execChildProcess);
/**
* creates the final sourcing string
* @param commandArg
*/
private createExecString(commandArg): string {
if (this.executor === 'bash') {
let sourceString = '';
for (let sourceFilePath of this.sourceFileArray) {
sourceString = sourceString + `source ${sourceFilePath} && `;
execChildProcess.stdout.on('data', data => {
if (!silentArg) {
spawnlogInstance.logToConsole(data);
}
return `bash -c '${sourceString} ${commandArg}'`;
} else {
return commandArg;
spawnlogInstance.addToBuffer(data);
});
execChildProcess.stderr.on('data', data => {
if (!silentArg) {
spawnlogInstance.logToConsole(data);
}
spawnlogInstance.addToBuffer(data);
});
if (streamingArg) {
done.resolve({
childProcess: execChildProcess,
finalPromise: childProcessEnded.promise,
kill: () => {
// this notation with the - kills the whole process group
process.kill(-execChildProcess.pid);
}
});
}
execChildProcess.on('exit', (code, signal) => {
this.smartexit.removeProcess(execChildProcess);
if (strictArg && code === 1) {
done.reject();
}
const execResult = {
exitCode: code,
stdout: spawnlogInstance.logStore.toString()
};
if (!streamingArg) {
done.resolve(execResult);
}
childProcessEnded.resolve(execResult);
});
const result = await done.promise;
return result;
}
async exec(commandStringArg: string): Promise<IExecResult> {
return (await this._exec(commandStringArg, false)) as IExecResult;
}
/**
* executes a given command async and silent
* @param commandStringArg
*/
async execSilent(commandStringArg: string): Promise<IExecResult> {
return (await this._exec(commandStringArg, true)) as IExecResult;
}
/**
* executes a command async and strict, meaning it rejects the promise if something happens
*/
async execStrict(commandStringArg: string): Promise<IExecResult> {
return (await this._exec(commandStringArg, true, true)) as IExecResult;
}
/**
* executes a command and allows you to stream output
*/
async execStreaming(
commandStringArg: string,
silentArg: boolean = false
): Promise<IExecResultStreaming> {
return (await this._exec(commandStringArg, silentArg, false, true)) as IExecResultStreaming;
}
async execStreamingSilent(commandStringArg: string) {
return (await this.execStreaming(commandStringArg, true)) as IExecResultStreaming;
}
/**
* executes a command and returns promise that will be fullfilled once an putput line matches RegexArg
* @param commandStringArg
* @param regexArg
*/
async execAndWaitForLine(commandStringArg: string, regexArg: RegExp, silentArg: boolean = false) {
let done = plugins.smartpromise.defer();
let execStreamingResult = await this.execStreaming(commandStringArg, silentArg);
execStreamingResult.childProcess.stdout.on('data', (stdOutChunk: string) => {
if (regexArg.test(stdOutChunk)) {
done.resolve();
}
});
return done.promise;
}
async execAndWaitForLineSilent(commandStringArg: string, regexArg: RegExp) {
this.execAndWaitForLine(commandStringArg, regexArg, true);
}
}

View File

@ -1,4 +1,5 @@
import * as smartexit from '@pushrocks/smartexit';
import * as smartpromise from '@pushrocks/smartpromise';
import * as which from 'which';
export { smartpromise, which };
export { smartexit, smartpromise, which };

View File

@ -1,204 +0,0 @@
import * as plugins from "./smartshell.plugins";
// interfaces
import * as cp from "child_process";
import { Deferred } from "@pushrocks/smartpromise";
/**
* interface for ExecResult
*/
export interface IExecResult {
exitCode: number;
stdout: string;
}
/**
* interface for streaming ExecResult
*/
export interface IExecResultStreaming {
childProcess: cp.ChildProcess;
finalPromise: Promise<IExecResult>;
}
/**
* imports path into the shell from env if available and returns it with
*/
let importEnvVarPath = (stringArg): string => {
if (process.env.SMARTSHELL_PATH) {
let commandResult = `PATH=${process.env.SMARTSHELL_PATH} && ${stringArg}`;
// console.log(commandResult)
return commandResult;
} else {
return stringArg;
}
};
/**
* executes a given command async
* @param commandStringArg
*/
export let exec = (
commandStringArg: string,
silentArg: boolean = false,
strictArg = false
): Promise<IExecResult> => {
let done = plugins.smartpromise.defer<IExecResult>();
const commandToExecute = importEnvVarPath(commandStringArg);
try {
const execChildProcess = cp.exec(commandToExecute, {
timeout: null,
maxBuffer: 1000000,
env: process.env
});
let logStore = "";
execChildProcess.stdout.on("data", (data: string) => {
if (!silentArg) {
console.log(data);
}
logStore += data;
});
execChildProcess.stderr.on("data", data => {
if (!silentArg) {
console.log(data);
}
logStore += data;
});
execChildProcess.on("exit", (code, signal) => {
done.resolve({
exitCode: code,
stdout: logStore
});
});
} catch (e) {
const error = e;
}
/*plugins.shelljs.exec(importEnvVarPath(commandStringArg), { async: true, silent: silentArg }, (code, stdout, stderr) => {
if (
stderr
&& (stderr !== '')
&& (!silentArg || strictArg)
&& (process.env.DEBUG === 'true')
) {
console.log('StdErr found.')
console.log(stderr)
}
if (strictArg) {
done.reject(new Error(stderr))
return
}
done.resolve({
exitCode: code,
stdout: stdout
})
})*/
return done.promise;
};
/**
* executes a given command async and silent
* @param commandStringArg
*/
export let execSilent = async (
commandStringArg: string
): Promise<IExecResult> => {
return await exec(commandStringArg, true);
};
/**
* executes strict, meaning it rejects the promise if something happens
*/
export let execStrict = async (
commandStringArg: string
): Promise<IExecResult> => {
return await exec(commandStringArg, true, true);
};
/**
* executes a command and allws you to stream output
*/
export let execStreaming = (
commandStringArg: string,
silentArg: boolean = false
) => {
let childProcessEnded = plugins.smartpromise.defer<IExecResult>();
const commandToExecute = importEnvVarPath(commandStringArg);
let execChildProcess = cp.exec(commandToExecute, {
timeout: null,
maxBuffer: 1000000,
env: process.env
});
let logStore = "";
execChildProcess.stdout.on("data", (data: string) => {
if (!silentArg) {
console.log(data);
}
logStore += data;
});
execChildProcess.stderr.on("data", data => {
if (!silentArg) {
console.log(data);
}
logStore += data;
});
execChildProcess.on("exit", (code, signal) => {
childProcessEnded.resolve({
exitCode: code,
stdout: logStore
});
});
return {
childProcess: execChildProcess,
finalPromise: childProcessEnded.promise
};
};
export let execStreamingSilent = (commandStringArg: string) => {
return execStreaming(commandStringArg, true);
};
/**
* executes a command and returns promise that will be fullfilled once an putput line matches RegexArg
* @param commandStringArg
* @param regexArg
*/
export let execAndWaitForLine = (
commandStringArg: string,
regexArg: RegExp,
silentArg: boolean = false
) => {
let done = plugins.smartpromise.defer();
let execStreamingResult = execStreaming(commandStringArg, silentArg);
execStreamingResult.childProcess.stdout.on("data", (stdOutChunk: string) => {
if (regexArg.test(stdOutChunk)) {
done.resolve();
}
});
return done.promise;
};
export let execAndWaitForLineSilent = (
commandStringArg: string,
regexArg: RegExp
) => {
execAndWaitForLine(commandStringArg, regexArg, true);
};
/**
* get a path
*/
export let which = (cmd: string): Promise<string> => {
let done = plugins.smartpromise.defer<string>();
plugins.which(cmd, (err, path: string) => {
if (err) {
done.reject(err);
}
done.resolve(path);
});
return done.promise;
};

View File

@ -1,3 +1,17 @@
{
"extends": "tslint-config-standard"
"extends": ["tslint:latest", "tslint-config-prettier"],
"rules": {
"semicolon": [true, "always"],
"no-console": false,
"ordered-imports": false,
"object-literal-sort-keys": false,
"member-ordering": {
"options":{
"order": [
"static-method"
]
}
}
},
"defaultSeverity": "warning"
}