compd
Version:
Run a command under a docker-compose setup
130 lines (129 loc) • 3.65 kB
JavaScript
;
/**
* The specification for compose files declares the follow syntaxes.
*
* Short syntax of ports as:
* - "3000"
* - "3000-3005"
* - "8000:8000"
* - "9090-9091:8080-8081"
* - "49100:22"
* - "127.0.0.1:8001:8001"
* - "127.0.0.1:5000-5010:5000-5010"
* - "6060:6060/udp"
*
* Long syntax:
* - target: 80
* published: 8080
* protocol: tcp
* mode: host
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.parsePorts = exports.parsePort = exports.InvalidPortSpecificationError = exports.PortRangeMismatchError = void 0;
class PortRangeMismatchError extends Error {
}
exports.PortRangeMismatchError = PortRangeMismatchError;
class InvalidPortSpecificationError extends Error {
}
exports.InvalidPortSpecificationError = InvalidPortSpecificationError;
/**
* Parses:
* - "3000"
* - "3000-3005"
* - "127.0.0.1:3000"
* - "127.0.0.1:3000-3005"
*/
function parseHostOrContainerPorts(value) {
if (value.includes(':')) {
const [hostIP, port] = value.split(':');
return parseHostOrContainerPorts(port)
.map(({ port }) => ({ hostIP, port }));
}
else {
if (value.includes('-')) {
const [lower, upper] = value.split('-');
return makePortRange(parseInt(lower, 10), parseInt(upper, 10))
.map(port => ({ port }));
}
else {
return [{ port: parseInt(value, 10) },];
}
}
}
/**
* Turns [3000, 3002] into [3000, 3001, 3002]
*/
function makePortRange(lower, uppper) {
const ret = [];
for (let i = lower; i <= uppper; ++i)
ret.push(i);
return ret;
}
/**
* Parses:
* - "3000"
* - "3000/udp"
* - "3000-3005"
* - "3000-3005/tcp"
*/
function parseContainerPorts(value) {
const m = value.match(/^([^/]+)(\/([^/]+))?$/);
if (!m)
throw new InvalidPortSpecificationError(`Invalid port definition: ${value}`);
const [, port, , protocol = 'tcp'] = [...m];
const proto = protocol;
return parseHostOrContainerPorts(port)
.map(({ hostIP, port }) => ({
hostIP,
container: port,
proto,
}));
}
// Splits a string on the *last* colon
function splitHostContainer(value) {
const m = value.match(/^(.+):([^:]+)$/);
if (!m)
throw new InvalidPortSpecificationError(`Invalid port definition: ${value}`);
return [m[1], m[2]];
}
function parsePortShort(value) {
value = `${value}`;
if (value.includes(':')) {
const [host, container] = splitHostContainer(value);
const portsHost = parseHostOrContainerPorts(host);
const portsContainer = parseContainerPorts(container);
if (portsHost.length !== portsContainer.length)
throw new PortRangeMismatchError(`Port range of different size: ${value}`);
return portsContainer
.map(({ container, proto }, index) => ({
hostIP: portsHost[index].hostIP,
host: portsHost[index].port,
container,
proto,
}));
}
else {
return parseContainerPorts(value);
}
}
function parsePortLong(value) {
return [
{
host: value.published,
container: value.target,
proto: value.protocol || 'tcp',
mode: value.mode || 'host',
},
];
}
function parsePort(value) {
return (typeof value === 'string' || typeof value === 'number')
? parsePortShort(value)
: parsePortLong(value);
}
exports.parsePort = parsePort;
function parsePorts(values) {
return []
.concat(...values.map(value => parsePort(value)));
}
exports.parsePorts = parsePorts;