@villedemontreal/general-utils 5.19.2 → 5.20.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/utils.d.ts +6 -0
- package/dist/src/utils.d.ts.map +1 -1
- package/dist/src/utils.js +62 -8
- package/dist/src/utils.js.map +1 -1
- package/dist/src/utils.test.js +74 -0
- package/dist/src/utils.test.js.map +1 -1
- package/dist/test-data/test_throwNotManaged/f8de8a2e-8f72-4363-a1c7-e765fa939434.d.ts +2 -0
- package/dist/test-data/test_throwNotManaged/f8de8a2e-8f72-4363-a1c7-e765fa939434.d.ts.map +1 -0
- package/dist/test-data/test_throwNotManaged/{bfcb8952-c362-4b5b-95df-f4f31730a8bb.js → f8de8a2e-8f72-4363-a1c7-e765fa939434.js} +1 -1
- package/dist/test-data/test_throwNotManaged/{bfcb8952-c362-4b5b-95df-f4f31730a8bb.js.map → f8de8a2e-8f72-4363-a1c7-e765fa939434.js.map} +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -6
- package/src/utils.test.ts +84 -0
- package/src/utils.ts +66 -10
- package/dist/test-data/test_throwNotManaged/bfcb8952-c362-4b5b-95df-f4f31730a8bb.d.ts +0 -2
- package/dist/test-data/test_throwNotManaged/bfcb8952-c362-4b5b-95df-f4f31730a8bb.d.ts.map +0 -1
package/src/utils.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { spawn, StdioOptions } from 'child_process';
|
|
1
|
+
import { ChildProcess, spawn, StdioOptions } from 'child_process';
|
|
2
2
|
import * as fs from 'fs';
|
|
3
3
|
import * as getPort from 'get-port';
|
|
4
|
+
import { isArray, isDate, isEqual, isFunction, isNil, isObject, isString, trimEnd } from 'lodash';
|
|
4
5
|
import * as pathUtils from 'path';
|
|
5
6
|
import { rimraf } from 'rimraf';
|
|
6
7
|
import * as tsconfig from 'tsconfig-extends';
|
|
7
8
|
import { constants } from './config/constants';
|
|
8
|
-
import { isArray, isDate, isEqual, isFunction, isNil, isObject, isString, trimEnd } from 'lodash';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* General utilities
|
|
@@ -308,9 +308,9 @@ export class Utils {
|
|
|
308
308
|
|
|
309
309
|
const cmd = 'node';
|
|
310
310
|
const tscCmd = constants.findModulePath('node_modules/typescript/lib/tsc.js');
|
|
311
|
-
const args = [tscCmd
|
|
311
|
+
const args = [tscCmd, ...this.tscCompilerOptions, ...files];
|
|
312
312
|
|
|
313
|
-
await this.
|
|
313
|
+
await this.exec(cmd, args, { useShellOption: false });
|
|
314
314
|
}
|
|
315
315
|
|
|
316
316
|
/**
|
|
@@ -428,6 +428,43 @@ export class Utils {
|
|
|
428
428
|
return false;
|
|
429
429
|
};
|
|
430
430
|
|
|
431
|
+
public shellescape(args: string[]) {
|
|
432
|
+
// Function inspired from: https://github.com/xxorax/node-shell-escape/blob/master/shell-escape.js
|
|
433
|
+
return args.map(this.shellescapeArgument).join(' ');
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
public shellescapeArgument(a: string) {
|
|
437
|
+
const trimSpaces = (str: string) => {
|
|
438
|
+
return str.replace(/^[ ]+|[ ]+$/g, '');
|
|
439
|
+
};
|
|
440
|
+
const innerQuotedArgEscape = (arg: string, quote: string): string => {
|
|
441
|
+
const re = new RegExp(quote, 'g');
|
|
442
|
+
let result = arg.substring(1, arg.length - 1);
|
|
443
|
+
result = result.replace(/'\\''/g, "'");
|
|
444
|
+
result = result.replace(/"\\""/g, '"');
|
|
445
|
+
result = result.replace(re, `${quote}\\${quote}${quote}`);
|
|
446
|
+
result = result.replace('\n', '\\n'); // handle new lines
|
|
447
|
+
result = result.replace('\t', '\\t'); // handle tabs
|
|
448
|
+
return `${quote}${result}${quote}`;
|
|
449
|
+
};
|
|
450
|
+
a = trimSpaces(a);
|
|
451
|
+
if (/[^A-Za-z0-9_/.$:=-]/.test(a)) {
|
|
452
|
+
if (a.startsWith('"') && a.endsWith('"')) {
|
|
453
|
+
return innerQuotedArgEscape(a, '"');
|
|
454
|
+
}
|
|
455
|
+
if (a.startsWith("'") && a.endsWith("'")) {
|
|
456
|
+
return innerQuotedArgEscape(a, "'");
|
|
457
|
+
}
|
|
458
|
+
a = "'" + a.replace(/'/g, "'\\''") + "'";
|
|
459
|
+
a = a
|
|
460
|
+
.replace(/^(?:'')+/g, '') // unduplicate single-quote at the beginning
|
|
461
|
+
.replace(/\\'''/g, "\\'") // remove non-escaped single-quote if there are enclosed between 2 escaped
|
|
462
|
+
.replace('\n', '\\n') // handle new lines
|
|
463
|
+
.replace('\t', '\\t'); // handle tabs
|
|
464
|
+
}
|
|
465
|
+
return a;
|
|
466
|
+
}
|
|
467
|
+
|
|
431
468
|
/**
|
|
432
469
|
* @deprecated Use `exec()` instead.
|
|
433
470
|
*/
|
|
@@ -478,6 +515,9 @@ export class Utils {
|
|
|
478
515
|
* https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options
|
|
479
516
|
* Defaults to `true`.
|
|
480
517
|
*
|
|
518
|
+
* @param options.escapeArgs will automatically escape the submitted args.
|
|
519
|
+
* Defaults to `false` to avoid any breaking changes.
|
|
520
|
+
*
|
|
481
521
|
* @returns The exit code
|
|
482
522
|
*
|
|
483
523
|
* @throws Will fail with a `ExecError` error if the process returns
|
|
@@ -494,10 +534,12 @@ export class Utils {
|
|
|
494
534
|
disableConsoleOutputs?: boolean;
|
|
495
535
|
stdio?: StdioOptions;
|
|
496
536
|
useShellOption?: boolean;
|
|
537
|
+
escapeArgs?: boolean;
|
|
497
538
|
},
|
|
498
539
|
): Promise<number> {
|
|
499
540
|
const optionsClean = options ?? {};
|
|
500
541
|
optionsClean.useShellOption = optionsClean.useShellOption ?? true;
|
|
542
|
+
optionsClean.escapeArgs = optionsClean.escapeArgs ?? false;
|
|
501
543
|
optionsClean.successExitCodes = optionsClean.successExitCodes
|
|
502
544
|
? isArray(optionsClean.successExitCodes)
|
|
503
545
|
? optionsClean.successExitCodes
|
|
@@ -511,13 +553,27 @@ export class Utils {
|
|
|
511
553
|
}
|
|
512
554
|
|
|
513
555
|
return new Promise<number>((resolve, reject) => {
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
556
|
+
let spawnedProcess: ChildProcess;
|
|
557
|
+
if (optionsClean.useShellOption && optionsClean.escapeArgs) {
|
|
558
|
+
const cmd = this.shellescape([bin, ...args]);
|
|
559
|
+
spawnedProcess = spawn(cmd, {
|
|
560
|
+
detached: false,
|
|
561
|
+
stdio: optionsClean.stdio,
|
|
562
|
+
shell: optionsClean.useShellOption,
|
|
563
|
+
windowsVerbatimArguments: false,
|
|
564
|
+
});
|
|
565
|
+
} else {
|
|
566
|
+
spawnedProcess = spawn(bin, args, {
|
|
567
|
+
detached: false,
|
|
568
|
+
stdio: optionsClean.stdio,
|
|
569
|
+
shell: optionsClean.useShellOption,
|
|
570
|
+
windowsVerbatimArguments: false,
|
|
571
|
+
});
|
|
572
|
+
}
|
|
520
573
|
|
|
574
|
+
spawnedProcess.on('error', (err: Error) => {
|
|
575
|
+
reject(new ExecError(`Error while executing command: ${err.message}`, 1));
|
|
576
|
+
});
|
|
521
577
|
spawnedProcess.on('close', (code: number) => {
|
|
522
578
|
const successExitCodes = optionsClean.successExitCodes as number[];
|
|
523
579
|
if (!successExitCodes.includes(code)) {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"bfcb8952-c362-4b5b-95df-f4f31730a8bb.d.ts","sourceRoot":"","sources":["../../../test-data/test_throwNotManaged/bfcb8952-c362-4b5b-95df-f4f31730a8bb.ts"],"names":[],"mappings":""}
|