Skip to content

Commit

Permalink
feat(exposed): wraps all exposed fns errors as WrappedError, so their…
Browse files Browse the repository at this point in the history
… stacktrace doesn't get logged
  • Loading branch information
rafamel committed Apr 27, 2019
1 parent a576f09 commit ec911e3
Show file tree
Hide file tree
Showing 13 changed files with 153 additions and 123 deletions.
1 change: 1 addition & 0 deletions src/core/paths/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export async function getRootPaths(directories: {
} catch (err) {
if (!root) return null;
throw wrap.ensure(err, {
allow: [],
message: `root scope couldn't be retrieved: ${root}`
});
}
Expand Down
57 changes: 30 additions & 27 deletions src/exposed/exec/parallel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,35 +29,38 @@ export interface IParallel {
* @returns A `TScript`, as a function, that won't be executed until called by `kpo` -hence, calling `parallel` won't have any effect until the returned function is called.
*/
const parallel: IParallel = function parallel(commands, options = {}) {
return async function parallel(args?: string[]): Promise<void> {
const argv: string[] = Array.isArray(commands)
? commands.concat()
: [commands];
return (args?: string[]): Promise<void> => {
return wrap.throws(async () => {
const argv: string[] = Array.isArray(commands)
? commands.concat()
: [commands];

if (options.names && options.names.length) {
argv.push('--names', options.names.join(','));
}
if (options.colors && options.colors.length) {
argv.push('-c', options.colors.join(','));
}
if (options.early) {
argv.push('--kill-others-on-fail');
}
if (options.names && options.names.length) {
argv.push('--names', options.names.join(','));
}
if (options.colors && options.colors.length) {
argv.push('-c', options.colors.join(','));
}
if (options.early) {
argv.push('--kill-others-on-fail');
}

try {
await core.exec(
require.resolve('concurrently/bin/concurrently'),
args ? argv.concat(args) : argv,
true,
options
);
} catch (e) {
const err = wrap.ensure(e, {
message: 'Parallel commands execution failed'
});
if (options.silent) logger.error(err);
else throw err;
}
try {
await core.exec(
require.resolve('concurrently/bin/concurrently'),
args ? argv.concat(args) : argv,
true,
options
);
} catch (e) {
const err = wrap.ensure(e, {
allow: [],
message: 'Parallel commands execution failed'
});
if (options.silent) logger.error(err);
else throw err;
}
});
};
};

Expand Down
29 changes: 16 additions & 13 deletions src/exposed/exec/series.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import core from '~/core';
import { IExecOptions, TScript, IOfType } from '~/types';
import logger from '~/utils/logger';
import { wrap } from '~/utils/errors';

export interface ISeriesOptions extends IExecOptions {
/**
Expand All @@ -26,21 +27,23 @@ export interface ISeries {
* @returns A `TScript`, as a function, that won't be executed until called by `kpo` -hence, calling `series` won't have any effect until the returned function is called.
*/
const series: ISeries = function series(commands, options = {}) {
return async function series(args?: string[]): Promise<void> {
if (!Array.isArray(commands)) commands = [commands];
return (args?: string[]): Promise<void> => {
return wrap.throws(async () => {
if (!Array.isArray(commands)) commands = [commands];

let err: Error | null = null;
for (let command of commands) {
try {
if (!command) throw Error(`No command passed for series`);
await core.exec(command, args || [], false, options);
} catch (e) {
err = e;
if (options.force || options.silent) logger.error(err);
if (!options.force) break;
let err: Error | null = null;
for (let command of commands) {
try {
if (!command) throw Error(`No command passed for series`);
await core.exec(command, args || [], false, options);
} catch (e) {
err = e;
if (options.force || options.silent) logger.error(err);
if (!options.force) break;
}
}
}
if (err && !options.silent) throw err;
if (err && !options.silent) throw err;
});
};
};

Expand Down
29 changes: 16 additions & 13 deletions src/exposed/json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { exists } from '~/utils/file';
import core from '~/core';
import { IOfType, TScript } from '~/types';
import { rejects } from 'errorish';
import { wrap } from '~/utils/errors';

/**
* Reads a JSON `file` and passes it as an argument to a callback `fn`. If the callback returns an object, **`file` will be overwritten** with its contents. `file` can be relative to the project's directory.
Expand All @@ -13,19 +14,21 @@ export default function json(
file: string,
fn: (json: IOfType<any>) => IOfType<any> | void | Promise<IOfType<any> | void>
): TScript {
return async function json(): Promise<void> {
if (!path.isAbsolute(file)) {
const paths = await core.paths();
file = path.join(paths.directory, file);
}
return (): Promise<void> => {
return wrap.throws(async () => {
if (!path.isAbsolute(file)) {
const paths = await core.paths();
file = path.join(paths.directory, file);
}

await exists(file, { fail: true });
const json = await fs.readJSON(file).catch(rejects);
const response = await fn(json);
if (response) {
await fs
.writeFile(file, JSON.stringify(response, null, 2))
.catch(rejects);
}
await exists(file, { fail: true });
const json = await fs.readJSON(file).catch(rejects);
const response = await fn(json);
if (response) {
await fs
.writeFile(file, JSON.stringify(response, null, 2))
.catch(rejects);
}
});
};
}
3 changes: 2 additions & 1 deletion src/exposed/options.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { options as _options } from '~/core';
import { IScopeOptions } from '~/types';
import { wrap } from '~/utils/errors';

export default function options(opts: IScopeOptions): void {
return _options.setScope(opts);
return wrap.throws(() => _options.setScope(opts));
}
51 changes: 27 additions & 24 deletions src/exposed/prompts/confirm.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { TScript } from '~/types';
import prompts from 'prompts';
import { status } from 'promist';
import { wrap } from '~/utils/errors';

/**
* Options taken by `confirm`.
Expand Down Expand Up @@ -33,32 +34,34 @@ function confirm(options?: IConfirmOptions): TScript;
* @returns A `TScript`, as a function, that won't be executed until called by `kpo` -hence, calling `confirm` won't have any effect until the returned function is called.
*/
function confirm(...args: any[]): TScript {
return async function confirm(): Promise<TScript> {
const message: string =
args[0] && typeof args[0] === 'string' ? args[0] : 'Continue?';
const options: IConfirmOptions =
args[1] || (args[0] && typeof args[0] !== 'string' ? args[0] : {});
return (): Promise<TScript> => {
return wrap.throws(async () => {
const message: string =
args[0] && typeof args[0] === 'string' ? args[0] : 'Continue?';
const options: IConfirmOptions =
args[1] || (args[0] && typeof args[0] !== 'string' ? args[0] : {});

const promise = status(
prompts({
type: 'confirm',
name: 'value',
message:
message +
(options.timeout
? ` [${Math.round(options.timeout / 100) / 10}s]`
: ''),
initial: options.initial === undefined ? true : options.initial
})
);
const promise = status(
prompts({
type: 'confirm',
name: 'value',
message:
message +
(options.timeout
? ` [${Math.round(options.timeout / 100) / 10}s]`
: ''),
initial: options.initial === undefined ? true : options.initial
})
);

if (options.timeout) {
setTimeout(() => {
if (promise.status === 'pending') process.stdin.emit('data', '\n');
}, options.timeout);
}
if (options.timeout) {
setTimeout(() => {
if (promise.status === 'pending') process.stdin.emit('data', '\n');
}, options.timeout);
}

const response = await promise;
return (response.value ? options.yes : options.no) || undefined;
const response = await promise;
return (response.value ? options.yes : options.no) || undefined;
});
};
}
41 changes: 23 additions & 18 deletions src/exposed/prompts/select.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { TScript, IOfType } from '~/types';
import prompts from 'prompts';
import { wrap } from '~/utils/errors';

/**
* Options taken by `select`.
Expand All @@ -24,26 +25,30 @@ function select(options?: ISelectOptions): TScript;
* @returns A `TScript`, as a function, that won't be executed until called by `kpo` -hence, calling `select` won't have any effect until the returned function is called.
*/
function select(...args: any[]): TScript {
return async function select(): Promise<TScript> {
const message: string =
args[0] && typeof args[0] === 'string' ? args[0] : 'Choose an option';
const options: ISelectOptions =
args[1] || (args[0] && typeof args[0] !== 'string' ? args[0] : {});
return (): Promise<TScript> => {
return wrap.throws(async () => {
const message: string =
args[0] && typeof args[0] === 'string' ? args[0] : 'Choose an option';
const options: ISelectOptions =
args[1] || (args[0] && typeof args[0] !== 'string' ? args[0] : {});

const keys = Object.keys(options.values || {});
if (!keys.length) throw Error(`No values passed to select`);
const keys = Object.keys(options.values || {});
if (!keys.length) throw Error(`No values passed to select`);

const response = await prompts({
type: 'select',
name: 'value',
message: message,
choices: keys.map((key) => ({
title: key,
value: key
})),
initial: options.initial ? Math.max(0, keys.indexOf(options.initial)) : 0
});
const response = await prompts({
type: 'select',
name: 'value',
message: message,
choices: keys.map((key) => ({
title: key,
value: key
})),
initial: options.initial
? Math.max(0, keys.indexOf(options.initial))
: 0
});

return options.values[response.value] || undefined;
return options.values[response.value] || undefined;
});
};
}
17 changes: 10 additions & 7 deletions src/exposed/tags/ensure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import core from '~/core';
import { TScript } from '~/types';
import asTag from '~/utils/as-tag';
import { rejects } from 'errorish';
import { wrap } from '~/utils/errors';

export default ensure;

Expand All @@ -17,13 +18,15 @@ function ensure(
* @returns A `TScript`, as a function, that won't be executed until called by `kpo` -hence, calling `ensure` won't have any effect until the returned function is called.
*/
function ensure(...args: any[]): TScript {
return async function ensure(): Promise<void> {
let directory = asTag(args.shift(), ...args);
if (!path.isAbsolute(directory)) {
const paths = await core.paths();
directory = path.join(paths.directory, directory);
}
return (): Promise<void> => {
return wrap.throws(async () => {
let directory = asTag(args.shift(), ...args);
if (!path.isAbsolute(directory)) {
const paths = await core.paths();
directory = path.join(paths.directory, directory);
}

await fs.ensureDir(directory).catch(rejects);
await fs.ensureDir(directory).catch(rejects);
});
};
}
17 changes: 10 additions & 7 deletions src/exposed/tags/exists.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import core from '~/core';
import asTag from '~/utils/as-tag';
import { exists as _exists } from '~/utils/file';
import { TScript } from '~/types';
import { wrap } from '~/utils/errors';

export default exists;

Expand All @@ -16,12 +17,14 @@ function exists(
* @returns A `TScript`, as a function, that won't be executed until called by `kpo` -hence, calling `exists` won't have any effect until the returned function is called.
*/
function exists(...args: any[]): TScript {
return async function exists(): Promise<void> {
let file = asTag(args.shift(), ...args);
if (!path.isAbsolute(file)) {
const paths = await core.paths();
file = path.join(paths.directory, file);
}
await _exists(file, { fail: true });
return (): Promise<void> => {
return wrap.throws(async () => {
let file = asTag(args.shift(), ...args);
if (!path.isAbsolute(file)) {
const paths = await core.paths();
file = path.join(paths.directory, file);
}
await _exists(file, { fail: true });
});
};
}
11 changes: 7 additions & 4 deletions src/exposed/tags/log.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { TScript } from '~/types';
import asTag from '~/utils/as-tag';
import { wrap } from '~/utils/errors';

export default log;

Expand All @@ -10,9 +11,11 @@ function log(literals: TemplateStringsArray, ...placeholders: any[]): TScript;
* @returns A `TScript`, as a function, that won't be executed until called by `kpo` -hence, calling `log` won't have any effect until the returned function is called.
*/
function log(...args: any[]): TScript {
return function log(): void {
const message = asTag(args.shift(), ...args);
// eslint-disable-next-line no-console
console.log(message);
return (): void => {
return wrap.throws(() => {
const message = asTag(args.shift(), ...args);
// eslint-disable-next-line no-console
console.log(message);
});
};
}

0 comments on commit ec911e3

Please sign in to comment.