Skip to content

Commit 2722931

Browse files
lydellshellscape
authored andcommitted
Exponential number notation (shellscape#36)
* Add failing tests for exponential number notation * Add support for exponential number notation * Fix exponential notation for numbers starting with a period * Extract digit charCodes to constants * Improve variable names
1 parent 036bbc6 commit 2722931

File tree

4 files changed

+80
-3
lines changed

4 files changed

+80
-3
lines changed

lib/parser.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,7 @@ module.exports = class Parser {
382382
splitWord () {
383383
let nextToken = this.nextToken,
384384
word = this.currToken[1],
385-
rNumber = /^[\+\-]?((\d+(\.\d*)?)|(\.\d+))/,
385+
rNumber = /^[\+\-]?((\d+(\.\d*)?)|(\.\d+))([eE][\+\-]?\d+)?/,
386386

387387
// treat css-like groupings differently so they can be inspected,
388388
// but don't address them as anything but a word, but allow hex values

lib/tokenize.js

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const singleQuote = '\''.charCodeAt(0);
88
const doubleQuote = '"'.charCodeAt(0);
99
const backslash = '\\'.charCodeAt(0);
1010
const slash = '/'.charCodeAt(0);
11+
const period = '.'.charCodeAt(0);
1112
const comma = ','.charCodeAt(0);
1213
const colon = ':'.charCodeAt(0);
1314
const asterisk = '*'.charCodeAt(0);
@@ -20,6 +21,10 @@ const feed = '\f'.charCodeAt(0);
2021
const tab = '\t'.charCodeAt(0);
2122
const cr = '\r'.charCodeAt(0);
2223
const at = '@'.charCodeAt(0);
24+
const lowerE = 'e'.charCodeAt(0);
25+
const upperE = 'E'.charCodeAt(0);
26+
const digit0 = '0'.charCodeAt(0);
27+
const digit9 = '9'.charCodeAt(0);
2328
const atEnd = /[ \n\t\r\{\(\)'"\\;,/]/g;
2429
const wordEnd = /[ \n\t\r\(\)\{\}\*:;@!&'"\+\|~>,\[\]\\]|\/(?=\*)/g;
2530
const wordEndNum = /[ \n\t\r\(\)\{\}\*:;@!&'"\-\+\|~>,\[\]\\]|\//g;
@@ -299,7 +304,7 @@ module.exports = function tokenize (input, options) {
299304

300305
// we're dealing with a word that starts with a number
301306
// those get treated differently
302-
if (code >= 48 && code <= 57) {
307+
if (code >= digit0 && code <= digit9) {
303308
regex = wordEndNum;
304309
}
305310

@@ -313,6 +318,29 @@ module.exports = function tokenize (input, options) {
313318
next = regex.lastIndex - 2;
314319
}
315320

321+
// Exponential number notation with minus or plus: 1e-10, 1e+10
322+
if (regex === wordEndNum || code === period) {
323+
let ncode1 = css.charCodeAt(next),
324+
ncode2 = css.charCodeAt(next + 1),
325+
ncode3 = css.charCodeAt(next + 2);
326+
327+
if (
328+
(ncode1 === lowerE || ncode1 === upperE) &&
329+
(ncode2 === minus || ncode2 === plus) &&
330+
(ncode3 >= digit0 && ncode3 <= digit9)
331+
) {
332+
wordEndNum.lastIndex = next + 2;
333+
wordEndNum.test(css);
334+
335+
if (wordEndNum.lastIndex === 0) {
336+
next = css.length - 1;
337+
}
338+
else {
339+
next = wordEndNum.lastIndex - 2;
340+
}
341+
}
342+
}
343+
316344
tokens.push(['word', css.slice(pos, next + 1),
317345
line, pos - offset,
318346
line, next - offset,

test/number.js

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,50 @@ describe('Parser → Number', () => {
9898
{
9999
test: '-16px -1px -1px -16px',
100100
expected: { value: '-16', unit: 'px', length: 4 }
101+
},
102+
{
103+
test: '1e10',
104+
expected: { value: '1e10', unit: '', length: 1 }
105+
},
106+
{
107+
test: '1E10',
108+
expected: { value: '1E10', unit: '', length: 1 }
109+
},
110+
{
111+
test: '1e-10',
112+
expected: { value: '1e-10', unit: '', length: 1 }
113+
},
114+
{
115+
test: '1E-10',
116+
expected: { value: '1E-10', unit: '', length: 1 }
117+
},
118+
{
119+
test: '1e+10',
120+
expected: { value: '1e+10', unit: '', length: 1 }
121+
},
122+
{
123+
test: '1E+10',
124+
expected: { value: '1E+10', unit: '', length: 1 }
125+
},
126+
{
127+
test: '1e -10',
128+
expected: { value: '-10', unit: '', length: 2 }
129+
},
130+
{
131+
test: '1e',
132+
expected: { value: '1', unit: 'e', length: 1 }
133+
},
134+
{
135+
test: '-.567800E-0012780em',
136+
expected: { value: '-.567800E-0012780', unit: 'em', length: 1 }
137+
},
138+
{
139+
test: '.1E-10',
140+
expected: { value: '.1E-10', unit: '', length: 1 }
141+
},
142+
{
143+
test: '.1E+10',
144+
expected: { value: '.1E+10', unit: '', length: 1 }
101145
}
102146
];
103147

@@ -174,6 +218,10 @@ describe('Parser → Number : Loose', () => {
174218
{
175219
test: '-16px -1px -1px 16px',
176220
expected: { value: '16', unit: 'px', length: 6 }
221+
},
222+
{
223+
test: '5e+5',
224+
expected: { value: '5e+5', unit: '', length: 1 }
177225
}
178226
];
179227

test/tokenize.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ describe('Tokenize', () => {
1515
{ value: 'Bond\\ 007', expectedLength: 4 },
1616
{ value: ' \\"word\\\'"\\ \\\t ', expectedLength: 7 },
1717
{ value: 'bar(baz(black, 10%), 10%)', expectedLength: 13 },
18-
{ value: '-16px -1px -1px -16px', expectedLength: 11 }
18+
{ value: '-16px -1px -1px -16px', expectedLength: 11 },
19+
{ value: '.56E-0123', expectedLength: 1 }
1920
];
2021

2122
fixtures.forEach((fixture) => {

0 commit comments

Comments
 (0)