Comparing version 14.0.3 to 14.0.4
@@ -28,3 +28,3 @@ import fs from 'node:fs'; | ||
let service = createService(resolver, token); | ||
let service = createService(resolver, token, shutdown); | ||
if (idle) { | ||
@@ -31,0 +31,0 @@ service = watchConnection(service, idle * 60000); |
import fs from 'node:fs'; | ||
import net from 'node:net'; | ||
import os from 'node:os'; | ||
import child_process from 'node:child_process'; | ||
@@ -49,3 +51,3 @@ import { loadConfig, removeConfig } from './config.js'; | ||
try { | ||
process.kill(config.pid, 'SIGTERM'); | ||
await platformAwareStopDaemon(config); | ||
} catch (err) { | ||
@@ -60,2 +62,20 @@ console.error(`eslint_d: ${err} - removing config`); | ||
/** | ||
* @param {Config} config | ||
* @returns {Promise<void>} | ||
*/ | ||
function platformAwareStopDaemon(config) { | ||
if (os.platform() === 'win32') { | ||
return new Promise((resolve, reject) => { | ||
const socket = net.connect(config.port, '127.0.0.1'); | ||
socket.once('error', reject); | ||
socket.write(JSON.stringify([config.token, 'ESLINT_D_STOP'])); | ||
socket.end(() => resolve(undefined)); | ||
}); | ||
} | ||
process.kill(config.pid, 'SIGTERM'); | ||
return Promise.resolve(); | ||
} | ||
/** | ||
* @returns {string} | ||
@@ -62,0 +82,0 @@ */ |
import fs from 'node:fs'; | ||
import fs_promises from 'node:fs/promises'; | ||
import os from 'node:os'; | ||
import net from 'node:net'; | ||
import child_process from 'node:child_process'; | ||
@@ -8,2 +10,3 @@ import EventEmitter from 'node:events'; | ||
import { launchDaemon, stopDaemon } from './launcher.js'; | ||
import { strictEqual } from 'node:assert'; | ||
@@ -190,6 +193,7 @@ describe('lib/launcher', () => { | ||
context('stopDaemon', () => { | ||
context('unix: stopDaemon', () => { | ||
const config = { token: 'token', port: 123, pid: 456, hash: 'hash' }; | ||
beforeEach(() => { | ||
sinon.replace(os, 'platform', sinon.fake.returns('darwin')); | ||
sinon.replace(fs_promises, 'unlink', sinon.fake.resolves()); | ||
@@ -218,2 +222,4 @@ }); | ||
await new Promise((resolve) => setTimeout(resolve)); | ||
assert.calledOnceWith(fs.watch, resolver.base); | ||
@@ -252,2 +258,96 @@ | ||
}); | ||
context('win32: stopDaemon', () => { | ||
const sockets = []; | ||
let server; | ||
let config; | ||
beforeEach((done) => { | ||
sinon.replace(os, 'platform', sinon.fake.returns('win32')); | ||
sinon.replace(fs_promises, 'unlink', sinon.fake.resolves()); | ||
server = net.createServer(); | ||
server.on('connection', (socket) => sockets.push(socket)); | ||
server.listen(0, '127.0.0.1', () => { | ||
const port = server.address()?.['port']; | ||
config = { token: 'token', port, pid: 456, hash: 'hash' }; | ||
done(); | ||
}); | ||
}); | ||
afterEach((done) => { | ||
sockets.forEach((socket) => socket.destroy()); | ||
server.close(done); | ||
}); | ||
context('without exception', () => { | ||
it('send stop command to server listening on port from config', (done) => { | ||
stopDaemon(resolver, config); | ||
let data = ''; | ||
server.once('connection', (socket) => { | ||
socket | ||
.on('data', (buf) => { | ||
data += buf.toString(); | ||
}) | ||
.on('end', () => { | ||
strictEqual(data, '["token","ESLINT_D_STOP"]'); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
it('does not remove the config', async () => { | ||
stopDaemon(resolver, config); | ||
await new Promise((resolve) => { | ||
server.on('connection', (socket) => { | ||
socket.on('data', () => {}).on('end', () => resolve('')); | ||
}); | ||
}); | ||
refute.called(fs_promises.unlink); | ||
}); | ||
it('waits for the config to be removed and resolves', async () => { | ||
const promise = stopDaemon(resolver, config); | ||
await new Promise((resolve) => { | ||
server.on('connection', (socket) => { | ||
socket.on('data', () => {}).on('end', () => resolve('')); | ||
}); | ||
}); | ||
assert.calledOnceWith(fs.watch, resolver.base); | ||
watcher.emit('change', 'rename', '.eslint_d'); | ||
assert.calledOnceWith(watcher.close); | ||
await assert.resolves(promise, undefined); | ||
}); | ||
}); | ||
context('with exception', () => { | ||
beforeEach(() => { | ||
const error = new Error('kill error'); | ||
sinon.replace(net, 'connect', sinon.fake.throws(error)); | ||
}); | ||
it('logs an error and removes the config file', async () => { | ||
const promise = stopDaemon(resolver, config); | ||
await assert.resolves(promise, undefined); | ||
assert.calledOnceWith( | ||
console.error, | ||
'eslint_d: Error: kill error - removing config' | ||
); | ||
assert.calledOnceWith(fs_promises.unlink, `${resolver.base}/.eslint_d`); | ||
}); | ||
it('does not watch for the config file', () => { | ||
stopDaemon(resolver, config); | ||
refute.called(fs.watch); | ||
}); | ||
}); | ||
}); | ||
}); |
@@ -14,5 +14,6 @@ import { createRequire } from 'node:module'; | ||
* @param {string} token | ||
* @param {() => void} shutdown | ||
* @returns {function(Socket): void} con | ||
*/ | ||
export function createService(resolver, token) { | ||
export function createService(resolver, token, shutdown) { | ||
const eslint = resolver.require(`${resolver.base}/lib/cli.js`); | ||
@@ -48,2 +49,7 @@ const chalk = createRequire(resolver.base)('chalk'); | ||
} | ||
if (color_level === 'ESLINT_D_STOP') { | ||
shutdown(); | ||
con.end(); | ||
return; | ||
} | ||
@@ -50,0 +56,0 @@ chalk.level = color_level; |
@@ -17,2 +17,3 @@ import { Socket } from 'node:net'; | ||
const token = 'token'; | ||
let shutdown_promise; | ||
let eslint_promise; | ||
@@ -24,5 +25,8 @@ let service; | ||
eslint_promise = sinon.promise(); | ||
shutdown_promise = sinon.promise(); | ||
sinon.replace(eslint, 'execute', sinon.fake.returns(eslint_promise)); | ||
sinon.replace(process, 'chdir', sinon.fake()); | ||
service = createService(resolver, token); | ||
service = createService(resolver, token, () => | ||
shutdown_promise.resolve() | ||
); | ||
chalk.level = '-'; | ||
@@ -155,3 +159,9 @@ con = new Socket({ allowHalfOpen: true }); | ||
}); | ||
it('shutdown daemon if ESLINT_D_STOP received', async () => { | ||
send(token, '"ESLINT_D_STOP"', '/', []); | ||
await shutdown_promise; | ||
}); | ||
}); | ||
}); |
{ | ||
"name": "eslint_d", | ||
"version": "14.0.3", | ||
"version": "14.0.4", | ||
"description": "Speed up eslint to accelerate your development workflow", | ||
@@ -25,2 +25,3 @@ "type": "module", | ||
"test:integration": "mocha --bail --slow 1000 test/test.integration.js", | ||
"test:coverage": "mcr --filter \"{'**/node_modules/**':false,'**/**':true}\" -r v8,console-details mocha '**/*.test.js'", | ||
"watch": "chokidar '**/*.js' -c 'npm t' --initial --silent", | ||
@@ -53,2 +54,3 @@ "prepare": "husky && sh scripts/install-fixture-deps.sh", | ||
"mocha": "^10.7.0", | ||
"monocart-coverage-reports": "^2.10.9", | ||
"prettier": "^3.3.3", | ||
@@ -55,0 +57,0 @@ "typescript": "^5.5.4" |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
74671
1913
12