@ -19,6 +19,9 @@ const LINE_BREAK_THRESHOLD = 50;
* /
export function print ( ast , options = undefined ) {
const comments = ( ast . type === 'Root' && ast . comments ) || [ ] ;
const css _comments =
( ast . type === 'Root' ? ast . css ? . comments : ast . type === 'StyleSheet' ? ast . comments : null ) ||
[ ] ;
return esrap . print (
ast ,
@ -29,7 +32,7 @@ export function print(ast, options = undefined) {
getTrailingComments : options ? . getTrailingComments
} ) ,
... svelte _visitors ( comments ) ,
... css _visitors
... css _visitors ( css _comments , comments )
} ) ,
{
indent : options ? . indent
@ -177,161 +180,263 @@ function base_element(node, context, comments) {
context . append ( child _context ) ;
}
/** @type {Visitors<AST.SvelteNode>} */
const css _visitors = {
Atrule ( node , context ) {
context . write ( ` @ ${ node . name } ` ) ;
if ( node . prelude ) context . write ( ` ${ node . prelude } ` ) ;
if ( node . block ) {
context . write ( ' ' ) ;
context . visit ( node . block ) ;
} else {
context . write ( ';' ) ;
}
} ,
/ * *
* @ param { AST . CSS . CSSComment [ ] } comments
* @ param { AST . JSComment [ ] } js _comments
* @ returns { Visitors < AST . SvelteNode > }
* /
function css _visitors ( comments , js _comments ) {
let comment _index = 0 ;
/** @param {number} end */
const has _comment _before = ( end ) => comments [ comment _index ] ? . start < end ;
/ * *
* @ param { Context } context
* @ param { AST . CSS . CSSComment } comment
* /
function write _comment ( context , comment ) {
context . write ( ` /* ${ comment . value } */ ` ) ;
}
AttributeSelector ( node , context ) {
context . write ( ` [ ${ node . name } ` ) ;
if ( node . matcher ) {
context . write ( node . matcher ) ;
context . write ( ` " ${ node . value } " ` ) ;
if ( node . flags ) {
context . write ( ` ${ node . flags } ` ) ;
}
/ * *
* @ param { Context } context
* @ param { number } end
* /
function write _inline _comments ( context , end ) {
let written = false ;
while ( has _comment _before ( end ) ) {
if ( written ) context . write ( ' ' ) ;
write _comment ( context , comments [ comment _index ++ ] ) ;
written = true ;
}
context . write ( ']' ) ;
} ,
Block ( node , context ) {
context . write ( '{' ) ;
return written ;
}
if ( node . children . length > 0 ) {
context . indent ( ) ;
context . newline ( ) ;
/ * *
* @ param { Context } context
* @ param { string } value
* @ param { number } end
* /
function write _value ( context , value , end ) {
let offset = 0 ;
while ( has _comment _before ( end ) ) {
const comment = comments [ comment _index ++ ] ;
const position = Math . max ( offset , Math . min ( comment . position ? ? 0 , value . length ) ) ;
context . write ( value . slice ( offset , position ) ) ;
write _comment ( context , comment ) ;
offset = position ;
}
let started = false ;
context . write ( value . slice ( offset ) ) ;
}
for ( const child of node . children ) {
if ( started ) {
context . newline ( ) ;
}
/ * *
* @ param { Context } context
* @ param { Array < AST . CSS . Rule | AST . CSS . Atrule | AST . CSS . Declaration > } children
* @ param { number } end
* @ param { boolean } margins
* /
function print _children ( context , children , end , margins ) {
let started = false ;
context . visit ( child ) ;
const separate = ( ) => {
if ( ! started ) return ;
if ( margins ) context . margin ( ) ;
context . newline ( ) ;
} ;
for ( const child of children ) {
while ( has _comment _before ( child . start ) ) {
separate ( ) ;
write _comment ( context , comments [ comment _index ++ ] ) ;
started = true ;
}
context . dedent ( ) ;
context . newline ( ) ;
separate ( ) ;
context . visit ( child ) ;
started = true ;
}
context . write ( '}' ) ;
} ,
while ( has _comment _before ( end ) ) {
separate ( ) ;
write _comment ( context , comments [ comment _index ++ ] ) ;
started = true ;
}
}
ClassSelector ( node , context ) {
context . write ( ` . ${ node . name } ` ) ;
} ,
/ * *
* @ param { AST . CSS . SelectorList } node
* @ param { Context } context
* @ param { boolean } multiline
* /
function print _selector _list ( node , context , multiline ) {
let needs _separator = false ;
let remaining _selectors = node . children . length ;
ComplexSelector ( node , context ) {
for ( const selector of node . children ) {
while ( has _comment _before ( selector . start ) ) {
if ( needs _separator ) context . write ( ' ' ) ;
write _comment ( context , comments [ comment _index ++ ] ) ;
needs _separator = true ;
}
if ( needs _separator ) {
if ( multiline ) context . newline ( ) ;
else context . write ( ' ' ) ;
}
context . visit ( selector ) ;
needs _separator = true ;
remaining _selectors -= 1 ;
if ( remaining _selectors > 0 ) context . write ( ',' ) ;
}
} ,
}
Declaration ( node , context ) {
context . write ( ` ${ node . property } : ${ node . value } ; ` ) ;
} ,
return {
Atrule( node , context ) {
context . write ( ` @ ${ node . name } ` ) ;
IdSelector ( node , context ) {
context . write ( ` # ${ node . name } ` ) ;
} ,
const prelude _end = node . block ? . start ? ? node . end ;
if ( node . prelude || has _comment _before ( prelude _end ) ) {
context . write ( ' ' ) ;
write _value ( context , node . prelude , prelude _end ) ;
}
NestingSelector ( node , context ) {
context . write ( '&' ) ;
} ,
if ( node . block ) {
context . write ( ' ' ) ;
context . visit ( node . block ) ;
} else {
context . write ( ';' ) ;
}
} ,
AttributeSelector ( node , context ) {
context . write ( ` [ ${ node . name } ` ) ;
if ( node . matcher ) {
context . write ( node . matcher ) ;
context . write ( ` " ${ node . value } " ` ) ;
if ( node . flags ) context . write ( ` ${ node . flags } ` ) ;
}
context . write ( ']' ) ;
} ,
Nth ( node , context ) {
context . write ( node . value ) ;
} ,
Block ( node , context ) {
context . write ( '{' ) ;
Percentage ( node , context ) {
context . write ( node . value ) ;
} ,
if ( node . children . length > 0 || has _comment _before ( node . end ) ) {
context . indent ( ) ;
context . newline ( ) ;
print _children ( context , node . children , node . end , false ) ;
context . dedent ( ) ;
context . newline ( ) ;
}
PseudoClassSelector ( node , context ) {
context . write ( ` : ${ node . name } ` ) ;
context . write ( '}' ) ;
} ,
if ( node . args ) {
context . write ( '(' ) ;
ClassSelector ( node , context ) {
context . write ( ` . ${ node . name } ` ) ;
} ,
let started = false ;
ComplexSelector ( node , context ) {
for ( const selector of node . children ) context . visit ( selector ) ;
} ,
for ( const arg of node . args . children ) {
if ( started ) {
context . write ( ', ' ) ;
}
Declaration ( node , context ) {
context . write ( ` ${ node . property } : ` ) ;
write _value ( context , node . value , node . end ) ;
context . write ( ';' ) ;
} ,
context . visit ( arg ) ;
IdSelector ( node , context ) {
context . write ( ` # ${ node . name } ` ) ;
} ,
started = true ;
}
NestingSelector ( node , context ) {
context . write ( '&' ) ;
} ,
context . write ( ')' ) ;
}
} ,
Nth ( node , context ) {
context . write ( node . value ) ;
} ,
PseudoElementSelector ( node , context ) {
context . write ( ` :: ${ node . name } ` ) ;
} ,
Percentage ( node , context ) {
context . write ( node . value ) ;
} ,
RelativeSelector ( node , context ) {
if ( node . combinator ) {
if ( node . combinator . name === ' ' ) {
context . write ( ' ' ) ;
} else {
context . write ( ` ${ node . combinator . name } ` ) ;
PseudoClassSelector ( node , context ) {
context . write ( ` : ${ node . name } ` ) ;
if ( node . args ) {
context . write ( '(' ) ;
context . visit ( node . args ) ;
if ( has _comment _before ( node . end ) ) {
context . write ( ' ' ) ;
write _inline _comments ( context , node . end ) ;
}
context . write ( ')' ) ;
}
}
} ,
PseudoElementSelector ( node , context ) {
context . write ( ` :: ${ node . name } ` ) ;
if ( node . args ) {
context . write ( '(' ) ;
context . visit ( node . args ) ;
if ( has _comment _before ( node . end ) ) {
context . write ( ' ' ) ;
write _inline _comments ( context , node . end ) ;
}
context . write ( ')' ) ;
}
} ,
for ( const selector of node . selectors ) {
context . visit ( selector ) ;
}
} ,
RelativeSelector ( node , context ) {
if ( node . combinator ) {
if ( node . combinator . name === ' ' ) context . write ( ' ' ) ;
else context . write ( ` ${ node . combinator . name } ` ) ;
}
Rule ( node , context ) {
let started = false ;
for ( const selector of node . selectors ) context . visit ( selector ) ;
} ,
for ( const selector of node . prelude . children ) {
if ( started ) {
context . write ( ',' ) ;
context . newline ( ) ;
}
Rule ( node , context ) {
print _selector _list ( node . prelude , context , true ) ;
context . write ( ' ' ) ;
if ( write _inline _comments ( context , node . block . start ) ) context . write ( ' ' ) ;
context . visit ( node . block ) ;
} ,
context . visit ( selector ) ;
started = true ;
}
SelectorList ( node , context ) {
print_selector _list ( node , context , false ) ;
} ,
context . write ( ' ' ) ;
context . visit ( node . block ) ;
} ,
StyleSheet ( node , context ) {
context . write ( '<style' ) ;
attributes ( node , node . attributes , context , js _comments ) ;
context . write ( '>' ) ;
SelectorList ( node , context ) {
let started = false ;
for ( const selector of node . children ) {
if ( started ) {
context . write ( ', ' ) ;
if ( node . children . length > 0 || node . comments . length > 0 ) {
context . indent ( ) ;
context . newline ( ) ;
print _children ( context , node . children , node . content . end , true ) ;
context . dedent ( ) ;
context . newline ( ) ;
}
context . visit ( selector ) ;
started = true ;
}
} ,
context . write ( '</style>' ) ;
} ,
TypeSelector ( node , context ) {
context . write ( node . name ) ;
}
} ;
TypeSelector ( node , context ) {
context . write ( node . name ) ;
}
} ;
}
/ * *
* @ param { AST . JSComment [ ] } comments
@ -845,34 +950,6 @@ const svelte_visitors = (comments) => ({
}
} ,
StyleSheet ( node , context ) {
context . write ( '<style' ) ;
attributes ( node , node . attributes , context , comments ) ;
context . write ( '>' ) ;
if ( node . children . length > 0 ) {
context . indent ( ) ;
context . newline ( ) ;
let started = false ;
for ( const child of node . children ) {
if ( started ) {
context . margin ( ) ;
context . newline ( ) ;
}
context . visit ( child ) ;
started = true ;
}
context . dedent ( ) ;
context . newline ( ) ;
}
context . write ( '</style>' ) ;
} ,
SvelteBody ( node , context ) {
base _element ( node , context , comments ) ;
} ,