From 87d15c6fca13263e76a3324a31a6312eaf1cbdd1 Mon Sep 17 00:00:00 2001 From: russa Date: Tue, 4 Sep 2018 21:16:44 +0200 Subject: [PATCH 01/10] strict mode for parsing numbers --- src/index.test.ts | 168 ++++++++++++++++++++++++++++++---------------- src/index.ts | 88 ++++++++++++++++++++++-- 2 files changed, 192 insertions(+), 64 deletions(-) diff --git a/src/index.test.ts b/src/index.test.ts index 6fd0aac..ac0ccc8 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -6,77 +6,123 @@ const cssResolutionUnits: string[] = require('css-resolution-units'); const cssFrequencyUnits: string[] = require('css-frequency-units'); const cssTimeUnits: string[] = require('css-time-units'); +const parseOptions = [, {strict: false}, {strict: true}]; + import CssDimension from './'; test('throws when a dot should be followed by a number', (t) => { - t.throws( - () => new CssDimension('12.'), - /The dot should be followed by a number/, - ); + parseOptions.forEach((options) => { + t.throws( + () => new CssDimension('12.', options), + /The dot should be followed by a number/, + ); + }); }); test('throws when more than one leading +/- is provided', (t) => { - t.throws( - () => new CssDimension('+-12.2'), - /Only one leading \+\/- is allowed/, - ); + parseOptions.forEach((options) => { + t.throws( + () => new CssDimension('+-12.2', options), + /Only one leading \+\/- is allowed/, + ); + }); }); test('throws when more than one dot is provided', (t) => { - t.throws( - () => new CssDimension('12.1.1'), - /Only one dot is allowed/, - ); + parseOptions.forEach((options) => { + t.throws( + () => new CssDimension('12.1.1', options), + /Only one dot is allowed/, + ); + }); }); test('throws when an invalid unit of "foo" is provided', (t) => { - t.throws( - () => new CssDimension('12foo'), - /Invalid unit: foo/, - ); + parseOptions.forEach((options) => { + t.throws( + () => new CssDimension('12foo', options), + /Invalid unit: foo/, + ); + }); }); -test('throws when an invalid number of "foo42" is provided', (t) => { +test('throws in mode when an invalid number of "foo42" is provided', (t) => { + parseOptions.forEach((options) => { + t.throws( + () => new CssDimension('foo42', options), + /Invalid number: foo/, + ); + }); +}); + +const strictInvalidENotationNumbers = [ + '23e.07', + '23e0.7', + '23e-.07', + '23e+0.07', +]; + +test('throws in mode when a number with invalid e-notation is provided', (t) => { + strictInvalidENotationNumbers.forEach((invalidNumber) => { + t.throws( + () => new CssDimension(invalidNumber, {strict: true}), + new RegExp('Invalid number: ' + invalidNumber.replace('+', '\\+')), + ); + }); +}); + +test('throws in strict when an invalid number of "35sdfs75rem" is provided', (t) => { t.throws( - () => new CssDimension('foo42'), - /Invalid number: foo/, + () => new CssDimension('35sdfs75rem', {strict: true}), + /Invalid number: 35sdfs75/, ); }); test('parse result is instance of CssDimension', (t) => { - t.is( - CssDimension.parse('42%') instanceof CssDimension, - true, - ); + parseOptions.forEach((options) => { + t.is( + CssDimension.parse('42%', options) instanceof CssDimension, + true, + ); + }); }); test('returns the numeric value with .value', (t) => { - t.true(typeof new CssDimension('42%').value === 'number'); + parseOptions.forEach((options) => { + t.true(typeof new CssDimension('42%', options).value === 'number'); + }); }); test('adding a number yields a concatenated string', (t) => { - t.is( - (CssDimension.parse('42%') as any) + 3, - '42%3', - ); + parseOptions.forEach((options) => { + t.is( + (CssDimension.parse('42%', options) as any) + 3, + '42%3', + ); + }); }); test('stringifies a percent', (t) => { - t.is( - new CssDimension('42%') + 'foo', - '42%foo', - ); + parseOptions.forEach((options) => { + t.is( + new CssDimension('42%', options) + 'foo', + '42%foo', + ); + }); }); test('stringifies a number', (t) => { - t.is( - new CssDimension('42') + 'foo', - '42foo', - ); + parseOptions.forEach((options) => { + t.is( + new CssDimension('42', options) + 'foo', + '42foo', + ); + }); }); const validNumbers = { '+0.0': 0, + '-.1': -0.1, '-0.0': -0, '-3.4e-2': -0.034, '-456.8': -456.8, @@ -85,24 +131,28 @@ const validNumbers = { '10e3': 10000, '12': 12, '4.01': 4.01, + '540': 540, + '89.3000': 89.3, }; test('number conversion', (t) => { const unit = '%'; - Object.keys(validNumbers).forEach((rawNumber) => { - const num = validNumbers[rawNumber]; - - const d1 = CssDimension.parse(rawNumber); - let msg = 'parses ' + rawNumber; - t.is(d1.type, 'number', msg); - t.is(d1.value, num, msg); - t.is(d1.unit, undefined, msg); - - const d2 = CssDimension.parse(rawNumber + unit); - msg += unit; - t.is(d2.type, 'percentage', msg); - t.is(d2.value, num, msg); - t.is(d2.unit, unit, msg); + parseOptions.forEach((options) => { + Object.keys(validNumbers).forEach((rawNumber) => { + const num = validNumbers[rawNumber]; + + const d1 = CssDimension.parse(rawNumber, options); + let msg = 'parses ' + rawNumber; + t.is(d1.type, 'number', msg); + t.is(d1.value, num, msg); + t.is(d1.unit, undefined, msg); + + const d2 = CssDimension.parse(rawNumber + unit, options); + msg += unit; + t.is(d2.type, 'percentage', msg); + t.is(d2.value, num, msg); + t.is(d2.unit, unit, msg); + }); }); }); @@ -130,14 +180,16 @@ test('units and unit types', (t) => { }, ].forEach((unitDef) => { unitDef.list.forEach((unit) => { - Object.keys(validNumbers).forEach((rawNumber) => { - const num = validNumbers[rawNumber]; - - const d1 = CssDimension.parse(rawNumber + unit); - const msg = 'parses ' + rawNumber + unit; - t.is(d1.type, unitDef.type, msg); - t.is(d1.value, num, msg); - t.is(d1.unit, unit, msg); + parseOptions.forEach((options) => { + Object.keys(validNumbers).forEach((rawNumber) => { + const num = validNumbers[rawNumber]; + + const d1 = CssDimension.parse(rawNumber + unit, options); + const msg = 'parses ' + rawNumber + unit; + t.is(d1.type, unitDef.type, msg); + t.is(d1.value, num, msg); + t.is(d1.unit, unit, msg); + }); }); }); }); diff --git a/src/index.ts b/src/index.ts index 3be746c..5594bb8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -8,24 +8,33 @@ const cssResolutionUnits: string[] = require('css-resolution-units'); const cssFrequencyUnits: string[] = require('css-frequency-units'); const cssTimeUnits: string[] = require('css-time-units'); +const numberPrefixPattern = /^(\+|-)?(\.)?\d/; + +export interface IOptions { + strict?: boolean; +} + export default class CssDimension { - public static parse(value: string) { - return new CssDimension(value); + public static parse(value: string, options?: IOptions) { + return new CssDimension(value, options); } public type: string; public value: number; public unit: string; - constructor(value: string) { + constructor(value: string, options?: IOptions) { + this.validateNumber(value); this.validateSign(value); this.validateDots(value); + const strict = !!(options && options.strict); + if (/%$/.test(value)) { this.type = 'percentage'; - this.value = tryParseFloat(value); + this.value = tryParseNumber(value.substring(0, value.length - 1), strict); this.unit = '%'; return; } @@ -33,12 +42,12 @@ export default class CssDimension { const unit = parseUnit(value); if (!unit) { this.type = 'number'; - this.value = tryParseFloat(value); + this.value = tryParseNumber(value, strict); return; } this.type = unitToType(unit); - this.value = tryParseFloat(value.substr(0, value.length - unit.length)); + this.value = tryParseNumber(value.substr(0, value.length - unit.length), strict); this.unit = unit; } @@ -74,6 +83,10 @@ function countDots(value: string) { return m ? m.length : 0; } +function tryParseNumber(value: string, strict: boolean) { + return strict ? tryParseStrict(value) : tryParseFloat(value); +} + function tryParseFloat(value: string) { const result = parseFloat(value); if (isNaN(result)) { @@ -82,6 +95,69 @@ function tryParseFloat(value: string) { return result; } +function normalizeNumber(value: string, allowDot: boolean = true): string { + const match = numberPrefixPattern.exec(value); + if (!match) { + throw new Error('Invalid number: ' + value); + } + const [, sign, dot] = match; + let dots = dot ? 1 : 0; + const endingZero = /0$/.test(value); + if (sign === '+') { + value = value.substring(1); + } + if (dot === '.') { + if (!allowDot) { + throw new Error('Invalid number (too many dots): ' + value); + } + if (sign === '-') { + value = '-0' + value.substring(1); + } else { + value = '0' + value; + } + } else if (endingZero || !allowDot) { + dots = countDots(value); + } + if (dots > 0) { + if (!allowDot) { + throw new Error('Invalid number (too many dots): ' + value); + } + if (endingZero) { + value = value.replace(/\.?0+$/, ''); + } + } + return value; +} + +function tryParseStrict(value: string): number { + const nval = normalizeNumber(value); + const result = parseFloat(nval); + if (result.toString() !== nval) { + if (verifyZero(value) || verifyENotation(value)) { + return result; + } + throw new Error('Invalid number: ' + value); + } + return result; +} + +function verifyZero(value: string) { + return /^[-+]?0\.0+$/.test(value); +} + +function verifyENotation(value: string) { + const m = /e/i.exec(value); + if (!m || m.index === value.length - 1) { + return false; + } + try { + const nval = normalizeNumber(value.substring(m.index + 1), false); + return parseInt(nval, 10).toString() === nval; + } catch (err) { + throw new Error('Invalid number: ' + value); + } +} + const units = cssAngleUnits.concat( cssFrequencyUnits, cssLengthUnits, From 604707f998cdcf7fa0f3bc37bedcc60a63b02418 Mon Sep 17 00:00:00 2001 From: russa Date: Thu, 6 Sep 2018 16:05:59 +0200 Subject: [PATCH 02/10] added test for invalid 'NaN' input --- src/index.test.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/index.test.ts b/src/index.test.ts index ac0ccc8..c073d91 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -46,7 +46,7 @@ test('throws when an invalid unit of "foo" is provided', (t) => { }); }); -test('throws in mode when an invalid number of "foo42" is provided', (t) => { +test('throws in strict mode when an invalid number of "foo42" is provided', (t) => { parseOptions.forEach((options) => { t.throws( () => new CssDimension('foo42', options), @@ -55,6 +55,15 @@ test('throws in mode when an invalid number of "foo42" is provided', (t) => { }); }); +test('throws in strict mode when an invalid number of "NaN%" is provided', (t) => { + parseOptions.forEach((options) => { + t.throws( + () => new CssDimension('NaN%', options), + /Invalid number: NaN/, + ); + }); +}); + const strictInvalidENotationNumbers = [ '23e.07', '23e0.7', @@ -62,7 +71,7 @@ const strictInvalidENotationNumbers = [ '23e+0.07', ]; -test('throws in mode when a number with invalid e-notation is provided', (t) => { +test('throws in strict mode when a number with invalid e-notation is provided', (t) => { strictInvalidENotationNumbers.forEach((invalidNumber) => { t.throws( () => new CssDimension(invalidNumber, {strict: true}), From 9464034786de0bf838b6d25c4795456baa79a4a6 Mon Sep 17 00:00:00 2001 From: russa Date: Thu, 6 Sep 2018 16:12:16 +0200 Subject: [PATCH 03/10] simplified normalizeNumber function as suggested by @jedmao --- src/index.ts | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/src/index.ts b/src/index.ts index 5594bb8..ac70eef 100644 --- a/src/index.ts +++ b/src/index.ts @@ -98,35 +98,25 @@ function tryParseFloat(value: string) { function normalizeNumber(value: string, allowDot: boolean = true): string { const match = numberPrefixPattern.exec(value); if (!match) { - throw new Error('Invalid number: ' + value); + throw new Error(`Invalid number: ${value}`); } const [, sign, dot] = match; - let dots = dot ? 1 : 0; - const endingZero = /0$/.test(value); if (sign === '+') { - value = value.substring(1); + value = value.substr(1); } - if (dot === '.') { + if (dot) { if (!allowDot) { - throw new Error('Invalid number (too many dots): ' + value); + throw new Error(`Invalid number (too many dots): ${value}`); } if (sign === '-') { - value = '-0' + value.substring(1); + value = '-0' + value.substr(1); } else { value = '0' + value; } - } else if (endingZero || !allowDot) { - dots = countDots(value); - } - if (dots > 0) { - if (!allowDot) { - throw new Error('Invalid number (too many dots): ' + value); - } - if (endingZero) { - value = value.replace(/\.?0+$/, ''); - } } - return value; + return (dot || countDots(value)) + ? value.replace(/\.?0+$/, '') + : value; } function tryParseStrict(value: string): number { From 707532f428c1c2f2534bccae46f5d4ef08154a23 Mon Sep 17 00:00:00 2001 From: russa Date: Thu, 6 Sep 2018 16:13:46 +0200 Subject: [PATCH 04/10] simplified tryParseStrict function as suggested by @jedmao --- src/index.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/index.ts b/src/index.ts index ac70eef..3ace642 100644 --- a/src/index.ts +++ b/src/index.ts @@ -122,11 +122,8 @@ function normalizeNumber(value: string, allowDot: boolean = true): string { function tryParseStrict(value: string): number { const nval = normalizeNumber(value); const result = parseFloat(nval); - if (result.toString() !== nval) { - if (verifyZero(value) || verifyENotation(value)) { - return result; - } - throw new Error('Invalid number: ' + value); + if (result.toString() !== nval && !verifyZero(value) && !verifyENotation(value)) { + throw new Error(`Invalid number: ${value}`); } return result; } From 8cffa1503db3a570188a0ad8d38c9799311126af Mon Sep 17 00:00:00 2001 From: russa Date: Thu, 6 Sep 2018 16:14:54 +0200 Subject: [PATCH 05/10] removed return-type declaration from functions --- src/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/index.ts b/src/index.ts index 3ace642..a1cd440 100644 --- a/src/index.ts +++ b/src/index.ts @@ -95,7 +95,7 @@ function tryParseFloat(value: string) { return result; } -function normalizeNumber(value: string, allowDot: boolean = true): string { +function normalizeNumber(value: string, allowDot: boolean = true) { const match = numberPrefixPattern.exec(value); if (!match) { throw new Error(`Invalid number: ${value}`); @@ -119,7 +119,7 @@ function normalizeNumber(value: string, allowDot: boolean = true): string { : value; } -function tryParseStrict(value: string): number { +function tryParseStrict(value: string) { const nval = normalizeNumber(value); const result = parseFloat(nval); if (result.toString() !== nval && !verifyZero(value) && !verifyENotation(value)) { From 1a379c63efdd839295dbd842d079272d8aa37a78 Mon Sep 17 00:00:00 2001 From: russa Date: Thu, 6 Sep 2018 16:18:42 +0200 Subject: [PATCH 06/10] refactor: return NULL in normalizeNumber() instead of throwing error --- src/index.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/index.ts b/src/index.ts index a1cd440..f520273 100644 --- a/src/index.ts +++ b/src/index.ts @@ -98,7 +98,7 @@ function tryParseFloat(value: string) { function normalizeNumber(value: string, allowDot: boolean = true) { const match = numberPrefixPattern.exec(value); if (!match) { - throw new Error(`Invalid number: ${value}`); + return null; } const [, sign, dot] = match; if (sign === '+') { @@ -106,7 +106,7 @@ function normalizeNumber(value: string, allowDot: boolean = true) { } if (dot) { if (!allowDot) { - throw new Error(`Invalid number (too many dots): ${value}`); + return null; } if (sign === '-') { value = '-0' + value.substr(1); @@ -121,6 +121,9 @@ function normalizeNumber(value: string, allowDot: boolean = true) { function tryParseStrict(value: string) { const nval = normalizeNumber(value); + if (!nval) { + throw new Error(`Invalid number: ${value}`); + } const result = parseFloat(nval); if (result.toString() !== nval && !verifyZero(value) && !verifyENotation(value)) { throw new Error(`Invalid number: ${value}`); @@ -137,12 +140,11 @@ function verifyENotation(value: string) { if (!m || m.index === value.length - 1) { return false; } - try { - const nval = normalizeNumber(value.substring(m.index + 1), false); - return parseInt(nval, 10).toString() === nval; - } catch (err) { - throw new Error('Invalid number: ' + value); + const nval = normalizeNumber(value.substring(m.index + 1), false); + if (!nval) { + throw new Error(`Invalid number: ${value}`); } + return parseInt(nval, 10).toString() === nval; } const units = cssAngleUnits.concat( From 8f6cdabe4b57ba84fa9feccd626bff2da241aaa8 Mon Sep 17 00:00:00 2001 From: russa Date: Thu, 6 Sep 2018 16:51:00 +0200 Subject: [PATCH 07/10] extended test cases --- src/index.test.ts | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/index.test.ts b/src/index.test.ts index c073d91..90a3d76 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -55,12 +55,19 @@ test('throws in strict mode when an invalid number of "foo42" is provided', (t) }); }); -test('throws in strict mode when an invalid number of "NaN%" is provided', (t) => { +const nonNumbers = [ + '+.NaN%', + 'NaN%', +]; + +test('throws in when non-number input with "NaN" is provided', (t) => { parseOptions.forEach((options) => { - t.throws( - () => new CssDimension('NaN%', options), - /Invalid number: NaN/, - ); + nonNumbers.forEach((nonNumber) => { + t.throws( + () => new CssDimension(nonNumber, options), + new RegExp('Invalid number: ' + nonNumber.replace('+', '\\+').replace(/%$/, '')), + ); + }); }); }); @@ -137,6 +144,7 @@ const validNumbers = { '-456.8': -456.8, '.60': 0.6, '0.0': 0, + '10E-3': 0.01, '10e3': 10000, '12': 12, '4.01': 4.01, From 332173410c5aff57375a1010796d0dda31e632a6 Mon Sep 17 00:00:00 2001 From: russa Date: Thu, 6 Sep 2018 17:04:29 +0200 Subject: [PATCH 08/10] added support for numbers with leading zeros in strict mode --- src/index.test.ts | 2 ++ src/index.ts | 1 + 2 files changed, 3 insertions(+) diff --git a/src/index.test.ts b/src/index.test.ts index 90a3d76..031547d 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -144,6 +144,8 @@ const validNumbers = { '-456.8': -456.8, '.60': 0.6, '0.0': 0, + '000289.6800': 289.68, + '068': 68, '10E-3': 0.01, '10e3': 10000, '12': 12, diff --git a/src/index.ts b/src/index.ts index f520273..c898363 100644 --- a/src/index.ts +++ b/src/index.ts @@ -96,6 +96,7 @@ function tryParseFloat(value: string) { } function normalizeNumber(value: string, allowDot: boolean = true) { + value = value[0] === '0' ? value.replace(/^0+(\d)/, '$1') : value; const match = numberPrefixPattern.exec(value); if (!match) { return null; From f8bf3c9b87d565aeaef02582fb5242ee75cab5c3 Mon Sep 17 00:00:00 2001 From: russa Date: Thu, 6 Sep 2018 18:29:51 +0200 Subject: [PATCH 09/10] validate numbers using regular expressions instead of parseFloat().toString()&input-manipulation --- src/index.test.ts | 1 + src/index.ts | 68 +++++++++++++++++------------------------------ 2 files changed, 26 insertions(+), 43 deletions(-) diff --git a/src/index.test.ts b/src/index.test.ts index 031547d..8fa6685 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -72,6 +72,7 @@ test('throws in when non-number input with "NaN" is provided', (t) => { }); const strictInvalidENotationNumbers = [ + '.23e-a07', '23e.07', '23e0.7', '23e-.07', diff --git a/src/index.ts b/src/index.ts index c898363..b2ddfbb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -8,7 +8,10 @@ const cssResolutionUnits: string[] = require('css-resolution-units'); const cssFrequencyUnits: string[] = require('css-frequency-units'); const cssTimeUnits: string[] = require('css-time-units'); -const numberPrefixPattern = /^(\+|-)?(\.)?\d/; +const numberPrefixPattern = /^[+|-]?(\.)?\d/; +const eNotationPattern = /e[+-]?/i; +const digitPattern = /^\d+$/; +const dotPattern = /\./; export interface IOptions { strict?: boolean; @@ -95,57 +98,36 @@ function tryParseFloat(value: string) { return result; } -function normalizeNumber(value: string, allowDot: boolean = true) { - value = value[0] === '0' ? value.replace(/^0+(\d)/, '$1') : value; - const match = numberPrefixPattern.exec(value); - if (!match) { - return null; - } - const [, sign, dot] = match; - if (sign === '+') { - value = value.substr(1); - } - if (dot) { - if (!allowDot) { - return null; - } - if (sign === '-') { - value = '-0' + value.substr(1); - } else { - value = '0' + value; - } - } - return (dot || countDots(value)) - ? value.replace(/\.?0+$/, '') - : value; -} - function tryParseStrict(value: string) { - const nval = normalizeNumber(value); - if (!nval) { + const m1 = numberPrefixPattern.exec(value); + if (!m1) { throw new Error(`Invalid number: ${value}`); } - const result = parseFloat(nval); - if (result.toString() !== nval && !verifyZero(value) && !verifyENotation(value)) { + const mval = value.substr(m1[0].length - 1); + if (m1[1] && !verifyIntExp(mval)) { throw new Error(`Invalid number: ${value}`); } - return result; -} - -function verifyZero(value: string) { - return /^[-+]?0\.0+$/.test(value); + const m2 = dotPattern.exec(mval); + if (m2) { + if (!verifyDigits(mval.substr(0, m2.index)) || !verifyIntExp(mval.substr(m2.index + 1))) { + throw new Error(`Invalid number: ${value}`); + } + } else if (!verifyIntExp(mval)) { + throw new Error(`Invalid number: ${value}`); + } + return parseFloat(value); } -function verifyENotation(value: string) { - const m = /e/i.exec(value); - if (!m || m.index === value.length - 1) { +function verifyIntExp(value: string) { + const m = eNotationPattern.exec(value); + if (m && !verifyDigits(value.substr(m.index + m[0].length))) { return false; } - const nval = normalizeNumber(value.substring(m.index + 1), false); - if (!nval) { - throw new Error(`Invalid number: ${value}`); - } - return parseInt(nval, 10).toString() === nval; + return verifyDigits(m ? value.substr(0, m.index) : value); +} + +function verifyDigits(value: string) { + return digitPattern.test(value); } const units = cssAngleUnits.concat( From 7d0bd70dd01985d84d840e87649349185e0b56e5 Mon Sep 17 00:00:00 2001 From: russa Date: Thu, 6 Sep 2018 18:55:18 +0200 Subject: [PATCH 10/10] simplified / removed unnecessary code --- src/index.ts | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/src/index.ts b/src/index.ts index b2ddfbb..2267776 100644 --- a/src/index.ts +++ b/src/index.ts @@ -8,7 +8,7 @@ const cssResolutionUnits: string[] = require('css-resolution-units'); const cssFrequencyUnits: string[] = require('css-frequency-units'); const cssTimeUnits: string[] = require('css-time-units'); -const numberPrefixPattern = /^[+|-]?(\.)?\d/; +const numberPrefixPattern = /^[+|-]?\.?/; const eNotationPattern = /e[+-]?/i; const digitPattern = /^\d+$/; const dotPattern = /\./; @@ -99,17 +99,10 @@ function tryParseFloat(value: string) { } function tryParseStrict(value: string) { - const m1 = numberPrefixPattern.exec(value); - if (!m1) { - throw new Error(`Invalid number: ${value}`); - } - const mval = value.substr(m1[0].length - 1); - if (m1[1] && !verifyIntExp(mval)) { - throw new Error(`Invalid number: ${value}`); - } - const m2 = dotPattern.exec(mval); - if (m2) { - if (!verifyDigits(mval.substr(0, m2.index)) || !verifyIntExp(mval.substr(m2.index + 1))) { + const mval = value.replace(numberPrefixPattern, ''); + const mdot = dotPattern.exec(mval); + if (mdot) { + if (!verifyDigits(mval.substr(0, mdot.index)) || !verifyIntExp(mval.substr(mdot.index + 1))) { throw new Error(`Invalid number: ${value}`); } } else if (!verifyIntExp(mval)) {