Skip to content

Commit

Permalink
feat: drop callback argument on SerialPort.list() (#1943)
Browse files Browse the repository at this point in the history
Promises are now standard

BREAKING: SerialPort.list() now takes no arguments and always returns a promise.
  • Loading branch information
reconbot committed Sep 25, 2019
1 parent b1cc840 commit 145b906
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 111 deletions.
30 changes: 10 additions & 20 deletions bin/write-a-lot.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,17 @@ process.env.DEBUG = '*'
const SerialPort = require('../packages/serialport')

// outputs the path to an arduino or nothing
function findArduino() {
return new Promise((resolve, reject) => {
if (process.argv[2]) {
return resolve(process.argv[2])
async function findArduino() {
if (process.argv[2]) {
return process.argv[2]
}
const ports = await SerialPort.list()
for (const port of ports) {
if (/arduino/i.test(port.manufacturer)) {
return port.path
}
SerialPort.list((err, ports) => {
if (err) {
return reject(err)
}
let resolved = false
ports.forEach(port => {
if (!resolved && /arduino/i.test(port.manufacturer)) {
resolved = true
return resolve(port.path)
}
})
if (!resolved) {
reject(new Error('No arduinos found'))
}
})
})
}
throw new Error('No arduinos found')
}

findArduino().then(
Expand Down
38 changes: 13 additions & 25 deletions packages/repl/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,32 +7,20 @@ const SerialPort = require('serialport')
process.env.DEBUG = process.env.DEBUG || '*'

// outputs the path to an arduino or nothing
function findArduino() {
return new Promise((resolve, reject) => {
const envPort = process.argv[2] || process.env.TEST_PORT
if (envPort) {
return resolve(envPort)
async function findArduino() {
const envPort = process.argv[2] || process.env.TEST_PORT
if (envPort) {
return envPort
}
const ports = await SerialPort.list()
for (const port of ports) {
if (/arduino/i.test(port.manufacturer)) {
return port.path
}
SerialPort.list((err, ports) => {
if (err) {
return reject(err)
}
let resolved = false
ports.forEach(port => {
if (!resolved && /arduino/i.test(port.manufacturer)) {
resolved = true
return resolve(port.path)
}
})
if (!resolved) {
reject(
new Error(
'No arduinos found. You must specify a port to load.\n\nFor example:\n\tserialport-repl COM3\n\tserialport-repl /dev/tty.my-serialport'
)
)
}
})
})
}
throw new Error(
'No arduinos found. You must specify a port to load.\n\nFor example:\n\tserialport-repl COM3\n\tserialport-repl /dev/tty.my-serialport'
)
}

findArduino()
Expand Down
16 changes: 4 additions & 12 deletions packages/serialport/lib/serialport.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,23 +46,15 @@ function integrationTest(platform, testPort, Binding) {

describe('static Method', () => {
describe('.list', () => {
it('contains the test port', done => {
it('contains the test port', async () => {
function normalizePath(name) {
const parts = name.split('.')
return parts[parts.length - 1].toLowerCase()
}

SerialPort.list((err, ports) => {
assert.isNull(err)
let foundPort = false
ports.forEach(port => {
if (normalizePath(port.path) === normalizePath(testPort)) {
foundPort = true
}
})
assert.isTrue(foundPort)
done()
})
const ports = await SerialPort.list()
const foundPort = ports.some(port => normalizePath(port.path) === normalizePath(testPort))
assert.isTrue(foundPort)
})
})
})
Expand Down
28 changes: 10 additions & 18 deletions packages/serialport/test-manual/many-writes.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,17 @@ const SerialPort = require('../../');
const fs = require('fs');
const Path = require('path');

function findArduino() {
return new Promise((resolve, reject) => {
if (process.argv[2]) {
return resolve(process.argv[2]);
async function findArduino() {
if (process.argv[2]) {
return process.argv[2]
}
const ports = await SerialPort.list()
for (const port of ports) {
if (/arduino/i.test(port.manufacturer)) {
return port.path
}
SerialPort.list((err, ports) => {
if (err) { return reject(err) }
let resolved = false;
ports.forEach((port) => {
if (!resolved && /arduino/i.test(port.manufacturer)) {
resolved = true;
return resolve(port.path);
}
});
if (!resolved) {
reject(new Error('No arduinos found'));
}
});
});
}
throw new Error('No arduinos found')
}

function writeAllCommands(port) {
Expand Down
27 changes: 5 additions & 22 deletions packages/stream/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -591,19 +591,11 @@ SerialPort.prototype.drain = function(callback) {
* @returns `this`
*/

/**
* This callback type is called `requestCallback`.
* @callback listCallback
* @param {?error} error
* @param {array} ports an array of objects with port info
*/

/**
* Retrieves a list of available serial ports with metadata. Only the `path` is guaranteed. If unavailable the other fields will be undefined. The `path` is either the path or an identifier (eg `COM1`) used to open the SerialPort.
*
* We make an effort to identify the hardware attached and have consistent results between systems. Linux and OS X are mostly consistent. Windows relies on 3rd party device drivers for the information and is unable to guarantee the information. On windows If you have a USB connected device can we provide a serial number otherwise it will be `undefined`. The `pnpId` and `locationId` are not the same or present on all systems. The examples below were run with the same Arduino Uno.
* @type {function}
* @param {listCallback=} callback Called with a list of available serial ports.
* @returns {Promise} Resolves with the list of available serial ports.
* @example
```js
Expand Down Expand Up @@ -643,31 +635,22 @@ SerialPort.prototype.drain = function(callback) {
```js
var SerialPort = require('serialport');
// callback approach
SerialPort.list(function (err, ports) {
ports.forEach(function(port) {
console.log(port.path);
console.log(port.pnpId);
console.log(port.manufacturer);
});
});
// promise approach
SerialPort.list()
.then(ports) {...});
.catch(err) {...});
```
*/
SerialPort.list = function(callback) {
SerialPort.list = async function(callback) {
debug('.list')
if (!SerialPort.Binding) {
throw new TypeError('No Binding set on `SerialPort.Binding`')
}
debug('.list')
const promise = SerialPort.Binding.list()
if (typeof callback === 'function') {
promise.then(ports => callback(null, ports), err => callback(err))
if (callback) {
throw new TypeError('SerialPort.list no longer takes a callback and only returns a promise')
}
return promise
return SerialPort.Binding.list()
}

module.exports = SerialPort
38 changes: 24 additions & 14 deletions packages/stream/lib/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -169,24 +169,34 @@ describe('SerialPort', () => {
})

describe('static methods', () => {
it('calls to the bindings', done => {
const spy = sinon.spy(MockBinding, 'list')
SerialPort.list((err, ports) => {
assert.isNull(err)
describe('Serialport#list', () => {
it('calls to the bindings', async () => {
const spy = sinon.spy(MockBinding, 'list')
const ports = await SerialPort.list()
assert.isArray(ports)
assert(spy.calledOnce)
done()
})
})

it('errors if there are no bindings', done => {
SerialPort.Binding = null
try {
SerialPort.list(() => {})
} catch (e) {
assert.instanceOf(e, TypeError)
done()
}
it('errors if there are no bindings', async () => {
SerialPort.Binding = null
try {
await SerialPort.list()
} catch (e) {
assert.instanceOf(e, TypeError)
return
}
throw new Error('no expected error')
})

it('errors if there is a callback', async () => {
try {
await SerialPort.list(() => {})
} catch (e) {
assert.instanceOf(e, TypeError)
return
}
throw new Error('no expected error')
})
})
})

Expand Down

0 comments on commit 145b906

Please sign in to comment.