Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/bootstrap-fork.ts
3285 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import * as performance from './vs/base/common/performance.js';
7
import { removeGlobalNodeJsModuleLookupPaths, devInjectNodeModuleLookupPath } from './bootstrap-node.js';
8
import { bootstrapESM } from './bootstrap-esm.js';
9
10
performance.mark('code/fork/start');
11
12
//#region Helpers
13
14
function pipeLoggingToParent(): void {
15
const MAX_STREAM_BUFFER_LENGTH = 1024 * 1024;
16
const MAX_LENGTH = 100000;
17
18
/**
19
* Prevent circular stringify and convert arguments to real array
20
*/
21
function safeToString(args: ArrayLike<unknown>): string {
22
const seen: unknown[] = [];
23
const argsArray: unknown[] = [];
24
25
// Massage some arguments with special treatment
26
if (args.length) {
27
for (let i = 0; i < args.length; i++) {
28
let arg = args[i];
29
30
// Any argument of type 'undefined' needs to be specially treated because
31
// JSON.stringify will simply ignore those. We replace them with the string
32
// 'undefined' which is not 100% right, but good enough to be logged to console
33
if (typeof arg === 'undefined') {
34
arg = 'undefined';
35
}
36
37
// Any argument that is an Error will be changed to be just the error stack/message
38
// itself because currently cannot serialize the error over entirely.
39
else if (arg instanceof Error) {
40
const errorObj = arg;
41
if (errorObj.stack) {
42
arg = errorObj.stack;
43
} else {
44
arg = errorObj.toString();
45
}
46
}
47
48
argsArray.push(arg);
49
}
50
}
51
52
try {
53
const res = JSON.stringify(argsArray, function (key, value: unknown) {
54
55
// Objects get special treatment to prevent circles
56
if (isObject(value) || Array.isArray(value)) {
57
if (seen.indexOf(value) !== -1) {
58
return '[Circular]';
59
}
60
61
seen.push(value);
62
}
63
64
return value;
65
});
66
67
if (res.length > MAX_LENGTH) {
68
return 'Output omitted for a large object that exceeds the limits';
69
}
70
71
return res;
72
} catch (error) {
73
return `Output omitted for an object that cannot be inspected ('${error.toString()}')`;
74
}
75
}
76
77
function safeSend(arg: { type: string; severity: string; arguments: string }): void {
78
try {
79
if (process.send) {
80
process.send(arg);
81
}
82
} catch (error) {
83
// Can happen if the parent channel is closed meanwhile
84
}
85
}
86
87
function isObject(obj: unknown): boolean {
88
return typeof obj === 'object'
89
&& obj !== null
90
&& !Array.isArray(obj)
91
&& !(obj instanceof RegExp)
92
&& !(obj instanceof Date);
93
}
94
95
function safeSendConsoleMessage(severity: 'log' | 'warn' | 'error', args: string): void {
96
safeSend({ type: '__$console', severity, arguments: args });
97
}
98
99
/**
100
* Wraps a console message so that it is transmitted to the renderer.
101
*
102
* The wrapped property is not defined with `writable: false` to avoid
103
* throwing errors, but rather a no-op setting. See https://github.com/microsoft/vscode-extension-telemetry/issues/88
104
*/
105
function wrapConsoleMethod(method: 'log' | 'info' | 'warn' | 'error', severity: 'log' | 'warn' | 'error'): void {
106
Object.defineProperty(console, method, {
107
set: () => { },
108
get: () => function () { safeSendConsoleMessage(severity, safeToString(arguments)); },
109
});
110
}
111
112
/**
113
* Wraps process.stderr/stdout.write() so that it is transmitted to the
114
* renderer or CLI. It both calls through to the original method as well
115
* as to console.log with complete lines so that they're made available
116
* to the debugger/CLI.
117
*/
118
function wrapStream(streamName: 'stdout' | 'stderr', severity: 'log' | 'warn' | 'error'): void {
119
const stream = process[streamName];
120
const original = stream.write;
121
122
let buf = '';
123
124
Object.defineProperty(stream, 'write', {
125
set: () => { },
126
get: () => (chunk: string | Buffer | Uint8Array, encoding: BufferEncoding | undefined, callback: ((err?: Error | undefined) => void) | undefined) => {
127
buf += chunk.toString(encoding);
128
const eol = buf.length > MAX_STREAM_BUFFER_LENGTH ? buf.length : buf.lastIndexOf('\n');
129
if (eol !== -1) {
130
console[severity](buf.slice(0, eol));
131
buf = buf.slice(eol + 1);
132
}
133
134
original.call(stream, chunk, encoding, callback);
135
},
136
});
137
}
138
139
// Pass console logging to the outside so that we have it in the main side if told so
140
if (process.env['VSCODE_VERBOSE_LOGGING'] === 'true') {
141
wrapConsoleMethod('info', 'log');
142
wrapConsoleMethod('log', 'log');
143
wrapConsoleMethod('warn', 'warn');
144
wrapConsoleMethod('error', 'error');
145
} else {
146
console.log = function () { /* ignore */ };
147
console.warn = function () { /* ignore */ };
148
console.info = function () { /* ignore */ };
149
wrapConsoleMethod('error', 'error');
150
}
151
152
wrapStream('stderr', 'error');
153
wrapStream('stdout', 'log');
154
}
155
156
function handleExceptions(): void {
157
158
// Handle uncaught exceptions
159
process.on('uncaughtException', function (err) {
160
console.error('Uncaught Exception: ', err);
161
});
162
163
// Handle unhandled promise rejections
164
process.on('unhandledRejection', function (reason) {
165
console.error('Unhandled Promise Rejection: ', reason);
166
});
167
}
168
169
function terminateWhenParentTerminates(): void {
170
const parentPid = Number(process.env['VSCODE_PARENT_PID']);
171
172
if (typeof parentPid === 'number' && !isNaN(parentPid)) {
173
setInterval(function () {
174
try {
175
process.kill(parentPid, 0); // throws an exception if the main process doesn't exist anymore.
176
} catch (e) {
177
process.exit();
178
}
179
}, 5000);
180
}
181
}
182
183
function configureCrashReporter(): void {
184
const crashReporterProcessType = process.env['VSCODE_CRASH_REPORTER_PROCESS_TYPE'];
185
if (crashReporterProcessType) {
186
try {
187
//@ts-ignore
188
if (process['crashReporter'] && typeof process['crashReporter'].addExtraParameter === 'function' /* Electron only */) {
189
//@ts-ignore
190
process['crashReporter'].addExtraParameter('processType', crashReporterProcessType);
191
}
192
} catch (error) {
193
console.error(error);
194
}
195
}
196
}
197
198
//#endregion
199
200
// Crash reporter
201
configureCrashReporter();
202
203
// Remove global paths from the node module lookup (node.js only)
204
removeGlobalNodeJsModuleLookupPaths();
205
206
if (process.env['VSCODE_DEV_INJECT_NODE_MODULE_LOOKUP_PATH']) {
207
devInjectNodeModuleLookupPath(process.env['VSCODE_DEV_INJECT_NODE_MODULE_LOOKUP_PATH']);
208
}
209
210
// Configure: pipe logging to parent process
211
if (!!process.send && process.env['VSCODE_PIPE_LOGGING'] === 'true') {
212
pipeLoggingToParent();
213
}
214
215
// Handle Exceptions
216
if (!process.env['VSCODE_HANDLES_UNCAUGHT_ERRORS']) {
217
handleExceptions();
218
}
219
220
// Terminate when parent terminates
221
if (process.env['VSCODE_PARENT_PID']) {
222
terminateWhenParentTerminates();
223
}
224
225
// Bootstrap ESM
226
await bootstrapESM();
227
228
// Load ESM entry point
229
await import([`./${process.env['VSCODE_ESM_ENTRYPOINT']}.js`].join('/') /* workaround: esbuild prints some strange warnings when trying to inline? */);
230
231