Replace custom parse-duration implementation with an existing lib

This commit is contained in:
Michael Lange
2019-12-13 12:24:13 -08:00
parent b9b6cda5b4
commit 4793dc9afb
5 changed files with 9 additions and 184 deletions

View File

@@ -3,7 +3,7 @@ import { computed } from '@ember/object';
import { equal } from '@ember/object/computed';
import { computed as overridable } from 'ember-overridable-computed';
import { task } from 'ember-concurrency';
import parseDuration from 'nomad-ui/utils/parse-duration';
import Duration from 'duration-js';
export default Component.extend({
tagName: '',
@@ -53,9 +53,9 @@ export default Component.extend({
let deadline;
try {
deadline = parseDuration(this.deadline);
deadline = new Duration(this.deadline).nanoseconds();
} catch (err) {
this.set('parseError', 'Failed to parse duration');
this.set('parseError', err.message);
return;
}

View File

@@ -1,88 +0,0 @@
const unitToMs = {
ms: 1,
s: 1000,
m: 1000 * 60,
h: 1000 * 60 * 60,
d: 1000 * 60 * 60 * 24,
};
const durationUnits = Object.keys(unitToMs);
const isNumeric = char => char >= 0 && char < 10;
const encodeUnit = (str, token) => {
// Convert it to a string and validate the unit type.
let newToken = token.join('');
if (!durationUnits.includes(newToken)) {
throw new Error(`ParseError: [${str}] Unallowed duration unit "${newToken}"`);
}
return newToken;
};
const encodeQuantity = (str, token) => {
return parseInt(token.join(''));
};
export default str => {
if (typeof str === 'number') return str;
// Split the string into characters to make iteration easier
const chars = str.split('');
// Bail early if the duration doesn't start with a number
if (!isNumeric(chars[0])) {
throw new Error(`ParseError: [${str}] Durations must start with a numeric quantity`);
}
// Collect tokens
const tokens = [];
// A token can be multi-character, so collect characters
let token = [];
// Alternate between numeric "quantity" tokens and non-numeric "unit" tokens
let unitMode = false;
while (chars.length) {
let finishToken = false;
let next = chars.shift();
// First identify if the next character is the first
// character of the next token.
if (isNumeric(next) && unitMode) {
unitMode = false;
finishToken = true;
} else if (!isNumeric(next) && !unitMode) {
unitMode = true;
finishToken = true;
}
// When a token is finished, validate it, encode it, and add it to the tokens list
if (finishToken) {
tokens.push(unitMode ? encodeQuantity(str, token) : encodeUnit(str, token));
token = [];
}
// Always add the next character to the token buffer.
token.push(next);
}
// Once the loop finishes, flush the token buffer one more time.
if (unitMode) {
tokens.push(encodeUnit(str, token));
} else {
throw new Error(`ParseError: [${str}] Unmatched quantities and units`);
}
// Loop over the tokens array, two at a time, converting unit and quanties into milliseconds
let duration = 0;
while (tokens.length) {
const quantity = tokens.shift();
const unit = tokens.shift();
duration += quantity * unitToMs[unit];
}
// Convert from Milliseconds to Nanoseconds
duration *= 1000000;
return duration;
};

View File

@@ -50,6 +50,7 @@
"d3-shape": "^1.2.0",
"d3-time-format": "^2.1.0",
"d3-transition": "^1.1.0",
"duration-js": "^4.0.0",
"ember-ajax": "^5.0.0",
"ember-auto-import": "^1.2.21",
"ember-can": "^2.0.0",

View File

@@ -1,93 +0,0 @@
import { module, test } from 'qunit';
import parseDuration from 'nomad-ui/utils/parse-duration';
const testCases = [
{
name: 'Only milliseconds',
in: '100ms',
out: 100 * 1000000,
},
{
name: 'Only seconds',
in: '5s',
out: 5 * 1000 * 1000000,
},
{
name: 'Only minutes',
in: '30m',
out: 30 * 60 * 1000 * 1000000,
},
{
name: 'Only hours',
in: '8h',
out: 8 * 60 * 60 * 1000 * 1000000,
},
{
name: 'Only days',
in: '2d',
out: 2 * 24 * 60 * 60 * 1000 * 1000000,
},
{
name: 'Composite',
in: '1d8h15m30s',
out: (((1 * 24 + 8) * 60 + 15) * 60 + 30) * 1000 * 1000000,
},
{
name: 'Zeroes',
in: '0d0h0m0s',
out: 0,
},
{
name: 'Improper durations',
in: '90m',
out: 90 * 60 * 1000 * 1000000,
},
{
name: 'Already parsed',
in: 1000000,
out: 1000000,
},
];
const errorCases = [
{
name: 'Empty string',
in: '',
error: /Durations must start with a numeric quantity/,
},
{
name: 'No quantity',
in: 'h',
error: /Durations must start with a numeric quantity/,
},
{
name: 'Unallowed unit',
in: '15M',
error: /Unallowed duration unit "M"/,
},
{
name: 'Float quantities',
in: '1.5m',
error: /Unallowed duration unit "\."/,
},
];
module('Unit | Util | parseDuration', function() {
testCases.forEach(testCase => {
test(testCase.name, function(assert) {
assert.equal(parseDuration(testCase.in), testCase.out, `'${testCase.in}' => ${testCase.out}`);
});
});
errorCases.forEach(testCase => {
test(`Error Case: ${testCase.name}`, function(assert) {
assert.throws(
() => {
parseDuration(testCase.in);
},
testCase.error,
`'${testCase.in}' throws ${testCase.error}`
);
});
});
});

View File

@@ -6375,6 +6375,11 @@ duplexify@^3.4.2, duplexify@^3.6.0:
readable-stream "^2.0.0"
stream-shift "^1.0.0"
duration-js@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/duration-js/-/duration-js-4.0.0.tgz#ab91575a4f1a6b096034685cfc6ea9aca99cd63f"
integrity sha1-q5FXWk8aawlgNGhc/G6prKmc1j8=
ecc-jsbn@~0.1.1:
version "0.1.2"
resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9"