1- // @ts -expect-error Typing of css-tree is incomplete
2- import parse from 'css-tree/parser'
3-
4- /**
5- * @typedef {import('css-tree').CssNode } CssNode
6- * @typedef {import('css-tree').List<CssNode> } List
7- * @typedef {import('css-tree').CssLocation } CssLocation
8- * @typedef {import('css-tree').Raw } Raw
9- * @typedef {import('css-tree').StyleSheet } StyleSheet
10- * @typedef {import('css-tree').Atrule } Atrule
11- * @typedef {import('css-tree').AtrulePrelude } AtrulePrelude
12- * @typedef {import('css-tree').Rule } Rule
13- * @typedef {import('css-tree').SelectorList } SelectorList
14- * @typedef {import('css-tree').Selector } Selector
15- * @typedef {import('css-tree').PseudoClassSelector } PseudoClassSelector
16- * @typedef {import('css-tree').PseudoElementSelector } PseudoElementSelector
17- * @typedef {import('css-tree').Block } Block
18- * @typedef {import('css-tree').Declaration } Declaration
19- * @typedef {import('css-tree').Value } Value
20- * @typedef {import('css-tree').Operator } Operator
21- */
1+ import {
2+ parse ,
3+ type CssNode ,
4+ type List ,
5+ type CssLocation ,
6+ type Raw ,
7+ type StyleSheet ,
8+ type Atrule ,
9+ type AtrulePrelude ,
10+ type Rule ,
11+ type SelectorList ,
12+ type Selector ,
13+ type PseudoClassSelector ,
14+ type PseudoElementSelector ,
15+ type Block ,
16+ type Declaration ,
17+ type Value ,
18+ type Operator ,
19+ } from 'css-tree'
2220
2321const SPACE = ' '
2422const EMPTY_STRING = ''
@@ -42,66 +40,51 @@ const TYPE_PSEUDO_ELEMENT_SELECTOR = 'PseudoElementSelector'
4240const TYPE_DECLARATION = 'Declaration'
4341const TYPE_OPERATOR = 'Operator'
4442
45- /** @param {string } str */
46- function lowercase ( str ) {
43+ function lowercase ( str : string ) {
4744 // Only create new strings in memory if we need to
4845 if ( / [ A - Z ] / . test ( str ) ) {
4946 return str . toLowerCase ( )
5047 }
5148 return str
5249}
5350
51+ export type FormatOptions = {
52+ /** Whether to minify the CSS or keep it formatted */
53+ minify ?: boolean
54+ /** Tell the formatter to use N spaces instead of tabs */
55+ tab_size ?: number
56+ }
57+
5458/**
55- * @typedef {Object } Options
56- * @property {boolean } [minify] Whether to minify the CSS or keep it formatted
57- * @property {number } [tab_size] Tell the formatter to use N spaces instead of tabs
58- *
5959 * Format a string of CSS using some simple rules
60- * @param {string } css The original CSS
61- * @param {Options } [options]
62- * @returns {string } The formatted CSS
6360 */
64- export function format ( css , {
65- minify = false ,
66- tab_size = undefined ,
67- } = Object . create ( null ) ) {
68-
61+ export function format ( css : string , { minify = false , tab_size = undefined } : FormatOptions = Object . create ( null ) ) : string {
6962 if ( tab_size !== undefined && Number ( tab_size ) < 1 ) {
7063 throw new TypeError ( 'tab_size must be a number greater than 0' )
7164 }
7265
73- /** @type { number[] } [start0, end0, start1, end1, etc.]*/
74- let comments = [ ]
66+ /** [start0, end0, start1, end1, etc.]*/
67+ let comments : number [ ] = [ ]
7568
76- /**
77- * @param {string } _ The comment text
78- * @param {CssLocation } position
79- */
80- function on_comment ( _ , position ) {
69+ function on_comment ( _ : string , position : CssLocation ) {
8170 comments . push ( position . start . offset , position . end . offset )
8271 }
8372
84- /** @type {StyleSheet } */
8573 let ast = parse ( css , {
8674 positions : true ,
8775 parseAtrulePrelude : false ,
8876 parseCustomProperty : true ,
8977 parseValue : true ,
9078 onComment : on_comment ,
91- } )
79+ } ) as StyleSheet
9280
9381 const NEWLINE = minify ? EMPTY_STRING : '\n'
9482 const OPTIONAL_SPACE = minify ? EMPTY_STRING : SPACE
9583 const LAST_SEMICOLON = minify ? EMPTY_STRING : SEMICOLON
9684
9785 let indent_level = 0
9886
99- /**
100- * Indent a string
101- * @param {number } size
102- * @returns {string } A string with [size] tabs/spaces
103- */
104- function indent ( size ) {
87+ function indent ( size : number ) {
10588 if ( minify === true ) return EMPTY_STRING
10689
10790 if ( tab_size !== undefined ) {
@@ -111,34 +94,29 @@ export function format(css, {
11194 return '\t' . repeat ( size )
11295 }
11396
114- /** @param {CssNode } node */
115- function substr ( node ) {
97+ function substr ( node : CssNode ) {
11698 let loc = node . loc
11799 // If the node has no location, return an empty string
118100 // This is necessary for space toggles
119101 if ( loc === undefined || loc === null ) return EMPTY_STRING
120102 return css . slice ( loc . start . offset , loc . end . offset )
121103 }
122104
123- /** @param {CssNode } node */
124- function start_offset ( node ) {
125- let loc = /** @type {CssLocation } */ ( node . loc )
126- return loc . start . offset
105+ function start_offset ( node : CssNode ) {
106+ return node . loc ?. start . offset
127107 }
128108
129- /** @param {CssNode } node */
130- function end_offset ( node ) {
131- let loc = /** @type {CssLocation } */ ( node . loc )
132- return loc . end . offset
109+ function end_offset ( node : CssNode ) {
110+ return node . loc ?. end . offset
133111 }
134112
135113 /**
136114 * Get a comment from the CSS string after the first offset and before the second offset
137- * @param { number | undefined } after After which offset to look for comments
138- * @param { number | undefined } before Before which offset to look for comments
139- * @returns { string | undefined } The comment string, if found
115+ * @param after After which offset to look for comments
116+ * @param before Before which offset to look for comments
117+ * @returns The comment string, if found
140118 */
141- function print_comment ( after , before ) {
119+ function print_comment ( after ?: number , before ?: number ) : string | undefined {
142120 if ( minify === true || after === undefined || before === undefined ) {
143121 return EMPTY_STRING
144122 }
@@ -160,9 +138,8 @@ export function format(css, {
160138 return buffer
161139 }
162140
163- /** @param {Rule } node */
164- function print_rule ( node ) {
165- let buffer
141+ function print_rule ( node : Rule ) {
142+ let buffer = ''
166143 let prelude = node . prelude
167144 let block = node . block
168145
@@ -182,8 +159,7 @@ export function format(css, {
182159 return buffer
183160 }
184161
185- /** @param {SelectorList } node */
186- function print_selectorlist ( node ) {
162+ function print_selectorlist ( node : SelectorList ) {
187163 let buffer = EMPTY_STRING
188164
189165 node . children . forEach ( ( selector , item ) => {
@@ -205,12 +181,11 @@ export function format(css, {
205181 return buffer
206182 }
207183
208- /** @param {Selector | PseudoClassSelector | PseudoElementSelector } node */
209- function print_simple_selector ( node ) {
184+ function print_simple_selector ( node : Selector | PseudoClassSelector | PseudoElementSelector ) {
210185 let buffer = EMPTY_STRING
211- let children = node . children || [ ]
186+ let children = node . children
212187
213- children . forEach ( ( child ) => {
188+ children ? .forEach ( ( child ) => {
214189 switch ( child . type ) {
215190 case 'TypeSelector' : {
216191 buffer += lowercase ( child . name )
@@ -327,8 +302,7 @@ export function format(css, {
327302 return buffer
328303 }
329304
330- /** @param {Block } node */
331- function print_block ( node ) {
305+ function print_block ( node : Block ) {
332306 let children = node . children
333307 let buffer = OPTIONAL_SPACE
334308
@@ -348,7 +322,7 @@ export function format(css, {
348322
349323 indent_level ++
350324
351- let opening_comment = print_comment ( start_offset ( node ) , start_offset ( /** @type { CssNode } */ ( children . first ) ) )
325+ let opening_comment = print_comment ( start_offset ( node ) , start_offset ( children . first ! ) )
352326 if ( opening_comment ) {
353327 buffer += indent ( indent_level ) + opening_comment + NEWLINE
354328 }
@@ -392,7 +366,7 @@ export function format(css, {
392366 }
393367 } )
394368
395- let closing_comment = print_comment ( end_offset ( /** @type { CssNode } */ ( children . last ) ) , end_offset ( node ) )
369+ let closing_comment = print_comment ( end_offset ( children . last ! ) , end_offset ( node ) )
396370 if ( closing_comment ) {
397371 buffer += NEWLINE + indent ( indent_level ) + closing_comment
398372 }
@@ -403,8 +377,7 @@ export function format(css, {
403377 return buffer
404378 }
405379
406- /** @param {Atrule } node */
407- function print_atrule ( node ) {
380+ function print_atrule ( node : Atrule ) {
408381 let buffer = indent ( indent_level ) + '@'
409382 let prelude = node . prelude
410383 let block = node . block
@@ -431,9 +404,8 @@ export function format(css, {
431404 * here to force some nice formatting.
432405 * Should be OK perf-wise, since the amount of atrules in most
433406 * stylesheets are limited, so this won't be called too often.
434- * @param {AtrulePrelude | Raw } node
435407 */
436- function print_prelude ( node ) {
408+ function print_prelude ( node : AtrulePrelude | Raw ) {
437409 let buffer = substr ( node )
438410
439411 return buffer
@@ -447,11 +419,10 @@ export function format(css, {
447419 let space = operator === '+' || operator === '-' ? SPACE : OPTIONAL_SPACE
448420 return `calc(${ left . trim ( ) } ${ space } ${ operator } ${ space } ${ right . trim ( ) } )`
449421 } )
450- . replace ( / s e l e c t o r | u r l | s u p p o r t s | l a y e r \( / ig , ( match ) => lowercase ( match ) ) // lowercase function names
422+ . replace ( / s e l e c t o r | u r l | s u p p o r t s | l a y e r \( / gi , ( match ) => lowercase ( match ) ) // lowercase function names
451423 }
452424
453- /** @param {Declaration } node */
454- function print_declaration ( node ) {
425+ function print_declaration ( node : Declaration ) {
455426 let property = node . property
456427
457428 // Lowercase the property, unless it's a custom property (starts with --)
@@ -481,8 +452,7 @@ export function format(css, {
481452 return indent ( indent_level ) + property + COLON + OPTIONAL_SPACE + value
482453 }
483454
484- /** @param {List } children */
485- function print_list ( children ) {
455+ function print_list ( children : List < CssNode > ) {
486456 let buffer = EMPTY_STRING
487457
488458 children . forEach ( ( node , item ) => {
@@ -519,8 +489,7 @@ export function format(css, {
519489 return buffer
520490 }
521491
522- /** @param {Operator } node */
523- function print_operator ( node ) {
492+ function print_operator ( node : Operator ) {
524493 let buffer = EMPTY_STRING
525494 // https://developer.mozilla.org/en-US/docs/Web/CSS/calc#notes
526495 // The + and - operators must be surrounded by whitespace
@@ -555,21 +524,15 @@ export function format(css, {
555524 return buffer
556525 }
557526
558- /** @param {Value | Raw } node */
559- function print_value ( node ) {
527+ function print_value ( node : Value | Raw ) {
560528 if ( node . type === 'Raw' ) {
561529 return print_unknown ( node , 0 )
562530 }
563531
564532 return print_list ( node . children )
565533 }
566534
567- /**
568- * @param {CssNode } node
569- * @param {number } indent_level
570- * @returns {string } A formatted unknown CSS string
571- */
572- function print_unknown ( node , indent_level ) {
535+ function print_unknown ( node : CssNode , indent_level : number ) {
573536 return indent ( indent_level ) + substr ( node ) . trim ( )
574537 }
575538
@@ -603,7 +566,7 @@ export function format(css, {
603566 }
604567 } )
605568
606- let closing_comment = print_comment ( end_offset ( /** @type { CssNode } */ ( children . last ) ) , end_offset ( ast ) )
569+ let closing_comment = print_comment ( end_offset ( children . last ! ) , end_offset ( ast ) )
607570 if ( closing_comment ) {
608571 buffer += NEWLINE + closing_comment
609572 }
@@ -619,6 +582,6 @@ export function format(css, {
619582 * @param {string } css The original CSS
620583 * @returns {string } The minified CSS
621584 */
622- export function minify ( css ) {
585+ export function minify ( css : string ) : string {
623586 return format ( css , { minify : true } )
624587}
0 commit comments