node-pty 1.0.0 → 1.1.0-beta10

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.
@@ -11,6 +11,7 @@ import * as tty from 'tty';
11
11
  import * as fs from 'fs';
12
12
  import { constants } from 'os';
13
13
  import { pollUntil } from './testUtils.test';
14
+ import { pid } from 'process';
14
15
 
15
16
  const FIXTURES_PATH = path.normalize(path.join(__dirname, '..', 'fixtures', 'utf8-character.txt'));
16
17
 
@@ -262,6 +263,40 @@ if (process.platform !== 'win32') {
262
263
  term.on('exit', () => done());
263
264
  term.destroy();
264
265
  });
266
+ it('should return the name of the sub process', (done) => {
267
+ const data = `
268
+ var pty = require('./lib/index');
269
+ var ptyProcess = pty.spawn('zsh', ['-c', 'python3'], {
270
+ env: process.env
271
+ });
272
+ ptyProcess.on('data', function (data) {
273
+ if (ptyProcess.process === 'Python') {
274
+ console.log('title', ptyProcess.process);
275
+ }
276
+ });
277
+ setTimeout(() => null, 500);
278
+ console.log('ready', ptyProcess.pid);
279
+ `;
280
+ const p = cp.spawn('node', ['-e', data]);
281
+ let sub = '';
282
+ let pid = '';
283
+ p.stdout.on('data', (data) => {
284
+ if (!data.toString().indexOf('title')) {
285
+ sub = data.toString().split(' ')[1].slice(0, -1);
286
+ setTimeout(() => {
287
+ process.kill(parseInt(pid), 'SIGINT');
288
+ p.kill('SIGINT');
289
+ }, 200);
290
+ } else if (!data.toString().indexOf('ready')) {
291
+ pid = data.toString().split(' ')[1].slice(0, -1);
292
+ }
293
+ });
294
+ p.on('exit', () => {
295
+ assert.notStrictEqual(pid, '');
296
+ assert.strictEqual(sub, 'Python');
297
+ done();
298
+ });
299
+ });
265
300
  it('should close on exec', (done) => {
266
301
  const data = `
267
302
  var pty = require('./lib/index');
@@ -263,7 +263,8 @@ export class UnixTerminal extends Terminal {
263
263
  */
264
264
  public get process(): string {
265
265
  if (process.platform === 'darwin') {
266
- return pty.process(this._pid) || this._file;
266
+ const title = pty.process(this._fd);
267
+ return (title !== 'kernel_task' ) ? title : this._file;
267
268
  }
268
269
 
269
270
  return pty.process(this._fd, this._pty) || this._file;
package/src/win/conpty.cc CHANGED
@@ -8,24 +8,20 @@
8
8
  * with pseudo-terminal file descriptors.
9
9
  */
10
10
 
11
- // node versions lower than 10 define this as 0x502 which disables many of the definitions needed to compile
12
- #include <node_version.h>
13
- #if NODE_MODULE_VERSION <= 57
14
- #define _WIN32_WINNT 0x600
15
- #endif
11
+ #define _WIN32_WINNT 0x600
16
12
 
17
- #include <iostream>
18
- #include <nan.h>
13
+ #define NODE_ADDON_API_DISABLE_DEPRECATED
14
+ #include <napi.h>
15
+ #include <assert.h>
19
16
  #include <Shlwapi.h> // PathCombine, PathIsRelative
20
17
  #include <sstream>
21
18
  #include <string>
19
+ #include <thread>
22
20
  #include <vector>
23
21
  #include <Windows.h>
24
22
  #include <strsafe.h>
25
23
  #include "path_util.h"
26
24
 
27
- extern "C" void init(v8::Local<v8::Object>);
28
-
29
25
  // Taken from the RS5 Windows SDK, but redefined here in case we're targeting <= 17134
30
26
  #ifndef PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE
31
27
  #define PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE \
@@ -46,10 +42,6 @@ struct pty_baton {
46
42
  HPCON hpc;
47
43
 
48
44
  HANDLE hShell;
49
- HANDLE hWait;
50
- Nan::Callback cb;
51
- uv_async_t async;
52
- uv_thread_t tid;
53
45
 
54
46
  pty_baton(int _id, HANDLE _hIn, HANDLE _hOut, HPCON _hpc) : id(_id), hIn(_hIn), hOut(_hOut), hpc(_hpc) {};
55
47
  };
@@ -67,19 +59,65 @@ static pty_baton* get_pty_baton(int id) {
67
59
  return nullptr;
68
60
  }
69
61
 
70
- template <typename T>
71
- std::vector<T> vectorFromString(const std::basic_string<T> &str) {
72
- return std::vector<T>(str.begin(), str.end());
62
+ static bool remove_pty_baton(int id) {
63
+ for (size_t i = 0; i < ptyHandles.size(); ++i) {
64
+ pty_baton* ptyHandle = ptyHandles[i];
65
+ if (ptyHandle->id == id) {
66
+ ptyHandles.erase(ptyHandles.begin() + i);
67
+ ptyHandle = nullptr;
68
+ return true;
69
+ }
70
+ }
71
+ return false;
72
+ }
73
+
74
+ struct ExitEvent {
75
+ int exit_code = 0;
76
+ };
77
+
78
+ void SetupExitCallback(Napi::Env env, Napi::Function cb, pty_baton* baton) {
79
+ std::thread *th = new std::thread;
80
+ // Don't use Napi::AsyncWorker which is limited by UV_THREADPOOL_SIZE.
81
+ auto tsfn = Napi::ThreadSafeFunction::New(
82
+ env,
83
+ cb, // JavaScript function called asynchronously
84
+ "SetupExitCallback_resource", // Name
85
+ 0, // Unlimited queue
86
+ 1, // Only one thread will use this initially
87
+ [th](Napi::Env) { // Finalizer used to clean threads up
88
+ th->join();
89
+ delete th;
90
+ });
91
+ *th = std::thread([tsfn = std::move(tsfn), baton] {
92
+ auto callback = [](Napi::Env env, Napi::Function cb, ExitEvent *exit_event) {
93
+ cb.Call({Napi::Number::New(env, exit_event->exit_code)});
94
+ delete exit_event;
95
+ };
96
+
97
+ ExitEvent *exit_event = new ExitEvent;
98
+ // Wait for process to complete.
99
+ WaitForSingleObject(baton->hShell, INFINITE);
100
+ // Get process exit code.
101
+ GetExitCodeProcess(baton->hShell, (LPDWORD)(&exit_event->exit_code));
102
+ // Clean up handles
103
+ // Calling DisconnectNamedPipes here or in PtyKill results in a crash,
104
+ // ref https://github.com/microsoft/node-pty/issues/512,
105
+ // so we only call CloseHandle for now.
106
+ CloseHandle(baton->hIn);
107
+ CloseHandle(baton->hOut);
108
+
109
+ auto status = tsfn.BlockingCall(exit_event, callback); // In main thread
110
+ assert(status == napi_ok);
111
+
112
+ tsfn.Release();
113
+ });
73
114
  }
74
115
 
75
- void throwNanError(const Nan::FunctionCallbackInfo<v8::Value>* info, const char* text, const bool getLastError) {
116
+ Napi::Error errorWithCode(const Napi::CallbackInfo& info, const char* text) {
76
117
  std::stringstream errorText;
77
118
  errorText << text;
78
- if (getLastError) {
79
- errorText << ", error code: " << GetLastError();
80
- }
81
- Nan::ThrowError(errorText.str().c_str());
82
- (*info).GetReturnValue().SetUndefined();
119
+ errorText << ", error code: " << GetLastError();
120
+ return Napi::Error::New(info.Env(), errorText.str());
83
121
  }
84
122
 
85
123
  // Returns a new server named pipe. It has not yet been connected.
@@ -158,32 +196,32 @@ HRESULT CreateNamedPipesAndPseudoConsole(COORD size,
158
196
  return HRESULT_FROM_WIN32(GetLastError());
159
197
  }
160
198
 
161
- static NAN_METHOD(PtyStartProcess) {
162
- Nan::HandleScope scope;
199
+ static Napi::Value PtyStartProcess(const Napi::CallbackInfo& info) {
200
+ Napi::Env env(info.Env());
201
+ Napi::HandleScope scope(env);
163
202
 
164
- v8::Local<v8::Object> marshal;
203
+ Napi::Object marshal;
165
204
  std::wstring inName, outName;
166
205
  BOOL fSuccess = FALSE;
167
206
  std::unique_ptr<wchar_t[]> mutableCommandline;
168
207
  PROCESS_INFORMATION _piClient{};
169
208
 
170
209
  if (info.Length() != 6 ||
171
- !info[0]->IsString() ||
172
- !info[1]->IsNumber() ||
173
- !info[2]->IsNumber() ||
174
- !info[3]->IsBoolean() ||
175
- !info[4]->IsString() ||
176
- !info[5]->IsBoolean()) {
177
- Nan::ThrowError("Usage: pty.startProcess(file, cols, rows, debug, pipeName, inheritCursor)");
178
- return;
210
+ !info[0].IsString() ||
211
+ !info[1].IsNumber() ||
212
+ !info[2].IsNumber() ||
213
+ !info[3].IsBoolean() ||
214
+ !info[4].IsString() ||
215
+ !info[5].IsBoolean()) {
216
+ throw Napi::Error::New(env, "Usage: pty.startProcess(file, cols, rows, debug, pipeName, inheritCursor)");
179
217
  }
180
218
 
181
- const std::wstring filename(path_util::to_wstring(Nan::Utf8String(info[0])));
182
- const SHORT cols = info[1]->Uint32Value(Nan::GetCurrentContext()).FromJust();
183
- const SHORT rows = info[2]->Uint32Value(Nan::GetCurrentContext()).FromJust();
184
- const bool debug = Nan::To<bool>(info[3]).FromJust();
185
- const std::wstring pipeName(path_util::to_wstring(Nan::Utf8String(info[4])));
186
- const bool inheritCursor = Nan::To<bool>(info[5]).FromJust();
219
+ const std::wstring filename(path_util::to_wstring(info[0].As<Napi::String>()));
220
+ const SHORT cols = static_cast<SHORT>(info[1].As<Napi::Number>().Uint32Value());
221
+ const SHORT rows = static_cast<SHORT>(info[2].As<Napi::Number>().Uint32Value());
222
+ const bool debug = info[3].As<Napi::Boolean>().Value();
223
+ const std::wstring pipeName(path_util::to_wstring(info[4].As<Napi::String>()));
224
+ const bool inheritCursor = info[5].As<Napi::Boolean>().Value();
187
225
 
188
226
  // use environment 'Path' variable to determine location of
189
227
  // the relative path that we have recieved (e.g cmd.exe)
@@ -194,13 +232,11 @@ static NAN_METHOD(PtyStartProcess) {
194
232
  shellpath = filename;
195
233
  }
196
234
 
197
- std::string shellpath_(shellpath.begin(), shellpath.end());
198
-
199
235
  if (shellpath.empty() || !path_util::file_exists(shellpath)) {
200
- std::stringstream why;
201
- why << "File not found: " << shellpath_;
202
- Nan::ThrowError(why.str().c_str());
203
- return;
236
+ std::string why;
237
+ why += "File not found: ";
238
+ why += path_util::wstring_to_string(shellpath);
239
+ throw Napi::Error::New(env, why);
204
240
  }
205
241
 
206
242
  HANDLE hIn, hOut;
@@ -211,61 +247,35 @@ static NAN_METHOD(PtyStartProcess) {
211
247
  SetConsoleCtrlHandler(NULL, FALSE);
212
248
 
213
249
  // Set return values
214
- marshal = Nan::New<v8::Object>();
250
+ marshal = Napi::Object::New(env);
215
251
 
216
252
  if (SUCCEEDED(hr)) {
217
253
  // We were able to instantiate a conpty
218
254
  const int ptyId = InterlockedIncrement(&ptyCounter);
219
- Nan::Set(marshal, Nan::New<v8::String>("pty").ToLocalChecked(), Nan::New<v8::Number>(ptyId));
255
+ marshal.Set("pty", Napi::Number::New(env, ptyId));
220
256
  ptyHandles.insert(ptyHandles.end(), new pty_baton(ptyId, hIn, hOut, hpc));
221
257
  } else {
222
- Nan::ThrowError("Cannot launch conpty");
223
- return;
258
+ throw Napi::Error::New(env, "Cannot launch conpty");
224
259
  }
225
260
 
226
- Nan::Set(marshal, Nan::New<v8::String>("fd").ToLocalChecked(), Nan::New<v8::Number>(-1));
227
- {
228
- std::string coninPipeNameStr(inName.begin(), inName.end());
229
- Nan::Set(marshal, Nan::New<v8::String>("conin").ToLocalChecked(), Nan::New<v8::String>(coninPipeNameStr).ToLocalChecked());
230
-
231
- std::string conoutPipeNameStr(outName.begin(), outName.end());
232
- Nan::Set(marshal, Nan::New<v8::String>("conout").ToLocalChecked(), Nan::New<v8::String>(conoutPipeNameStr).ToLocalChecked());
261
+ std::string inNameStr = path_util::wstring_to_string(inName);
262
+ if (inNameStr.empty()) {
263
+ throw Napi::Error::New(env, "Failed to initialize conpty conin");
264
+ }
265
+ std::string outNameStr = path_util::wstring_to_string(outName);
266
+ if (outNameStr.empty()) {
267
+ throw Napi::Error::New(env, "Failed to initialize conpty conout");
233
268
  }
234
- info.GetReturnValue().Set(marshal);
235
- }
236
-
237
- VOID CALLBACK OnProcessExitWinEvent(
238
- _In_ PVOID context,
239
- _In_ BOOLEAN TimerOrWaitFired) {
240
- pty_baton *baton = static_cast<pty_baton*>(context);
241
-
242
- // Fire OnProcessExit
243
- uv_async_send(&baton->async);
244
- }
245
-
246
- static void OnProcessExit(uv_async_t *async) {
247
- Nan::HandleScope scope;
248
- pty_baton *baton = static_cast<pty_baton*>(async->data);
249
-
250
- UnregisterWait(baton->hWait);
251
-
252
- // Get exit code
253
- DWORD exitCode = 0;
254
- GetExitCodeProcess(baton->hShell, &exitCode);
255
-
256
- // Call function
257
- v8::Local<v8::Value> args[1] = {
258
- Nan::New<v8::Number>(exitCode)
259
- };
260
269
 
261
- Nan::AsyncResource asyncResource("node-pty.callback");
262
- baton->cb.Call(1, args, &asyncResource);
263
- // Clean up
264
- baton->cb.Reset();
270
+ marshal.Set("fd", Napi::Number::New(env, -1));
271
+ marshal.Set("conin", Napi::String::New(env, inNameStr));
272
+ marshal.Set("conout", Napi::String::New(env, outNameStr));
273
+ return marshal;
265
274
  }
266
275
 
267
- static NAN_METHOD(PtyConnect) {
268
- Nan::HandleScope scope;
276
+ static Napi::Value PtyConnect(const Napi::CallbackInfo& info) {
277
+ Napi::Env env(info.Env());
278
+ Napi::HandleScope scope(env);
269
279
 
270
280
  // If we're working with conpty's we need to call ConnectNamedPipe here AFTER
271
281
  // the Socket has attempted to connect to the other end, then actually
@@ -275,26 +285,24 @@ static NAN_METHOD(PtyConnect) {
275
285
  BOOL fSuccess = FALSE;
276
286
 
277
287
  if (info.Length() != 5 ||
278
- !info[0]->IsNumber() ||
279
- !info[1]->IsString() ||
280
- !info[2]->IsString() ||
281
- !info[3]->IsArray() ||
282
- !info[4]->IsFunction()) {
283
- Nan::ThrowError("Usage: pty.connect(id, cmdline, cwd, env, exitCallback)");
284
- return;
288
+ !info[0].IsNumber() ||
289
+ !info[1].IsString() ||
290
+ !info[2].IsString() ||
291
+ !info[3].IsArray() ||
292
+ !info[4].IsFunction()) {
293
+ throw Napi::Error::New(env, "Usage: pty.connect(id, cmdline, cwd, env, exitCallback)");
285
294
  }
286
295
 
287
- const int id = info[0]->Int32Value(Nan::GetCurrentContext()).FromJust();
288
- const std::wstring cmdline(path_util::to_wstring(Nan::Utf8String(info[1])));
289
- const std::wstring cwd(path_util::to_wstring(Nan::Utf8String(info[2])));
290
- const v8::Local<v8::Array> envValues = info[3].As<v8::Array>();
291
- const v8::Local<v8::Function> exitCallback = v8::Local<v8::Function>::Cast(info[4]);
296
+ const int id = info[0].As<Napi::Number>().Int32Value();
297
+ const std::wstring cmdline(path_util::to_wstring(info[1].As<Napi::String>()));
298
+ const std::wstring cwd(path_util::to_wstring(info[2].As<Napi::String>()));
299
+ const Napi::Array envValues = info[3].As<Napi::Array>();
300
+ Napi::Function exitCallback = info[4].As<Napi::Function>();
292
301
 
293
302
  // Fetch pty handle from ID and start process
294
303
  pty_baton* handle = get_pty_baton(id);
295
304
  if (!handle) {
296
- Nan::ThrowError("Invalid pty handle");
297
- return;
305
+ throw Napi::Error::New(env, "Invalid pty handle");
298
306
  }
299
307
 
300
308
  // Prepare command line
@@ -306,17 +314,17 @@ static NAN_METHOD(PtyConnect) {
306
314
  hr = StringCchCopyW(mutableCwd.get(), cwd.length() + 1, cwd.c_str());
307
315
 
308
316
  // Prepare environment
309
- std::wstring env;
317
+ std::wstring envStr;
310
318
  if (!envValues.IsEmpty()) {
311
- std::wstringstream envBlock;
312
- for(uint32_t i = 0; i < envValues->Length(); i++) {
313
- std::wstring envValue(path_util::to_wstring(Nan::Utf8String(Nan::Get(envValues, i).ToLocalChecked())));
314
- envBlock << envValue << L'\0';
319
+ std::wstring envBlock;
320
+ for(uint32_t i = 0; i < envValues.Length(); i++) {
321
+ envBlock += path_util::to_wstring(envValues.Get(i).As<Napi::String>());
322
+ envBlock += L'\0';
315
323
  }
316
- envBlock << L'\0';
317
- env = envBlock.str();
324
+ envBlock += L'\0';
325
+ envStr = std::move(envBlock);
318
326
  }
319
- auto envV = vectorFromString(env);
327
+ std::vector<wchar_t> envV(envStr.cbegin(), envStr.cend());
320
328
  LPWSTR envArg = envV.empty() ? nullptr : envV.data();
321
329
 
322
330
  ConnectNamedPipe(handle->hIn, nullptr);
@@ -337,7 +345,7 @@ static NAN_METHOD(PtyConnect) {
337
345
 
338
346
  fSuccess = InitializeProcThreadAttributeList(siEx.lpAttributeList, 1, 0, &size);
339
347
  if (!fSuccess) {
340
- return throwNanError(&info, "InitializeProcThreadAttributeList failed", true);
348
+ throw errorWithCode(info, "InitializeProcThreadAttributeList failed");
341
349
  }
342
350
  fSuccess = UpdateProcThreadAttribute(siEx.lpAttributeList,
343
351
  0,
@@ -347,7 +355,7 @@ static NAN_METHOD(PtyConnect) {
347
355
  NULL,
348
356
  NULL);
349
357
  if (!fSuccess) {
350
- return throwNanError(&info, "UpdateProcThreadAttribute failed", true);
358
+ throw errorWithCode(info, "UpdateProcThreadAttribute failed");
351
359
  }
352
360
 
353
361
  PROCESS_INFORMATION piClient{};
@@ -364,40 +372,34 @@ static NAN_METHOD(PtyConnect) {
364
372
  &piClient // lpProcessInformation
365
373
  );
366
374
  if (!fSuccess) {
367
- return throwNanError(&info, "Cannot create process", true);
375
+ throw errorWithCode(info, "Cannot create process");
368
376
  }
369
377
 
370
378
  // Update handle
371
379
  handle->hShell = piClient.hProcess;
372
- handle->cb.Reset(exitCallback);
373
- handle->async.data = handle;
374
-
375
- // Setup OnProcessExit callback
376
- uv_async_init(uv_default_loop(), &handle->async, OnProcessExit);
377
380
 
378
- // Setup Windows wait for process exit event
379
- RegisterWaitForSingleObject(&handle->hWait, piClient.hProcess, OnProcessExitWinEvent, (PVOID)handle, INFINITE, WT_EXECUTEONLYONCE);
381
+ SetupExitCallback(env, exitCallback, handle);
380
382
 
381
383
  // Return
382
- v8::Local<v8::Object> marshal = Nan::New<v8::Object>();
383
- Nan::Set(marshal, Nan::New<v8::String>("pid").ToLocalChecked(), Nan::New<v8::Number>(piClient.dwProcessId));
384
- info.GetReturnValue().Set(marshal);
384
+ auto marshal = Napi::Object::New(env);
385
+ marshal.Set("pid", Napi::Number::New(env, piClient.dwProcessId));
386
+ return marshal;
385
387
  }
386
388
 
387
- static NAN_METHOD(PtyResize) {
388
- Nan::HandleScope scope;
389
+ static Napi::Value PtyResize(const Napi::CallbackInfo& info) {
390
+ Napi::Env env(info.Env());
391
+ Napi::HandleScope scope(env);
389
392
 
390
393
  if (info.Length() != 3 ||
391
- !info[0]->IsNumber() ||
392
- !info[1]->IsNumber() ||
393
- !info[2]->IsNumber()) {
394
- Nan::ThrowError("Usage: pty.resize(id, cols, rows)");
395
- return;
394
+ !info[0].IsNumber() ||
395
+ !info[1].IsNumber() ||
396
+ !info[2].IsNumber()) {
397
+ throw Napi::Error::New(env, "Usage: pty.resize(id, cols, rows)");
396
398
  }
397
399
 
398
- int id = info[0]->Int32Value(Nan::GetCurrentContext()).FromJust();
399
- SHORT cols = info[1]->Uint32Value(Nan::GetCurrentContext()).FromJust();
400
- SHORT rows = info[2]->Uint32Value(Nan::GetCurrentContext()).FromJust();
400
+ int id = info[0].As<Napi::Number>().Int32Value();
401
+ SHORT cols = static_cast<SHORT>(info[1].As<Napi::Number>().Uint32Value());
402
+ SHORT rows = static_cast<SHORT>(info[2].As<Napi::Number>().Uint32Value());
401
403
 
402
404
  const pty_baton* handle = get_pty_baton(id);
403
405
 
@@ -415,48 +417,48 @@ static NAN_METHOD(PtyResize) {
415
417
  }
416
418
  }
417
419
 
418
- return info.GetReturnValue().SetUndefined();
420
+ return env.Undefined();
419
421
  }
420
422
 
421
- static NAN_METHOD(PtyClear) {
422
- Nan::HandleScope scope;
423
+ static Napi::Value PtyClear(const Napi::CallbackInfo& info) {
424
+ Napi::Env env(info.Env());
425
+ Napi::HandleScope scope(env);
423
426
 
424
427
  if (info.Length() != 1 ||
425
- !info[0]->IsNumber()) {
426
- Nan::ThrowError("Usage: pty.clear(id)");
427
- return;
428
+ !info[0].IsNumber()) {
429
+ throw Napi::Error::New(env, "Usage: pty.clear(id)");
428
430
  }
429
431
 
430
- int id = info[0]->Int32Value(Nan::GetCurrentContext()).FromJust();
432
+ // int id = info[0].As<Napi::Number>().Int32Value();
431
433
 
432
- const pty_baton* handle = get_pty_baton(id);
434
+ // const pty_baton* handle = get_pty_baton(id);
433
435
 
434
- if (handle != nullptr) {
435
- HANDLE hLibrary = LoadLibraryExW(L"kernel32.dll", 0, 0);
436
- bool fLoadedDll = hLibrary != nullptr;
437
- if (fLoadedDll)
438
- {
439
- PFNCLEARPSEUDOCONSOLE const pfnClearPseudoConsole = (PFNCLEARPSEUDOCONSOLE)GetProcAddress((HMODULE)hLibrary, "ClearPseudoConsole");
440
- if (pfnClearPseudoConsole)
441
- {
442
- pfnClearPseudoConsole(handle->hpc);
443
- }
444
- }
445
- }
436
+ // if (handle != nullptr) {
437
+ // HANDLE hLibrary = LoadLibraryExW(L"kernel32.dll", 0, 0);
438
+ // bool fLoadedDll = hLibrary != nullptr;
439
+ // if (fLoadedDll)
440
+ // {
441
+ // PFNCLEARPSEUDOCONSOLE const pfnClearPseudoConsole = (PFNCLEARPSEUDOCONSOLE)GetProcAddress((HMODULE)hLibrary, "ClearPseudoConsole");
442
+ // if (pfnClearPseudoConsole)
443
+ // {
444
+ // pfnClearPseudoConsole(handle->hpc);
445
+ // }
446
+ // }
447
+ // }
446
448
 
447
- return info.GetReturnValue().SetUndefined();
449
+ return env.Undefined();
448
450
  }
449
451
 
450
- static NAN_METHOD(PtyKill) {
451
- Nan::HandleScope scope;
452
+ static Napi::Value PtyKill(const Napi::CallbackInfo& info) {
453
+ Napi::Env env(info.Env());
454
+ Napi::HandleScope scope(env);
452
455
 
453
456
  if (info.Length() != 1 ||
454
- !info[0]->IsNumber()) {
455
- Nan::ThrowError("Usage: pty.kill(id)");
456
- return;
457
+ !info[0].IsNumber()) {
458
+ throw Napi::Error::New(env, "Usage: pty.kill(id)");
457
459
  }
458
460
 
459
- int id = info[0]->Int32Value(Nan::GetCurrentContext()).FromJust();
461
+ int id = info[0].As<Napi::Number>().Int32Value();
460
462
 
461
463
  const pty_baton* handle = get_pty_baton(id);
462
464
 
@@ -472,27 +474,24 @@ static NAN_METHOD(PtyKill) {
472
474
  }
473
475
  }
474
476
 
475
- DisconnectNamedPipe(handle->hIn);
476
- DisconnectNamedPipe(handle->hOut);
477
- CloseHandle(handle->hIn);
478
- CloseHandle(handle->hOut);
479
477
  CloseHandle(handle->hShell);
478
+ assert(remove_pty_baton(id));
480
479
  }
481
480
 
482
- return info.GetReturnValue().SetUndefined();
481
+ return env.Undefined();
483
482
  }
484
483
 
485
484
  /**
486
485
  * Init
487
486
  */
488
487
 
489
- extern "C" void init(v8::Local<v8::Object> target) {
490
- Nan::HandleScope scope;
491
- Nan::SetMethod(target, "startProcess", PtyStartProcess);
492
- Nan::SetMethod(target, "connect", PtyConnect);
493
- Nan::SetMethod(target, "resize", PtyResize);
494
- Nan::SetMethod(target, "clear", PtyClear);
495
- Nan::SetMethod(target, "kill", PtyKill);
488
+ Napi::Object init(Napi::Env env, Napi::Object exports) {
489
+ exports.Set("startProcess", Napi::Function::New(env, PtyStartProcess));
490
+ exports.Set("connect", Napi::Function::New(env, PtyConnect));
491
+ exports.Set("resize", Napi::Function::New(env, PtyResize));
492
+ exports.Set("clear", Napi::Function::New(env, PtyClear));
493
+ exports.Set("kill", Napi::Function::New(env, PtyKill));
494
+ return exports;
496
495
  };
497
496
 
498
- NODE_MODULE(pty, init);
497
+ NODE_API_MODULE(NODE_GYP_MODULE_NAME, init);
@@ -2,42 +2,43 @@
2
2
  * Copyright (c) 2019, Microsoft Corporation (MIT License).
3
3
  */
4
4
 
5
- #include <nan.h>
5
+ #define NODE_ADDON_API_DISABLE_DEPRECATED
6
+ #include <napi.h>
6
7
  #include <windows.h>
7
8
 
8
- static NAN_METHOD(ApiConsoleProcessList) {
9
+ static Napi::Value ApiConsoleProcessList(const Napi::CallbackInfo& info) {
10
+ Napi::Env env(info.Env());
9
11
  if (info.Length() != 1 ||
10
- !info[0]->IsNumber()) {
11
- Nan::ThrowError("Usage: getConsoleProcessList(shellPid)");
12
- return;
12
+ !info[0].IsNumber()) {
13
+ throw Napi::Error::New(env, "Usage: getConsoleProcessList(shellPid)");
13
14
  }
14
15
 
15
- const SHORT pid = info[0]->Uint32Value(Nan::GetCurrentContext()).FromJust();
16
+ const DWORD pid = info[0].As<Napi::Number>().Uint32Value();
16
17
 
17
18
  if (!FreeConsole()) {
18
- Nan::ThrowError("FreeConsole failed");
19
+ throw Napi::Error::New(env, "FreeConsole failed");
19
20
  }
20
21
  if (!AttachConsole(pid)) {
21
- Nan::ThrowError("AttachConsole failed");
22
+ throw Napi::Error::New(env, "AttachConsole failed");
22
23
  }
23
24
  auto processList = std::vector<DWORD>(64);
24
- auto processCount = GetConsoleProcessList(&processList[0], processList.size());
25
+ auto processCount = GetConsoleProcessList(&processList[0], static_cast<DWORD>(processList.size()));
25
26
  if (processList.size() < processCount) {
26
27
  processList.resize(processCount);
27
- processCount = GetConsoleProcessList(&processList[0], processList.size());
28
+ processCount = GetConsoleProcessList(&processList[0], static_cast<DWORD>(processList.size()));
28
29
  }
29
30
  FreeConsole();
30
31
 
31
- v8::Local<v8::Array> result = Nan::New<v8::Array>();
32
+ Napi::Array result = Napi::Array::New(env);
32
33
  for (DWORD i = 0; i < processCount; i++) {
33
- Nan::Set(result, i, Nan::New<v8::Number>(processList[i]));
34
+ result.Set(i, Napi::Number::New(env, processList[i]));
34
35
  }
35
- info.GetReturnValue().Set(result);
36
+ return result;
36
37
  }
37
38
 
38
- extern "C" void init(v8::Local<v8::Object> target) {
39
- Nan::HandleScope scope;
40
- Nan::SetMethod(target, "getConsoleProcessList", ApiConsoleProcessList);
39
+ Napi::Object init(Napi::Env env, Napi::Object exports) {
40
+ exports.Set("getConsoleProcessList", Napi::Function::New(env, ApiConsoleProcessList));
41
+ return exports;
41
42
  };
42
43
 
43
- NODE_MODULE(pty, init);
44
+ NODE_API_MODULE(NODE_GYP_MODULE_NAME, init);