Skip to content

Commit

Permalink
Require Node.js 12.20 and move to ESM
Browse files Browse the repository at this point in the history
  • Loading branch information
sindresorhus committed Nov 4, 2021
1 parent 6ba1dc7 commit 32bffd7
Show file tree
Hide file tree
Showing 10 changed files with 100 additions and 108 deletions.
3 changes: 0 additions & 3 deletions .github/funding.yml

This file was deleted.

4 changes: 2 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ jobs:
fail-fast: false
matrix:
node-version:
- 16
- 14
- 12
- 10
os:
- ubuntu-latest
- windows-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
- uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
- run: npm install
Expand Down
3 changes: 1 addition & 2 deletions fixtures/sleep-forever.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
#!/usr/bin/env node
'use strict';

const sleep = () => {
setTimeout(sleep, 10000);
setTimeout(sleep, 10_000);
};

sleep();
86 changes: 40 additions & 46 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -1,57 +1,51 @@
declare namespace psList {
interface Options {
/**
Include other users' processes as well as your own.
On Windows this has no effect and will always be the users' own processes.
@default true
*/
readonly all?: boolean;
}

interface ProcessDescriptor {
readonly pid: number;
readonly name: string;
readonly ppid: number;

/**
Not supported on Windows.
*/
readonly cmd?: string;

/**
Not supported on Windows.
*/
readonly cpu?: number;

/**
Not supported on Windows.
*/
readonly memory?: number;

/**
Not supported on Windows.
*/
readonly uid?: number;
}
export interface Options {
/**
Include other users' processes as well as your own.
On Windows this has no effect and will always be the users' own processes.
@default true
*/
readonly all?: boolean;
}

export interface ProcessDescriptor {
readonly pid: number;
readonly name: string;
readonly ppid: number;

/**
Not supported on Windows.
*/
readonly cmd?: string;

/**
Not supported on Windows.
*/
readonly cpu?: number;

/**
Not supported on Windows.
*/
readonly memory?: number;

/**
Not supported on Windows.
*/
readonly uid?: number;
}

/**
Get running processes.
@returns List of running processes.
@returns A list of running processes.
@example
```
import psList = require('ps-list');
import psList from 'ps-list';
(async () => {
console.log(await psList());
//=> [{pid: 3213, name: 'node', cmd: 'node test.js', ppid: 1, uid: 501, cpu: 0.1, memory: 1.5}, …]
})();
console.log(await psList());
//=> [{pid: 3213, name: 'node', cmd: 'node test.js', ppid: 1, uid: 501, cpu: 0.1, memory: 1.5}, …]
```
*/
declare function psList(options?: psList.Options): Promise<psList.ProcessDescriptor[]>;

export = psList;
export default function psList(options?: Options): Promise<ProcessDescriptor[]>;
50 changes: 27 additions & 23 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,32 @@
'use strict';
const util = require('util');
const path = require('path');
const childProcess = require('child_process');
import process from 'node:process';
import {promisify} from 'node:util';
import path from 'node:path';
import {fileURLToPath} from 'node:url';
import childProcess from 'node:child_process';

const __dirname = path.dirname(fileURLToPath(import.meta.url));

const TEN_MEGABYTES = 1000 * 1000 * 10;
const execFile = util.promisify(childProcess.execFile);
const execFile = promisify(childProcess.execFile);

const windows = async () => {
// Source: https://github.com/MarkTiedemann/fastlist
let bin;
let binary;
switch (process.arch) {
case 'x64':
bin = 'fastlist-0.3.0-x64.exe';
binary = 'fastlist-0.3.0-x64.exe';
break;
case 'ia32':
bin = 'fastlist-0.3.0-x86.exe';
binary = 'fastlist-0.3.0-x86.exe';
break;
default:
throw new Error(`Unsupported architecture: ${process.arch}`);
}

const binPath = path.join(__dirname, 'vendor', bin);
const {stdout} = await execFile(binPath, {
const binaryPath = path.join(__dirname, 'vendor', binary);
const {stdout} = await execFile(binaryPath, {
maxBuffer: TEN_MEGABYTES,
windowsHide: true
windowsHide: true,
});

return stdout
Expand All @@ -33,33 +36,33 @@ const windows = async () => {
.map(([pid, ppid, name]) => ({
pid: Number.parseInt(pid, 10),
ppid: Number.parseInt(ppid, 10),
name
name,
}));
};

const nonWindowsMultipleCalls = async (options = {}) => {
const flags = (options.all === false ? '' : 'a') + 'wwxo';
const ret = {};
const returnValue = {};

await Promise.all(['comm', 'args', 'ppid', 'uid', '%cpu', '%mem'].map(async cmd => {
const {stdout} = await execFile('ps', [flags, `pid,${cmd}`], {maxBuffer: TEN_MEGABYTES});

for (let line of stdout.trim().split('\n').slice(1)) {
line = line.trim();
const [pid] = line.split(' ', 1);
const val = line.slice(pid.length + 1).trim();
const value = line.slice(pid.length + 1).trim();

if (ret[pid] === undefined) {
ret[pid] = {};
if (returnValue[pid] === undefined) {
returnValue[pid] = {};
}

ret[pid][cmd] = val;
returnValue[pid][cmd] = value;
}
}));

// Filter out inconsistencies as there might be race
// issues due to differences in `ps` between the spawns
return Object.entries(ret)
return Object.entries(returnValue)
.filter(([, value]) => value.comm && value.args && value.ppid && value.uid && value['%cpu'] && value['%mem'])
.map(([key, value]) => ({
pid: Number.parseInt(key, 10),
Expand All @@ -68,15 +71,14 @@ const nonWindowsMultipleCalls = async (options = {}) => {
ppid: Number.parseInt(value.ppid, 10),
uid: Number.parseInt(value.uid, 10),
cpu: Number.parseFloat(value['%cpu']),
memory: Number.parseFloat(value['%mem'])
memory: Number.parseFloat(value['%mem']),
}));
};

const ERROR_MESSAGE_PARSING_FAILED = 'ps output parsing failed';

const psFields = 'pid,ppid,uid,%cpu,%mem,comm,args';

// TODO: Use named capture groups when targeting Node.js 10
const psOutputRegex = /^[ \t]*(?<pid>\d+)[ \t]+(?<ppid>\d+)[ \t]+(?<uid>\d+)[ \t]+(?<cpu>\d+\.\d+)[ \t]+(?<memory>\d+\.\d+)[ \t]+/;

const nonWindowsSingleCall = async (options = {}) => {
Expand Down Expand Up @@ -115,7 +117,7 @@ const nonWindowsSingleCall = async (options = {}) => {
cpu: Number.parseFloat(cpu),
memory: Number.parseFloat(memory),
name: undefined,
cmd: undefined
cmd: undefined,
};

if (processInfo.pid === psPid) {
Expand Down Expand Up @@ -144,9 +146,11 @@ const nonWindowsSingleCall = async (options = {}) => {
const nonWindows = async (options = {}) => {
try {
return await nonWindowsSingleCall(options);
} catch (_) { // If the error is not a parsing error, it should manifest itself in multicall version too.
} catch { // If the error is not a parsing error, it should manifest itself in multicall version too.
return nonWindowsMultipleCalls(options);
}
};

module.exports = process.platform === 'win32' ? windows : nonWindows;
const psList = process.platform === 'win32' ? windows : nonWindows;

export default psList;
5 changes: 2 additions & 3 deletions index.test-d.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import {expectType} from 'tsd';
import psList = require('.');
import {ProcessDescriptor} from '.';
import psList, {ProcessDescriptor} from './index.js';

const processes: ProcessDescriptor[] = await psList();
psList({all: false});
await psList({all: false});

expectType<number>(processes[0].pid);
expectType<string>(processes[0].name);
Expand Down
2 changes: 1 addition & 1 deletion license
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

Expand Down
15 changes: 8 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@
"author": {
"name": "Sindre Sorhus",
"email": "sindresorhus@gmail.com",
"url": "sindresorhus.com"
"url": "https://sindresorhus.com"
},
"type": "module",
"exports": "./index.js",
"engines": {
"node": ">=10"
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"scripts": {
"test": "xo && ava && tsd"
Expand All @@ -31,10 +33,9 @@
"tasklist"
],
"devDependencies": {
"ava": "^1.4.1",
"noop-process": "^4.0.0",
"semver": "^7.3.2",
"tsd": "^0.11.0",
"xo": "^0.25.3"
"ava": "^3.15.0",
"noop-process": "^5.0.0",
"tsd": "^0.18.0",
"xo": "^0.46.4"
}
}
14 changes: 6 additions & 8 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,24 @@ Works on macOS, Linux, and Windows.

## Install

```
$ npm install ps-list
```sh
npm install ps-list
```

## Usage

```js
const psList = require('ps-list');
import psList from 'ps-list';

(async () => {
console.log(await psList());
//=> [{pid: 3213, name: 'node', cmd: 'node test.js', ppid: 1, uid: 501, cpu: 0.1, memory: 1.5}, …]
})();
console.log(await psList());
//=> [{pid: 3213, name: 'node', cmd: 'node test.js', ppid: 1, uid: 501, cpu: 0.1, memory: 1.5}, …]
```

## API

### psList(options?)

Returns a `Promise<Array>` with the running processes.
Returns a `Promise<object[]>` with the running processes.

On macOS and Linux, the `name` property is truncated to 15 characters by the system. The `cmd` property can be used to extract the full name.

Expand Down
26 changes: 13 additions & 13 deletions test.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import childProcess from 'child_process';
import process from 'node:process';
import childProcess from 'node:child_process';
import test from 'ava';
import noopProcess from 'noop-process';
import semver from 'semver';
import psList from '.';
import psList from './index.js';

const isWindows = process.platform === 'win32';
const nodeBinaryName = isWindows ? 'node.exe' : 'node';
Expand All @@ -19,20 +19,20 @@ test('main', async t => {

t.true(
list.every(x =>
typeof x.pid === 'number' &&
typeof x.name === 'string' &&
typeof x.ppid === 'number'
)
typeof x.pid === 'number'
&& typeof x.name === 'string'
&& typeof x.ppid === 'number',
),
);

if (!isWindows) {
t.true(
list.every(x =>
typeof x.cmd === 'string' &&
typeof x.cpu === 'number' &&
typeof x.memory === 'number' &&
typeof x.uid === 'number'
)
typeof x.cmd === 'string'
&& typeof x.cpu === 'number'
&& typeof x.memory === 'number'
&& typeof x.uid === 'number',
),
);
}
});
Expand Down Expand Up @@ -67,7 +67,7 @@ test('custom binary', async t => {
}
});

if (process.platform === 'linux' && semver.gte(process.version, '12.17.0')) {
if (process.platform === 'linux') {
// https://github.com/nodejs/node/issues/35503
test.failing('process name can\'t work in Linux on Node.js >=12.17', async t => {
const title = 'noop-process';
Expand Down

0 comments on commit 32bffd7

Please sign in to comment.