Skip to content

Commit f2e8e7a

Browse files
committed
fix unclosed string and resolution parsing #8
1 parent 1ee6b18 commit f2e8e7a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+976
-179641
lines changed

.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
/docs/** linguist-vendored
1414
/tools/** linguist-vendored
1515
/dist/** linguist-vendored
16+
/test/** linguist-vendored
1617
/coverage/** linguist-vendored
1718
#
1819
# do not replace lf by crlf

dist/index-umd-web.js

Lines changed: 122 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -165,37 +165,30 @@
165165
return true;
166166
}
167167
function isDimension(name) {
168-
let index = 0;
169-
while (index++ < name.length) {
170-
if (isDigit(name.charCodeAt(name.length - index))) {
171-
index--;
172-
break;
173-
}
174-
if (index == 3) {
175-
break;
168+
let index = name.length;
169+
while (index--) {
170+
if (isLetter(name.charCodeAt(index))) {
171+
continue;
176172
}
173+
index++;
174+
break;
177175
}
178-
if (index == 0 || index > 3) {
179-
return false;
180-
}
181-
const number = name.slice(0, -index);
182-
return number.length > 0 && isIdentStart(name.charCodeAt(name.length - index)) && isNumber(number);
176+
const number = name.slice(0, index);
177+
return number.length > 0 && isIdentStart(name.charCodeAt(index)) && isNumber(number);
183178
}
184179
function isPercentage(name) {
185180
return name.endsWith('%') && isNumber(name.slice(0, -1));
186181
}
187182
function parseDimension(name) {
188-
let index = 0;
189-
while (index++ < name.length) {
190-
if (isDigit(name.charCodeAt(name.length - index))) {
191-
index--;
192-
break;
193-
}
194-
if (index == 3) {
195-
break;
183+
let index = name.length;
184+
while (index--) {
185+
if (isLetter(name.charCodeAt(index))) {
186+
continue;
196187
}
188+
index++;
189+
break;
197190
}
198-
const dimension = { typ: 'Dimension', val: name.slice(0, -index), unit: name.slice(-index) };
191+
const dimension = { typ: 'Dimension', val: name.slice(0, index), unit: name.slice(index) };
199192
if (isAngle(dimension)) {
200193
// @ts-ignore
201194
dimension.typ = 'Angle';
@@ -1504,7 +1497,7 @@
15041497
return `#${rgb.reduce((acc, curr) => acc + curr.toString(16).padStart(2, '0'), '')}`;
15051498
}
15061499
function getAngle(token) {
1507-
if (token.typ == 'Dimension') {
1500+
if (token.typ == 'Angle') {
15081501
switch (token.unit) {
15091502
case 'deg':
15101503
// @ts-ignore
@@ -1577,6 +1570,23 @@
15771570
return values;
15781571
}
15791572

1573+
function reduceNumber(val) {
1574+
val = (+val).toString();
1575+
if (val === '0') {
1576+
return '0';
1577+
}
1578+
const chr = val.charAt(0);
1579+
if (chr == '-') {
1580+
const slice = val.slice(0, 2);
1581+
if (slice == '-0') {
1582+
return val.length == 2 ? '0' : '-' + val.slice(2);
1583+
}
1584+
}
1585+
if (chr == '0') {
1586+
return val.slice(1);
1587+
}
1588+
return val;
1589+
}
15801590
function render(data, opt = {}) {
15811591
const startTime = performance.now();
15821592
const options = Object.assign(opt.minify ?? true ? {
@@ -1589,7 +1599,8 @@
15891599
compress: false,
15901600
removeComments: false,
15911601
}, { colorConvert: true, preserveLicense: false }, opt);
1592-
return { code: doRender(data, options, function reducer(acc, curr) {
1602+
return {
1603+
code: doRender(data, options, function reducer(acc, curr) {
15931604
if (curr.typ == 'Comment' && options.removeComments) {
15941605
if (!options.preserveLicense || !curr.val.startsWith('/*!')) {
15951606
return acc;
@@ -1599,7 +1610,8 @@
15991610
return acc + renderToken(curr, options, reducer);
16001611
}, 0), stats: {
16011612
total: `${(performance.now() - startTime).toFixed(2)}ms`
1602-
} };
1613+
}
1614+
};
16031615
}
16041616
// @ts-ignore
16051617
function doRender(data, options, reducer, level = 0, indents = []) {
@@ -1763,35 +1775,71 @@
17631775
case 'Attr':
17641776
return '[' + token.chi.reduce(reducer, '') + ']';
17651777
case 'Time':
1766-
case 'Frequency':
17671778
case 'Angle':
17681779
case 'Length':
17691780
case 'Dimension':
1770-
const val = (+token.val).toString();
1781+
case 'Frequency':
1782+
case 'Resolution':
1783+
let val = reduceNumber(token.val);
1784+
let unit = token.unit;
1785+
if (token.typ == 'Angle') {
1786+
const angle = getAngle(token);
1787+
let v;
1788+
let value = val + unit;
1789+
for (const u of ['turn', 'deg', 'rad', 'grad']) {
1790+
if (token.unit == u) {
1791+
continue;
1792+
}
1793+
switch (u) {
1794+
case 'turn':
1795+
v = reduceNumber(angle);
1796+
if (v.length + 4 < value.length) {
1797+
val = v;
1798+
unit = u;
1799+
value = v + u;
1800+
}
1801+
break;
1802+
case 'deg':
1803+
v = reduceNumber(angle * 360);
1804+
if (v.length + 3 < value.length) {
1805+
val = v;
1806+
unit = u;
1807+
value = v + u;
1808+
}
1809+
break;
1810+
case 'rad':
1811+
v = reduceNumber(angle * (2 * Math.PI));
1812+
if (v.length + 3 < value.length) {
1813+
val = v;
1814+
unit = u;
1815+
value = v + u;
1816+
}
1817+
break;
1818+
case 'grad':
1819+
v = reduceNumber(angle * 400);
1820+
if (v.length + 4 < value.length) {
1821+
val = v;
1822+
unit = u;
1823+
value = v + u;
1824+
}
1825+
break;
1826+
}
1827+
}
1828+
}
17711829
if (val === '0') {
1772-
if (token.typ == 'Time') {
1830+
if (unit == 'Time') {
17731831
return '0s';
17741832
}
1775-
if (token.typ == 'Frequency') {
1833+
if (unit == 'Frequency') {
17761834
return '0Hz';
17771835
}
17781836
// @ts-ignore
1779-
if (token.typ == 'Resolution') {
1837+
if (unit == 'Resolution') {
17801838
return '0x';
17811839
}
17821840
return '0';
17831841
}
1784-
const chr = val.charAt(0);
1785-
if (chr == '-') {
1786-
const slice = val.slice(0, 2);
1787-
if (slice == '-0') {
1788-
return (val.length == 2 ? '0' : '-' + val.slice(2)) + token.unit;
1789-
}
1790-
}
1791-
else if (chr == '0') {
1792-
return val.slice(1) + token.unit;
1793-
}
1794-
return val + token.unit;
1842+
return val + unit;
17951843
case 'Perc':
17961844
return token.val + '%';
17971845
case 'Number':
@@ -3372,9 +3420,23 @@
33723420
}
33733421
break;
33743422
}
3423+
// @ts-ignore
3424+
if (isNewLine(codepoint)) {
3425+
if (i == 1) {
3426+
buffer += value + escapeSequence.slice(0, i);
3427+
next(i + 1);
3428+
continue;
3429+
}
3430+
// else {
3431+
yield pushToken(buffer + value + escapeSequence.slice(0, i), 'Bad-string');
3432+
buffer = '';
3433+
// }
3434+
next(i + 1);
3435+
break;
3436+
}
33753437
// not hex or new line
33763438
// @ts-ignore
3377-
if (i == 1 && !isNewLine(codepoint)) {
3439+
else if (i == 1) {
33783440
buffer += value + sequence[i];
33793441
next(2);
33803442
continue;
@@ -3403,19 +3465,28 @@
34033465
next();
34043466
// i += value.length;
34053467
buffer = '';
3406-
break;
3468+
return;
34073469
}
34083470
if (isNewLine(value.charCodeAt(0))) {
34093471
hasNewLine = true;
34103472
}
34113473
if (hasNewLine && value == ';') {
3412-
yield pushToken(buffer, 'Bad-string');
3474+
yield pushToken(buffer + value, 'Bad-string');
34133475
buffer = '';
3476+
next();
34143477
break;
34153478
}
34163479
buffer += value;
34173480
next();
34183481
}
3482+
if (hasNewLine) {
3483+
yield pushToken(buffer, 'Bad-string');
3484+
}
3485+
else {
3486+
// EOF - 'Unclosed-string' fixed
3487+
yield pushToken(buffer + quote, 'String');
3488+
}
3489+
buffer = '';
34193490
}
34203491
function peek(count = 1) {
34213492
if (count == 1) {
@@ -3650,7 +3721,7 @@
36503721
break;
36513722
case '(':
36523723
if (buffer.length == 0) {
3653-
yield pushToken('', 'Start-parens');
3724+
yield pushToken(value);
36543725
break;
36553726
}
36563727
buffer += value;
@@ -3764,6 +3835,7 @@
37643835
if (buffer.length > 0) {
37653836
yield pushToken(buffer);
37663837
}
3838+
// yield pushToken('', 'EOF');
37673839
}
37683840

37693841
const urlTokenMatcher = /^(["']?)[a-zA-Z0-9_/.-][a-zA-Z0-9_/:.#?-]+(\1)$/;
@@ -3814,6 +3886,10 @@
38143886
let tokens = results.map(mapToken);
38153887
let i;
38163888
let loc;
3889+
// if ((<Token>tokens.at(-1))?.typ == 'EOF') {
3890+
//
3891+
// tokens.pop();
3892+
// }
38173893
for (i = 0; i < tokens.length; i++) {
38183894
if (tokens[i].typ == 'Comment') {
38193895
// @ts-ignore
@@ -4168,7 +4244,7 @@
41684244
return ([
41694245
'Whitespace', 'Semi-colon', 'Colon', 'Block-start',
41704246
'Block-start', 'Attr-start', 'Attr-end', 'Start-parens', 'End-parens',
4171-
'Comma', 'Gt', 'Lt', 'Gte', 'Lte'
4247+
'Comma', 'Gt', 'Lt', 'Gte', 'Lte', 'EOF'
41724248
].includes(hint) ? { typ: hint } : { typ: hint, val });
41734249
}
41744250
if (val == ' ') {

0 commit comments

Comments
 (0)