Skip to content

Commit c30586d

Browse files
Fix missing space when AtRule#params is set after parsing (#2113)
1 parent 5bfc3b9 commit c30586d

2 files changed

Lines changed: 30 additions & 5 deletions

File tree

lib/stringifier.js

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
const STYLE_TAG = /(<)(\/?style\b)/gi
77
const COMMENT_OPEN = /(<)(!--)/g
88

9+
// Characters that end an at-rule name, mirroring RE_AT_END in the tokenizer.
10+
// Params starting with anything else need a space to stay separate tokens.
11+
const AT_NAME_END = /[\t\n\f\r "#'()/;[\\\]{}]/
12+
913
function escapeHTMLInCSS(str) {
1014
if (typeof str !== 'string') return str
1115
if (!str.includes('<')) return str
@@ -34,14 +38,15 @@ function capitalize(str) {
3438
function atruleStart(str, node) {
3539
let name = '@' + node.name
3640
let params = node.params ? str.rawValue(node, 'params') : ''
41+
let afterName = node.raws.afterName
3742

38-
if (typeof node.raws.afterName !== 'undefined') {
39-
name += node.raws.afterName
40-
} else if (params) {
41-
name += ' '
43+
if (typeof afterName === 'undefined') {
44+
afterName = params ? ' ' : ''
45+
} else if (afterName === '' && params && !AT_NAME_END.test(params[0])) {
46+
afterName = ' '
4247
}
4348

44-
return name + params
49+
return name + afterName + params
4550
}
4651

4752
function pushBody(str, stack, node) {

test/stringifier.test.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,26 @@ test('always calls raw to retrieve raws', () => {
358358
)
359359
})
360360

361+
test('adds space before params set on an at-rule parsed without them', () => {
362+
let root = parse('@layer{a{color:black}}')
363+
root.first.params = 'utilities'
364+
is(root.toString(), '@layer utilities{a{color:black}}')
365+
366+
let media = parse('@media;').first
367+
media.params = 'print'
368+
is(media.toString(), '@media print')
369+
})
370+
371+
test('keeps params glued to at-rule name when CSS allows it', () => {
372+
let root = parse('@media(min-width:0){}')
373+
root.first.params = '(min-width:1px)'
374+
is(root.toString(), '@media(min-width:1px){}')
375+
376+
let imported = parse('@import"a.css"').first
377+
imported.params = '"b.css"'
378+
is(imported.toString(), '@import"b.css"')
379+
})
380+
361381
test('supports subclasses with overridden traversal methods', () => {
362382
class CustomStringifier extends Stringifier {
363383
rule(node) {

0 commit comments

Comments
 (0)