mirror of
https://github.com/kemko/nomad.git
synced 2026-01-06 10:25:42 +03:00
Replace custom parse-duration implementation with an existing lib
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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",
|
||||
|
||||
@@ -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}`
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user