@fengmk2/ps-tree
Advanced tools
| #!/usr/bin/env node | ||
| // | ||
| // Change the default parent PID if running | ||
| // under Windows. | ||
| // | ||
| let ppid = 1; | ||
| if (process.platform === 'win32') { | ||
| ppid = 0; | ||
| } | ||
| // eslint-disable-next-line @typescript-eslint/no-var-requires | ||
| require('..').psTree(process.argv[2] || ppid).then(children => { | ||
| console.log(children); | ||
| }); |
| export interface PSTreeChild { | ||
| PPID: string; | ||
| PID: string; | ||
| STAT: string; | ||
| COMMAND: string; | ||
| } | ||
| export declare function psTree(pid: number | string, callback?: (err: Error | null, children?: PSTreeChild[]) => void): Promise<PSTreeChild[]> | undefined; |
| "use strict"; | ||
| var __importDefault = (this && this.__importDefault) || function (mod) { | ||
| return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
| }; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.psTree = psTree; | ||
| const node_child_process_1 = require("node:child_process"); | ||
| const event_stream_1 = __importDefault(require("event-stream")); | ||
| function psTree(pid, callback) { | ||
| const promise = childrenOfPid(pid); | ||
| if (!callback) { | ||
| return promise; | ||
| } | ||
| // keep compatibility for `psTree(pid, callback)` | ||
| promise.then(children => callback(null, children)) | ||
| .catch(err => callback(err)); | ||
| } | ||
| function childrenOfPid(pid) { | ||
| return new Promise((resolve, reject) => { | ||
| let headers; | ||
| if (typeof pid === 'number') { | ||
| pid = String(pid); | ||
| } | ||
| // | ||
| // The `ps-tree` module behaves differently on *nix vs. Windows | ||
| // by spawning different programs and parsing their output. | ||
| // | ||
| // Linux: | ||
| // 1. " <defunct> " need to be striped | ||
| // ```bash | ||
| // $ ps -A -o comm,ppid,pid,stat | ||
| // COMMAND PPID PID STAT | ||
| // bbsd 2899 16958 Ss | ||
| // watch <defunct> 1914 16964 Z | ||
| // ps 20688 16965 R+ | ||
| // ``` | ||
| // | ||
| // Darwin: | ||
| // $ ps -A -o comm,ppid,pid,stat | ||
| // COMM PPID PID STAT | ||
| // /sbin/launchd 0 1 Ss | ||
| // /usr/libexec/Use 1 43 Ss | ||
| // | ||
| // Win32: | ||
| // 1. wmic PROCESS WHERE ParentProcessId=4604 GET Name,ParentProcessId,ProcessId,Status) | ||
| // 2. The order of head columns is fixed | ||
| // ```shell | ||
| // > wmic PROCESS GET Name,ProcessId,ParentProcessId,Status | ||
| // Name ParentProcessId ProcessId Status | ||
| // System Idle Process 0 0 | ||
| // System 0 4 | ||
| // smss.exe 4 228 | ||
| // ``` | ||
| let processLister; | ||
| if (process.platform === 'win32') { | ||
| // See also: https://github.com/nodejs/node-v0.x-archive/issues/2318 | ||
| processLister = (0, node_child_process_1.spawn)('wmic.exe', ['PROCESS', 'GET', 'Name,ProcessId,ParentProcessId,Status']); | ||
| } | ||
| else { | ||
| processLister = (0, node_child_process_1.spawn)('ps', ['-A', '-o', 'ppid,pid,stat,comm']); | ||
| } | ||
| event_stream_1.default.pipeline( | ||
| // spawn('ps', ['-A', '-o', 'ppid,pid,stat,comm']).stdout, | ||
| processLister.stdout, event_stream_1.default.split(), event_stream_1.default.map((line, cb) => { | ||
| const columns = line.trim().split(/\s+/); | ||
| if (!headers) { | ||
| headers = columns; | ||
| // | ||
| // Rename Win32 header name, to as same as the linux, for compatible. | ||
| // | ||
| headers = headers.map(normalizeHeader); | ||
| return cb(); | ||
| } | ||
| const row = {}; | ||
| // For each header | ||
| const h = headers.slice(); | ||
| while (h.length) { | ||
| const key = h.shift(); | ||
| row[key] = h.length ? columns.shift() : columns.join(' '); | ||
| } | ||
| return cb(null, row); | ||
| }), event_stream_1.default.writeArray((_err, ps) => { | ||
| const parents = {}; | ||
| const children = []; | ||
| parents[pid] = true; | ||
| ps.forEach((proc) => { | ||
| if (parents[proc.PPID]) { | ||
| parents[proc.PID] = true; | ||
| children.push(proc); | ||
| } | ||
| }); | ||
| resolve(children); | ||
| })).on('error', reject); | ||
| }); | ||
| } | ||
| /** | ||
| * Normalizes the given header `str` from the Windows | ||
| * title to the *nix title. | ||
| * | ||
| * @param {string} str Header string to normalize | ||
| */ | ||
| function normalizeHeader(str) { | ||
| switch (str) { | ||
| case 'Name': // for win32 | ||
| case 'COMM': // for darwin | ||
| return 'COMMAND'; | ||
| case 'ParentProcessId': | ||
| return 'PPID'; | ||
| case 'ProcessId': | ||
| return 'PID'; | ||
| case 'Status': | ||
| return 'STAT'; | ||
| default: | ||
| return str; | ||
| } | ||
| } | ||
| //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFVQSx3QkFTQztBQW5CRCwyREFBMkU7QUFDM0UsZ0VBQThCO0FBUzlCLFNBQWdCLE1BQU0sQ0FBQyxHQUFvQixFQUFFLFFBQWdFO0lBQzNHLE1BQU0sT0FBTyxHQUFHLGFBQWEsQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUNuQyxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7UUFDZCxPQUFPLE9BQU8sQ0FBQztJQUNqQixDQUFDO0lBRUQsaURBQWlEO0lBQ2pELE9BQU8sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLFFBQVEsQ0FBQyxDQUFDO1NBQy9DLEtBQUssQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO0FBQ2pDLENBQUM7QUFFRCxTQUFTLGFBQWEsQ0FBQyxHQUFvQjtJQUN6QyxPQUFPLElBQUksT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxFQUFFO1FBQ3JDLElBQUksT0FBaUIsQ0FBQztRQUV0QixJQUFJLE9BQU8sR0FBRyxLQUFLLFFBQVEsRUFBRSxDQUFDO1lBQzVCLEdBQUcsR0FBRyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDcEIsQ0FBQztRQUVELEVBQUU7UUFDRiwrREFBK0Q7UUFDL0QsMkRBQTJEO1FBQzNELEVBQUU7UUFDRixTQUFTO1FBQ1Qsc0NBQXNDO1FBQ3RDLFVBQVU7UUFDVixnQ0FBZ0M7UUFDaEMsbUNBQW1DO1FBQ25DLGlDQUFpQztRQUNqQyxnQ0FBZ0M7UUFDaEMsaUNBQWlDO1FBQ2pDLE1BQU07UUFDTixFQUFFO1FBQ0YsVUFBVTtRQUNWLGdDQUFnQztRQUNoQyxvQ0FBb0M7UUFDcEMsa0NBQWtDO1FBQ2xDLGtDQUFrQztRQUNsQyxFQUFFO1FBQ0Ys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 |
| { | ||
| "type": "commonjs" | ||
| } |
| export interface PSTreeChild { | ||
| PPID: string; | ||
| PID: string; | ||
| STAT: string; | ||
| COMMAND: string; | ||
| } | ||
| export declare function psTree(pid: number | string, callback?: (err: Error | null, children?: PSTreeChild[]) => void): Promise<PSTreeChild[]> | undefined; |
| import { spawn } from 'node:child_process'; | ||
| import es from 'event-stream'; | ||
| export function psTree(pid, callback) { | ||
| const promise = childrenOfPid(pid); | ||
| if (!callback) { | ||
| return promise; | ||
| } | ||
| // keep compatibility for `psTree(pid, callback)` | ||
| promise.then(children => callback(null, children)) | ||
| .catch(err => callback(err)); | ||
| } | ||
| function childrenOfPid(pid) { | ||
| return new Promise((resolve, reject) => { | ||
| let headers; | ||
| if (typeof pid === 'number') { | ||
| pid = String(pid); | ||
| } | ||
| // | ||
| // The `ps-tree` module behaves differently on *nix vs. Windows | ||
| // by spawning different programs and parsing their output. | ||
| // | ||
| // Linux: | ||
| // 1. " <defunct> " need to be striped | ||
| // ```bash | ||
| // $ ps -A -o comm,ppid,pid,stat | ||
| // COMMAND PPID PID STAT | ||
| // bbsd 2899 16958 Ss | ||
| // watch <defunct> 1914 16964 Z | ||
| // ps 20688 16965 R+ | ||
| // ``` | ||
| // | ||
| // Darwin: | ||
| // $ ps -A -o comm,ppid,pid,stat | ||
| // COMM PPID PID STAT | ||
| // /sbin/launchd 0 1 Ss | ||
| // /usr/libexec/Use 1 43 Ss | ||
| // | ||
| // Win32: | ||
| // 1. wmic PROCESS WHERE ParentProcessId=4604 GET Name,ParentProcessId,ProcessId,Status) | ||
| // 2. The order of head columns is fixed | ||
| // ```shell | ||
| // > wmic PROCESS GET Name,ProcessId,ParentProcessId,Status | ||
| // Name ParentProcessId ProcessId Status | ||
| // System Idle Process 0 0 | ||
| // System 0 4 | ||
| // smss.exe 4 228 | ||
| // ``` | ||
| let processLister; | ||
| if (process.platform === 'win32') { | ||
| // See also: https://github.com/nodejs/node-v0.x-archive/issues/2318 | ||
| processLister = spawn('wmic.exe', ['PROCESS', 'GET', 'Name,ProcessId,ParentProcessId,Status']); | ||
| } | ||
| else { | ||
| processLister = spawn('ps', ['-A', '-o', 'ppid,pid,stat,comm']); | ||
| } | ||
| es.pipeline( | ||
| // spawn('ps', ['-A', '-o', 'ppid,pid,stat,comm']).stdout, | ||
| processLister.stdout, es.split(), es.map((line, cb) => { | ||
| const columns = line.trim().split(/\s+/); | ||
| if (!headers) { | ||
| headers = columns; | ||
| // | ||
| // Rename Win32 header name, to as same as the linux, for compatible. | ||
| // | ||
| headers = headers.map(normalizeHeader); | ||
| return cb(); | ||
| } | ||
| const row = {}; | ||
| // For each header | ||
| const h = headers.slice(); | ||
| while (h.length) { | ||
| const key = h.shift(); | ||
| row[key] = h.length ? columns.shift() : columns.join(' '); | ||
| } | ||
| return cb(null, row); | ||
| }), es.writeArray((_err, ps) => { | ||
| const parents = {}; | ||
| const children = []; | ||
| parents[pid] = true; | ||
| ps.forEach((proc) => { | ||
| if (parents[proc.PPID]) { | ||
| parents[proc.PID] = true; | ||
| children.push(proc); | ||
| } | ||
| }); | ||
| resolve(children); | ||
| })).on('error', reject); | ||
| }); | ||
| } | ||
| /** | ||
| * Normalizes the given header `str` from the Windows | ||
| * title to the *nix title. | ||
| * | ||
| * @param {string} str Header string to normalize | ||
| */ | ||
| function normalizeHeader(str) { | ||
| switch (str) { | ||
| case 'Name': // for win32 | ||
| case 'COMM': // for darwin | ||
| return 'COMMAND'; | ||
| case 'ParentProcessId': | ||
| return 'PPID'; | ||
| case 'ProcessId': | ||
| return 'PID'; | ||
| case 'Status': | ||
| return 'STAT'; | ||
| default: | ||
| return str; | ||
| } | ||
| } | ||
| //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLEtBQUssRUFBa0MsTUFBTSxvQkFBb0IsQ0FBQztBQUMzRSxPQUFPLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFTOUIsTUFBTSxVQUFVLE1BQU0sQ0FBQyxHQUFvQixFQUFFLFFBQWdFO0lBQzNHLE1BQU0sT0FBTyxHQUFHLGFBQWEsQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUNuQyxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7UUFDZCxPQUFPLE9BQU8sQ0FBQztJQUNqQixDQUFDO0lBRUQsaURBQWlEO0lBQ2pELE9BQU8sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLFFBQVEsQ0FBQyxDQUFDO1NBQy9DLEtBQUssQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO0FBQ2pDLENBQUM7QUFFRCxTQUFTLGFBQWEsQ0FBQyxHQUFvQjtJQUN6QyxPQUFPLElBQUksT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxFQUFFO1FBQ3JDLElBQUksT0FBaUIsQ0FBQztRQUV0QixJQUFJLE9BQU8sR0FBRyxLQUFLLFFBQVEsRUFBRSxDQUFDO1lBQzVCLEdBQUcsR0FBRyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDcEIsQ0FBQztRQUVELEVBQUU7UUFDRiwrREFBK0Q7UUFDL0QsMkRBQTJEO1FBQzNELEVBQUU7UUFDRixTQUFTO1FBQ1Qsc0NBQXNDO1FBQ3RDLFVBQVU7UUFDVixnQ0FBZ0M7UUFDaEMsbUNBQW1DO1FBQ25DLGlDQUFpQztRQUNqQyxnQ0FBZ0M7UUFDaEMsaUNBQWlDO1FBQ2pDLE1BQU07UUFDTixFQUFFO1FBQ0YsVUFBVTtRQUNWLGdDQUFnQztRQUNoQyxvQ0FBb0M7UUFDcEMs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 |
| { | ||
| "type": "module" | ||
| } |
| { | ||
| "name": "@fengmk2/ps-tree", | ||
| "version": "2.0.0" | ||
| } |
+130
| import { spawn, ChildProcessWithoutNullStreams } from 'node:child_process'; | ||
| import es from 'event-stream'; | ||
| export interface PSTreeChild { | ||
| PPID: string; | ||
| PID: string; | ||
| STAT: string; | ||
| COMMAND: string; | ||
| } | ||
| export function psTree(pid: number | string, callback?: (err: Error | null, children?: PSTreeChild[]) => void) { | ||
| const promise = childrenOfPid(pid); | ||
| if (!callback) { | ||
| return promise; | ||
| } | ||
| // keep compatibility for `psTree(pid, callback)` | ||
| promise.then(children => callback(null, children)) | ||
| .catch(err => callback(err)); | ||
| } | ||
| function childrenOfPid(pid: number | string): Promise<PSTreeChild[]> { | ||
| return new Promise((resolve, reject) => { | ||
| let headers: string[]; | ||
| if (typeof pid === 'number') { | ||
| pid = String(pid); | ||
| } | ||
| // | ||
| // The `ps-tree` module behaves differently on *nix vs. Windows | ||
| // by spawning different programs and parsing their output. | ||
| // | ||
| // Linux: | ||
| // 1. " <defunct> " need to be striped | ||
| // ```bash | ||
| // $ ps -A -o comm,ppid,pid,stat | ||
| // COMMAND PPID PID STAT | ||
| // bbsd 2899 16958 Ss | ||
| // watch <defunct> 1914 16964 Z | ||
| // ps 20688 16965 R+ | ||
| // ``` | ||
| // | ||
| // Darwin: | ||
| // $ ps -A -o comm,ppid,pid,stat | ||
| // COMM PPID PID STAT | ||
| // /sbin/launchd 0 1 Ss | ||
| // /usr/libexec/Use 1 43 Ss | ||
| // | ||
| // Win32: | ||
| // 1. wmic PROCESS WHERE ParentProcessId=4604 GET Name,ParentProcessId,ProcessId,Status) | ||
| // 2. The order of head columns is fixed | ||
| // ```shell | ||
| // > wmic PROCESS GET Name,ProcessId,ParentProcessId,Status | ||
| // Name ParentProcessId ProcessId Status | ||
| // System Idle Process 0 0 | ||
| // System 0 4 | ||
| // smss.exe 4 228 | ||
| // ``` | ||
| let processLister: ChildProcessWithoutNullStreams; | ||
| if (process.platform === 'win32') { | ||
| // See also: https://github.com/nodejs/node-v0.x-archive/issues/2318 | ||
| processLister = spawn('wmic.exe', [ 'PROCESS', 'GET', 'Name,ProcessId,ParentProcessId,Status' ]); | ||
| } else { | ||
| processLister = spawn('ps', [ '-A', '-o', 'ppid,pid,stat,comm' ]); | ||
| } | ||
| es.pipeline( | ||
| // spawn('ps', ['-A', '-o', 'ppid,pid,stat,comm']).stdout, | ||
| processLister.stdout as any, | ||
| es.split(), | ||
| es.map((line: string, cb: (...args: any[]) => void) => { // this could parse alot of unix command output | ||
| const columns = line.trim().split(/\s+/); | ||
| if (!headers) { | ||
| headers = columns; | ||
| // | ||
| // Rename Win32 header name, to as same as the linux, for compatible. | ||
| // | ||
| headers = headers.map(normalizeHeader); | ||
| return cb(); | ||
| } | ||
| const row: Record<string, string | undefined> = {}; | ||
| // For each header | ||
| const h = headers.slice(); | ||
| while (h.length) { | ||
| const key = h.shift(); | ||
| row[key!] = h.length ? columns.shift() : columns.join(' '); | ||
| } | ||
| return cb(null, row); | ||
| }), | ||
| es.writeArray((_err: any, ps: any[]) => { | ||
| const parents: Record<string, true> = {}; | ||
| const children: PSTreeChild[] = []; | ||
| parents[pid] = true; | ||
| ps.forEach((proc: any) => { | ||
| if (parents[proc.PPID]) { | ||
| parents[proc.PID] = true; | ||
| children.push(proc); | ||
| } | ||
| }); | ||
| resolve(children); | ||
| }), | ||
| ).on('error', reject); | ||
| }); | ||
| } | ||
| /** | ||
| * Normalizes the given header `str` from the Windows | ||
| * title to the *nix title. | ||
| * | ||
| * @param {string} str Header string to normalize | ||
| */ | ||
| function normalizeHeader(str: string) { | ||
| switch (str) { | ||
| case 'Name': // for win32 | ||
| case 'COMM': // for darwin | ||
| return 'COMMAND'; | ||
| case 'ParentProcessId': | ||
| return 'PPID'; | ||
| case 'ProcessId': | ||
| return 'PID'; | ||
| case 'Status': | ||
| return 'STAT'; | ||
| default: | ||
| return str; | ||
| } | ||
| } |
+1
-0
| The MIT License (MIT) | ||
| Copyright (c) 2014 Domenic Tarr, Charlie Robbins & the Contributors | ||
| Copyright (c) 2024-present fengmk2 and the Contributors | ||
@@ -5,0 +6,0 @@ Permission is hereby granted, free of charge, to any person obtaining a copy |
+60
-24
| { | ||
| "name": "@fengmk2/ps-tree", | ||
| "version": "1.2.0", | ||
| "version": "2.0.0", | ||
| "publishConfig": { | ||
| "access": "public" | ||
| }, | ||
| "description": "Get all children of a pid", | ||
| "description": "Get all children of a pid and support CommonJS and ESM both", | ||
| "license": "MIT", | ||
| "homepage": "http://github.com/indexzero/ps-tree#readme", | ||
| "repository": "github:indexzero/ps-tree", | ||
| "homepage": "http://github.com/fengmk2/ps-tree#readme", | ||
| "repository": "github:fengmk2/ps-tree", | ||
| "bugs": { | ||
| "url": "https://github.com/indexzero/ps-tree/issues", | ||
| "email": "charlie.robbins@gmail.com" | ||
| "url": "https://github.com/fengmk2/ps-tree/issues" | ||
| }, | ||
@@ -27,27 +26,64 @@ "author": "Charlie Robbins <charlie.robbins@gmail.com>", | ||
| ], | ||
| "main": "index.js", | ||
| "bin": { | ||
| "ps-tree": "./bin/ps-tree.js" | ||
| "ps-tree": "./bin/ps-tree.cjs" | ||
| }, | ||
| "files": [ | ||
| "bin", | ||
| "index.js" | ||
| ], | ||
| "dependencies": { | ||
| "event-stream": "^4.0.1" | ||
| }, | ||
| "devDependencies": { | ||
| "@arethetypeswrong/cli": "^0.17.1", | ||
| "@eggjs/tsconfig": "1", | ||
| "@types/event-stream": "^4.0.5", | ||
| "@types/mocha": "10", | ||
| "@types/node": "22", | ||
| "c8": "^10.1.3", | ||
| "egg-bin": "6", | ||
| "eslint": "8", | ||
| "eslint-config-egg": "14", | ||
| "tape": "^4.17.0", | ||
| "tree-kill": "^1.1.0", | ||
| "tshy": "3", | ||
| "tshy-after": "1", | ||
| "typescript": "5" | ||
| }, | ||
| "engines": { | ||
| "node": ">= 0.10" | ||
| "node": ">= 18.19.0" | ||
| }, | ||
| "scripts": { | ||
| "test": "istanbul cover node_modules/tape/bin/tape test/test.js", | ||
| "coverage": "cross-env CODECLIMATE_REPO_TOKEN=84436b4f13c70ace9c62e7f04928bf23c234eb212c0232d39d7fb1535beb2da5 node_modules/.bin/codeclimate-test-reporter < coverage/lcov.info" | ||
| "lint": "eslint --cache src --ext .ts", | ||
| "pretest": "npm run lint -- --fix && npm run prepublishOnly", | ||
| "test": "npm run test-local", | ||
| "test-local": "tape test/test.cjs", | ||
| "preci": "npm run lint && npm run prepublishOnly", | ||
| "ci": "c8 tape test/test.cjs && attw --pack", | ||
| "prepublishOnly": "tshy && tshy-after" | ||
| }, | ||
| "dependencies": { | ||
| "event-stream": "=3.3.4" | ||
| "type": "module", | ||
| "tshy": { | ||
| "exports": { | ||
| ".": "./src/index.ts", | ||
| "./package.json": "./package.json" | ||
| } | ||
| }, | ||
| "devDependencies": { | ||
| "codeclimate-test-reporter": "^0.5.0", | ||
| "cross-env": "^2.0.1", | ||
| "istanbul": "^0.4.5", | ||
| "tape": "^4.9.0", | ||
| "tree-kill": "^1.1.0" | ||
| } | ||
| "exports": { | ||
| ".": { | ||
| "import": { | ||
| "types": "./dist/esm/index.d.ts", | ||
| "default": "./dist/esm/index.js" | ||
| }, | ||
| "require": { | ||
| "types": "./dist/commonjs/index.d.ts", | ||
| "default": "./dist/commonjs/index.js" | ||
| } | ||
| }, | ||
| "./package.json": "./package.json" | ||
| }, | ||
| "files": [ | ||
| "dist", | ||
| "src", | ||
| "bin" | ||
| ], | ||
| "types": "./dist/commonjs/index.d.ts", | ||
| "main": "./dist/commonjs/index.js", | ||
| "module": "./dist/esm/index.js" | ||
| } |
+49
-26
@@ -1,10 +0,21 @@ | ||
| # ps-tree | ||
| # @fengmk2/ps-tree | ||
| [](https://github.com/indexzero/ps-tree/actions/workflows/ci-test.yml) | ||
| [](https://codeclimate.com/github/indexzero/ps-tree) | ||
| [](https://codeclimate.com/github/indexzero/ps-tree) | ||
| [](https://www.npmjs.com/package/ps-tree) | ||
| [](http://nodejs.org/download/) | ||
| [](https://david-dm.org/indexzero/ps-tree) | ||
| [![NPM version][npm-image]][npm-url] | ||
| [](https://github.com/fengmk2/ps-tree/actions/workflows/nodejs.yml) | ||
| [![Test coverage][codecov-image]][codecov-url] | ||
| [![Known Vulnerabilities][snyk-image]][snyk-url] | ||
| [![npm download][download-image]][download-url] | ||
| [](http://nodejs.org/download/) | ||
| [npm-image]: https://img.shields.io/npm/v/@fengmk2/ps-tree.svg?style=flat-square | ||
| [npm-url]: https://npmjs.org/package/@fengmk2/ps-tree | ||
| [codecov-image]: https://codecov.io/github/fengmk2/ps-tree/coverage.svg?branch=master | ||
| [codecov-url]: https://codecov.io/github/fengmk2/ps-tree?branch=master | ||
| [snyk-image]: https://snyk.io/test/npm/@fengmk2/ps-tree/badge.svg?style=flat-square | ||
| [snyk-url]: https://snyk.io/test/npm/@fengmk2/ps-tree | ||
| [download-image]: https://img.shields.io/npm/dm/@fengmk2/ps-tree.svg?style=flat-square | ||
| [download-url]: https://npmjs.org/package/@fengmk2/ps-tree | ||
| > Fork [indexzero/ps-tree](https://github.com/indexzero/ps-tree), refactor in TypeScript to support CommonJS and ESM both | ||
| Sometimes you cannot kill child processes like you would expect, this a feature of UNIX. | ||
@@ -17,7 +28,6 @@ | ||
| ``` js | ||
| var cp = require('child_process'), | ||
| psTree = require('ps-tree'); | ||
| ```ts | ||
| import cp from 'node:child_process'; | ||
| var child = cp.exec("node -e 'while (true);'", function () {...}); | ||
| const child = cp.exec("node -e 'while (true);'", function () {...}); | ||
@@ -30,4 +40,4 @@ // This will not actually kill the child it will kill the `sh` process. | ||
| ``` js | ||
| function exec (cmd, cb) { | ||
| ```js | ||
| function exec(cmd, cb) { | ||
| spawn('sh', ['-c', cmd]); | ||
@@ -43,23 +53,26 @@ ... | ||
| ``` js | ||
| var cp = require('child_process'), | ||
| psTree = require('ps-tree'); | ||
| ```js | ||
| import cp from 'node:child_process'; | ||
| import { psTree } from '@fengmk2/ps-tree'; | ||
| var child = cp.exec("node -e 'while (true);'", function () { /*...*/ }); | ||
| const child = cp.exec("node -e 'while (true);'", function () { /*...*/ }); | ||
| psTree(child.pid, function (err, children) { | ||
| cp.spawn('kill', ['-9'].concat(children.map(function (p) { return p.PID }))); | ||
| }); | ||
| psTree(child.pid) | ||
| .then(children => { | ||
| cp.spawn('kill', ['-9'].concat(children.map(function (p) { return p.PID }))); | ||
| }).catch(err => { | ||
| console.error(err); | ||
| }); | ||
| ``` | ||
| If you prefer to run **psTree** from the command line, use: `node ./bin/ps-tree.js` | ||
| If you prefer to run **psTree** from the command line, use: `node ./bin/ps-tree.cjs` | ||
| ## Cross Platform support | ||
| The `ps-tree` module behaves differently on *nix vs. Windows by spawning different programs and parsing their output. This is based on `process.platform` and not on checking to see if a `ps` compatible program exists on the system. | ||
| #### *nix | ||
| ### *nix | ||
| 1. " <defunct> " need to be striped | ||
| 1. `" <defunct> "` need to be striped | ||
| ```bash | ||
@@ -74,4 +87,6 @@ $ ps -A -o comm,ppid,pid,stat | ||
| ### Windows | ||
| 1. `wmic PROCESS WHERE ParentProcessId=4604 GET Name,ParentProcessId,ProcessId,Status)` | ||
| 2. The order of head columns is fixed | ||
| ```shell | ||
@@ -87,3 +102,3 @@ > wmic PROCESS GET Name,ProcessId,ParentProcessId,Status | ||
| 1. " " need to be striped | ||
| 1. `" "` need to be striped | ||
@@ -97,2 +112,10 @@ ```shell | ||
| ### LICENSE: MIT | ||
| ### LICENSE | ||
| [MIT](LICENSE) | ||
| ## Contributors | ||
| [](https://github.com/fengmk2/ps-tree/graphs/contributors) | ||
| Made with [contributors-img](https://contrib.rocks). |
| #!/usr/bin/env node | ||
| 'use strict'; | ||
| // | ||
| // Change the default parent PID if running | ||
| // under Windows. | ||
| // | ||
| var ppid = 1; | ||
| if (process.platform === 'win32') { | ||
| ppid = 0; | ||
| } | ||
| require('../')(process.argv[2] || ppid, function (err, data) { | ||
| console.log(data); | ||
| }); |
-122
| 'use strict'; | ||
| var spawn = require('child_process').spawn, | ||
| es = require('event-stream'); | ||
| module.exports = function childrenOfPid(pid, callback) { | ||
| var headers = null; | ||
| if (typeof callback !== 'function') { | ||
| throw new Error('childrenOfPid(pid, callback) expects callback'); | ||
| } | ||
| if (typeof pid === 'number') { | ||
| pid = pid.toString(); | ||
| } | ||
| // | ||
| // The `ps-tree` module behaves differently on *nix vs. Windows | ||
| // by spawning different programs and parsing their output. | ||
| // | ||
| // Linux: | ||
| // 1. " <defunct> " need to be striped | ||
| // ```bash | ||
| // $ ps -A -o comm,ppid,pid,stat | ||
| // COMMAND PPID PID STAT | ||
| // bbsd 2899 16958 Ss | ||
| // watch <defunct> 1914 16964 Z | ||
| // ps 20688 16965 R+ | ||
| // ``` | ||
| // | ||
| // Darwin: | ||
| // $ ps -A -o comm,ppid,pid,stat | ||
| // COMM PPID PID STAT | ||
| // /sbin/launchd 0 1 Ss | ||
| // /usr/libexec/Use 1 43 Ss | ||
| // | ||
| // Win32: | ||
| // 1. wmic PROCESS WHERE ParentProcessId=4604 GET Name,ParentProcessId,ProcessId,Status) | ||
| // 2. The order of head columns is fixed | ||
| // ```shell | ||
| // > wmic PROCESS GET Name,ProcessId,ParentProcessId,Status | ||
| // Name ParentProcessId ProcessId Status | ||
| // System Idle Process 0 0 | ||
| // System 0 4 | ||
| // smss.exe 4 228 | ||
| // ``` | ||
| var processLister; | ||
| if (process.platform === 'win32') { | ||
| // See also: https://github.com/nodejs/node-v0.x-archive/issues/2318 | ||
| processLister = spawn('wmic.exe', ['PROCESS', 'GET', 'Name,ProcessId,ParentProcessId,Status']); | ||
| } else { | ||
| processLister = spawn('ps', ['-A', '-o', 'ppid,pid,stat,comm']); | ||
| } | ||
| es.connect( | ||
| // spawn('ps', ['-A', '-o', 'ppid,pid,stat,comm']).stdout, | ||
| processLister.stdout, | ||
| es.split(), | ||
| es.map(function (line, cb) { //this could parse alot of unix command output | ||
| var columns = line.trim().split(/\s+/); | ||
| if (!headers) { | ||
| headers = columns; | ||
| // | ||
| // Rename Win32 header name, to as same as the linux, for compatible. | ||
| // | ||
| headers = headers.map(normalizeHeader); | ||
| return cb(); | ||
| } | ||
| var row = {}; | ||
| // For each header | ||
| var h = headers.slice(); | ||
| while (h.length) { | ||
| row[h.shift()] = h.length ? columns.shift() : columns.join(' '); | ||
| } | ||
| return cb(null, row); | ||
| }), | ||
| es.writeArray(function (err, ps) { | ||
| var parents = {}, | ||
| children = []; | ||
| parents[pid] = true; | ||
| ps.forEach(function (proc) { | ||
| if (parents[proc.PPID]) { | ||
| parents[proc.PID] = true; | ||
| children.push(proc) | ||
| } | ||
| }); | ||
| callback(null, children); | ||
| }) | ||
| ).on('error', callback) | ||
| } | ||
| /** | ||
| * Normalizes the given header `str` from the Windows | ||
| * title to the *nix title. | ||
| * | ||
| * @param {string} str Header string to normalize | ||
| */ | ||
| function normalizeHeader(str) { | ||
| switch (str) { | ||
| case 'Name': // for win32 | ||
| case 'COMM': // for darwin | ||
| return 'COMMAND'; | ||
| break; | ||
| case 'ParentProcessId': | ||
| return 'PPID'; | ||
| break; | ||
| case 'ProcessId': | ||
| return 'PID'; | ||
| break; | ||
| case 'Status': | ||
| return 'STAT'; | ||
| break; | ||
| default: | ||
| return str | ||
| } | ||
| } |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
28290
196.45%12
140%372
204.92%116
24.73%Yes
NaN14
180%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
Updated