generated from shadow578/typescript-project-template
-
Notifications
You must be signed in to change notification settings - Fork 0
/
DefaultShim.ts
117 lines (105 loc) · 3.74 KB
/
DefaultShim.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
import { matchObject, matchArray } from '@shadow578/type-guardian';
import { base64Decode, base64Encode } from '../../util';
import { isPowerShellException } from '../PowerShellException';
import { ParameterRecord } from './Parameters';
import { Shim, ShimOptions, ShimParseResult } from './Shim';
import { isString } from '@shadow578/type-guardian/lib/TypeGuards';
/**
* output format of the default shim
*/
interface ShimOutput {
success: boolean;
data: unknown[];
}
/**
* type guard for {@link ShimOutput}
*/
const isShimOutput = matchObject<ShimOutput>({
success: 'boolean',
data: matchArray('any'),
});
export class DefaultShim implements Shim {
get requiresStdout() {
return true;
}
get requiresStderr() {
return false;
}
prepare(id: string, command: string, parameters: ParameterRecord, options: ShimOptions): string {
// convert the json to a utf-8 encoded base64 string
// doing the transfer in base64 ensures that we don't run into issues
// in case wierd characters are used in the parameter values
const paramsBase64String = base64Encode(JSON.stringify(parameters));
// build the shim
//prettier-ignore
return `function __shim() {
.{
function __target() {
${command}
}
try {
$params = ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String("${paramsBase64String}")) | ConvertFrom-Json)
${
// parameter expansion
options.expandParameters
? '$params.PSObject.Properties | ForEach-Object { Set-Variable -Name $_.Name -Value $_.Value }'
: ''
}
$__capture = @{
"success" = $true
"data" = @(__target)
}
}
catch {
$__capture = @{
"success" = $false
"data" = @(@{
"Exception" = ($_.Exception.Message)
"FullyQualifiedErrorId" = ($_.FullyQualifiedErrorId)
"InvocationInfo" = ("$($_.InvocationInfo.Line) (at $($_.InvocationInfo.ScriptLineNumber),$($_.InvocationInfo.OffsetInLine) )")
})
}
}
} | Out-Null
Write-Output "{{${id}=$(([System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes((ConvertTo-Json $__capture -Depth (${ Math.min(options.resultSerializationDepth + 1, 100) }) -Compress)))))}}"
}; __shim`;
}
parseResult(id: string, stdout?: string, _stderr?: string): ShimParseResult {
if (!isString(stdout)) {
throw new TypeError('stdout was not defined');
}
// find the result data in the output stream
const resultMatch = stdout.match(new RegExp(`{{(?:${id})=([A-Za-z0-9+/-_]*={0,3})}}`));
if (!resultMatch) {
throw new Error('could not find result data in output stream');
}
// base64-decode and parse the result
const outputJson = base64Decode(resultMatch[1]);
const output = JSON.parse(outputJson);
// check result
if (!isShimOutput(output)) {
throw new TypeError('could not decode shim output');
}
// transform output
if (output.success) {
// if output data is zero length, the command returned nothing (void call)
// so we have to return undefined in data
if (output.data.length === 0) {
return {
data: undefined,
};
} else {
return {
data: output.data,
};
}
} else {
if (!isPowerShellException(output.data[0])) {
throw new TypeError('could not decode exception from shim output');
}
return {
error: output.data[0],
};
}
}
}