Skip to content

Commit c2039f0

Browse files
committed
fix the github issues
1 parent b782d3a commit c2039f0

2 files changed

Lines changed: 84 additions & 19 deletions

File tree

src/parse/index.ts

Lines changed: 76 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ import {
2929
type CssStartingStyleAST,
3030
type CssStylesheetAST,
3131
type CssSupportsAST,
32-
type CssViewTransitionAST,
3332
CssTypes,
33+
type CssViewTransitionAST,
3434
} from '../type';
3535
import {
3636
indexOfArrayWithBracketAndQuoteSupport,
@@ -156,12 +156,32 @@ export const parse = (
156156
const rules: Array<CssRuleAST | CssAtRuleAST> = [];
157157
whitespace();
158158
comments(rules);
159-
while (css.length && css.charAt(0) !== '}') {
159+
while (css.length) {
160+
if (css.charAt(0) === '}') {
161+
if (options?.silent) {
162+
// Skip stray closing braces at top level
163+
error("extra '}'");
164+
const fakeMatch = ['}'] as unknown as RegExpExecArray;
165+
processMatch(fakeMatch);
166+
whitespace();
167+
comments(rules);
168+
continue;
169+
}
170+
break;
171+
}
160172
node = atRule() || rule();
161173
if (node) {
162174
rules.push(node);
163175
comments(rules);
164176
} else {
177+
if (options?.silent) {
178+
// Skip unrecognized character to recover
179+
const fakeMatch = [css.charAt(0)] as unknown as RegExpExecArray;
180+
processMatch(fakeMatch);
181+
whitespace();
182+
comments(rules);
183+
continue;
184+
}
165185
break;
166186
}
167187
}
@@ -311,6 +331,27 @@ export const parse = (
311331
comments(decls);
312332
decl = declaration();
313333
}
334+
// In silent mode, try to recover from errors by skipping to next semicolon
335+
while (options?.silent && css.length && css.charAt(0) !== '}') {
336+
const semiPos = css.indexOf(';');
337+
const bracePos = css.indexOf('}');
338+
if (semiPos !== -1 && (bracePos === -1 || semiPos < bracePos)) {
339+
const fakeMatch = [
340+
css.substring(0, semiPos + 1),
341+
] as unknown as RegExpExecArray;
342+
processMatch(fakeMatch);
343+
whitespace();
344+
comments(decls);
345+
decl = declaration();
346+
while (decl) {
347+
decls.push(decl);
348+
comments(decls);
349+
decl = declaration();
350+
}
351+
} else {
352+
break;
353+
}
354+
}
314355

315356
if (!close()) {
316357
return error("missing '}'");
@@ -382,7 +423,20 @@ export const parse = (
382423
continue;
383424
}
384425

385-
// nothing matched
426+
// nothing matched — skip to next semicolon or closing brace to recover
427+
if (options?.silent) {
428+
const semiPos = css.indexOf(';');
429+
const bracePos = css.indexOf('}');
430+
if (semiPos !== -1 && (bracePos === -1 || semiPos < bracePos)) {
431+
const fakeMatch = [
432+
css.substring(0, semiPos + 1),
433+
] as unknown as RegExpExecArray;
434+
processMatch(fakeMatch);
435+
whitespace();
436+
comments(items);
437+
continue;
438+
}
439+
}
386440
break;
387441
}
388442

@@ -398,9 +452,7 @@ export const parse = (
398452
* both top-level rules and declarations when nested inside a rule.
399453
*/
400454
function rulesOrDeclarations() {
401-
const items: Array<
402-
CssAtRuleAST | CssDeclarationAST | CssCommentAST
403-
> = [];
455+
const items: Array<CssAtRuleAST | CssDeclarationAST | CssCommentAST> = [];
404456
whitespace();
405457
comments(items);
406458
while (css.length && css.charAt(0) !== '}') {
@@ -432,7 +484,20 @@ export const parse = (
432484
continue;
433485
}
434486

435-
// nothing matched
487+
// nothing matched — skip to next semicolon or closing brace to recover
488+
if (options?.silent) {
489+
const semiPos = css.indexOf(';');
490+
const bracePos = css.indexOf('}');
491+
if (semiPos !== -1 && (bracePos === -1 || semiPos < bracePos)) {
492+
const fakeMatch = [
493+
css.substring(0, semiPos + 1),
494+
] as unknown as RegExpExecArray;
495+
processMatch(fakeMatch);
496+
whitespace();
497+
comments(items);
498+
continue;
499+
}
500+
}
436501
break;
437502
}
438503
return items;
@@ -703,7 +768,7 @@ export const parse = (
703768
'right-bottom',
704769
];
705770
const pageMarginBoxRegex = new RegExp(
706-
'^@(' + pageMarginBoxNames.join('|') + ')(?![\\w-])\\s*',
771+
`^@(${pageMarginBoxNames.join('|')})(?![\\w-])\\s*`,
707772
);
708773

709774
function atPageMarginBox(): CssPageMarginBoxAST | undefined {
@@ -1118,7 +1183,9 @@ export const parse = (
11181183
const preludeEnd = indexOfArrayWithBracketAndQuoteSupport(css, ['{', ';']);
11191184
if (preludeEnd !== -1 && preludeEnd > 0) {
11201185
prelude = trim(css.substring(0, preludeEnd));
1121-
const fakeMatch = [css.substring(0, preludeEnd)] as unknown as RegExpExecArray;
1186+
const fakeMatch = [
1187+
css.substring(0, preludeEnd),
1188+
] as unknown as RegExpExecArray;
11221189
processMatch(fakeMatch);
11231190
}
11241191

src/stringify/compiler.ts

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ import {
2727
type CssStartingStyleAST,
2828
type CssStylesheetAST,
2929
type CssSupportsAST,
30-
type CssViewTransitionAST,
3130
CssTypes,
31+
type CssViewTransitionAST,
3232
} from '../type';
3333

3434
export type CompilerOptions = {
@@ -510,10 +510,7 @@ class Compiler {
510510
fontFeatureValues(node: CssFontFeatureValuesAST) {
511511
if (this.compress) {
512512
return (
513-
this.emit(
514-
`@font-feature-values ${node.fontFamily}`,
515-
node.position,
516-
) +
513+
this.emit(`@font-feature-values ${node.fontFamily}`, node.position) +
517514
this.emit('{') +
518515
this.mapVisit(node.rules) +
519516
this.emit('}')
@@ -617,18 +614,19 @@ class Compiler {
617614
);
618615
}
619616
const hasNestedRules = node.rules.some(
620-
(r) =>
621-
r.type !== CssTypes.declaration && r.type !== CssTypes.comment,
617+
(r) => r.type !== CssTypes.declaration && r.type !== CssTypes.comment,
622618
);
623619
const delim = hasNestedRules ? '\n\n' : '\n';
624620
return (
625621
this.emit(`${this.indent()}@${node.name}${prelude}`, node.position) +
626622
this.emit(hasNestedRules ? ` {\n${this.indent(1)}` : ' {\n') +
627623
this.emit(hasNestedRules ? '' : this.indent(1)) +
628624
this.mapVisit(<CssAllNodesAST[]>node.rules, delim) +
629-
this.emit(hasNestedRules
630-
? `\n${this.indent(-1)}${this.indent()}}`
631-
: `${this.indent(-1)}\n${this.indent()}}`)
625+
this.emit(
626+
hasNestedRules
627+
? `\n${this.indent(-1)}${this.indent()}}`
628+
: `${this.indent(-1)}\n${this.indent()}}`,
629+
)
632630
);
633631
}
634632

0 commit comments

Comments
 (0)