├── .gitignore ├── .travis.yml ├── History.md ├── LICENSE ├── Readme.md ├── benchmark ├── LICENSES ├── index.js ├── large.css └── small.css ├── generate-tests.js ├── index.js ├── lib ├── parse │ └── index.js └── stringify │ ├── compiler.js │ ├── compress.js │ ├── identity.js │ ├── index.js │ └── source-map-support.js ├── package.json └── test ├── cases.js ├── cases ├── at-namespace │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── charset-linebreak │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── charset │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── colon-space │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── comma-attribute │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── comma-selector-function │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── comment-in │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── comment-url │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── comment │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── custom-media-linebreak │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── custom-media │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── data-url │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── document-linebreak │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── document │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── empty │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── escapes │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── font-face-linebreak │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── font-face │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── hose-linebreak │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── host │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── import-linebreak │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── import-messed │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── import │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── keyframes-advanced │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── keyframes-complex │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── keyframes-linebreak │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── keyframes-messed │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── keyframes-vendor │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── keyframes │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── media-linebreak │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── media-messed │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── media │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── messed-up │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── namespace-linebreak │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── namespace │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── no-semi │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── page-linebreak │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── paged-media │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── props │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── quote-escape │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── quoted │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── rule │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── rules │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── selectors │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── supports-linebreak │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── supports │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css └── wtf │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── parse.js ├── source-map ├── apply.css ├── apply.css.map ├── apply.scss └── test.css └── stringify.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.10" 4 | -------------------------------------------------------------------------------- /History.md: -------------------------------------------------------------------------------- 1 | 2.2.1 / 2015-06-17 2 | ================== 3 | 4 | * fix parsing escaped quotes in quoted strings 5 | 6 | 2.2.0 / 2015-02-18 7 | ================== 8 | 9 | * add `parsingErrors` to list errors when parsing with `silent: true` 10 | * accept EOL characters and all other whitespace characters in `@` rules such 11 | as `@media` 12 | 13 | 2.1.0 / 2014-08-05 14 | ================== 15 | 16 | * change error message format and add `.reason` property to errors 17 | * add `inputSourcemaps` option to disable input source map processing 18 | * use `inherits` for inheritance (fixes some browsers) 19 | * add `sourcemap: 'generator'` option to return the `SourceMapGenerator` 20 | object 21 | 22 | 2.0.0 / 2014-06-18 23 | ================== 24 | 25 | * add non-enumerable parent reference to each node 26 | * drop Component(1) support 27 | * add support for @custom-media, @host, and @font-face 28 | * allow commas inside selector functions 29 | * allow empty property values 30 | * changed default options.position value to true 31 | * remove comments from properties and values 32 | * asserts when selectors are missing 33 | * added node.position.content property 34 | * absorb css-parse and css-stringify libraries 35 | * apply original source maps from source files 36 | 37 | 1.6.1 / 2014-01-02 38 | ================== 39 | 40 | * fix component.json 41 | 42 | 1.6.0 / 2013-12-21 43 | ================== 44 | 45 | * update deps 46 | 47 | 1.5.0 / 2013-12-03 48 | ================== 49 | 50 | * update deps 51 | 52 | 1.1.0 / 2013-04-04 53 | ================== 54 | 55 | * update deps 56 | 57 | 1.0.7 / 2012-11-21 58 | ================== 59 | 60 | * fix component.json 61 | 62 | 1.0.4 / 2012-11-15 63 | ================== 64 | 65 | * update css-stringify 66 | 67 | 1.0.3 / 2012-09-01 68 | ================== 69 | 70 | * add component support 71 | 72 | 0.0.1 / 2010-01-03 73 | ================== 74 | 75 | * Initial release 76 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | (The MIT License) 2 | 3 | Copyright (c) 2012 TJ Holowaychuk 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # css [![Build Status](https://travis-ci.org/reworkcss/css.svg?branch=master)](https://travis-ci.org/reworkcss/css) 2 | 3 | CSS parser / stringifier. 4 | 5 | ## Installation 6 | 7 | $ npm install css 8 | 9 | ## Usage 10 | 11 | ```js 12 | var css = require('css'); 13 | var obj = css.parse('body { font-size: 12px; }', options); 14 | css.stringify(obj, options); 15 | ``` 16 | 17 | ## API 18 | 19 | ### css.parse(code, [options]) 20 | 21 | Accepts a CSS string and returns an AST `object`. 22 | 23 | `options`: 24 | 25 | - silent: silently fail on parse errors. 26 | - source: the path to the file containing `css`. Makes errors and source 27 | maps more helpful, by letting them know where code comes from. 28 | 29 | ### css.stringify(object, [options]) 30 | 31 | Accepts an AST `object` (as `css.parse` produces) and returns a CSS string. 32 | 33 | `options`: 34 | 35 | - indent: the string used to indent the output. Defaults to two spaces. 36 | - compress: omit comments and extraneous whitespace. 37 | - sourcemap: return a sourcemap along with the CSS output. Using the `source` 38 | option of `css.parse` is strongly recommended when creating a source map. 39 | Specify `sourcemap: 'generator'` to return the SourceMapGenerator object 40 | instead of serializing the source map. 41 | - inputSourcemaps: (enabled by default, specify `false` to disable) reads any 42 | source maps referenced by the input files when generating the output source 43 | map. When enabled, file system access may be required for reading the 44 | referenced source maps. 45 | 46 | ### Example 47 | 48 | ```js 49 | var ast = css.parse('body { font-size: 12px; }', { source: 'source.css' }); 50 | 51 | var css = css.stringify(ast); 52 | 53 | var result = css.stringify(ast, { sourcemap: true }); 54 | result.code // string with CSS 55 | result.map // source map object 56 | ``` 57 | 58 | ### Errors 59 | 60 | Errors thrown during parsing have the following properties: 61 | 62 | - message: `String`. The full error message with the source position. 63 | - reason: `String`. The error message without position. 64 | - filename: `String` or `undefined`. The value of `options.source` if 65 | passed to `css.parse`. Otherwise `undefined`. 66 | - line: `Integer`. 67 | - column: `Integer`. 68 | - source: `String`. The portion of code that couldn't be parsed. 69 | 70 | When parsing with the `silent` option, errors are listed in the 71 | `parsingErrors` property of the [`stylesheet`](#stylesheet) node instead 72 | of being thrown. 73 | 74 | If you create any errors in plugins such as in 75 | [rework](https://github.com/reworkcss/rework), you __must__ set the same 76 | properties for consistency. 77 | 78 | ## AST 79 | 80 | Interactively explore the AST with . 81 | 82 | ### Common properties 83 | 84 | All nodes have the following properties. 85 | 86 | #### position 87 | 88 | Information about the position in the source string that corresponds to 89 | the node. 90 | 91 | `Object`: 92 | 93 | - start: `Object`: 94 | - line: `Number`. 95 | - column: `Number`. 96 | - end: `Object`: 97 | - line: `Number`. 98 | - column: `Number`. 99 | - source: `String` or `undefined`. The value of `options.source` if passed to 100 | `css.parse`. Otherwise `undefined`. 101 | - content: `String`. The full source string passed to `css.parse`. 102 | 103 | The line and column numbers are 1-based: The first line is 1 and the first 104 | column of a line is 1 (not 0). 105 | 106 | The `position` property lets you know from which source file the node comes 107 | from (if available), what that file contains, and what part of that file was 108 | parsed into the node. 109 | 110 | #### type 111 | 112 | `String`. The possible values are the ones listed in the Types section below. 113 | 114 | #### parent 115 | 116 | A reference to the parent node, or `null` if the node has no parent. 117 | 118 | ### Types 119 | 120 | The available values of `node.type` are listed below, as well as the available 121 | properties of each node (other than the common properties listed above.) 122 | 123 | #### stylesheet 124 | 125 | The root node returned by `css.parse`. 126 | 127 | - stylesheet: `Object`: 128 | - rules: `Array` of nodes with the types `rule`, `comment` and any of the 129 | at-rule types. 130 | - parsingErrors: `Array` of `Error`s. Errors collected during parsing when 131 | option `silent` is true. 132 | 133 | #### rule 134 | 135 | - selectors: `Array` of `String`s. The list of selectors of the rule, split 136 | on commas. Each selector is trimmed from whitespace and comments. 137 | - declarations: `Array` of nodes with the types `declaration` and `comment`. 138 | 139 | #### declaration 140 | 141 | - property: `String`. The property name, trimmed from whitespace and 142 | comments. May not be empty. 143 | - value: `String`. The value of the property, trimmed from whitespace and 144 | comments. Empty values are allowed. 145 | 146 | #### comment 147 | 148 | A rule-level or declaration-level comment. Comments inside selectors, 149 | properties and values etc. are lost. 150 | 151 | - comment: `String`. The part between the starting `/*` and the ending `*/` 152 | of the comment, including whitespace. 153 | 154 | #### charset 155 | 156 | The `@charset` at-rule. 157 | 158 | - charset: `String`. The part following `@charset `. 159 | 160 | #### custom-media 161 | 162 | The `@custom-media` at-rule. 163 | 164 | - name: `String`. The `--`-prefixed name. 165 | - media: `String`. The part following the name. 166 | 167 | #### document 168 | 169 | The `@document` at-rule. 170 | 171 | - document: `String`. The part following `@document `. 172 | - vendor: `String` or `undefined`. The vendor prefix in `@document`, or 173 | `undefined` if there is none. 174 | - rules: `Array` of nodes with the types `rule`, `comment` and any of the 175 | at-rule types. 176 | 177 | #### font-face 178 | 179 | The `@font-face` at-rule. 180 | 181 | - declarations: `Array` of nodes with the types `declaration` and `comment`. 182 | 183 | #### host 184 | 185 | The `@host` at-rule. 186 | 187 | - rules: `Array` of nodes with the types `rule`, `comment` and any of the 188 | at-rule types. 189 | 190 | #### import 191 | 192 | The `@import` at-rule. 193 | 194 | - import: `String`. The part following `@import `. 195 | 196 | #### keyframes 197 | 198 | The `@keyframes` at-rule. 199 | 200 | - name: `String`. The name of the keyframes rule. 201 | - vendor: `String` or `undefined`. The vendor prefix in `@keyframes`, or 202 | `undefined` if there is none. 203 | - keyframes: `Array` of nodes with the types `keyframe` and `comment`. 204 | 205 | #### keyframe 206 | 207 | - values: `Array` of `String`s. The list of “selectors” of the keyframe rule, 208 | split on commas. Each “selector” is trimmed from whitespace. 209 | - declarations: `Array` of nodes with the types `declaration` and `comment`. 210 | 211 | #### media 212 | 213 | The `@media` at-rule. 214 | 215 | - media: `String`. The part following `@media `. 216 | - rules: `Array` of nodes with the types `rule`, `comment` and any of the 217 | at-rule types. 218 | 219 | #### namespace 220 | 221 | The `@namespace` at-rule. 222 | 223 | - namespace: `String`. The part following `@namespace `. 224 | 225 | #### page 226 | 227 | The `@page` at-rule. 228 | 229 | - selectors: `Array` of `String`s. The list of selectors of the rule, split 230 | on commas. Each selector is trimmed from whitespace and comments. 231 | - declarations: `Array` of nodes with the types `declaration` and `comment`. 232 | 233 | #### supports 234 | 235 | The `@supports` at-rule. 236 | 237 | - supports: `String`. The part following `@supports `. 238 | - rules: `Array` of nodes with the types `rule`, `comment` and any of the 239 | at-rule types. 240 | 241 | ### Example 242 | 243 | CSS: 244 | 245 | ```css 246 | body { 247 | background: #eee; 248 | color: #888; 249 | } 250 | ``` 251 | 252 | Parse tree: 253 | 254 | ```json 255 | { 256 | "type": "stylesheet", 257 | "stylesheet": { 258 | "rules": [ 259 | { 260 | "type": "rule", 261 | "selectors": [ 262 | "body" 263 | ], 264 | "declarations": [ 265 | { 266 | "type": "declaration", 267 | "property": "background", 268 | "value": "#eee", 269 | "position": { 270 | "start": { 271 | "line": 2, 272 | "column": 3 273 | }, 274 | "end": { 275 | "line": 2, 276 | "column": 19 277 | } 278 | } 279 | }, 280 | { 281 | "type": "declaration", 282 | "property": "color", 283 | "value": "#888", 284 | "position": { 285 | "start": { 286 | "line": 3, 287 | "column": 3 288 | }, 289 | "end": { 290 | "line": 3, 291 | "column": 14 292 | } 293 | } 294 | } 295 | ], 296 | "position": { 297 | "start": { 298 | "line": 1, 299 | "column": 1 300 | }, 301 | "end": { 302 | "line": 4, 303 | "column": 2 304 | } 305 | } 306 | } 307 | ] 308 | } 309 | } 310 | ``` 311 | 312 | ## License 313 | 314 | MIT 315 | -------------------------------------------------------------------------------- /benchmark/LICENSES: -------------------------------------------------------------------------------- 1 | File: large.css 2 | Copyright: 2013 Contributors 3 | License: MIT 4 | Origin: https://raw.githubusercontent.com/Semantic-Org/Semantic-UI/0.16.1/build/packaged/css/semantic.css 5 | 6 | File: small.css 7 | Copyright: Nicolas Gallagher and Jonathan Neal 8 | License: MIT 9 | Origin: https://raw.githubusercontent.com/necolas/normalize.css/3.0.1/normalize.css 10 | 11 | 12 | License: MIT 13 | Permission is hereby granted, free of charge, to any person obtaining a 14 | copy of this software and associated documentation files (the 15 | 'Software'), to deal in the Software without restriction, including 16 | without limitation the rights to use, copy, modify, merge, publish, 17 | distribute, sublicense, and/or sell copies of the Software, and to 18 | permit persons to whom the Software is furnished to do so, subject to 19 | the following conditions: 20 | 21 | The above copyright notice and this permission notice shall be included 22 | in all copies or substantial portions of the Software. 23 | 24 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS 25 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 27 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 28 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 29 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 30 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 31 | -------------------------------------------------------------------------------- /benchmark/index.js: -------------------------------------------------------------------------------- 1 | 2 | var bytes = require('bytes'); 3 | var parse = require('..').parse; 4 | var fs = require('fs'); 5 | 6 | var small = fs.readFileSync('benchmark/small.css', 'utf8'); 7 | var large = fs.readFileSync('benchmark/large.css', 'utf8'); 8 | var huge = Array(8).join(large); 9 | 10 | function lines(str) { 11 | return str.split(/\n/g).length; 12 | } 13 | 14 | console.log(); 15 | console.log(' small : %s : %s lines', bytes(Buffer.byteLength(small)), lines(small)); 16 | console.log(' large : %s : %s lines', bytes(Buffer.byteLength(large)), lines(large)); 17 | console.log(' huge : %s : %s lines', bytes(Buffer.byteLength(huge)), lines(huge)); 18 | 19 | suite('css parse', function(){ 20 | bench('small', function(){ 21 | parse(small); 22 | }); 23 | 24 | bench('large', function(){ 25 | parse(large); 26 | }); 27 | 28 | bench('huge', function(){ 29 | parse(huge); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /benchmark/small.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v3.0.1 | MIT License | git.io/normalize */ 2 | 3 | /** 4 | * 1. Set default font family to sans-serif. 5 | * 2. Prevent iOS text size adjust after orientation change, without disabling 6 | * user zoom. 7 | */ 8 | 9 | html { 10 | font-family: sans-serif; /* 1 */ 11 | -ms-text-size-adjust: 100%; /* 2 */ 12 | -webkit-text-size-adjust: 100%; /* 2 */ 13 | } 14 | 15 | /** 16 | * Remove default margin. 17 | */ 18 | 19 | body { 20 | margin: 0; 21 | } 22 | 23 | /* HTML5 display definitions 24 | ========================================================================== */ 25 | 26 | /** 27 | * Correct `block` display not defined for any HTML5 element in IE 8/9. 28 | * Correct `block` display not defined for `details` or `summary` in IE 10/11 and Firefox. 29 | * Correct `block` display not defined for `main` in IE 11. 30 | */ 31 | 32 | article, 33 | aside, 34 | details, 35 | figcaption, 36 | figure, 37 | footer, 38 | header, 39 | hgroup, 40 | main, 41 | nav, 42 | section, 43 | summary { 44 | display: block; 45 | } 46 | 47 | /** 48 | * 1. Correct `inline-block` display not defined in IE 8/9. 49 | * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. 50 | */ 51 | 52 | audio, 53 | canvas, 54 | progress, 55 | video { 56 | display: inline-block; /* 1 */ 57 | vertical-align: baseline; /* 2 */ 58 | } 59 | 60 | /** 61 | * Prevent modern browsers from displaying `audio` without controls. 62 | * Remove excess height in iOS 5 devices. 63 | */ 64 | 65 | audio:not([controls]) { 66 | display: none; 67 | height: 0; 68 | } 69 | 70 | /** 71 | * Address `[hidden]` styling not present in IE 8/9/10. 72 | * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22. 73 | */ 74 | 75 | [hidden], 76 | template { 77 | display: none; 78 | } 79 | 80 | /* Links 81 | ========================================================================== */ 82 | 83 | /** 84 | * Remove the gray background color from active links in IE 10. 85 | */ 86 | 87 | a { 88 | background: transparent; 89 | } 90 | 91 | /** 92 | * Improve readability when focused and also mouse hovered in all browsers. 93 | */ 94 | 95 | a:active, 96 | a:hover { 97 | outline: 0; 98 | } 99 | 100 | /* Text-level semantics 101 | ========================================================================== */ 102 | 103 | /** 104 | * Address styling not present in IE 8/9/10/11, Safari, and Chrome. 105 | */ 106 | 107 | abbr[title] { 108 | border-bottom: 1px dotted; 109 | } 110 | 111 | /** 112 | * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. 113 | */ 114 | 115 | b, 116 | strong { 117 | font-weight: bold; 118 | } 119 | 120 | /** 121 | * Address styling not present in Safari and Chrome. 122 | */ 123 | 124 | dfn { 125 | font-style: italic; 126 | } 127 | 128 | /** 129 | * Address variable `h1` font-size and margin within `section` and `article` 130 | * contexts in Firefox 4+, Safari, and Chrome. 131 | */ 132 | 133 | h1 { 134 | font-size: 2em; 135 | margin: 0.67em 0; 136 | } 137 | 138 | /** 139 | * Address styling not present in IE 8/9. 140 | */ 141 | 142 | mark { 143 | background: #ff0; 144 | color: #000; 145 | } 146 | 147 | /** 148 | * Address inconsistent and variable font size in all browsers. 149 | */ 150 | 151 | small { 152 | font-size: 80%; 153 | } 154 | 155 | /** 156 | * Prevent `sub` and `sup` affecting `line-height` in all browsers. 157 | */ 158 | 159 | sub, 160 | sup { 161 | font-size: 75%; 162 | line-height: 0; 163 | position: relative; 164 | vertical-align: baseline; 165 | } 166 | 167 | sup { 168 | top: -0.5em; 169 | } 170 | 171 | sub { 172 | bottom: -0.25em; 173 | } 174 | 175 | /* Embedded content 176 | ========================================================================== */ 177 | 178 | /** 179 | * Remove border when inside `a` element in IE 8/9/10. 180 | */ 181 | 182 | img { 183 | border: 0; 184 | } 185 | 186 | /** 187 | * Correct overflow not hidden in IE 9/10/11. 188 | */ 189 | 190 | svg:not(:root) { 191 | overflow: hidden; 192 | } 193 | 194 | /* Grouping content 195 | ========================================================================== */ 196 | 197 | /** 198 | * Address margin not present in IE 8/9 and Safari. 199 | */ 200 | 201 | figure { 202 | margin: 1em 40px; 203 | } 204 | 205 | /** 206 | * Address differences between Firefox and other browsers. 207 | */ 208 | 209 | hr { 210 | -moz-box-sizing: content-box; 211 | box-sizing: content-box; 212 | height: 0; 213 | } 214 | 215 | /** 216 | * Contain overflow in all browsers. 217 | */ 218 | 219 | pre { 220 | overflow: auto; 221 | } 222 | 223 | /** 224 | * Address odd `em`-unit font size rendering in all browsers. 225 | */ 226 | 227 | code, 228 | kbd, 229 | pre, 230 | samp { 231 | font-family: monospace, monospace; 232 | font-size: 1em; 233 | } 234 | 235 | /* Forms 236 | ========================================================================== */ 237 | 238 | /** 239 | * Known limitation: by default, Chrome and Safari on OS X allow very limited 240 | * styling of `select`, unless a `border` property is set. 241 | */ 242 | 243 | /** 244 | * 1. Correct color not being inherited. 245 | * Known issue: affects color of disabled elements. 246 | * 2. Correct font properties not being inherited. 247 | * 3. Address margins set differently in Firefox 4+, Safari, and Chrome. 248 | */ 249 | 250 | button, 251 | input, 252 | optgroup, 253 | select, 254 | textarea { 255 | color: inherit; /* 1 */ 256 | font: inherit; /* 2 */ 257 | margin: 0; /* 3 */ 258 | } 259 | 260 | /** 261 | * Address `overflow` set to `hidden` in IE 8/9/10/11. 262 | */ 263 | 264 | button { 265 | overflow: visible; 266 | } 267 | 268 | /** 269 | * Address inconsistent `text-transform` inheritance for `button` and `select`. 270 | * All other form control elements do not inherit `text-transform` values. 271 | * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. 272 | * Correct `select` style inheritance in Firefox. 273 | */ 274 | 275 | button, 276 | select { 277 | text-transform: none; 278 | } 279 | 280 | /** 281 | * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` 282 | * and `video` controls. 283 | * 2. Correct inability to style clickable `input` types in iOS. 284 | * 3. Improve usability and consistency of cursor style between image-type 285 | * `input` and others. 286 | */ 287 | 288 | button, 289 | html input[type="button"], /* 1 */ 290 | input[type="reset"], 291 | input[type="submit"] { 292 | -webkit-appearance: button; /* 2 */ 293 | cursor: pointer; /* 3 */ 294 | } 295 | 296 | /** 297 | * Re-set default cursor for disabled elements. 298 | */ 299 | 300 | button[disabled], 301 | html input[disabled] { 302 | cursor: default; 303 | } 304 | 305 | /** 306 | * Remove inner padding and border in Firefox 4+. 307 | */ 308 | 309 | button::-moz-focus-inner, 310 | input::-moz-focus-inner { 311 | border: 0; 312 | padding: 0; 313 | } 314 | 315 | /** 316 | * Address Firefox 4+ setting `line-height` on `input` using `!important` in 317 | * the UA stylesheet. 318 | */ 319 | 320 | input { 321 | line-height: normal; 322 | } 323 | 324 | /** 325 | * It's recommended that you don't attempt to style these elements. 326 | * Firefox's implementation doesn't respect box-sizing, padding, or width. 327 | * 328 | * 1. Address box sizing set to `content-box` in IE 8/9/10. 329 | * 2. Remove excess padding in IE 8/9/10. 330 | */ 331 | 332 | input[type="checkbox"], 333 | input[type="radio"] { 334 | box-sizing: border-box; /* 1 */ 335 | padding: 0; /* 2 */ 336 | } 337 | 338 | /** 339 | * Fix the cursor style for Chrome's increment/decrement buttons. For certain 340 | * `font-size` values of the `input`, it causes the cursor style of the 341 | * decrement button to change from `default` to `text`. 342 | */ 343 | 344 | input[type="number"]::-webkit-inner-spin-button, 345 | input[type="number"]::-webkit-outer-spin-button { 346 | height: auto; 347 | } 348 | 349 | /** 350 | * 1. Address `appearance` set to `searchfield` in Safari and Chrome. 351 | * 2. Address `box-sizing` set to `border-box` in Safari and Chrome 352 | * (include `-moz` to future-proof). 353 | */ 354 | 355 | input[type="search"] { 356 | -webkit-appearance: textfield; /* 1 */ 357 | -moz-box-sizing: content-box; 358 | -webkit-box-sizing: content-box; /* 2 */ 359 | box-sizing: content-box; 360 | } 361 | 362 | /** 363 | * Remove inner padding and search cancel button in Safari and Chrome on OS X. 364 | * Safari (but not Chrome) clips the cancel button when the search input has 365 | * padding (and `textfield` appearance). 366 | */ 367 | 368 | input[type="search"]::-webkit-search-cancel-button, 369 | input[type="search"]::-webkit-search-decoration { 370 | -webkit-appearance: none; 371 | } 372 | 373 | /** 374 | * Define consistent border, margin, and padding. 375 | */ 376 | 377 | fieldset { 378 | border: 1px solid #c0c0c0; 379 | margin: 0 2px; 380 | padding: 0.35em 0.625em 0.75em; 381 | } 382 | 383 | /** 384 | * 1. Correct `color` not being inherited in IE 8/9/10/11. 385 | * 2. Remove padding so people aren't caught out if they zero out fieldsets. 386 | */ 387 | 388 | legend { 389 | border: 0; /* 1 */ 390 | padding: 0; /* 2 */ 391 | } 392 | 393 | /** 394 | * Remove default vertical scrollbar in IE 8/9/10/11. 395 | */ 396 | 397 | textarea { 398 | overflow: auto; 399 | } 400 | 401 | /** 402 | * Don't inherit the `font-weight` (applied by a rule above). 403 | * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. 404 | */ 405 | 406 | optgroup { 407 | font-weight: bold; 408 | } 409 | 410 | /* Tables 411 | ========================================================================== */ 412 | 413 | /** 414 | * Remove most spacing between table cells. 415 | */ 416 | 417 | table { 418 | border-collapse: collapse; 419 | border-spacing: 0; 420 | } 421 | 422 | td, 423 | th { 424 | padding: 0; 425 | } 426 | -------------------------------------------------------------------------------- /generate-tests.js: -------------------------------------------------------------------------------- 1 | // Generates missing output source and AST files for the test cases 2 | // IMPORTANT: Always verify the generated files when using this! 3 | 4 | var fs = require('fs'); 5 | var path = require('path'); 6 | var parse = require('./').parse; 7 | var stringify = require('./').stringify; 8 | 9 | var casesDir = path.join(__dirname, 'test', 'cases'); 10 | var cases = fs.readdirSync(casesDir) 11 | .map(function(f) { return path.join(casesDir, f); }); 12 | 13 | cases.forEach(function(dir) { 14 | var inputFile = path.join(dir, 'input.css'); 15 | if (!fs.existsSync(inputFile)) 16 | throw new Error('Missing input file ' + inputFile); 17 | 18 | var input = fs.readFileSync(inputFile, 'utf8'); 19 | var parsed; 20 | try { 21 | parsed = parse(input, { source: 'input.css' }); 22 | } catch(e) { 23 | console.log('Failed to parse', inputFile); 24 | throw e; 25 | } 26 | 27 | var outputFile = path.join(dir, 'output.css'); 28 | if (!fs.existsSync(outputFile)) { 29 | console.log('Generating', outputFile); 30 | var output = stringify(parsed); 31 | fs.writeFileSync(outputFile, output, 'utf8'); 32 | } 33 | 34 | var compressedFile = path.join(dir, 'compressed.css'); 35 | if (!fs.existsSync(compressedFile)) { 36 | console.log('Generating', compressedFile); 37 | var compressed = stringify(parsed, { compress: true }); 38 | fs.writeFileSync(compressedFile, compressed, 'utf8'); 39 | } 40 | 41 | var astFile = path.join(dir, 'ast.json'); 42 | if (!fs.existsSync(astFile)) { 43 | console.log('Generating', astFile); 44 | var ast = JSON.stringify(parsed, null, ' '); 45 | fs.writeFileSync(astFile, ast, 'utf8'); 46 | } 47 | }); 48 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | exports.parse = require('./lib/parse'); 2 | exports.stringify = require('./lib/stringify'); 3 | -------------------------------------------------------------------------------- /lib/stringify/compiler.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Expose `Compiler`. 4 | */ 5 | 6 | module.exports = Compiler; 7 | 8 | /** 9 | * Initialize a compiler. 10 | * 11 | * @param {Type} name 12 | * @return {Type} 13 | * @api public 14 | */ 15 | 16 | function Compiler(opts) { 17 | this.options = opts || {}; 18 | } 19 | 20 | /** 21 | * Emit `str` 22 | */ 23 | 24 | Compiler.prototype.emit = function(str) { 25 | return str; 26 | }; 27 | 28 | /** 29 | * Visit `node`. 30 | */ 31 | 32 | Compiler.prototype.visit = function(node){ 33 | return this[node.type](node); 34 | }; 35 | 36 | /** 37 | * Map visit over array of `nodes`, optionally using a `delim` 38 | */ 39 | 40 | Compiler.prototype.mapVisit = function(nodes, delim){ 41 | var buf = ''; 42 | delim = delim || ''; 43 | 44 | for (var i = 0, length = nodes.length; i < length; i++) { 45 | buf += this.visit(nodes[i]); 46 | if (delim && i < length - 1) buf += this.emit(delim); 47 | } 48 | 49 | return buf; 50 | }; 51 | -------------------------------------------------------------------------------- /lib/stringify/compress.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Module dependencies. 4 | */ 5 | 6 | var Base = require('./compiler'); 7 | var inherits = require('inherits'); 8 | 9 | /** 10 | * Expose compiler. 11 | */ 12 | 13 | module.exports = Compiler; 14 | 15 | /** 16 | * Initialize a new `Compiler`. 17 | */ 18 | 19 | function Compiler(options) { 20 | Base.call(this, options); 21 | } 22 | 23 | /** 24 | * Inherit from `Base.prototype`. 25 | */ 26 | 27 | inherits(Compiler, Base); 28 | 29 | /** 30 | * Compile `node`. 31 | */ 32 | 33 | Compiler.prototype.compile = function(node){ 34 | return node.stylesheet 35 | .rules.map(this.visit, this) 36 | .join(''); 37 | }; 38 | 39 | /** 40 | * Visit comment node. 41 | */ 42 | 43 | Compiler.prototype.comment = function(node){ 44 | return this.emit('', node.position); 45 | }; 46 | 47 | /** 48 | * Visit import node. 49 | */ 50 | 51 | Compiler.prototype.import = function(node){ 52 | return this.emit('@import ' + node.import + ';', node.position); 53 | }; 54 | 55 | /** 56 | * Visit media node. 57 | */ 58 | 59 | Compiler.prototype.media = function(node){ 60 | return this.emit('@media ' + node.media, node.position) 61 | + this.emit('{') 62 | + this.mapVisit(node.rules) 63 | + this.emit('}'); 64 | }; 65 | 66 | /** 67 | * Visit document node. 68 | */ 69 | 70 | Compiler.prototype.document = function(node){ 71 | var doc = '@' + (node.vendor || '') + 'document ' + node.document; 72 | 73 | return this.emit(doc, node.position) 74 | + this.emit('{') 75 | + this.mapVisit(node.rules) 76 | + this.emit('}'); 77 | }; 78 | 79 | /** 80 | * Visit charset node. 81 | */ 82 | 83 | Compiler.prototype.charset = function(node){ 84 | return this.emit('@charset ' + node.charset + ';', node.position); 85 | }; 86 | 87 | /** 88 | * Visit namespace node. 89 | */ 90 | 91 | Compiler.prototype.namespace = function(node){ 92 | return this.emit('@namespace ' + node.namespace + ';', node.position); 93 | }; 94 | 95 | /** 96 | * Visit supports node. 97 | */ 98 | 99 | Compiler.prototype.supports = function(node){ 100 | return this.emit('@supports ' + node.supports, node.position) 101 | + this.emit('{') 102 | + this.mapVisit(node.rules) 103 | + this.emit('}'); 104 | }; 105 | 106 | /** 107 | * Visit keyframes node. 108 | */ 109 | 110 | Compiler.prototype.keyframes = function(node){ 111 | return this.emit('@' 112 | + (node.vendor || '') 113 | + 'keyframes ' 114 | + node.name, node.position) 115 | + this.emit('{') 116 | + this.mapVisit(node.keyframes) 117 | + this.emit('}'); 118 | }; 119 | 120 | /** 121 | * Visit keyframe node. 122 | */ 123 | 124 | Compiler.prototype.keyframe = function(node){ 125 | var decls = node.declarations; 126 | 127 | return this.emit(node.values.join(','), node.position) 128 | + this.emit('{') 129 | + this.mapVisit(decls) 130 | + this.emit('}'); 131 | }; 132 | 133 | /** 134 | * Visit page node. 135 | */ 136 | 137 | Compiler.prototype.page = function(node){ 138 | var sel = node.selectors.length 139 | ? node.selectors.join(', ') 140 | : ''; 141 | 142 | return this.emit('@page ' + sel, node.position) 143 | + this.emit('{') 144 | + this.mapVisit(node.declarations) 145 | + this.emit('}'); 146 | }; 147 | 148 | /** 149 | * Visit font-face node. 150 | */ 151 | 152 | Compiler.prototype['font-face'] = function(node){ 153 | return this.emit('@font-face', node.position) 154 | + this.emit('{') 155 | + this.mapVisit(node.declarations) 156 | + this.emit('}'); 157 | }; 158 | 159 | /** 160 | * Visit host node. 161 | */ 162 | 163 | Compiler.prototype.host = function(node){ 164 | return this.emit('@host', node.position) 165 | + this.emit('{') 166 | + this.mapVisit(node.rules) 167 | + this.emit('}'); 168 | }; 169 | 170 | /** 171 | * Visit custom-media node. 172 | */ 173 | 174 | Compiler.prototype['custom-media'] = function(node){ 175 | return this.emit('@custom-media ' + node.name + ' ' + node.media + ';', node.position); 176 | }; 177 | 178 | /** 179 | * Visit rule node. 180 | */ 181 | 182 | Compiler.prototype.rule = function(node){ 183 | var decls = node.declarations; 184 | if (!decls.length) return ''; 185 | 186 | return this.emit(node.selectors.join(','), node.position) 187 | + this.emit('{') 188 | + this.mapVisit(decls) 189 | + this.emit('}'); 190 | }; 191 | 192 | /** 193 | * Visit declaration node. 194 | */ 195 | 196 | Compiler.prototype.declaration = function(node){ 197 | return this.emit(node.property + ':' + node.value, node.position) + this.emit(';'); 198 | }; 199 | 200 | -------------------------------------------------------------------------------- /lib/stringify/identity.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Module dependencies. 4 | */ 5 | 6 | var Base = require('./compiler'); 7 | var inherits = require('inherits'); 8 | 9 | /** 10 | * Expose compiler. 11 | */ 12 | 13 | module.exports = Compiler; 14 | 15 | /** 16 | * Initialize a new `Compiler`. 17 | */ 18 | 19 | function Compiler(options) { 20 | options = options || {}; 21 | Base.call(this, options); 22 | this.indentation = options.indent; 23 | } 24 | 25 | /** 26 | * Inherit from `Base.prototype`. 27 | */ 28 | 29 | inherits(Compiler, Base); 30 | 31 | /** 32 | * Compile `node`. 33 | */ 34 | 35 | Compiler.prototype.compile = function(node){ 36 | return this.stylesheet(node); 37 | }; 38 | 39 | /** 40 | * Visit stylesheet node. 41 | */ 42 | 43 | Compiler.prototype.stylesheet = function(node){ 44 | return this.mapVisit(node.stylesheet.rules, '\n\n'); 45 | }; 46 | 47 | /** 48 | * Visit comment node. 49 | */ 50 | 51 | Compiler.prototype.comment = function(node){ 52 | return this.emit(this.indent() + '/*' + node.comment + '*/', node.position); 53 | }; 54 | 55 | /** 56 | * Visit import node. 57 | */ 58 | 59 | Compiler.prototype.import = function(node){ 60 | return this.emit('@import ' + node.import + ';', node.position); 61 | }; 62 | 63 | /** 64 | * Visit media node. 65 | */ 66 | 67 | Compiler.prototype.media = function(node){ 68 | return this.emit('@media ' + node.media, node.position) 69 | + this.emit( 70 | ' {\n' 71 | + this.indent(1)) 72 | + this.mapVisit(node.rules, '\n\n') 73 | + this.emit( 74 | this.indent(-1) 75 | + '\n}'); 76 | }; 77 | 78 | /** 79 | * Visit document node. 80 | */ 81 | 82 | Compiler.prototype.document = function(node){ 83 | var doc = '@' + (node.vendor || '') + 'document ' + node.document; 84 | 85 | return this.emit(doc, node.position) 86 | + this.emit( 87 | ' ' 88 | + ' {\n' 89 | + this.indent(1)) 90 | + this.mapVisit(node.rules, '\n\n') 91 | + this.emit( 92 | this.indent(-1) 93 | + '\n}'); 94 | }; 95 | 96 | /** 97 | * Visit charset node. 98 | */ 99 | 100 | Compiler.prototype.charset = function(node){ 101 | return this.emit('@charset ' + node.charset + ';', node.position); 102 | }; 103 | 104 | /** 105 | * Visit namespace node. 106 | */ 107 | 108 | Compiler.prototype.namespace = function(node){ 109 | return this.emit('@namespace ' + node.namespace + ';', node.position); 110 | }; 111 | 112 | /** 113 | * Visit supports node. 114 | */ 115 | 116 | Compiler.prototype.supports = function(node){ 117 | return this.emit('@supports ' + node.supports, node.position) 118 | + this.emit( 119 | ' {\n' 120 | + this.indent(1)) 121 | + this.mapVisit(node.rules, '\n\n') 122 | + this.emit( 123 | this.indent(-1) 124 | + '\n}'); 125 | }; 126 | 127 | /** 128 | * Visit keyframes node. 129 | */ 130 | 131 | Compiler.prototype.keyframes = function(node){ 132 | return this.emit('@' + (node.vendor || '') + 'keyframes ' + node.name, node.position) 133 | + this.emit( 134 | ' {\n' 135 | + this.indent(1)) 136 | + this.mapVisit(node.keyframes, '\n') 137 | + this.emit( 138 | this.indent(-1) 139 | + '}'); 140 | }; 141 | 142 | /** 143 | * Visit keyframe node. 144 | */ 145 | 146 | Compiler.prototype.keyframe = function(node){ 147 | var decls = node.declarations; 148 | 149 | return this.emit(this.indent()) 150 | + this.emit(node.values.join(', '), node.position) 151 | + this.emit( 152 | ' {\n' 153 | + this.indent(1)) 154 | + this.mapVisit(decls, '\n') 155 | + this.emit( 156 | this.indent(-1) 157 | + '\n' 158 | + this.indent() + '}\n'); 159 | }; 160 | 161 | /** 162 | * Visit page node. 163 | */ 164 | 165 | Compiler.prototype.page = function(node){ 166 | var sel = node.selectors.length 167 | ? node.selectors.join(', ') + ' ' 168 | : ''; 169 | 170 | return this.emit('@page ' + sel, node.position) 171 | + this.emit('{\n') 172 | + this.emit(this.indent(1)) 173 | + this.mapVisit(node.declarations, '\n') 174 | + this.emit(this.indent(-1)) 175 | + this.emit('\n}'); 176 | }; 177 | 178 | /** 179 | * Visit font-face node. 180 | */ 181 | 182 | Compiler.prototype['font-face'] = function(node){ 183 | return this.emit('@font-face ', node.position) 184 | + this.emit('{\n') 185 | + this.emit(this.indent(1)) 186 | + this.mapVisit(node.declarations, '\n') 187 | + this.emit(this.indent(-1)) 188 | + this.emit('\n}'); 189 | }; 190 | 191 | /** 192 | * Visit host node. 193 | */ 194 | 195 | Compiler.prototype.host = function(node){ 196 | return this.emit('@host', node.position) 197 | + this.emit( 198 | ' {\n' 199 | + this.indent(1)) 200 | + this.mapVisit(node.rules, '\n\n') 201 | + this.emit( 202 | this.indent(-1) 203 | + '\n}'); 204 | }; 205 | 206 | /** 207 | * Visit custom-media node. 208 | */ 209 | 210 | Compiler.prototype['custom-media'] = function(node){ 211 | return this.emit('@custom-media ' + node.name + ' ' + node.media + ';', node.position); 212 | }; 213 | 214 | /** 215 | * Visit rule node. 216 | */ 217 | 218 | Compiler.prototype.rule = function(node){ 219 | var indent = this.indent(); 220 | var decls = node.declarations; 221 | if (!decls.length) return ''; 222 | 223 | return this.emit(node.selectors.map(function(s){ return indent + s }).join(',\n'), node.position) 224 | + this.emit(' {\n') 225 | + this.emit(this.indent(1)) 226 | + this.mapVisit(decls, '\n') 227 | + this.emit(this.indent(-1)) 228 | + this.emit('\n' + this.indent() + '}'); 229 | }; 230 | 231 | /** 232 | * Visit declaration node. 233 | */ 234 | 235 | Compiler.prototype.declaration = function(node){ 236 | return this.emit(this.indent()) 237 | + this.emit(node.property + ': ' + node.value, node.position) 238 | + this.emit(';'); 239 | }; 240 | 241 | /** 242 | * Increase, decrease or return current indentation. 243 | */ 244 | 245 | Compiler.prototype.indent = function(level) { 246 | this.level = this.level || 1; 247 | 248 | if (null != level) { 249 | this.level += level; 250 | return ''; 251 | } 252 | 253 | return Array(this.level).join(this.indentation || ' '); 254 | }; 255 | -------------------------------------------------------------------------------- /lib/stringify/index.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Module dependencies. 4 | */ 5 | 6 | var Compressed = require('./compress'); 7 | var Identity = require('./identity'); 8 | 9 | /** 10 | * Stringfy the given AST `node`. 11 | * 12 | * Options: 13 | * 14 | * - `compress` space-optimized output 15 | * - `sourcemap` return an object with `.code` and `.map` 16 | * 17 | * @param {Object} node 18 | * @param {Object} [options] 19 | * @return {String} 20 | * @api public 21 | */ 22 | 23 | module.exports = function(node, options){ 24 | options = options || {}; 25 | 26 | var compiler = options.compress 27 | ? new Compressed(options) 28 | : new Identity(options); 29 | 30 | // source maps 31 | if (options.sourcemap) { 32 | var sourcemaps = require('./source-map-support'); 33 | sourcemaps(compiler); 34 | 35 | var code = compiler.compile(node); 36 | compiler.applySourceMaps(); 37 | 38 | var map = options.sourcemap === 'generator' 39 | ? compiler.map 40 | : compiler.map.toJSON(); 41 | 42 | return { code: code, map: map }; 43 | } 44 | 45 | var code = compiler.compile(node); 46 | return code; 47 | }; 48 | -------------------------------------------------------------------------------- /lib/stringify/source-map-support.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Module dependencies. 4 | */ 5 | 6 | var SourceMap = require('source-map').SourceMapGenerator; 7 | var SourceMapConsumer = require('source-map').SourceMapConsumer; 8 | var sourceMapResolve = require('source-map-resolve'); 9 | var urix = require('urix'); 10 | var fs = require('fs'); 11 | var path = require('path'); 12 | 13 | /** 14 | * Expose `mixin()`. 15 | */ 16 | 17 | module.exports = mixin; 18 | 19 | /** 20 | * Mixin source map support into `compiler`. 21 | * 22 | * @param {Compiler} compiler 23 | * @api public 24 | */ 25 | 26 | function mixin(compiler) { 27 | compiler._comment = compiler.comment; 28 | compiler.map = new SourceMap(); 29 | compiler.position = { line: 1, column: 1 }; 30 | compiler.files = {}; 31 | for (var k in exports) compiler[k] = exports[k]; 32 | } 33 | 34 | /** 35 | * Update position. 36 | * 37 | * @param {String} str 38 | * @api private 39 | */ 40 | 41 | exports.updatePosition = function(str) { 42 | var lines = str.match(/\n/g); 43 | if (lines) this.position.line += lines.length; 44 | var i = str.lastIndexOf('\n'); 45 | this.position.column = ~i ? str.length - i : this.position.column + str.length; 46 | }; 47 | 48 | /** 49 | * Emit `str`. 50 | * 51 | * @param {String} str 52 | * @param {Object} [pos] 53 | * @return {String} 54 | * @api private 55 | */ 56 | 57 | exports.emit = function(str, pos) { 58 | if (pos) { 59 | var sourceFile = urix(pos.source || 'source.css'); 60 | 61 | this.map.addMapping({ 62 | source: sourceFile, 63 | generated: { 64 | line: this.position.line, 65 | column: Math.max(this.position.column - 1, 0) 66 | }, 67 | original: { 68 | line: pos.start.line, 69 | column: pos.start.column - 1 70 | } 71 | }); 72 | 73 | this.addFile(sourceFile, pos); 74 | } 75 | 76 | this.updatePosition(str); 77 | 78 | return str; 79 | }; 80 | 81 | /** 82 | * Adds a file to the source map output if it has not already been added 83 | * @param {String} file 84 | * @param {Object} pos 85 | */ 86 | 87 | exports.addFile = function(file, pos) { 88 | if (typeof pos.content !== 'string') return; 89 | if (Object.prototype.hasOwnProperty.call(this.files, file)) return; 90 | 91 | this.files[file] = pos.content; 92 | }; 93 | 94 | /** 95 | * Applies any original source maps to the output and embeds the source file 96 | * contents in the source map. 97 | */ 98 | 99 | exports.applySourceMaps = function() { 100 | Object.keys(this.files).forEach(function(file) { 101 | var content = this.files[file]; 102 | this.map.setSourceContent(file, content); 103 | 104 | if (this.options.inputSourcemaps !== false) { 105 | var originalMap = sourceMapResolve.resolveSync( 106 | content, file, fs.readFileSync); 107 | if (originalMap) { 108 | var map = new SourceMapConsumer(originalMap.map); 109 | var relativeTo = originalMap.sourcesRelativeTo; 110 | this.map.applySourceMap(map, file, urix(path.dirname(relativeTo))); 111 | } 112 | } 113 | }, this); 114 | }; 115 | 116 | /** 117 | * Process comments, drops sourceMap comments. 118 | * @param {Object} node 119 | */ 120 | 121 | exports.comment = function(node) { 122 | if (/^# sourceMappingURL=/.test(node.comment)) 123 | return this.emit('', node.position); 124 | else 125 | return this._comment(node); 126 | }; 127 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "css", 3 | "version": "2.2.4", 4 | "description": "CSS parser / stringifier", 5 | "main": "index", 6 | "files": [ 7 | "index.js", 8 | "lib", 9 | "Readme.md" 10 | ], 11 | "dependencies": { 12 | "inherits": "^2.0.3", 13 | "source-map": "^0.6.1", 14 | "source-map-resolve": "^0.5.2", 15 | "urix": "^0.1.0" 16 | }, 17 | "devDependencies": { 18 | "mocha": "^1.21.3", 19 | "should": "^4.0.4", 20 | "matcha": "^0.5.0", 21 | "bytes": "^1.0.0" 22 | }, 23 | "scripts": { 24 | "benchmark": "matcha", 25 | "test": "mocha --require should --reporter spec --bail test/*.js" 26 | }, 27 | "author": "TJ Holowaychuk ", 28 | "license": "MIT", 29 | "repository": { 30 | "type": "git", 31 | "url": "https://github.com/reworkcss/css.git" 32 | }, 33 | "keywords": [ 34 | "css", 35 | "parser", 36 | "stringifier", 37 | "stylesheet" 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /test/cases.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var path = require('path'); 3 | var parse = require('../').parse; 4 | var stringify = require('../').stringify; 5 | 6 | var cases = fs.readdirSync(path.join(__dirname, 'cases')); 7 | cases.forEach(function(name) { 8 | describe('cases/' + name, function() { 9 | var dir = path.join(__dirname, 'cases', name); 10 | var inputFile = path.join(dir, 'input.css'); 11 | var astFile = path.join(dir, 'ast.json'); 12 | var outputFile = path.join(dir, 'output.css'); 13 | var compressedFile = path.join(dir, 'compressed.css'); 14 | 15 | it('should match ast.json', function() { 16 | var ast = parseInput(); 17 | ast.should.containDeep(JSON.parse(readFile(astFile))); 18 | }); 19 | 20 | it('should match output.css', function() { 21 | var output = stringify(parseInput()); 22 | output.should.equal(readFile(outputFile).trim()); 23 | }); 24 | 25 | it('should match compressed.css', function() { 26 | var compressed = stringify(parseInput(), { compress: true }); 27 | compressed.should.equal(readFile(compressedFile)); 28 | }); 29 | 30 | function parseInput() { 31 | return parse(readFile(inputFile), { source: 'input.css' }); 32 | } 33 | }); 34 | }); 35 | 36 | function readFile(file) { 37 | var src = fs.readFileSync(file, 'utf8'); 38 | // normalize line endings 39 | src = src.replace(/\r\n/, '\n'); 40 | // remove trailing newline 41 | src = src.replace(/\n$/, ''); 42 | 43 | return src; 44 | } 45 | -------------------------------------------------------------------------------- /test/cases/at-namespace/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "namespace", 7 | "namespace": "svg \"http://www.w3.org/2000/svg\"", 8 | "position": { 9 | "start": { 10 | "line": 1, 11 | "column": 1 12 | }, 13 | "end": { 14 | "line": 1, 15 | "column": 45 16 | }, 17 | "source": "input.css" 18 | } 19 | } 20 | ] 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /test/cases/at-namespace/compressed.css: -------------------------------------------------------------------------------- 1 | @namespace svg "http://www.w3.org/2000/svg"; 2 | -------------------------------------------------------------------------------- /test/cases/at-namespace/input.css: -------------------------------------------------------------------------------- 1 | @namespace svg "http://www.w3.org/2000/svg"; 2 | -------------------------------------------------------------------------------- /test/cases/at-namespace/output.css: -------------------------------------------------------------------------------- 1 | @namespace svg "http://www.w3.org/2000/svg"; 2 | -------------------------------------------------------------------------------- /test/cases/charset-linebreak/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "charset", 7 | "charset": "\"UTF-8\"", 8 | "position": { 9 | "start": { 10 | "line": 1, 11 | "column": 1 12 | }, 13 | "end": { 14 | "line": 3, 15 | "column": 6 16 | }, 17 | "source": "input.css" 18 | } 19 | } 20 | ] 21 | } 22 | } -------------------------------------------------------------------------------- /test/cases/charset-linebreak/compressed.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; -------------------------------------------------------------------------------- /test/cases/charset-linebreak/input.css: -------------------------------------------------------------------------------- 1 | @charset 2 | "UTF-8" 3 | ; 4 | -------------------------------------------------------------------------------- /test/cases/charset-linebreak/output.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; -------------------------------------------------------------------------------- /test/cases/charset/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "charset", 7 | "charset": "\"UTF-8\"", 8 | "position": { 9 | "start": { 10 | "line": 1, 11 | "column": 1 12 | }, 13 | "end": { 14 | "line": 1, 15 | "column": 18 16 | }, 17 | "source": "input.css" 18 | } 19 | }, 20 | { 21 | "type": "comment", 22 | "comment": " Set the encoding of the style sheet to Unicode UTF-8 ", 23 | "position": { 24 | "start": { 25 | "line": 1, 26 | "column": 25 27 | }, 28 | "end": { 29 | "line": 1, 30 | "column": 83 31 | }, 32 | "source": "input.css" 33 | } 34 | }, 35 | { 36 | "type": "charset", 37 | "charset": "'iso-8859-15'", 38 | "position": { 39 | "start": { 40 | "line": 2, 41 | "column": 1 42 | }, 43 | "end": { 44 | "line": 2, 45 | "column": 24 46 | }, 47 | "source": "input.css" 48 | } 49 | }, 50 | { 51 | "type": "comment", 52 | "comment": " Set the encoding of the style sheet to Latin-9 (Western European languages, with euro sign) ", 53 | "position": { 54 | "start": { 55 | "line": 2, 56 | "column": 25 57 | }, 58 | "end": { 59 | "line": 2, 60 | "column": 122 61 | }, 62 | "source": "input.css" 63 | } 64 | } 65 | ] 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /test/cases/charset/compressed.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8";@charset 'iso-8859-15'; 2 | -------------------------------------------------------------------------------- /test/cases/charset/input.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; /* Set the encoding of the style sheet to Unicode UTF-8 */ 2 | @charset 'iso-8859-15'; /* Set the encoding of the style sheet to Latin-9 (Western European languages, with euro sign) */ 3 | -------------------------------------------------------------------------------- /test/cases/charset/output.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /* Set the encoding of the style sheet to Unicode UTF-8 */ 4 | 5 | @charset 'iso-8859-15'; 6 | 7 | /* Set the encoding of the style sheet to Latin-9 (Western European languages, with euro sign) */ 8 | -------------------------------------------------------------------------------- /test/cases/colon-space/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "rule", 7 | "selectors": [ 8 | "a" 9 | ], 10 | "declarations": [ 11 | { 12 | "type": "declaration", 13 | "property": "margin", 14 | "value": "auto", 15 | "position": { 16 | "start": { 17 | "line": 2, 18 | "column": 5 19 | }, 20 | "end": { 21 | "line": 2, 22 | "column": 19 23 | }, 24 | "source": "input.css" 25 | } 26 | }, 27 | { 28 | "type": "declaration", 29 | "property": "padding", 30 | "value": "0", 31 | "position": { 32 | "start": { 33 | "line": 3, 34 | "column": 5 35 | }, 36 | "end": { 37 | "line": 3, 38 | "column": 16 39 | }, 40 | "source": "input.css" 41 | } 42 | } 43 | ], 44 | "position": { 45 | "start": { 46 | "line": 1, 47 | "column": 1 48 | }, 49 | "end": { 50 | "line": 4, 51 | "column": 2 52 | }, 53 | "source": "input.css" 54 | } 55 | } 56 | ] 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /test/cases/colon-space/compressed.css: -------------------------------------------------------------------------------- 1 | a{margin:auto;padding:0;} 2 | -------------------------------------------------------------------------------- /test/cases/colon-space/input.css: -------------------------------------------------------------------------------- 1 | a { 2 | margin : auto; 3 | padding : 0; 4 | } 5 | -------------------------------------------------------------------------------- /test/cases/colon-space/output.css: -------------------------------------------------------------------------------- 1 | a { 2 | margin: auto; 3 | padding: 0; 4 | } 5 | -------------------------------------------------------------------------------- /test/cases/comma-attribute/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "rule", 7 | "selectors": [ 8 | ".foo[bar=\"baz,quz\"]" 9 | ], 10 | "declarations": [ 11 | { 12 | "type": "declaration", 13 | "property": "foobar", 14 | "value": "123", 15 | "position": { 16 | "start": { 17 | "line": 2, 18 | "column": 3 19 | }, 20 | "end": { 21 | "line": 2, 22 | "column": 14 23 | }, 24 | "source": "input.css" 25 | } 26 | } 27 | ], 28 | "position": { 29 | "start": { 30 | "line": 1, 31 | "column": 1 32 | }, 33 | "end": { 34 | "line": 3, 35 | "column": 2 36 | }, 37 | "source": "input.css" 38 | } 39 | }, 40 | { 41 | "type": "rule", 42 | "selectors": [ 43 | ".bar", 44 | "#bar[baz=\"qux,foo\"]", 45 | "#qux" 46 | ], 47 | "declarations": [ 48 | { 49 | "type": "declaration", 50 | "property": "foobar", 51 | "value": "456", 52 | "position": { 53 | "start": { 54 | "line": 8, 55 | "column": 3 56 | }, 57 | "end": { 58 | "line": 8, 59 | "column": 14 60 | }, 61 | "source": "input.css" 62 | } 63 | } 64 | ], 65 | "position": { 66 | "start": { 67 | "line": 5, 68 | "column": 1 69 | }, 70 | "end": { 71 | "line": 9, 72 | "column": 2 73 | }, 74 | "source": "input.css" 75 | } 76 | }, 77 | { 78 | "type": "rule", 79 | "selectors": [ 80 | ".baz[qux=\",foo\"]", 81 | ".baz[qux=\"foo,\"]", 82 | ".baz[qux=\"foo,bar,baz\"]", 83 | ".baz[qux=\",foo,bar,baz,\"]", 84 | ".baz[qux=\" , foo , bar , baz , \"]" 85 | ], 86 | "declarations": [ 87 | { 88 | "type": "declaration", 89 | "property": "foobar", 90 | "value": "789", 91 | "position": { 92 | "start": { 93 | "line": 16, 94 | "column": 3 95 | }, 96 | "end": { 97 | "line": 16, 98 | "column": 14 99 | }, 100 | "source": "input.css" 101 | } 102 | } 103 | ], 104 | "position": { 105 | "start": { 106 | "line": 11, 107 | "column": 1 108 | }, 109 | "end": { 110 | "line": 17, 111 | "column": 2 112 | }, 113 | "source": "input.css" 114 | } 115 | }, 116 | { 117 | "type": "rule", 118 | "selectors": [ 119 | ".qux[foo='bar,baz']", 120 | ".qux[bar=\"baz,foo\"]", 121 | "#qux[foo=\"foobar\"]", 122 | "#qux[foo=',bar,baz, ']" 123 | ], 124 | "declarations": [ 125 | { 126 | "type": "declaration", 127 | "property": "foobar", 128 | "value": "012", 129 | "position": { 130 | "start": { 131 | "line": 23, 132 | "column": 3 133 | }, 134 | "end": { 135 | "line": 23, 136 | "column": 14 137 | }, 138 | "source": "input.css" 139 | } 140 | } 141 | ], 142 | "position": { 143 | "start": { 144 | "line": 19, 145 | "column": 1 146 | }, 147 | "end": { 148 | "line": 24, 149 | "column": 2 150 | }, 151 | "source": "input.css" 152 | } 153 | }, 154 | { 155 | "type": "rule", 156 | "selectors": [ 157 | "#foo[foo=\"\"]", 158 | "#foo[bar=\" \"]", 159 | "#foo[bar=\",\"]", 160 | "#foo[bar=\", \"]", 161 | "#foo[bar=\" ,\"]", 162 | "#foo[bar=\" , \"]", 163 | "#foo[baz='']", 164 | "#foo[qux=' ']", 165 | "#foo[qux=',']", 166 | "#foo[qux=', ']", 167 | "#foo[qux=' ,']", 168 | "#foo[qux=' , ']" 169 | ], 170 | "declarations": [ 171 | { 172 | "type": "declaration", 173 | "property": "foobar", 174 | "value": "345", 175 | "position": { 176 | "start": { 177 | "line": 38, 178 | "column": 3 179 | }, 180 | "end": { 181 | "line": 38, 182 | "column": 14 183 | }, 184 | "source": "input.css" 185 | } 186 | } 187 | ], 188 | "position": { 189 | "start": { 190 | "line": 26, 191 | "column": 1 192 | }, 193 | "end": { 194 | "line": 39, 195 | "column": 2 196 | }, 197 | "source": "input.css" 198 | } 199 | } 200 | ] 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /test/cases/comma-attribute/compressed.css: -------------------------------------------------------------------------------- 1 | .foo[bar="baz,quz"]{foobar:123;}.bar,#bar[baz="qux,foo"],#qux{foobar:456;}.baz[qux=",foo"],.baz[qux="foo,"],.baz[qux="foo,bar,baz"],.baz[qux=",foo,bar,baz,"],.baz[qux=" , foo , bar , baz , "]{foobar:789;}.qux[foo='bar,baz'],.qux[bar="baz,foo"],#qux[foo="foobar"],#qux[foo=',bar,baz, ']{foobar:012;}#foo[foo=""],#foo[bar=" "],#foo[bar=","],#foo[bar=", "],#foo[bar=" ,"],#foo[bar=" , "],#foo[baz=''],#foo[qux=' '],#foo[qux=','],#foo[qux=', '],#foo[qux=' ,'],#foo[qux=' , ']{foobar:345;} 2 | -------------------------------------------------------------------------------- /test/cases/comma-attribute/input.css: -------------------------------------------------------------------------------- 1 | .foo[bar="baz,quz"] { 2 | foobar: 123; 3 | } 4 | 5 | .bar, 6 | #bar[baz="qux,foo"], 7 | #qux { 8 | foobar: 456; 9 | } 10 | 11 | .baz[qux=",foo"], 12 | .baz[qux="foo,"], 13 | .baz[qux="foo,bar,baz"], 14 | .baz[qux=",foo,bar,baz,"], 15 | .baz[qux=" , foo , bar , baz , "] { 16 | foobar: 789; 17 | } 18 | 19 | .qux[foo='bar,baz'], 20 | .qux[bar="baz,foo"], 21 | #qux[foo="foobar"], 22 | #qux[foo=',bar,baz, '] { 23 | foobar: 012; 24 | } 25 | 26 | #foo[foo=""], 27 | #foo[bar=" "], 28 | #foo[bar=","], 29 | #foo[bar=", "], 30 | #foo[bar=" ,"], 31 | #foo[bar=" , "], 32 | #foo[baz=''], 33 | #foo[qux=' '], 34 | #foo[qux=','], 35 | #foo[qux=', '], 36 | #foo[qux=' ,'], 37 | #foo[qux=' , '] { 38 | foobar: 345; 39 | } 40 | -------------------------------------------------------------------------------- /test/cases/comma-attribute/output.css: -------------------------------------------------------------------------------- 1 | .foo[bar="baz,quz"] { 2 | foobar: 123; 3 | } 4 | 5 | .bar, 6 | #bar[baz="qux,foo"], 7 | #qux { 8 | foobar: 456; 9 | } 10 | 11 | .baz[qux=",foo"], 12 | .baz[qux="foo,"], 13 | .baz[qux="foo,bar,baz"], 14 | .baz[qux=",foo,bar,baz,"], 15 | .baz[qux=" , foo , bar , baz , "] { 16 | foobar: 789; 17 | } 18 | 19 | .qux[foo='bar,baz'], 20 | .qux[bar="baz,foo"], 21 | #qux[foo="foobar"], 22 | #qux[foo=',bar,baz, '] { 23 | foobar: 012; 24 | } 25 | 26 | #foo[foo=""], 27 | #foo[bar=" "], 28 | #foo[bar=","], 29 | #foo[bar=", "], 30 | #foo[bar=" ,"], 31 | #foo[bar=" , "], 32 | #foo[baz=''], 33 | #foo[qux=' '], 34 | #foo[qux=','], 35 | #foo[qux=', '], 36 | #foo[qux=' ,'], 37 | #foo[qux=' , '] { 38 | foobar: 345; 39 | } 40 | -------------------------------------------------------------------------------- /test/cases/comma-selector-function/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "rule", 7 | "selectors": [ 8 | ".foo:matches(.bar,.baz)", 9 | ".foo:matches(.bar, .baz)", 10 | ".foo:matches(.bar , .baz)", 11 | ".foo:matches(.bar ,.baz)" 12 | ], 13 | "declarations": [ 14 | { 15 | "type": "declaration", 16 | "property": "prop", 17 | "value": "value", 18 | "position": { 19 | "start": { 20 | "line": 5, 21 | "column": 3 22 | }, 23 | "end": { 24 | "line": 5, 25 | "column": 14 26 | }, 27 | "source": "input.css" 28 | } 29 | } 30 | ], 31 | "position": { 32 | "start": { 33 | "line": 1, 34 | "column": 1 35 | }, 36 | "end": { 37 | "line": 6, 38 | "column": 2 39 | }, 40 | "source": "input.css" 41 | } 42 | }, 43 | { 44 | "type": "rule", 45 | "selectors": [ 46 | ".foo:matches(.bar,.baz,.foobar)", 47 | ".foo:matches(.bar, .baz,)", 48 | ".foo:matches(,.bar , .baz)" 49 | ], 50 | "declarations": [ 51 | { 52 | "type": "declaration", 53 | "property": "anotherprop", 54 | "value": "anothervalue", 55 | "position": { 56 | "start": { 57 | "line": 11, 58 | "column": 3 59 | }, 60 | "end": { 61 | "line": 11, 62 | "column": 28 63 | }, 64 | "source": "input.css" 65 | } 66 | } 67 | ], 68 | "position": { 69 | "start": { 70 | "line": 8, 71 | "column": 1 72 | }, 73 | "end": { 74 | "line": 12, 75 | "column": 2 76 | }, 77 | "source": "input.css" 78 | } 79 | } 80 | ] 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /test/cases/comma-selector-function/compressed.css: -------------------------------------------------------------------------------- 1 | .foo:matches(.bar,.baz),.foo:matches(.bar, .baz),.foo:matches(.bar , .baz),.foo:matches(.bar ,.baz){prop:value;}.foo:matches(.bar,.baz,.foobar),.foo:matches(.bar, .baz,),.foo:matches(,.bar , .baz){anotherprop:anothervalue;} 2 | -------------------------------------------------------------------------------- /test/cases/comma-selector-function/input.css: -------------------------------------------------------------------------------- 1 | .foo:matches(.bar,.baz), 2 | .foo:matches(.bar, .baz), 3 | .foo:matches(.bar , .baz), 4 | .foo:matches(.bar ,.baz) { 5 | prop: value; 6 | } 7 | 8 | .foo:matches(.bar,.baz,.foobar), 9 | .foo:matches(.bar, .baz,), 10 | .foo:matches(,.bar , .baz) { 11 | anotherprop: anothervalue; 12 | } 13 | -------------------------------------------------------------------------------- /test/cases/comma-selector-function/output.css: -------------------------------------------------------------------------------- 1 | .foo:matches(.bar,.baz), 2 | .foo:matches(.bar, .baz), 3 | .foo:matches(.bar , .baz), 4 | .foo:matches(.bar ,.baz) { 5 | prop: value; 6 | } 7 | 8 | .foo:matches(.bar,.baz,.foobar), 9 | .foo:matches(.bar, .baz,), 10 | .foo:matches(,.bar , .baz) { 11 | anotherprop: anothervalue; 12 | } 13 | -------------------------------------------------------------------------------- /test/cases/comment-in/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "rule", 7 | "selectors": [ 8 | "a" 9 | ], 10 | "declarations": [ 11 | { 12 | "type": "declaration", 13 | "property": "color", 14 | "value": "12px", 15 | "position": { 16 | "start": { 17 | "line": 2, 18 | "column": 5 19 | }, 20 | "end": { 21 | "line": 2, 22 | "column": 20 23 | }, 24 | "source": "input.css" 25 | } 26 | }, 27 | { 28 | "type": "declaration", 29 | "property": "padding", 30 | "value": "1px 2px 3px", 31 | "position": { 32 | "start": { 33 | "line": 3, 34 | "column": 5 35 | }, 36 | "end": { 37 | "line": 3, 38 | "column": 51 39 | }, 40 | "source": "input.css" 41 | } 42 | }, 43 | { 44 | "type": "declaration", 45 | "property": "border", 46 | "value": "solid", 47 | "position": { 48 | "start": { 49 | "line": 4, 50 | "column": 5 51 | }, 52 | "end": { 53 | "line": 4, 54 | "column": 24 55 | }, 56 | "source": "input.css" 57 | } 58 | }, 59 | { 60 | "type": "declaration", 61 | "property": "border-top", 62 | "value": "none\\9", 63 | "position": { 64 | "start": { 65 | "line": 4, 66 | "column": 26 67 | }, 68 | "end": { 69 | "line": 4, 70 | "column": 50 71 | }, 72 | "source": "input.css" 73 | } 74 | } 75 | ], 76 | "position": { 77 | "start": { 78 | "line": 1, 79 | "column": 1 80 | }, 81 | "end": { 82 | "line": 5, 83 | "column": 2 84 | }, 85 | "source": "input.css" 86 | } 87 | } 88 | ] 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /test/cases/comment-in/compressed.css: -------------------------------------------------------------------------------- 1 | a{color:12px;padding:1px 2px 3px;border:solid;border-top:none\9;} 2 | -------------------------------------------------------------------------------- /test/cases/comment-in/input.css: -------------------------------------------------------------------------------- 1 | a { 2 | color/**/: 12px; 3 | padding/*4815162342*/: 1px /**/ 2px /*13*/ 3px; 4 | border/*\**/: solid; border-top/*\**/: none\9; 5 | } 6 | -------------------------------------------------------------------------------- /test/cases/comment-in/output.css: -------------------------------------------------------------------------------- 1 | a { 2 | color: 12px; 3 | padding: 1px 2px 3px; 4 | border: solid; 5 | border-top: none\9; 6 | } 7 | -------------------------------------------------------------------------------- /test/cases/comment-url/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "comment", 7 | "comment": " http://foo.com/bar/baz.html ", 8 | "position": { 9 | "start": { 10 | "line": 1, 11 | "column": 1 12 | }, 13 | "end": { 14 | "line": 1, 15 | "column": 34 16 | }, 17 | "source": "input.css" 18 | } 19 | }, 20 | { 21 | "type": "comment", 22 | "comment": "", 23 | "position": { 24 | "start": { 25 | "line": 2, 26 | "column": 1 27 | }, 28 | "end": { 29 | "line": 2, 30 | "column": 5 31 | }, 32 | "source": "input.css" 33 | } 34 | }, 35 | { 36 | "type": "rule", 37 | "selectors": [ 38 | "foo" 39 | ], 40 | "declarations": [ 41 | { 42 | "type": "comment", 43 | "comment": "/", 44 | "position": { 45 | "start": { 46 | "line": 4, 47 | "column": 7 48 | }, 49 | "end": { 50 | "line": 4, 51 | "column": 12 52 | }, 53 | "source": "input.css" 54 | } 55 | }, 56 | { 57 | "type": "comment", 58 | "comment": " something ", 59 | "position": { 60 | "start": { 61 | "line": 5, 62 | "column": 3 63 | }, 64 | "end": { 65 | "line": 5, 66 | "column": 18 67 | }, 68 | "source": "input.css" 69 | } 70 | }, 71 | { 72 | "type": "declaration", 73 | "property": "bar", 74 | "value": "baz", 75 | "position": { 76 | "start": { 77 | "line": 6, 78 | "column": 3 79 | }, 80 | "end": { 81 | "line": 6, 82 | "column": 11 83 | }, 84 | "source": "input.css" 85 | } 86 | }, 87 | { 88 | "type": "comment", 89 | "comment": " http://foo.com/bar/baz.html ", 90 | "position": { 91 | "start": { 92 | "line": 6, 93 | "column": 13 94 | }, 95 | "end": { 96 | "line": 6, 97 | "column": 46 98 | }, 99 | "source": "input.css" 100 | } 101 | } 102 | ], 103 | "position": { 104 | "start": { 105 | "line": 4, 106 | "column": 1 107 | }, 108 | "end": { 109 | "line": 7, 110 | "column": 2 111 | }, 112 | "source": "input.css" 113 | } 114 | } 115 | ] 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /test/cases/comment-url/compressed.css: -------------------------------------------------------------------------------- 1 | foo{bar:baz;} 2 | -------------------------------------------------------------------------------- /test/cases/comment-url/input.css: -------------------------------------------------------------------------------- 1 | /* http://foo.com/bar/baz.html */ 2 | /**/ 3 | 4 | foo { /*/*/ 5 | /* something */ 6 | bar: baz; /* http://foo.com/bar/baz.html */ 7 | } 8 | -------------------------------------------------------------------------------- /test/cases/comment-url/output.css: -------------------------------------------------------------------------------- 1 | /* http://foo.com/bar/baz.html */ 2 | 3 | /**/ 4 | 5 | foo { 6 | /*/*/ 7 | /* something */ 8 | bar: baz; 9 | /* http://foo.com/bar/baz.html */ 10 | } 11 | -------------------------------------------------------------------------------- /test/cases/comment/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "comment", 7 | "comment": " 1 ", 8 | "position": { 9 | "start": { 10 | "line": 1, 11 | "column": 1 12 | }, 13 | "end": { 14 | "line": 1, 15 | "column": 8 16 | }, 17 | "source": "input.css" 18 | } 19 | }, 20 | { 21 | "type": "rule", 22 | "selectors": [ 23 | "head", 24 | "body" 25 | ], 26 | "declarations": [ 27 | { 28 | "type": "comment", 29 | "comment": " 2 ", 30 | "position": { 31 | "start": { 32 | "line": 3, 33 | "column": 37 34 | }, 35 | "end": { 36 | "line": 3, 37 | "column": 44 38 | }, 39 | "source": "input.css" 40 | } 41 | }, 42 | { 43 | "type": "comment", 44 | "comment": " 3 ", 45 | "position": { 46 | "start": { 47 | "line": 4, 48 | "column": 3 49 | }, 50 | "end": { 51 | "line": 4, 52 | "column": 10 53 | }, 54 | "source": "input.css" 55 | } 56 | }, 57 | { 58 | "type": "comment", 59 | "comment": "", 60 | "position": { 61 | "start": { 62 | "line": 5, 63 | "column": 3 64 | }, 65 | "end": { 66 | "line": 5, 67 | "column": 7 68 | }, 69 | "source": "input.css" 70 | } 71 | }, 72 | { 73 | "type": "declaration", 74 | "property": "foo", 75 | "value": "'bar'", 76 | "position": { 77 | "start": { 78 | "line": 5, 79 | "column": 7 80 | }, 81 | "end": { 82 | "line": 5, 83 | "column": 17 84 | }, 85 | "source": "input.css" 86 | } 87 | }, 88 | { 89 | "type": "comment", 90 | "comment": " 4 ", 91 | "position": { 92 | "start": { 93 | "line": 6, 94 | "column": 3 95 | }, 96 | "end": { 97 | "line": 6, 98 | "column": 10 99 | }, 100 | "source": "input.css" 101 | } 102 | } 103 | ], 104 | "position": { 105 | "start": { 106 | "line": 3, 107 | "column": 1 108 | }, 109 | "end": { 110 | "line": 7, 111 | "column": 2 112 | }, 113 | "source": "input.css" 114 | } 115 | }, 116 | { 117 | "type": "comment", 118 | "comment": " 5 ", 119 | "position": { 120 | "start": { 121 | "line": 7, 122 | "column": 3 123 | }, 124 | "end": { 125 | "line": 7, 126 | "column": 10 127 | }, 128 | "source": "input.css" 129 | } 130 | }, 131 | { 132 | "type": "comment", 133 | "comment": " 6 ", 134 | "position": { 135 | "start": { 136 | "line": 9, 137 | "column": 1 138 | }, 139 | "end": { 140 | "line": 9, 141 | "column": 8 142 | }, 143 | "source": "input.css" 144 | } 145 | } 146 | ] 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /test/cases/comment/compressed.css: -------------------------------------------------------------------------------- 1 | head,body{foo:'bar';} 2 | -------------------------------------------------------------------------------- /test/cases/comment/input.css: -------------------------------------------------------------------------------- 1 | /* 1 */ 2 | 3 | head, /* footer, */body/*, nav */ { /* 2 */ 4 | /* 3 */ 5 | /**/foo: 'bar'; 6 | /* 4 */ 7 | } /* 5 */ 8 | 9 | /* 6 */ 10 | -------------------------------------------------------------------------------- /test/cases/comment/output.css: -------------------------------------------------------------------------------- 1 | /* 1 */ 2 | 3 | head, 4 | body { 5 | /* 2 */ 6 | /* 3 */ 7 | /**/ 8 | foo: 'bar'; 9 | /* 4 */ 10 | } 11 | 12 | /* 5 */ 13 | 14 | /* 6 */ 15 | -------------------------------------------------------------------------------- /test/cases/custom-media-linebreak/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "custom-media", 7 | "name": "--test", 8 | "media": "(min-width: 200px)", 9 | "position": { 10 | "start": { 11 | "line": 1, 12 | "column": 1 13 | }, 14 | "end": { 15 | "line": 4, 16 | "column": 2 17 | }, 18 | "source": "input.css" 19 | } 20 | } 21 | ] 22 | } 23 | } -------------------------------------------------------------------------------- /test/cases/custom-media-linebreak/compressed.css: -------------------------------------------------------------------------------- 1 | @custom-media --test (min-width: 200px); -------------------------------------------------------------------------------- /test/cases/custom-media-linebreak/input.css: -------------------------------------------------------------------------------- 1 | @custom-media 2 | --test 3 | (min-width: 200px) 4 | ; 5 | -------------------------------------------------------------------------------- /test/cases/custom-media-linebreak/output.css: -------------------------------------------------------------------------------- 1 | @custom-media --test (min-width: 200px); -------------------------------------------------------------------------------- /test/cases/custom-media/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "custom-media", 7 | "name": "--narrow-window", 8 | "media": "(max-width: 30em)", 9 | "position": { 10 | "start": { 11 | "line": 1, 12 | "column": 1 13 | }, 14 | "end": { 15 | "line": 1, 16 | "column": 49 17 | }, 18 | "source": "input.css" 19 | } 20 | }, 21 | { 22 | "type": "custom-media", 23 | "name": "--wide-window", 24 | "media": "screen and (min-width: 40em)", 25 | "position": { 26 | "start": { 27 | "line": 2, 28 | "column": 1 29 | }, 30 | "end": { 31 | "line": 2, 32 | "column": 58 33 | }, 34 | "source": "input.css" 35 | } 36 | } 37 | ] 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /test/cases/custom-media/compressed.css: -------------------------------------------------------------------------------- 1 | @custom-media --narrow-window (max-width: 30em);@custom-media --wide-window screen and (min-width: 40em); 2 | -------------------------------------------------------------------------------- /test/cases/custom-media/input.css: -------------------------------------------------------------------------------- 1 | @custom-media --narrow-window (max-width: 30em); 2 | @custom-media --wide-window screen and (min-width: 40em); 3 | -------------------------------------------------------------------------------- /test/cases/custom-media/output.css: -------------------------------------------------------------------------------- 1 | @custom-media --narrow-window (max-width: 30em); 2 | 3 | @custom-media --wide-window screen and (min-width: 40em); 4 | -------------------------------------------------------------------------------- /test/cases/data-url/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "rule", 7 | "selectors": [ 8 | ".foo" 9 | ], 10 | "declarations": [ 11 | { 12 | "type": "declaration", 13 | "property": "background-image", 14 | "value": "url(\"data:image/svg+xml;charset=utf8,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220 0 13 9%22%20preserveAspectRatio%3D%22none%22%3E%0A%09%3Cpath%20fill%3D%22rgba(5,178,189,.99)%22%20d%3D%22M8.53 0L7.19 1.352l2.18 2.193H0v1.912h9.37L7.19 7.65l1.34 1.352 4.47-4.5z%22%20%2F%3E%0A%3C%2Fsvg%3E\")", 15 | "position": { 16 | "start": { 17 | "line": 1, 18 | "column": 6 19 | }, 20 | "end": { 21 | "line": 1, 22 | "column": 366 23 | }, 24 | "source": "input.css" 25 | } 26 | } 27 | ], 28 | "position": { 29 | "start": { 30 | "line": 1, 31 | "column": 1 32 | }, 33 | "end": { 34 | "line": 1, 35 | "column": 367 36 | }, 37 | "source": "input.css" 38 | } 39 | }, 40 | { 41 | "type": "rule", 42 | "selectors": [ 43 | ".bar" 44 | ], 45 | "declarations": [ 46 | { 47 | "type": "declaration", 48 | "property": "background-image", 49 | "value": "url(\"data:image/svg+xml;charset=utf8,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220 0 25 21%22%20preserveAspectRatio%3D%22none%22%3E%0A%09%3Cpath%20fill%3D%22rgba(5,46,73,.99)%22%20d%3D%22M7.5,15.6l-4.8-4.9L0,13.4l6.4,6.5l0,0L7.5,21l18-18.3L22.8,0L7.5,15.6z%22%20%2F%3E%0A%3C%2Fsvg%3E\")", 50 | "position": { 51 | "start": { 52 | "line": 1, 53 | "column": 372 54 | }, 55 | "end": { 56 | "line": 1, 57 | "column": 727 58 | }, 59 | "source": "input.css" 60 | } 61 | } 62 | ], 63 | "position": { 64 | "start": { 65 | "line": 1, 66 | "column": 367 67 | }, 68 | "end": { 69 | "line": 1, 70 | "column": 728 71 | }, 72 | "source": "input.css" 73 | } 74 | } 75 | ], 76 | "parsingErrors": [] 77 | } 78 | } -------------------------------------------------------------------------------- /test/cases/data-url/compressed.css: -------------------------------------------------------------------------------- 1 | .foo{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220 0 13 9%22%20preserveAspectRatio%3D%22none%22%3E%0A%09%3Cpath%20fill%3D%22rgba(5,178,189,.99)%22%20d%3D%22M8.53 0L7.19 1.352l2.18 2.193H0v1.912h9.37L7.19 7.65l1.34 1.352 4.47-4.5z%22%20%2F%3E%0A%3C%2Fsvg%3E");}.bar{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220 0 25 21%22%20preserveAspectRatio%3D%22none%22%3E%0A%09%3Cpath%20fill%3D%22rgba(5,46,73,.99)%22%20d%3D%22M7.5,15.6l-4.8-4.9L0,13.4l6.4,6.5l0,0L7.5,21l18-18.3L22.8,0L7.5,15.6z%22%20%2F%3E%0A%3C%2Fsvg%3E");} -------------------------------------------------------------------------------- /test/cases/data-url/input.css: -------------------------------------------------------------------------------- 1 | .foo{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220 0 13 9%22%20preserveAspectRatio%3D%22none%22%3E%0A%09%3Cpath%20fill%3D%22rgba(5,178,189,.99)%22%20d%3D%22M8.53 0L7.19 1.352l2.18 2.193H0v1.912h9.37L7.19 7.65l1.34 1.352 4.47-4.5z%22%20%2F%3E%0A%3C%2Fsvg%3E")}.bar{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220 0 25 21%22%20preserveAspectRatio%3D%22none%22%3E%0A%09%3Cpath%20fill%3D%22rgba(5,46,73,.99)%22%20d%3D%22M7.5,15.6l-4.8-4.9L0,13.4l6.4,6.5l0,0L7.5,21l18-18.3L22.8,0L7.5,15.6z%22%20%2F%3E%0A%3C%2Fsvg%3E")} -------------------------------------------------------------------------------- /test/cases/data-url/output.css: -------------------------------------------------------------------------------- 1 | .foo { 2 | background-image: url("data:image/svg+xml;charset=utf8,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220 0 13 9%22%20preserveAspectRatio%3D%22none%22%3E%0A%09%3Cpath%20fill%3D%22rgba(5,178,189,.99)%22%20d%3D%22M8.53 0L7.19 1.352l2.18 2.193H0v1.912h9.37L7.19 7.65l1.34 1.352 4.47-4.5z%22%20%2F%3E%0A%3C%2Fsvg%3E"); 3 | } 4 | 5 | .bar { 6 | background-image: url("data:image/svg+xml;charset=utf8,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220 0 25 21%22%20preserveAspectRatio%3D%22none%22%3E%0A%09%3Cpath%20fill%3D%22rgba(5,46,73,.99)%22%20d%3D%22M7.5,15.6l-4.8-4.9L0,13.4l6.4,6.5l0,0L7.5,21l18-18.3L22.8,0L7.5,15.6z%22%20%2F%3E%0A%3C%2Fsvg%3E"); 7 | } -------------------------------------------------------------------------------- /test/cases/document-linebreak/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "document", 7 | "document": "url-prefix()", 8 | "vendor": "", 9 | "rules": [ 10 | { 11 | "type": "rule", 12 | "selectors": [ 13 | ".test" 14 | ], 15 | "declarations": [ 16 | { 17 | "type": "declaration", 18 | "property": "color", 19 | "value": "blue", 20 | "position": { 21 | "start": { 22 | "line": 6, 23 | "column": 13 24 | }, 25 | "end": { 26 | "line": 6, 27 | "column": 24 28 | }, 29 | "source": "input.css" 30 | } 31 | } 32 | ], 33 | "position": { 34 | "start": { 35 | "line": 5, 36 | "column": 9 37 | }, 38 | "end": { 39 | "line": 7, 40 | "column": 10 41 | }, 42 | "source": "input.css" 43 | } 44 | } 45 | ], 46 | "position": { 47 | "start": { 48 | "line": 1, 49 | "column": 1 50 | }, 51 | "end": { 52 | "line": 9, 53 | "column": 6 54 | }, 55 | "source": "input.css" 56 | } 57 | } 58 | ] 59 | } 60 | } -------------------------------------------------------------------------------- /test/cases/document-linebreak/compressed.css: -------------------------------------------------------------------------------- 1 | @document url-prefix(){.test{color:blue;}} -------------------------------------------------------------------------------- /test/cases/document-linebreak/input.css: -------------------------------------------------------------------------------- 1 | @document 2 | url-prefix() 3 | { 4 | 5 | .test { 6 | color: blue; 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /test/cases/document-linebreak/output.css: -------------------------------------------------------------------------------- 1 | @document url-prefix() { 2 | .test { 3 | color: blue; 4 | } 5 | } -------------------------------------------------------------------------------- /test/cases/document/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "document", 7 | "document": "url-prefix()", 8 | "vendor": "-moz-", 9 | "rules": [ 10 | { 11 | "type": "comment", 12 | "comment": " ui above ", 13 | "position": { 14 | "start": { 15 | "line": 2, 16 | "column": 3 17 | }, 18 | "end": { 19 | "line": 2, 20 | "column": 17 21 | }, 22 | "source": "input.css" 23 | } 24 | }, 25 | { 26 | "type": "rule", 27 | "selectors": [ 28 | ".ui-select .ui-btn select" 29 | ], 30 | "declarations": [ 31 | { 32 | "type": "comment", 33 | "comment": " ui inside ", 34 | "position": { 35 | "start": { 36 | "line": 4, 37 | "column": 5 38 | }, 39 | "end": { 40 | "line": 4, 41 | "column": 20 42 | }, 43 | "source": "input.css" 44 | } 45 | }, 46 | { 47 | "type": "declaration", 48 | "property": "opacity", 49 | "value": ".0001", 50 | "position": { 51 | "start": { 52 | "line": 5, 53 | "column": 5 54 | }, 55 | "end": { 56 | "line": 6, 57 | "column": 3 58 | }, 59 | "source": "input.css" 60 | } 61 | } 62 | ], 63 | "position": { 64 | "start": { 65 | "line": 3, 66 | "column": 3 67 | }, 68 | "end": { 69 | "line": 6, 70 | "column": 4 71 | }, 72 | "source": "input.css" 73 | } 74 | }, 75 | { 76 | "type": "rule", 77 | "selectors": [ 78 | ".icon-spin" 79 | ], 80 | "declarations": [ 81 | { 82 | "type": "declaration", 83 | "property": "height", 84 | "value": ".9em", 85 | "position": { 86 | "start": { 87 | "line": 9, 88 | "column": 5 89 | }, 90 | "end": { 91 | "line": 9, 92 | "column": 17 93 | }, 94 | "source": "input.css" 95 | } 96 | } 97 | ], 98 | "position": { 99 | "start": { 100 | "line": 8, 101 | "column": 3 102 | }, 103 | "end": { 104 | "line": 10, 105 | "column": 4 106 | }, 107 | "source": "input.css" 108 | } 109 | } 110 | ], 111 | "position": { 112 | "start": { 113 | "line": 1, 114 | "column": 1 115 | }, 116 | "end": { 117 | "line": 11, 118 | "column": 2 119 | }, 120 | "source": "input.css" 121 | } 122 | } 123 | ] 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /test/cases/document/compressed.css: -------------------------------------------------------------------------------- 1 | @-moz-document url-prefix(){.ui-select .ui-btn select{opacity:.0001;}.icon-spin{height:.9em;}} 2 | -------------------------------------------------------------------------------- /test/cases/document/input.css: -------------------------------------------------------------------------------- 1 | @-moz-document url-prefix() { 2 | /* ui above */ 3 | .ui-select .ui-btn select { 4 | /* ui inside */ 5 | opacity:.0001 6 | } 7 | 8 | .icon-spin { 9 | height: .9em; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test/cases/document/output.css: -------------------------------------------------------------------------------- 1 | @-moz-document url-prefix() { 2 | /* ui above */ 3 | 4 | .ui-select .ui-btn select { 5 | /* ui inside */ 6 | opacity: .0001; 7 | } 8 | 9 | .icon-spin { 10 | height: .9em; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/cases/empty/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [] 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/cases/empty/compressed.css: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /test/cases/empty/input.css: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /test/cases/empty/output.css: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /test/cases/escapes/compressed.css: -------------------------------------------------------------------------------- 1 | html{font:1.2em/1.6 Arial;}code{font-family:Consolas;}li code{background:rgba(255, 255, 255, .5);padding:.3em;}li{background:orange;}#♥{background:lime;}#©{background:lime;}#“‘’”{background:lime;}#☺☃{background:lime;}#⌘⌥{background:lime;}#𝄞♪♩♫♬{background:lime;}#\?{background:lime;}#\@{background:lime;}#\.{background:lime;}#\3A \){background:lime;}#\3A \`\({background:lime;}#\31 23{background:lime;}#\31 a2b3c{background:lime;}#\{background:lime;}#\<\>\<\<\<\>\>\<\>{background:lime;}#\+\+\+\+\+\+\+\+\+\+\[\>\+\+\+\+\+\+\+\>\+\+\+\+\+\+\+\+\+\+\>\+\+\+\>\+\<\<\<\<\-\]\>\+\+\.\>\+\.\+\+\+\+\+\+\+\.\.\+\+\+\.\>\+\+\.\<\<\+\+\+\+\+\+\+\+\+\+\+\+\+\+\+\.\>\.\+\+\+\.\-\-\-\-\-\-\.\-\-\-\-\-\-\-\-\.\>\+\.\>\.{background:lime;}#\#{background:lime;}#\#\#{background:lime;}#\#\.\#\.\#{background:lime;}#\_{background:lime;}#\.fake\-class{background:lime;}#foo\.bar{background:lime;}#\3A hover{background:lime;}#\3A hover\3A focus\3A active{background:lime;}#\[attr\=value\]{background:lime;}#f\/o\/o{background:lime;}#f\\o\\o{background:lime;}#f\*o\*o{background:lime;}#f\!o\!o{background:lime;}#f\'o\'o{background:lime;}#f\~o\~o{background:lime;}#f\+o\+o{background:lime;} 2 | -------------------------------------------------------------------------------- /test/cases/escapes/input.css: -------------------------------------------------------------------------------- 1 | /* tests compressed for easy testing */ 2 | /* http://mathiasbynens.be/notes/css-escapes */ 3 | /* will match elements with class=":`(" */ 4 | .\3A \`\({} 5 | /* will match elements with class="1a2b3c" */ 6 | .\31 a2b3c{} 7 | /* will match the element with id="#fake-id" */ 8 | #\#fake-id{} 9 | /* will match the element with id="---" */ 10 | #\---{} 11 | /* will match the element with id="-a-b-c-" */ 12 | #-a-b-c-{} 13 | /* will match the element with id="©" */ 14 | #©{} 15 | /* More tests from http://mathiasbynens.be/demo/html5-id */ 16 | html{font:1.2em/1.6 Arial;} 17 | code{font-family:Consolas;} 18 | li code{background:rgba(255, 255, 255, .5);padding:.3em;} 19 | li{background:orange;} 20 | #♥{background:lime;} 21 | #©{background:lime;} 22 | #“‘’”{background:lime;} 23 | #☺☃{background:lime;} 24 | #⌘⌥{background:lime;} 25 | #𝄞♪♩♫♬{background:lime;} 26 | #\?{background:lime;} 27 | #\@{background:lime;} 28 | #\.{background:lime;} 29 | #\3A \){background:lime;} 30 | #\3A \`\({background:lime;} 31 | #\31 23{background:lime;} 32 | #\31 a2b3c{background:lime;} 33 | #\{background:lime;} 34 | #\<\>\<\<\<\>\>\<\>{background:lime;} 35 | #\+\+\+\+\+\+\+\+\+\+\[\>\+\+\+\+\+\+\+\>\+\+\+\+\+\+\+\+\+\+\>\+\+\+\>\+\<\<\<\<\-\]\>\+\+\.\>\+\.\+\+\+\+\+\+\+\.\.\+\+\+\.\>\+\+\.\<\<\+\+\+\+\+\+\+\+\+\+\+\+\+\+\+\.\>\.\+\+\+\.\-\-\-\-\-\-\.\-\-\-\-\-\-\-\-\.\>\+\.\>\.{background:lime;} 36 | #\#{background:lime;} 37 | #\#\#{background:lime;} 38 | #\#\.\#\.\#{background:lime;} 39 | #\_{background:lime;} 40 | #\.fake\-class{background:lime;} 41 | #foo\.bar{background:lime;} 42 | #\3A hover{background:lime;} 43 | #\3A hover\3A focus\3A active{background:lime;} 44 | #\[attr\=value\]{background:lime;} 45 | #f\/o\/o{background:lime;} 46 | #f\\o\\o{background:lime;} 47 | #f\*o\*o{background:lime;} 48 | #f\!o\!o{background:lime;} 49 | #f\'o\'o{background:lime;} 50 | #f\~o\~o{background:lime;} 51 | #f\+o\+o{background:lime;} 52 | 53 | /* css-parse does not yet pass this test */ 54 | /*#\{\}{background:lime;}*/ 55 | -------------------------------------------------------------------------------- /test/cases/escapes/output.css: -------------------------------------------------------------------------------- 1 | /* tests compressed for easy testing */ 2 | 3 | /* http://mathiasbynens.be/notes/css-escapes */ 4 | 5 | /* will match elements with class=":`(" */ 6 | 7 | 8 | 9 | /* will match elements with class="1a2b3c" */ 10 | 11 | 12 | 13 | /* will match the element with id="#fake-id" */ 14 | 15 | 16 | 17 | /* will match the element with id="---" */ 18 | 19 | 20 | 21 | /* will match the element with id="-a-b-c-" */ 22 | 23 | 24 | 25 | /* will match the element with id="©" */ 26 | 27 | 28 | 29 | /* More tests from http://mathiasbynens.be/demo/html5-id */ 30 | 31 | html { 32 | font: 1.2em/1.6 Arial; 33 | } 34 | 35 | code { 36 | font-family: Consolas; 37 | } 38 | 39 | li code { 40 | background: rgba(255, 255, 255, .5); 41 | padding: .3em; 42 | } 43 | 44 | li { 45 | background: orange; 46 | } 47 | 48 | #♥ { 49 | background: lime; 50 | } 51 | 52 | #© { 53 | background: lime; 54 | } 55 | 56 | #“‘’” { 57 | background: lime; 58 | } 59 | 60 | #☺☃ { 61 | background: lime; 62 | } 63 | 64 | #⌘⌥ { 65 | background: lime; 66 | } 67 | 68 | #𝄞♪♩♫♬ { 69 | background: lime; 70 | } 71 | 72 | #\? { 73 | background: lime; 74 | } 75 | 76 | #\@ { 77 | background: lime; 78 | } 79 | 80 | #\. { 81 | background: lime; 82 | } 83 | 84 | #\3A \) { 85 | background: lime; 86 | } 87 | 88 | #\3A \`\( { 89 | background: lime; 90 | } 91 | 92 | #\31 23 { 93 | background: lime; 94 | } 95 | 96 | #\31 a2b3c { 97 | background: lime; 98 | } 99 | 100 | #\ { 101 | background: lime; 102 | } 103 | 104 | #\<\>\<\<\<\>\>\<\> { 105 | background: lime; 106 | } 107 | 108 | #\+\+\+\+\+\+\+\+\+\+\[\>\+\+\+\+\+\+\+\>\+\+\+\+\+\+\+\+\+\+\>\+\+\+\>\+\<\<\<\<\-\]\>\+\+\.\>\+\.\+\+\+\+\+\+\+\.\.\+\+\+\.\>\+\+\.\<\<\+\+\+\+\+\+\+\+\+\+\+\+\+\+\+\.\>\.\+\+\+\.\-\-\-\-\-\-\.\-\-\-\-\-\-\-\-\.\>\+\.\>\. { 109 | background: lime; 110 | } 111 | 112 | #\# { 113 | background: lime; 114 | } 115 | 116 | #\#\# { 117 | background: lime; 118 | } 119 | 120 | #\#\.\#\.\# { 121 | background: lime; 122 | } 123 | 124 | #\_ { 125 | background: lime; 126 | } 127 | 128 | #\.fake\-class { 129 | background: lime; 130 | } 131 | 132 | #foo\.bar { 133 | background: lime; 134 | } 135 | 136 | #\3A hover { 137 | background: lime; 138 | } 139 | 140 | #\3A hover\3A focus\3A active { 141 | background: lime; 142 | } 143 | 144 | #\[attr\=value\] { 145 | background: lime; 146 | } 147 | 148 | #f\/o\/o { 149 | background: lime; 150 | } 151 | 152 | #f\\o\\o { 153 | background: lime; 154 | } 155 | 156 | #f\*o\*o { 157 | background: lime; 158 | } 159 | 160 | #f\!o\!o { 161 | background: lime; 162 | } 163 | 164 | #f\'o\'o { 165 | background: lime; 166 | } 167 | 168 | #f\~o\~o { 169 | background: lime; 170 | } 171 | 172 | #f\+o\+o { 173 | background: lime; 174 | } 175 | 176 | /* css-parse does not yet pass this test */ 177 | 178 | /*#\{\}{background:lime;}*/ 179 | -------------------------------------------------------------------------------- /test/cases/font-face-linebreak/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "font-face", 7 | "declarations": [ 8 | { 9 | "type": "declaration", 10 | "property": "font-family", 11 | "value": "\"Bitstream Vera Serif Bold\"", 12 | "position": { 13 | "start": { 14 | "line": 4, 15 | "column": 3 16 | }, 17 | "end": { 18 | "line": 4, 19 | "column": 43 20 | }, 21 | "source": "input.css" 22 | } 23 | }, 24 | { 25 | "type": "declaration", 26 | "property": "src", 27 | "value": "url(\"http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf\")", 28 | "position": { 29 | "start": { 30 | "line": 5, 31 | "column": 3 32 | }, 33 | "end": { 34 | "line": 5, 35 | "column": 78 36 | }, 37 | "source": "input.css" 38 | } 39 | } 40 | ], 41 | "position": { 42 | "start": { 43 | "line": 1, 44 | "column": 1 45 | }, 46 | "end": { 47 | "line": 6, 48 | "column": 2 49 | }, 50 | "source": "input.css" 51 | } 52 | }, 53 | { 54 | "type": "rule", 55 | "selectors": [ 56 | "body" 57 | ], 58 | "declarations": [ 59 | { 60 | "type": "declaration", 61 | "property": "font-family", 62 | "value": "\"Bitstream Vera Serif Bold\", serif", 63 | "position": { 64 | "start": { 65 | "line": 9, 66 | "column": 3 67 | }, 68 | "end": { 69 | "line": 9, 70 | "column": 50 71 | }, 72 | "source": "input.css" 73 | } 74 | } 75 | ], 76 | "position": { 77 | "start": { 78 | "line": 8, 79 | "column": 1 80 | }, 81 | "end": { 82 | "line": 10, 83 | "column": 2 84 | }, 85 | "source": "input.css" 86 | } 87 | } 88 | ] 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /test/cases/font-face-linebreak/compressed.css: -------------------------------------------------------------------------------- 1 | @font-face{font-family:"Bitstream Vera Serif Bold";src:url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");}body{font-family:"Bitstream Vera Serif Bold", serif;} 2 | -------------------------------------------------------------------------------- /test/cases/font-face-linebreak/input.css: -------------------------------------------------------------------------------- 1 | @font-face 2 | 3 | { 4 | font-family: "Bitstream Vera Serif Bold"; 5 | src: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf"); 6 | } 7 | 8 | body { 9 | font-family: "Bitstream Vera Serif Bold", serif; 10 | } 11 | -------------------------------------------------------------------------------- /test/cases/font-face-linebreak/output.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: "Bitstream Vera Serif Bold"; 3 | src: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf"); 4 | } 5 | 6 | body { 7 | font-family: "Bitstream Vera Serif Bold", serif; 8 | } 9 | -------------------------------------------------------------------------------- /test/cases/font-face/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "font-face", 7 | "declarations": [ 8 | { 9 | "type": "declaration", 10 | "property": "font-family", 11 | "value": "\"Bitstream Vera Serif Bold\"", 12 | "position": { 13 | "start": { 14 | "line": 2, 15 | "column": 3 16 | }, 17 | "end": { 18 | "line": 2, 19 | "column": 43 20 | }, 21 | "source": "input.css" 22 | } 23 | }, 24 | { 25 | "type": "declaration", 26 | "property": "src", 27 | "value": "url(\"http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf\")", 28 | "position": { 29 | "start": { 30 | "line": 3, 31 | "column": 3 32 | }, 33 | "end": { 34 | "line": 3, 35 | "column": 78 36 | }, 37 | "source": "input.css" 38 | } 39 | } 40 | ], 41 | "position": { 42 | "start": { 43 | "line": 1, 44 | "column": 1 45 | }, 46 | "end": { 47 | "line": 4, 48 | "column": 2 49 | }, 50 | "source": "input.css" 51 | } 52 | }, 53 | { 54 | "type": "rule", 55 | "selectors": [ 56 | "body" 57 | ], 58 | "declarations": [ 59 | { 60 | "type": "declaration", 61 | "property": "font-family", 62 | "value": "\"Bitstream Vera Serif Bold\", serif", 63 | "position": { 64 | "start": { 65 | "line": 7, 66 | "column": 3 67 | }, 68 | "end": { 69 | "line": 7, 70 | "column": 50 71 | }, 72 | "source": "input.css" 73 | } 74 | } 75 | ], 76 | "position": { 77 | "start": { 78 | "line": 6, 79 | "column": 1 80 | }, 81 | "end": { 82 | "line": 8, 83 | "column": 2 84 | }, 85 | "source": "input.css" 86 | } 87 | } 88 | ] 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /test/cases/font-face/compressed.css: -------------------------------------------------------------------------------- 1 | @font-face{font-family:"Bitstream Vera Serif Bold";src:url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");}body{font-family:"Bitstream Vera Serif Bold", serif;} 2 | -------------------------------------------------------------------------------- /test/cases/font-face/input.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: "Bitstream Vera Serif Bold"; 3 | src: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf"); 4 | } 5 | 6 | body { 7 | font-family: "Bitstream Vera Serif Bold", serif; 8 | } 9 | -------------------------------------------------------------------------------- /test/cases/font-face/output.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: "Bitstream Vera Serif Bold"; 3 | src: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf"); 4 | } 5 | 6 | body { 7 | font-family: "Bitstream Vera Serif Bold", serif; 8 | } 9 | -------------------------------------------------------------------------------- /test/cases/hose-linebreak/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "host", 7 | "rules": [ 8 | { 9 | "type": "rule", 10 | "selectors": [ 11 | ":scope" 12 | ], 13 | "declarations": [ 14 | { 15 | "type": "declaration", 16 | "property": "color", 17 | "value": "white", 18 | "position": { 19 | "start": { 20 | "line": 3, 21 | "column": 18 22 | }, 23 | "end": { 24 | "line": 3, 25 | "column": 30 26 | }, 27 | "source": "input.css" 28 | } 29 | } 30 | ], 31 | "position": { 32 | "start": { 33 | "line": 3, 34 | "column": 9 35 | }, 36 | "end": { 37 | "line": 3, 38 | "column": 33 39 | }, 40 | "source": "input.css" 41 | } 42 | } 43 | ], 44 | "position": { 45 | "start": { 46 | "line": 1, 47 | "column": 1 48 | }, 49 | "end": { 50 | "line": 4, 51 | "column": 6 52 | }, 53 | "source": "input.css" 54 | } 55 | } 56 | ] 57 | } 58 | } -------------------------------------------------------------------------------- /test/cases/hose-linebreak/compressed.css: -------------------------------------------------------------------------------- 1 | @host{:scope{color:white;}} -------------------------------------------------------------------------------- /test/cases/hose-linebreak/input.css: -------------------------------------------------------------------------------- 1 | @host 2 | { 3 | :scope { color: white; } 4 | } 5 | -------------------------------------------------------------------------------- /test/cases/hose-linebreak/output.css: -------------------------------------------------------------------------------- 1 | @host { 2 | :scope { 3 | color: white; 4 | } 5 | } -------------------------------------------------------------------------------- /test/cases/host/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "host", 7 | "rules": [ 8 | { 9 | "type": "rule", 10 | "selectors": [ 11 | ":scope" 12 | ], 13 | "declarations": [ 14 | { 15 | "type": "declaration", 16 | "property": "display", 17 | "value": "block", 18 | "position": { 19 | "start": { 20 | "line": 3, 21 | "column": 5 22 | }, 23 | "end": { 24 | "line": 3, 25 | "column": 19 26 | }, 27 | "source": "input.css" 28 | } 29 | } 30 | ], 31 | "position": { 32 | "start": { 33 | "line": 2, 34 | "column": 3 35 | }, 36 | "end": { 37 | "line": 4, 38 | "column": 4 39 | }, 40 | "source": "input.css" 41 | } 42 | } 43 | ], 44 | "position": { 45 | "start": { 46 | "line": 1, 47 | "column": 1 48 | }, 49 | "end": { 50 | "line": 5, 51 | "column": 2 52 | }, 53 | "source": "input.css" 54 | } 55 | } 56 | ] 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /test/cases/host/compressed.css: -------------------------------------------------------------------------------- 1 | @host{:scope{display:block;}} 2 | -------------------------------------------------------------------------------- /test/cases/host/input.css: -------------------------------------------------------------------------------- 1 | @host { 2 | :scope { 3 | display: block; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /test/cases/host/output.css: -------------------------------------------------------------------------------- 1 | @host { 2 | :scope { 3 | display: block; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /test/cases/import-linebreak/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "import", 7 | "import": "url(test.css)\n screen", 8 | "position": { 9 | "start": { 10 | "line": 1, 11 | "column": 1 12 | }, 13 | "end": { 14 | "line": 4, 15 | "column": 6 16 | }, 17 | "source": "input.css" 18 | } 19 | } 20 | ] 21 | } 22 | } -------------------------------------------------------------------------------- /test/cases/import-linebreak/compressed.css: -------------------------------------------------------------------------------- 1 | @import url(test.css) 2 | screen; -------------------------------------------------------------------------------- /test/cases/import-linebreak/input.css: -------------------------------------------------------------------------------- 1 | @import 2 | url(test.css) 3 | screen 4 | ; 5 | -------------------------------------------------------------------------------- /test/cases/import-linebreak/output.css: -------------------------------------------------------------------------------- 1 | @import url(test.css) 2 | screen; -------------------------------------------------------------------------------- /test/cases/import-messed/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "import", 7 | "import": "url(\"fineprint.css\") print", 8 | "position": { 9 | "start": { 10 | "line": 2, 11 | "column": 4 12 | }, 13 | "end": { 14 | "line": 2, 15 | "column": 39 16 | }, 17 | "source": "input.css" 18 | } 19 | }, 20 | { 21 | "type": "import", 22 | "import": "url(\"bluish.css\") projection, tv", 23 | "position": { 24 | "start": { 25 | "line": 3, 26 | "column": 3 27 | }, 28 | "end": { 29 | "line": 3, 30 | "column": 44 31 | }, 32 | "source": "input.css" 33 | } 34 | }, 35 | { 36 | "type": "import", 37 | "import": "'custom.css'", 38 | "position": { 39 | "start": { 40 | "line": 4, 41 | "column": 7 42 | }, 43 | "end": { 44 | "line": 4, 45 | "column": 28 46 | }, 47 | "source": "input.css" 48 | } 49 | }, 50 | { 51 | "type": "import", 52 | "import": "\"common.css\" screen, projection", 53 | "position": { 54 | "start": { 55 | "line": 5, 56 | "column": 3 57 | }, 58 | "end": { 59 | "line": 5, 60 | "column": 45 61 | }, 62 | "source": "input.css" 63 | } 64 | }, 65 | { 66 | "type": "import", 67 | "import": "url('landscape.css') screen and (orientation:landscape)", 68 | "position": { 69 | "start": { 70 | "line": 7, 71 | "column": 3 72 | }, 73 | "end": { 74 | "line": 7, 75 | "column": 67 76 | }, 77 | "source": "input.css" 78 | } 79 | } 80 | ] 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /test/cases/import-messed/compressed.css: -------------------------------------------------------------------------------- 1 | @import url("fineprint.css") print;@import url("bluish.css") projection, tv;@import 'custom.css';@import "common.css" screen, projection;@import url('landscape.css') screen and (orientation:landscape); 2 | -------------------------------------------------------------------------------- /test/cases/import-messed/input.css: -------------------------------------------------------------------------------- 1 | 2 | @import url("fineprint.css") print; 3 | @import url("bluish.css") projection, tv; 4 | @import 'custom.css'; 5 | @import "common.css" screen, projection ; 6 | 7 | @import url('landscape.css') screen and (orientation:landscape); 8 | -------------------------------------------------------------------------------- /test/cases/import-messed/output.css: -------------------------------------------------------------------------------- 1 | @import url("fineprint.css") print; 2 | 3 | @import url("bluish.css") projection, tv; 4 | 5 | @import 'custom.css'; 6 | 7 | @import "common.css" screen, projection; 8 | 9 | @import url('landscape.css') screen and (orientation:landscape); 10 | -------------------------------------------------------------------------------- /test/cases/import/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "import", 7 | "import": "url(\"fineprint.css\") print", 8 | "position": { 9 | "start": { 10 | "line": 1, 11 | "column": 1 12 | }, 13 | "end": { 14 | "line": 1, 15 | "column": 36 16 | }, 17 | "source": "input.css" 18 | } 19 | }, 20 | { 21 | "type": "import", 22 | "import": "url(\"bluish.css\") projection, tv", 23 | "position": { 24 | "start": { 25 | "line": 2, 26 | "column": 1 27 | }, 28 | "end": { 29 | "line": 2, 30 | "column": 42 31 | }, 32 | "source": "input.css" 33 | } 34 | }, 35 | { 36 | "type": "import", 37 | "import": "'custom.css'", 38 | "position": { 39 | "start": { 40 | "line": 3, 41 | "column": 1 42 | }, 43 | "end": { 44 | "line": 3, 45 | "column": 22 46 | }, 47 | "source": "input.css" 48 | } 49 | }, 50 | { 51 | "type": "import", 52 | "import": "\"common.css\" screen, projection", 53 | "position": { 54 | "start": { 55 | "line": 4, 56 | "column": 1 57 | }, 58 | "end": { 59 | "line": 4, 60 | "column": 41 61 | }, 62 | "source": "input.css" 63 | } 64 | }, 65 | { 66 | "type": "import", 67 | "import": "url('landscape.css') screen and (orientation:landscape)", 68 | "position": { 69 | "start": { 70 | "line": 5, 71 | "column": 1 72 | }, 73 | "end": { 74 | "line": 5, 75 | "column": 65 76 | }, 77 | "source": "input.css" 78 | } 79 | } 80 | ] 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /test/cases/import/compressed.css: -------------------------------------------------------------------------------- 1 | @import url("fineprint.css") print;@import url("bluish.css") projection, tv;@import 'custom.css';@import "common.css" screen, projection;@import url('landscape.css') screen and (orientation:landscape); 2 | -------------------------------------------------------------------------------- /test/cases/import/input.css: -------------------------------------------------------------------------------- 1 | @import url("fineprint.css") print; 2 | @import url("bluish.css") projection, tv; 3 | @import 'custom.css'; 4 | @import "common.css" screen, projection; 5 | @import url('landscape.css') screen and (orientation:landscape); 6 | -------------------------------------------------------------------------------- /test/cases/import/output.css: -------------------------------------------------------------------------------- 1 | @import url("fineprint.css") print; 2 | 3 | @import url("bluish.css") projection, tv; 4 | 5 | @import 'custom.css'; 6 | 7 | @import "common.css" screen, projection; 8 | 9 | @import url('landscape.css') screen and (orientation:landscape); 10 | -------------------------------------------------------------------------------- /test/cases/keyframes-advanced/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "keyframes", 7 | "name": "advanced", 8 | "keyframes": [ 9 | { 10 | "type": "keyframe", 11 | "values": [ 12 | "top" 13 | ], 14 | "declarations": [ 15 | { 16 | "type": "declaration", 17 | "property": "opacity[sqrt]", 18 | "value": "0", 19 | "position": { 20 | "start": { 21 | "line": 3, 22 | "column": 5 23 | }, 24 | "end": { 25 | "line": 3, 26 | "column": 21 27 | }, 28 | "source": "input.css" 29 | } 30 | } 31 | ], 32 | "position": { 33 | "start": { 34 | "line": 2, 35 | "column": 3 36 | }, 37 | "end": { 38 | "line": 4, 39 | "column": 4 40 | }, 41 | "source": "input.css" 42 | } 43 | }, 44 | { 45 | "type": "keyframe", 46 | "values": [ 47 | "100" 48 | ], 49 | "declarations": [ 50 | { 51 | "type": "declaration", 52 | "property": "opacity", 53 | "value": "0.5", 54 | "position": { 55 | "start": { 56 | "line": 7, 57 | "column": 5 58 | }, 59 | "end": { 60 | "line": 7, 61 | "column": 17 62 | }, 63 | "source": "input.css" 64 | } 65 | } 66 | ], 67 | "position": { 68 | "start": { 69 | "line": 6, 70 | "column": 3 71 | }, 72 | "end": { 73 | "line": 8, 74 | "column": 4 75 | }, 76 | "source": "input.css" 77 | } 78 | }, 79 | { 80 | "type": "keyframe", 81 | "values": [ 82 | "bottom" 83 | ], 84 | "declarations": [ 85 | { 86 | "type": "declaration", 87 | "property": "opacity", 88 | "value": "1", 89 | "position": { 90 | "start": { 91 | "line": 11, 92 | "column": 5 93 | }, 94 | "end": { 95 | "line": 11, 96 | "column": 15 97 | }, 98 | "source": "input.css" 99 | } 100 | } 101 | ], 102 | "position": { 103 | "start": { 104 | "line": 10, 105 | "column": 3 106 | }, 107 | "end": { 108 | "line": 12, 109 | "column": 4 110 | }, 111 | "source": "input.css" 112 | } 113 | } 114 | ], 115 | "position": { 116 | "start": { 117 | "line": 1, 118 | "column": 1 119 | }, 120 | "end": { 121 | "line": 13, 122 | "column": 2 123 | }, 124 | "source": "input.css" 125 | } 126 | } 127 | ] 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /test/cases/keyframes-advanced/compressed.css: -------------------------------------------------------------------------------- 1 | @keyframes advanced{top{opacity[sqrt]:0;}100{opacity:0.5;}bottom{opacity:1;}} 2 | -------------------------------------------------------------------------------- /test/cases/keyframes-advanced/input.css: -------------------------------------------------------------------------------- 1 | @keyframes advanced { 2 | top { 3 | opacity[sqrt]: 0; 4 | } 5 | 6 | 100 { 7 | opacity: 0.5; 8 | } 9 | 10 | bottom { 11 | opacity: 1; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/cases/keyframes-advanced/output.css: -------------------------------------------------------------------------------- 1 | @keyframes advanced { 2 | top { 3 | opacity[sqrt]: 0; 4 | } 5 | 6 | 100 { 7 | opacity: 0.5; 8 | } 9 | 10 | bottom { 11 | opacity: 1; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/cases/keyframes-complex/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "keyframes", 7 | "name": "foo", 8 | "keyframes": [ 9 | { 10 | "type": "keyframe", 11 | "values": [ 12 | "0%" 13 | ], 14 | "declarations": [ 15 | { 16 | "type": "declaration", 17 | "property": "top", 18 | "value": "0", 19 | "position": { 20 | "start": { 21 | "line": 2, 22 | "column": 8 23 | }, 24 | "end": { 25 | "line": 2, 26 | "column": 14 27 | }, 28 | "source": "input.css" 29 | } 30 | }, 31 | { 32 | "type": "declaration", 33 | "property": "left", 34 | "value": "0", 35 | "position": { 36 | "start": { 37 | "line": 2, 38 | "column": 16 39 | }, 40 | "end": { 41 | "line": 2, 42 | "column": 24 43 | }, 44 | "source": "input.css" 45 | } 46 | } 47 | ], 48 | "position": { 49 | "start": { 50 | "line": 2, 51 | "column": 3 52 | }, 53 | "end": { 54 | "line": 2, 55 | "column": 25 56 | }, 57 | "source": "input.css" 58 | } 59 | }, 60 | { 61 | "type": "keyframe", 62 | "values": [ 63 | "30.50%" 64 | ], 65 | "declarations": [ 66 | { 67 | "type": "declaration", 68 | "property": "top", 69 | "value": "50px", 70 | "position": { 71 | "start": { 72 | "line": 3, 73 | "column": 12 74 | }, 75 | "end": { 76 | "line": 3, 77 | "column": 22 78 | }, 79 | "source": "input.css" 80 | } 81 | } 82 | ], 83 | "position": { 84 | "start": { 85 | "line": 3, 86 | "column": 3 87 | }, 88 | "end": { 89 | "line": 3, 90 | "column": 23 91 | }, 92 | "source": "input.css" 93 | } 94 | }, 95 | { 96 | "type": "keyframe", 97 | "values": [ 98 | ".68%", 99 | "72%", 100 | "85%" 101 | ], 102 | "declarations": [ 103 | { 104 | "type": "declaration", 105 | "property": "left", 106 | "value": "50px", 107 | "position": { 108 | "start": { 109 | "line": 6, 110 | "column": 15 111 | }, 112 | "end": { 113 | "line": 6, 114 | "column": 26 115 | }, 116 | "source": "input.css" 117 | } 118 | } 119 | ], 120 | "position": { 121 | "start": { 122 | "line": 4, 123 | "column": 3 124 | }, 125 | "end": { 126 | "line": 6, 127 | "column": 27 128 | }, 129 | "source": "input.css" 130 | } 131 | }, 132 | { 133 | "type": "keyframe", 134 | "values": [ 135 | "100%" 136 | ], 137 | "declarations": [ 138 | { 139 | "type": "declaration", 140 | "property": "top", 141 | "value": "100px", 142 | "position": { 143 | "start": { 144 | "line": 7, 145 | "column": 10 146 | }, 147 | "end": { 148 | "line": 7, 149 | "column": 20 150 | }, 151 | "source": "input.css" 152 | } 153 | }, 154 | { 155 | "type": "declaration", 156 | "property": "left", 157 | "value": "100%", 158 | "position": { 159 | "start": { 160 | "line": 7, 161 | "column": 22 162 | }, 163 | "end": { 164 | "line": 7, 165 | "column": 33 166 | }, 167 | "source": "input.css" 168 | } 169 | } 170 | ], 171 | "position": { 172 | "start": { 173 | "line": 7, 174 | "column": 3 175 | }, 176 | "end": { 177 | "line": 7, 178 | "column": 34 179 | }, 180 | "source": "input.css" 181 | } 182 | } 183 | ], 184 | "position": { 185 | "start": { 186 | "line": 1, 187 | "column": 1 188 | }, 189 | "end": { 190 | "line": 8, 191 | "column": 2 192 | }, 193 | "source": "input.css" 194 | } 195 | } 196 | ] 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /test/cases/keyframes-complex/compressed.css: -------------------------------------------------------------------------------- 1 | @keyframes foo{0%{top:0;left:0;}30.50%{top:50px;}.68%,72%,85%{left:50px;}100%{top:100px;left:100%;}} 2 | -------------------------------------------------------------------------------- /test/cases/keyframes-complex/input.css: -------------------------------------------------------------------------------- 1 | @keyframes foo { 2 | 0% { top: 0; left: 0 } 3 | 30.50% { top: 50px } 4 | .68% , 5 | 72% 6 | , 85% { left: 50px } 7 | 100% { top: 100px; left: 100% } 8 | } 9 | -------------------------------------------------------------------------------- /test/cases/keyframes-complex/output.css: -------------------------------------------------------------------------------- 1 | @keyframes foo { 2 | 0% { 3 | top: 0; 4 | left: 0; 5 | } 6 | 7 | 30.50% { 8 | top: 50px; 9 | } 10 | 11 | .68%, 72%, 85% { 12 | left: 50px; 13 | } 14 | 15 | 100% { 16 | top: 100px; 17 | left: 100%; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/cases/keyframes-linebreak/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "keyframes", 7 | "name": "test", 8 | "keyframes": [ 9 | { 10 | "type": "keyframe", 11 | "values": [ 12 | "from" 13 | ], 14 | "declarations": [ 15 | { 16 | "type": "declaration", 17 | "property": "opacity", 18 | "value": "1", 19 | "position": { 20 | "start": { 21 | "line": 4, 22 | "column": 16 23 | }, 24 | "end": { 25 | "line": 4, 26 | "column": 26 27 | }, 28 | "source": "input.css" 29 | } 30 | } 31 | ], 32 | "position": { 33 | "start": { 34 | "line": 4, 35 | "column": 9 36 | }, 37 | "end": { 38 | "line": 4, 39 | "column": 29 40 | }, 41 | "source": "input.css" 42 | } 43 | }, 44 | { 45 | "type": "keyframe", 46 | "values": [ 47 | "to" 48 | ], 49 | "declarations": [ 50 | { 51 | "type": "declaration", 52 | "property": "opacity", 53 | "value": "0", 54 | "position": { 55 | "start": { 56 | "line": 5, 57 | "column": 14 58 | }, 59 | "end": { 60 | "line": 5, 61 | "column": 24 62 | }, 63 | "source": "input.css" 64 | } 65 | } 66 | ], 67 | "position": { 68 | "start": { 69 | "line": 5, 70 | "column": 9 71 | }, 72 | "end": { 73 | "line": 5, 74 | "column": 27 75 | }, 76 | "source": "input.css" 77 | } 78 | } 79 | ], 80 | "position": { 81 | "start": { 82 | "line": 1, 83 | "column": 1 84 | }, 85 | "end": { 86 | "line": 6, 87 | "column": 6 88 | }, 89 | "source": "input.css" 90 | } 91 | } 92 | ] 93 | } 94 | } -------------------------------------------------------------------------------- /test/cases/keyframes-linebreak/compressed.css: -------------------------------------------------------------------------------- 1 | @keyframes test{from{opacity:1;}to{opacity:0;}} -------------------------------------------------------------------------------- /test/cases/keyframes-linebreak/input.css: -------------------------------------------------------------------------------- 1 | @keyframes 2 | test 3 | { 4 | from { opacity: 1; } 5 | to { opacity: 0; } 6 | } 7 | -------------------------------------------------------------------------------- /test/cases/keyframes-linebreak/output.css: -------------------------------------------------------------------------------- 1 | @keyframes test { 2 | from { 3 | opacity: 1; 4 | } 5 | 6 | to { 7 | opacity: 0; 8 | } 9 | } -------------------------------------------------------------------------------- /test/cases/keyframes-messed/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "keyframes", 7 | "name": "fade", 8 | "keyframes": [ 9 | { 10 | "type": "keyframe", 11 | "values": [ 12 | "from" 13 | ], 14 | "declarations": [ 15 | { 16 | "type": "declaration", 17 | "property": "opacity", 18 | "value": "0", 19 | "position": { 20 | "start": { 21 | "line": 2, 22 | "column": 4 23 | }, 24 | "end": { 25 | "line": 2, 26 | "column": 14 27 | }, 28 | "source": "input.css" 29 | } 30 | } 31 | ], 32 | "position": { 33 | "start": { 34 | "line": 1, 35 | "column": 18 36 | }, 37 | "end": { 38 | "line": 3, 39 | "column": 7 40 | }, 41 | "source": "input.css" 42 | } 43 | }, 44 | { 45 | "type": "keyframe", 46 | "values": [ 47 | "to" 48 | ], 49 | "declarations": [ 50 | { 51 | "type": "declaration", 52 | "property": "opacity", 53 | "value": "1", 54 | "position": { 55 | "start": { 56 | "line": 6, 57 | "column": 6 58 | }, 59 | "end": { 60 | "line": 6, 61 | "column": 16 62 | }, 63 | "source": "input.css" 64 | } 65 | } 66 | ], 67 | "position": { 68 | "start": { 69 | "line": 4, 70 | "column": 1 71 | }, 72 | "end": { 73 | "line": 6, 74 | "column": 18 75 | }, 76 | "source": "input.css" 77 | } 78 | } 79 | ], 80 | "position": { 81 | "start": { 82 | "line": 1, 83 | "column": 1 84 | }, 85 | "end": { 86 | "line": 6, 87 | "column": 19 88 | }, 89 | "source": "input.css" 90 | } 91 | } 92 | ] 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /test/cases/keyframes-messed/compressed.css: -------------------------------------------------------------------------------- 1 | @keyframes fade{from{opacity:0;}to{opacity:1;}} 2 | -------------------------------------------------------------------------------- /test/cases/keyframes-messed/input.css: -------------------------------------------------------------------------------- 1 | @keyframes fade {from 2 | {opacity: 0; 3 | } 4 | to 5 | { 6 | opacity: 1;}} 7 | -------------------------------------------------------------------------------- /test/cases/keyframes-messed/output.css: -------------------------------------------------------------------------------- 1 | @keyframes fade { 2 | from { 3 | opacity: 0; 4 | } 5 | 6 | to { 7 | opacity: 1; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/cases/keyframes-vendor/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "keyframes", 7 | "name": "fade", 8 | "vendor": "-webkit-", 9 | "keyframes": [ 10 | { 11 | "type": "keyframe", 12 | "values": [ 13 | "from" 14 | ], 15 | "declarations": [ 16 | { 17 | "type": "declaration", 18 | "property": "opacity", 19 | "value": "0", 20 | "position": { 21 | "start": { 22 | "line": 2, 23 | "column": 10 24 | }, 25 | "end": { 26 | "line": 2, 27 | "column": 21 28 | }, 29 | "source": "input.css" 30 | } 31 | } 32 | ], 33 | "position": { 34 | "start": { 35 | "line": 2, 36 | "column": 3 37 | }, 38 | "end": { 39 | "line": 2, 40 | "column": 22 41 | }, 42 | "source": "input.css" 43 | } 44 | }, 45 | { 46 | "type": "keyframe", 47 | "values": [ 48 | "to" 49 | ], 50 | "declarations": [ 51 | { 52 | "type": "declaration", 53 | "property": "opacity", 54 | "value": "1", 55 | "position": { 56 | "start": { 57 | "line": 3, 58 | "column": 8 59 | }, 60 | "end": { 61 | "line": 3, 62 | "column": 19 63 | }, 64 | "source": "input.css" 65 | } 66 | } 67 | ], 68 | "position": { 69 | "start": { 70 | "line": 3, 71 | "column": 3 72 | }, 73 | "end": { 74 | "line": 3, 75 | "column": 20 76 | }, 77 | "source": "input.css" 78 | } 79 | } 80 | ], 81 | "position": { 82 | "start": { 83 | "line": 1, 84 | "column": 1 85 | }, 86 | "end": { 87 | "line": 4, 88 | "column": 2 89 | }, 90 | "source": "input.css" 91 | } 92 | } 93 | ] 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /test/cases/keyframes-vendor/compressed.css: -------------------------------------------------------------------------------- 1 | @-webkit-keyframes fade{from{opacity:0;}to{opacity:1;}} 2 | -------------------------------------------------------------------------------- /test/cases/keyframes-vendor/input.css: -------------------------------------------------------------------------------- 1 | @-webkit-keyframes fade { 2 | from { opacity: 0 } 3 | to { opacity: 1 } 4 | } 5 | -------------------------------------------------------------------------------- /test/cases/keyframes-vendor/output.css: -------------------------------------------------------------------------------- 1 | @-webkit-keyframes fade { 2 | from { 3 | opacity: 0; 4 | } 5 | 6 | to { 7 | opacity: 1; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/cases/keyframes/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "keyframes", 7 | "name": "fade", 8 | "keyframes": [ 9 | { 10 | "type": "comment", 11 | "comment": " from above ", 12 | "position": { 13 | "start": { 14 | "line": 2, 15 | "column": 3 16 | }, 17 | "end": { 18 | "line": 2, 19 | "column": 19 20 | }, 21 | "source": "input.css" 22 | } 23 | }, 24 | { 25 | "type": "keyframe", 26 | "values": [ 27 | "from" 28 | ], 29 | "declarations": [ 30 | { 31 | "type": "comment", 32 | "comment": " from inside ", 33 | "position": { 34 | "start": { 35 | "line": 4, 36 | "column": 5 37 | }, 38 | "end": { 39 | "line": 4, 40 | "column": 22 41 | }, 42 | "source": "input.css" 43 | } 44 | }, 45 | { 46 | "type": "declaration", 47 | "property": "opacity", 48 | "value": "0", 49 | "position": { 50 | "start": { 51 | "line": 5, 52 | "column": 5 53 | }, 54 | "end": { 55 | "line": 5, 56 | "column": 15 57 | }, 58 | "source": "input.css" 59 | } 60 | } 61 | ], 62 | "position": { 63 | "start": { 64 | "line": 3, 65 | "column": 3 66 | }, 67 | "end": { 68 | "line": 6, 69 | "column": 4 70 | }, 71 | "source": "input.css" 72 | } 73 | }, 74 | { 75 | "type": "comment", 76 | "comment": " to above ", 77 | "position": { 78 | "start": { 79 | "line": 8, 80 | "column": 3 81 | }, 82 | "end": { 83 | "line": 8, 84 | "column": 17 85 | }, 86 | "source": "input.css" 87 | } 88 | }, 89 | { 90 | "type": "keyframe", 91 | "values": [ 92 | "to" 93 | ], 94 | "declarations": [ 95 | { 96 | "type": "comment", 97 | "comment": " to inside ", 98 | "position": { 99 | "start": { 100 | "line": 10, 101 | "column": 5 102 | }, 103 | "end": { 104 | "line": 10, 105 | "column": 20 106 | }, 107 | "source": "input.css" 108 | } 109 | }, 110 | { 111 | "type": "declaration", 112 | "property": "opacity", 113 | "value": "1", 114 | "position": { 115 | "start": { 116 | "line": 11, 117 | "column": 5 118 | }, 119 | "end": { 120 | "line": 11, 121 | "column": 15 122 | }, 123 | "source": "input.css" 124 | } 125 | } 126 | ], 127 | "position": { 128 | "start": { 129 | "line": 9, 130 | "column": 3 131 | }, 132 | "end": { 133 | "line": 12, 134 | "column": 4 135 | }, 136 | "source": "input.css" 137 | } 138 | } 139 | ], 140 | "position": { 141 | "start": { 142 | "line": 1, 143 | "column": 1 144 | }, 145 | "end": { 146 | "line": 13, 147 | "column": 2 148 | }, 149 | "source": "input.css" 150 | } 151 | } 152 | ] 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /test/cases/keyframes/compressed.css: -------------------------------------------------------------------------------- 1 | @keyframes fade{from{opacity:0;}to{opacity:1;}} 2 | -------------------------------------------------------------------------------- /test/cases/keyframes/input.css: -------------------------------------------------------------------------------- 1 | @keyframes fade { 2 | /* from above */ 3 | from { 4 | /* from inside */ 5 | opacity: 0; 6 | } 7 | 8 | /* to above */ 9 | to { 10 | /* to inside */ 11 | opacity: 1; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/cases/keyframes/output.css: -------------------------------------------------------------------------------- 1 | @keyframes fade { 2 | /* from above */ 3 | from { 4 | /* from inside */ 5 | opacity: 0; 6 | } 7 | 8 | /* to above */ 9 | to { 10 | /* to inside */ 11 | opacity: 1; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/cases/media-linebreak/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "media", 7 | "media": "(\n min-width: 300px\n)", 8 | "rules": [ 9 | { 10 | "type": "rule", 11 | "selectors": [ 12 | ".test" 13 | ], 14 | "declarations": [ 15 | { 16 | "type": "declaration", 17 | "property": "width", 18 | "value": "100px", 19 | "position": { 20 | "start": { 21 | "line": 7, 22 | "column": 13 23 | }, 24 | "end": { 25 | "line": 7, 26 | "column": 25 27 | }, 28 | "source": "input.css" 29 | } 30 | } 31 | ], 32 | "position": { 33 | "start": { 34 | "line": 7, 35 | "column": 5 36 | }, 37 | "end": { 38 | "line": 7, 39 | "column": 28 40 | }, 41 | "source": "input.css" 42 | } 43 | } 44 | ], 45 | "position": { 46 | "start": { 47 | "line": 1, 48 | "column": 1 49 | }, 50 | "end": { 51 | "line": 8, 52 | "column": 2 53 | }, 54 | "source": "input.css" 55 | } 56 | } 57 | ] 58 | } 59 | } -------------------------------------------------------------------------------- /test/cases/media-linebreak/compressed.css: -------------------------------------------------------------------------------- 1 | @media ( 2 | min-width: 300px 3 | ){.test{width:100px;}} -------------------------------------------------------------------------------- /test/cases/media-linebreak/input.css: -------------------------------------------------------------------------------- 1 | @media 2 | 3 | ( 4 | min-width: 300px 5 | ) 6 | { 7 | .test { width: 100px; } 8 | } 9 | -------------------------------------------------------------------------------- /test/cases/media-linebreak/output.css: -------------------------------------------------------------------------------- 1 | @media ( 2 | min-width: 300px 3 | ) { 4 | .test { 5 | width: 100px; 6 | } 7 | } -------------------------------------------------------------------------------- /test/cases/media-messed/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "media", 7 | "media": "screen, projection", 8 | "rules": [ 9 | { 10 | "type": "rule", 11 | "selectors": [ 12 | "html" 13 | ], 14 | "declarations": [ 15 | { 16 | "type": "declaration", 17 | "property": "background", 18 | "value": "#fffef0", 19 | "position": { 20 | "start": { 21 | "line": 4, 22 | "column": 1 23 | }, 24 | "end": { 25 | "line": 4, 26 | "column": 20 27 | }, 28 | "source": "input.css" 29 | } 30 | }, 31 | { 32 | "type": "declaration", 33 | "property": "color", 34 | "value": "#300", 35 | "position": { 36 | "start": { 37 | "line": 5, 38 | "column": 5 39 | }, 40 | "end": { 41 | "line": 5, 42 | "column": 15 43 | }, 44 | "source": "input.css" 45 | } 46 | } 47 | ], 48 | "position": { 49 | "start": { 50 | "line": 1, 51 | "column": 28 52 | }, 53 | "end": { 54 | "line": 6, 55 | "column": 4 56 | }, 57 | "source": "input.css" 58 | } 59 | }, 60 | { 61 | "type": "rule", 62 | "selectors": [ 63 | "body" 64 | ], 65 | "declarations": [ 66 | { 67 | "type": "declaration", 68 | "property": "max-width", 69 | "value": "35em", 70 | "position": { 71 | "start": { 72 | "line": 10, 73 | "column": 5 74 | }, 75 | "end": { 76 | "line": 10, 77 | "column": 20 78 | }, 79 | "source": "input.css" 80 | } 81 | }, 82 | { 83 | "type": "declaration", 84 | "property": "margin", 85 | "value": "0 auto", 86 | "position": { 87 | "start": { 88 | "line": 11, 89 | "column": 5 90 | }, 91 | "end": { 92 | "line": 11, 93 | "column": 19 94 | }, 95 | "source": "input.css" 96 | } 97 | } 98 | ], 99 | "position": { 100 | "start": { 101 | "line": 7, 102 | "column": 3 103 | }, 104 | "end": { 105 | "line": 14, 106 | "column": 2 107 | }, 108 | "source": "input.css" 109 | } 110 | } 111 | ], 112 | "position": { 113 | "start": { 114 | "line": 1, 115 | "column": 1 116 | }, 117 | "end": { 118 | "line": 15, 119 | "column": 4 120 | }, 121 | "source": "input.css" 122 | } 123 | }, 124 | { 125 | "type": "media", 126 | "media": "print", 127 | "rules": [ 128 | { 129 | "type": "rule", 130 | "selectors": [ 131 | "html" 132 | ], 133 | "declarations": [ 134 | { 135 | "type": "declaration", 136 | "property": "background", 137 | "value": "#fff", 138 | "position": { 139 | "start": { 140 | "line": 20, 141 | "column": 15 142 | }, 143 | "end": { 144 | "line": 20, 145 | "column": 31 146 | }, 147 | "source": "input.css" 148 | } 149 | }, 150 | { 151 | "type": "declaration", 152 | "property": "color", 153 | "value": "#000", 154 | "position": { 155 | "start": { 156 | "line": 21, 157 | "column": 15 158 | }, 159 | "end": { 160 | "line": 21, 161 | "column": 26 162 | }, 163 | "source": "input.css" 164 | } 165 | } 166 | ], 167 | "position": { 168 | "start": { 169 | "line": 19, 170 | "column": 15 171 | }, 172 | "end": { 173 | "line": 22, 174 | "column": 16 175 | }, 176 | "source": "input.css" 177 | } 178 | }, 179 | { 180 | "type": "rule", 181 | "selectors": [ 182 | "body" 183 | ], 184 | "declarations": [ 185 | { 186 | "type": "declaration", 187 | "property": "padding", 188 | "value": "1in", 189 | "position": { 190 | "start": { 191 | "line": 24, 192 | "column": 15 193 | }, 194 | "end": { 195 | "line": 24, 196 | "column": 27 197 | }, 198 | "source": "input.css" 199 | } 200 | }, 201 | { 202 | "type": "declaration", 203 | "property": "border", 204 | "value": "0.5pt solid #666", 205 | "position": { 206 | "start": { 207 | "line": 25, 208 | "column": 15 209 | }, 210 | "end": { 211 | "line": 25, 212 | "column": 39 213 | }, 214 | "source": "input.css" 215 | } 216 | } 217 | ], 218 | "position": { 219 | "start": { 220 | "line": 23, 221 | "column": 15 222 | }, 223 | "end": { 224 | "line": 26, 225 | "column": 16 226 | }, 227 | "source": "input.css" 228 | } 229 | } 230 | ], 231 | "position": { 232 | "start": { 233 | "line": 17, 234 | "column": 1 235 | }, 236 | "end": { 237 | "line": 27, 238 | "column": 2 239 | }, 240 | "source": "input.css" 241 | } 242 | } 243 | ] 244 | } 245 | } 246 | -------------------------------------------------------------------------------- /test/cases/media-messed/compressed.css: -------------------------------------------------------------------------------- 1 | @media screen, projection{html{background:#fffef0;color:#300;}body{max-width:35em;margin:0 auto;}}@media print{html{background:#fff;color:#000;}body{padding:1in;border:0.5pt solid #666;}} 2 | -------------------------------------------------------------------------------- /test/cases/media-messed/input.css: -------------------------------------------------------------------------------- 1 | @media screen, projection{ html 2 | 3 | { 4 | background: #fffef0; 5 | color:#300; 6 | } 7 | body 8 | 9 | { 10 | max-width: 35em; 11 | margin: 0 auto; 12 | 13 | 14 | } 15 | } 16 | 17 | @media print 18 | { 19 | html { 20 | background: #fff; 21 | color: #000; 22 | } 23 | body { 24 | padding: 1in; 25 | border: 0.5pt solid #666; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test/cases/media-messed/output.css: -------------------------------------------------------------------------------- 1 | @media screen, projection { 2 | html { 3 | background: #fffef0; 4 | color: #300; 5 | } 6 | 7 | body { 8 | max-width: 35em; 9 | margin: 0 auto; 10 | } 11 | } 12 | 13 | @media print { 14 | html { 15 | background: #fff; 16 | color: #000; 17 | } 18 | 19 | body { 20 | padding: 1in; 21 | border: 0.5pt solid #666; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test/cases/media/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "media", 7 | "media": "screen, projection", 8 | "rules": [ 9 | { 10 | "type": "comment", 11 | "comment": " html above ", 12 | "position": { 13 | "start": { 14 | "line": 2, 15 | "column": 3 16 | }, 17 | "end": { 18 | "line": 2, 19 | "column": 19 20 | }, 21 | "source": "input.css" 22 | } 23 | }, 24 | { 25 | "type": "rule", 26 | "selectors": [ 27 | "html" 28 | ], 29 | "declarations": [ 30 | { 31 | "type": "comment", 32 | "comment": " html inside ", 33 | "position": { 34 | "start": { 35 | "line": 4, 36 | "column": 5 37 | }, 38 | "end": { 39 | "line": 4, 40 | "column": 22 41 | }, 42 | "source": "input.css" 43 | } 44 | }, 45 | { 46 | "type": "declaration", 47 | "property": "background", 48 | "value": "#fffef0", 49 | "position": { 50 | "start": { 51 | "line": 5, 52 | "column": 5 53 | }, 54 | "end": { 55 | "line": 5, 56 | "column": 24 57 | }, 58 | "source": "input.css" 59 | } 60 | }, 61 | { 62 | "type": "declaration", 63 | "property": "color", 64 | "value": "#300", 65 | "position": { 66 | "start": { 67 | "line": 6, 68 | "column": 5 69 | }, 70 | "end": { 71 | "line": 6, 72 | "column": 16 73 | }, 74 | "source": "input.css" 75 | } 76 | } 77 | ], 78 | "position": { 79 | "start": { 80 | "line": 3, 81 | "column": 3 82 | }, 83 | "end": { 84 | "line": 7, 85 | "column": 4 86 | }, 87 | "source": "input.css" 88 | } 89 | }, 90 | { 91 | "type": "comment", 92 | "comment": " body above ", 93 | "position": { 94 | "start": { 95 | "line": 9, 96 | "column": 3 97 | }, 98 | "end": { 99 | "line": 9, 100 | "column": 19 101 | }, 102 | "source": "input.css" 103 | } 104 | }, 105 | { 106 | "type": "rule", 107 | "selectors": [ 108 | "body" 109 | ], 110 | "declarations": [ 111 | { 112 | "type": "comment", 113 | "comment": " body inside ", 114 | "position": { 115 | "start": { 116 | "line": 11, 117 | "column": 5 118 | }, 119 | "end": { 120 | "line": 11, 121 | "column": 22 122 | }, 123 | "source": "input.css" 124 | } 125 | }, 126 | { 127 | "type": "declaration", 128 | "property": "max-width", 129 | "value": "35em", 130 | "position": { 131 | "start": { 132 | "line": 12, 133 | "column": 5 134 | }, 135 | "end": { 136 | "line": 12, 137 | "column": 20 138 | }, 139 | "source": "input.css" 140 | } 141 | }, 142 | { 143 | "type": "declaration", 144 | "property": "margin", 145 | "value": "0 auto", 146 | "position": { 147 | "start": { 148 | "line": 13, 149 | "column": 5 150 | }, 151 | "end": { 152 | "line": 13, 153 | "column": 19 154 | }, 155 | "source": "input.css" 156 | } 157 | } 158 | ], 159 | "position": { 160 | "start": { 161 | "line": 10, 162 | "column": 3 163 | }, 164 | "end": { 165 | "line": 14, 166 | "column": 4 167 | }, 168 | "source": "input.css" 169 | } 170 | } 171 | ], 172 | "position": { 173 | "start": { 174 | "line": 1, 175 | "column": 1 176 | }, 177 | "end": { 178 | "line": 15, 179 | "column": 2 180 | }, 181 | "source": "input.css" 182 | } 183 | }, 184 | { 185 | "type": "media", 186 | "media": "print", 187 | "rules": [ 188 | { 189 | "type": "rule", 190 | "selectors": [ 191 | "html" 192 | ], 193 | "declarations": [ 194 | { 195 | "type": "declaration", 196 | "property": "background", 197 | "value": "#fff", 198 | "position": { 199 | "start": { 200 | "line": 19, 201 | "column": 5 202 | }, 203 | "end": { 204 | "line": 19, 205 | "column": 21 206 | }, 207 | "source": "input.css" 208 | } 209 | }, 210 | { 211 | "type": "declaration", 212 | "property": "color", 213 | "value": "#000", 214 | "position": { 215 | "start": { 216 | "line": 20, 217 | "column": 5 218 | }, 219 | "end": { 220 | "line": 20, 221 | "column": 16 222 | }, 223 | "source": "input.css" 224 | } 225 | } 226 | ], 227 | "position": { 228 | "start": { 229 | "line": 18, 230 | "column": 3 231 | }, 232 | "end": { 233 | "line": 21, 234 | "column": 4 235 | }, 236 | "source": "input.css" 237 | } 238 | }, 239 | { 240 | "type": "rule", 241 | "selectors": [ 242 | "body" 243 | ], 244 | "declarations": [ 245 | { 246 | "type": "declaration", 247 | "property": "padding", 248 | "value": "1in", 249 | "position": { 250 | "start": { 251 | "line": 23, 252 | "column": 5 253 | }, 254 | "end": { 255 | "line": 23, 256 | "column": 17 257 | }, 258 | "source": "input.css" 259 | } 260 | }, 261 | { 262 | "type": "declaration", 263 | "property": "border", 264 | "value": "0.5pt solid #666", 265 | "position": { 266 | "start": { 267 | "line": 24, 268 | "column": 5 269 | }, 270 | "end": { 271 | "line": 24, 272 | "column": 29 273 | }, 274 | "source": "input.css" 275 | } 276 | } 277 | ], 278 | "position": { 279 | "start": { 280 | "line": 22, 281 | "column": 3 282 | }, 283 | "end": { 284 | "line": 25, 285 | "column": 4 286 | }, 287 | "source": "input.css" 288 | } 289 | } 290 | ], 291 | "position": { 292 | "start": { 293 | "line": 17, 294 | "column": 1 295 | }, 296 | "end": { 297 | "line": 26, 298 | "column": 2 299 | }, 300 | "source": "input.css" 301 | } 302 | } 303 | ] 304 | } 305 | } 306 | -------------------------------------------------------------------------------- /test/cases/media/compressed.css: -------------------------------------------------------------------------------- 1 | @media screen, projection{html{background:#fffef0;color:#300;}body{max-width:35em;margin:0 auto;}}@media print{html{background:#fff;color:#000;}body{padding:1in;border:0.5pt solid #666;}} 2 | -------------------------------------------------------------------------------- /test/cases/media/input.css: -------------------------------------------------------------------------------- 1 | @media screen, projection { 2 | /* html above */ 3 | html { 4 | /* html inside */ 5 | background: #fffef0; 6 | color: #300; 7 | } 8 | 9 | /* body above */ 10 | body { 11 | /* body inside */ 12 | max-width: 35em; 13 | margin: 0 auto; 14 | } 15 | } 16 | 17 | @media print { 18 | html { 19 | background: #fff; 20 | color: #000; 21 | } 22 | body { 23 | padding: 1in; 24 | border: 0.5pt solid #666; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/cases/media/output.css: -------------------------------------------------------------------------------- 1 | @media screen, projection { 2 | /* html above */ 3 | 4 | html { 5 | /* html inside */ 6 | background: #fffef0; 7 | color: #300; 8 | } 9 | 10 | /* body above */ 11 | 12 | body { 13 | /* body inside */ 14 | max-width: 35em; 15 | margin: 0 auto; 16 | } 17 | } 18 | 19 | @media print { 20 | html { 21 | background: #fff; 22 | color: #000; 23 | } 24 | 25 | body { 26 | padding: 1in; 27 | border: 0.5pt solid #666; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /test/cases/messed-up/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "rule", 7 | "selectors": [ 8 | "body" 9 | ], 10 | "declarations": [ 11 | { 12 | "type": "declaration", 13 | "property": "foo", 14 | "value": "'bar'", 15 | "position": { 16 | "start": { 17 | "line": 1, 18 | "column": 8 19 | }, 20 | "end": { 21 | "line": 3, 22 | "column": 9 23 | }, 24 | "source": "input.css" 25 | } 26 | } 27 | ], 28 | "position": { 29 | "start": { 30 | "line": 1, 31 | "column": 1 32 | }, 33 | "end": { 34 | "line": 3, 35 | "column": 10 36 | }, 37 | "source": "input.css" 38 | } 39 | }, 40 | { 41 | "type": "rule", 42 | "selectors": [ 43 | "body" 44 | ], 45 | "declarations": [ 46 | { 47 | "type": "declaration", 48 | "property": "foo", 49 | "value": "bar", 50 | "position": { 51 | "start": { 52 | "line": 5, 53 | "column": 9 54 | }, 55 | "end": { 56 | "line": 5, 57 | "column": 16 58 | }, 59 | "source": "input.css" 60 | } 61 | }, 62 | { 63 | "type": "declaration", 64 | "property": "bar", 65 | "value": "baz", 66 | "position": { 67 | "start": { 68 | "line": 5, 69 | "column": 17 70 | }, 71 | "end": { 72 | "line": 5, 73 | "column": 24 74 | }, 75 | "source": "input.css" 76 | } 77 | } 78 | ], 79 | "position": { 80 | "start": { 81 | "line": 5, 82 | "column": 4 83 | }, 84 | "end": { 85 | "line": 5, 86 | "column": 25 87 | }, 88 | "source": "input.css" 89 | } 90 | }, 91 | { 92 | "type": "rule", 93 | "selectors": [ 94 | "body" 95 | ], 96 | "declarations": [ 97 | { 98 | "type": "declaration", 99 | "property": "foo", 100 | "value": "bar", 101 | "position": { 102 | "start": { 103 | "line": 8, 104 | "column": 6 105 | }, 106 | "end": { 107 | "line": 11, 108 | "column": 6 109 | }, 110 | "source": "input.css" 111 | } 112 | }, 113 | { 114 | "type": "declaration", 115 | "property": "bar", 116 | "value": "baz", 117 | "position": { 118 | "start": { 119 | "line": 12, 120 | "column": 6 121 | }, 122 | "end": { 123 | "line": 15, 124 | "column": 6 125 | }, 126 | "source": "input.css" 127 | } 128 | } 129 | ], 130 | "position": { 131 | "start": { 132 | "line": 6, 133 | "column": 4 134 | }, 135 | "end": { 136 | "line": 15, 137 | "column": 7 138 | }, 139 | "source": "input.css" 140 | } 141 | } 142 | ] 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /test/cases/messed-up/compressed.css: -------------------------------------------------------------------------------- 1 | body{foo:'bar';}body{foo:bar;bar:baz;}body{foo:bar;bar:baz;} 2 | -------------------------------------------------------------------------------- /test/cases/messed-up/input.css: -------------------------------------------------------------------------------- 1 | body { foo 2 | : 3 | 'bar' } 4 | 5 | body{foo:bar;bar:baz} 6 | body 7 | { 8 | foo 9 | : 10 | bar 11 | ; 12 | bar 13 | : 14 | baz 15 | } 16 | -------------------------------------------------------------------------------- /test/cases/messed-up/output.css: -------------------------------------------------------------------------------- 1 | body { 2 | foo: 'bar'; 3 | } 4 | 5 | body { 6 | foo: bar; 7 | bar: baz; 8 | } 9 | 10 | body { 11 | foo: bar; 12 | bar: baz; 13 | } 14 | -------------------------------------------------------------------------------- /test/cases/namespace-linebreak/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "namespace", 7 | "namespace": "\"http://www.w3.org/1999/xhtml\"", 8 | "position": { 9 | "start": { 10 | "line": 1, 11 | "column": 1 12 | }, 13 | "end": { 14 | "line": 3, 15 | "column": 6 16 | }, 17 | "source": "input.css" 18 | } 19 | } 20 | ] 21 | } 22 | } -------------------------------------------------------------------------------- /test/cases/namespace-linebreak/compressed.css: -------------------------------------------------------------------------------- 1 | @namespace "http://www.w3.org/1999/xhtml"; -------------------------------------------------------------------------------- /test/cases/namespace-linebreak/input.css: -------------------------------------------------------------------------------- 1 | @namespace 2 | "http://www.w3.org/1999/xhtml" 3 | ; 4 | -------------------------------------------------------------------------------- /test/cases/namespace-linebreak/output.css: -------------------------------------------------------------------------------- 1 | @namespace "http://www.w3.org/1999/xhtml"; -------------------------------------------------------------------------------- /test/cases/namespace/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "namespace", 7 | "namespace": "\"http://www.w3.org/1999/xhtml\"", 8 | "position": { 9 | "start": { 10 | "line": 1, 11 | "column": 1 12 | }, 13 | "end": { 14 | "line": 1, 15 | "column": 43 16 | }, 17 | "source": "input.css" 18 | } 19 | }, 20 | { 21 | "type": "namespace", 22 | "namespace": "svg \"http://www.w3.org/2000/svg\"", 23 | "position": { 24 | "start": { 25 | "line": 2, 26 | "column": 1 27 | }, 28 | "end": { 29 | "line": 2, 30 | "column": 45 31 | }, 32 | "source": "input.css" 33 | } 34 | } 35 | ] 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /test/cases/namespace/compressed.css: -------------------------------------------------------------------------------- 1 | @namespace "http://www.w3.org/1999/xhtml";@namespace svg "http://www.w3.org/2000/svg"; 2 | -------------------------------------------------------------------------------- /test/cases/namespace/input.css: -------------------------------------------------------------------------------- 1 | @namespace "http://www.w3.org/1999/xhtml"; 2 | @namespace svg "http://www.w3.org/2000/svg"; 3 | -------------------------------------------------------------------------------- /test/cases/namespace/output.css: -------------------------------------------------------------------------------- 1 | @namespace "http://www.w3.org/1999/xhtml"; 2 | 3 | @namespace svg "http://www.w3.org/2000/svg"; 4 | -------------------------------------------------------------------------------- /test/cases/no-semi/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "rule", 7 | "selectors": [ 8 | "tobi loki jane" 9 | ], 10 | "declarations": [ 11 | { 12 | "type": "declaration", 13 | "property": "are", 14 | "value": "'all'", 15 | "position": { 16 | "start": { 17 | "line": 3, 18 | "column": 3 19 | }, 20 | "end": { 21 | "line": 3, 22 | "column": 13 23 | }, 24 | "source": "input.css" 25 | } 26 | }, 27 | { 28 | "type": "declaration", 29 | "property": "the-species", 30 | "value": "called \"ferrets\"", 31 | "position": { 32 | "start": { 33 | "line": 4, 34 | "column": 3 35 | }, 36 | "end": { 37 | "line": 5, 38 | "column": 1 39 | }, 40 | "source": "input.css" 41 | } 42 | } 43 | ], 44 | "position": { 45 | "start": { 46 | "line": 2, 47 | "column": 1 48 | }, 49 | "end": { 50 | "line": 5, 51 | "column": 2 52 | }, 53 | "source": "input.css" 54 | } 55 | } 56 | ] 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /test/cases/no-semi/compressed.css: -------------------------------------------------------------------------------- 1 | tobi loki jane{are:'all';the-species:called "ferrets";} 2 | -------------------------------------------------------------------------------- /test/cases/no-semi/input.css: -------------------------------------------------------------------------------- 1 | 2 | tobi loki jane { 3 | are: 'all'; 4 | the-species: called "ferrets" 5 | } 6 | -------------------------------------------------------------------------------- /test/cases/no-semi/output.css: -------------------------------------------------------------------------------- 1 | tobi loki jane { 2 | are: 'all'; 3 | the-species: called "ferrets"; 4 | } 5 | -------------------------------------------------------------------------------- /test/cases/page-linebreak/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "page", 7 | "selectors": [ 8 | "toc" 9 | ], 10 | "declarations": [ 11 | { 12 | "type": "declaration", 13 | "property": "color", 14 | "value": "black", 15 | "position": { 16 | "start": { 17 | "line": 4, 18 | "column": 9 19 | }, 20 | "end": { 21 | "line": 4, 22 | "column": 21 23 | }, 24 | "source": "input.css" 25 | } 26 | } 27 | ], 28 | "position": { 29 | "start": { 30 | "line": 1, 31 | "column": 1 32 | }, 33 | "end": { 34 | "line": 5, 35 | "column": 6 36 | }, 37 | "source": "input.css" 38 | } 39 | } 40 | ] 41 | } 42 | } -------------------------------------------------------------------------------- /test/cases/page-linebreak/compressed.css: -------------------------------------------------------------------------------- 1 | @page toc{color:black;} -------------------------------------------------------------------------------- /test/cases/page-linebreak/input.css: -------------------------------------------------------------------------------- 1 | @page 2 | toc 3 | { 4 | color: black; 5 | } 6 | -------------------------------------------------------------------------------- /test/cases/page-linebreak/output.css: -------------------------------------------------------------------------------- 1 | @page toc { 2 | color: black; 3 | } -------------------------------------------------------------------------------- /test/cases/paged-media/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "comment", 7 | "comment": " toc above ", 8 | "position": { 9 | "start": { 10 | "line": 1, 11 | "column": 1 12 | }, 13 | "end": { 14 | "line": 1, 15 | "column": 16 16 | }, 17 | "source": "input.css" 18 | } 19 | }, 20 | { 21 | "type": "page", 22 | "selectors": [ 23 | "toc", 24 | "index:blank" 25 | ], 26 | "declarations": [ 27 | { 28 | "type": "comment", 29 | "comment": " toc inside ", 30 | "position": { 31 | "start": { 32 | "line": 3, 33 | "column": 3 34 | }, 35 | "end": { 36 | "line": 3, 37 | "column": 19 38 | }, 39 | "source": "input.css" 40 | } 41 | }, 42 | { 43 | "type": "declaration", 44 | "property": "color", 45 | "value": "green", 46 | "position": { 47 | "start": { 48 | "line": 4, 49 | "column": 3 50 | }, 51 | "end": { 52 | "line": 4, 53 | "column": 15 54 | }, 55 | "source": "input.css" 56 | } 57 | } 58 | ], 59 | "position": { 60 | "start": { 61 | "line": 2, 62 | "column": 1 63 | }, 64 | "end": { 65 | "line": 5, 66 | "column": 2 67 | }, 68 | "source": "input.css" 69 | } 70 | }, 71 | { 72 | "type": "page", 73 | "selectors": [], 74 | "declarations": [ 75 | { 76 | "type": "declaration", 77 | "property": "font-size", 78 | "value": "16pt", 79 | "position": { 80 | "start": { 81 | "line": 8, 82 | "column": 3 83 | }, 84 | "end": { 85 | "line": 8, 86 | "column": 18 87 | }, 88 | "source": "input.css" 89 | } 90 | } 91 | ], 92 | "position": { 93 | "start": { 94 | "line": 7, 95 | "column": 1 96 | }, 97 | "end": { 98 | "line": 9, 99 | "column": 2 100 | }, 101 | "source": "input.css" 102 | } 103 | }, 104 | { 105 | "type": "page", 106 | "selectors": [ 107 | ":left" 108 | ], 109 | "declarations": [ 110 | { 111 | "type": "declaration", 112 | "property": "margin-left", 113 | "value": "5cm", 114 | "position": { 115 | "start": { 116 | "line": 12, 117 | "column": 3 118 | }, 119 | "end": { 120 | "line": 12, 121 | "column": 19 122 | }, 123 | "source": "input.css" 124 | } 125 | } 126 | ], 127 | "position": { 128 | "start": { 129 | "line": 11, 130 | "column": 1 131 | }, 132 | "end": { 133 | "line": 13, 134 | "column": 2 135 | }, 136 | "source": "input.css" 137 | } 138 | } 139 | ] 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /test/cases/paged-media/compressed.css: -------------------------------------------------------------------------------- 1 | @page toc, index:blank{color:green;}@page {font-size:16pt;}@page :left{margin-left:5cm;} 2 | -------------------------------------------------------------------------------- /test/cases/paged-media/input.css: -------------------------------------------------------------------------------- 1 | /* toc above */ 2 | @page toc, index:blank { 3 | /* toc inside */ 4 | color: green; 5 | } 6 | 7 | @page { 8 | font-size: 16pt; 9 | } 10 | 11 | @page :left { 12 | margin-left: 5cm; 13 | } 14 | -------------------------------------------------------------------------------- /test/cases/paged-media/output.css: -------------------------------------------------------------------------------- 1 | /* toc above */ 2 | 3 | @page toc, index:blank { 4 | /* toc inside */ 5 | color: green; 6 | } 7 | 8 | @page { 9 | font-size: 16pt; 10 | } 11 | 12 | @page :left { 13 | margin-left: 5cm; 14 | } 15 | -------------------------------------------------------------------------------- /test/cases/props/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "rule", 7 | "selectors": [ 8 | "tobi loki jane" 9 | ], 10 | "declarations": [ 11 | { 12 | "type": "declaration", 13 | "property": "are", 14 | "value": "'all'", 15 | "position": { 16 | "start": { 17 | "line": 3, 18 | "column": 3 19 | }, 20 | "end": { 21 | "line": 3, 22 | "column": 13 23 | }, 24 | "source": "input.css" 25 | } 26 | }, 27 | { 28 | "type": "declaration", 29 | "property": "the-species", 30 | "value": "called \"ferrets\"", 31 | "position": { 32 | "start": { 33 | "line": 4, 34 | "column": 3 35 | }, 36 | "end": { 37 | "line": 4, 38 | "column": 32 39 | }, 40 | "source": "input.css" 41 | } 42 | }, 43 | { 44 | "type": "declaration", 45 | "property": "*even", 46 | "value": "'ie crap'", 47 | "position": { 48 | "start": { 49 | "line": 5, 50 | "column": 3 51 | }, 52 | "end": { 53 | "line": 5, 54 | "column": 19 55 | }, 56 | "source": "input.css" 57 | } 58 | } 59 | ], 60 | "position": { 61 | "start": { 62 | "line": 2, 63 | "column": 1 64 | }, 65 | "end": { 66 | "line": 6, 67 | "column": 2 68 | }, 69 | "source": "input.css" 70 | } 71 | } 72 | ] 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /test/cases/props/compressed.css: -------------------------------------------------------------------------------- 1 | tobi loki jane{are:'all';the-species:called "ferrets";*even:'ie crap';} 2 | -------------------------------------------------------------------------------- /test/cases/props/input.css: -------------------------------------------------------------------------------- 1 | 2 | tobi loki jane { 3 | are: 'all'; 4 | the-species: called "ferrets"; 5 | *even: 'ie crap'; 6 | } 7 | -------------------------------------------------------------------------------- /test/cases/props/output.css: -------------------------------------------------------------------------------- 1 | tobi loki jane { 2 | are: 'all'; 3 | the-species: called "ferrets"; 4 | *even: 'ie crap'; 5 | } 6 | -------------------------------------------------------------------------------- /test/cases/quote-escape/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "rule", 7 | "selectors": [ 8 | "p[qwe=\"a\\\",b\"]" 9 | ], 10 | "declarations": [ 11 | { 12 | "type": "declaration", 13 | "property": "color", 14 | "value": "red", 15 | "position": { 16 | "start": { 17 | "line": 1, 18 | "column": 18 19 | }, 20 | "end": { 21 | "line": 1, 22 | "column": 29 23 | }, 24 | "source": "input.css" 25 | } 26 | } 27 | ], 28 | "position": { 29 | "start": { 30 | "line": 1, 31 | "column": 1 32 | }, 33 | "end": { 34 | "line": 1, 35 | "column": 30 36 | }, 37 | "source": "input.css" 38 | } 39 | } 40 | ], 41 | "parsingErrors": [] 42 | } 43 | } -------------------------------------------------------------------------------- /test/cases/quote-escape/compressed.css: -------------------------------------------------------------------------------- 1 | p[qwe="a\",b"]{color:red;} -------------------------------------------------------------------------------- /test/cases/quote-escape/input.css: -------------------------------------------------------------------------------- 1 | p[qwe="a\",b"] { color: red } 2 | -------------------------------------------------------------------------------- /test/cases/quote-escape/output.css: -------------------------------------------------------------------------------- 1 | p[qwe="a\",b"] { 2 | color: red; 3 | } -------------------------------------------------------------------------------- /test/cases/quoted/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "rule", 7 | "selectors": [ 8 | "body" 9 | ], 10 | "declarations": [ 11 | { 12 | "type": "declaration", 13 | "property": "background", 14 | "value": "url('some;stuff;here') 50% 50% no-repeat", 15 | "position": { 16 | "start": { 17 | "line": 2, 18 | "column": 3 19 | }, 20 | "end": { 21 | "line": 2, 22 | "column": 55 23 | }, 24 | "source": "input.css" 25 | } 26 | } 27 | ], 28 | "position": { 29 | "start": { 30 | "line": 1, 31 | "column": 1 32 | }, 33 | "end": { 34 | "line": 3, 35 | "column": 2 36 | }, 37 | "source": "input.css" 38 | } 39 | } 40 | ] 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /test/cases/quoted/compressed.css: -------------------------------------------------------------------------------- 1 | body{background:url('some;stuff;here') 50% 50% no-repeat;} 2 | -------------------------------------------------------------------------------- /test/cases/quoted/input.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: url('some;stuff;here') 50% 50% no-repeat; 3 | } 4 | -------------------------------------------------------------------------------- /test/cases/quoted/output.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: url('some;stuff;here') 50% 50% no-repeat; 3 | } 4 | -------------------------------------------------------------------------------- /test/cases/rule/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "rule", 7 | "selectors": [ 8 | "foo" 9 | ], 10 | "declarations": [ 11 | { 12 | "type": "declaration", 13 | "property": "bar", 14 | "value": "'baz'", 15 | "position": { 16 | "start": { 17 | "line": 2, 18 | "column": 3 19 | }, 20 | "end": { 21 | "line": 2, 22 | "column": 13 23 | }, 24 | "source": "input.css" 25 | } 26 | } 27 | ], 28 | "position": { 29 | "start": { 30 | "line": 1, 31 | "column": 1 32 | }, 33 | "end": { 34 | "line": 3, 35 | "column": 2 36 | }, 37 | "source": "input.css" 38 | } 39 | } 40 | ] 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /test/cases/rule/compressed.css: -------------------------------------------------------------------------------- 1 | foo{bar:'baz';} 2 | -------------------------------------------------------------------------------- /test/cases/rule/input.css: -------------------------------------------------------------------------------- 1 | foo { 2 | bar: 'baz'; 3 | } 4 | -------------------------------------------------------------------------------- /test/cases/rule/output.css: -------------------------------------------------------------------------------- 1 | foo { 2 | bar: 'baz'; 3 | } 4 | -------------------------------------------------------------------------------- /test/cases/rules/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "rule", 7 | "selectors": [ 8 | "tobi" 9 | ], 10 | "declarations": [ 11 | { 12 | "type": "declaration", 13 | "property": "name", 14 | "value": "'tobi'", 15 | "position": { 16 | "start": { 17 | "line": 2, 18 | "column": 3 19 | }, 20 | "end": { 21 | "line": 2, 22 | "column": 15 23 | }, 24 | "source": "input.css" 25 | } 26 | }, 27 | { 28 | "type": "declaration", 29 | "property": "age", 30 | "value": "2", 31 | "position": { 32 | "start": { 33 | "line": 3, 34 | "column": 3 35 | }, 36 | "end": { 37 | "line": 3, 38 | "column": 9 39 | }, 40 | "source": "input.css" 41 | } 42 | } 43 | ], 44 | "position": { 45 | "start": { 46 | "line": 1, 47 | "column": 1 48 | }, 49 | "end": { 50 | "line": 4, 51 | "column": 2 52 | }, 53 | "source": "input.css" 54 | } 55 | }, 56 | { 57 | "type": "rule", 58 | "selectors": [ 59 | "loki" 60 | ], 61 | "declarations": [ 62 | { 63 | "type": "declaration", 64 | "property": "name", 65 | "value": "'loki'", 66 | "position": { 67 | "start": { 68 | "line": 7, 69 | "column": 3 70 | }, 71 | "end": { 72 | "line": 7, 73 | "column": 15 74 | }, 75 | "source": "input.css" 76 | } 77 | }, 78 | { 79 | "type": "declaration", 80 | "property": "age", 81 | "value": "1", 82 | "position": { 83 | "start": { 84 | "line": 8, 85 | "column": 3 86 | }, 87 | "end": { 88 | "line": 8, 89 | "column": 9 90 | }, 91 | "source": "input.css" 92 | } 93 | } 94 | ], 95 | "position": { 96 | "start": { 97 | "line": 6, 98 | "column": 1 99 | }, 100 | "end": { 101 | "line": 9, 102 | "column": 2 103 | }, 104 | "source": "input.css" 105 | } 106 | } 107 | ] 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /test/cases/rules/compressed.css: -------------------------------------------------------------------------------- 1 | tobi{name:'tobi';age:2;}loki{name:'loki';age:1;} 2 | -------------------------------------------------------------------------------- /test/cases/rules/input.css: -------------------------------------------------------------------------------- 1 | tobi { 2 | name: 'tobi'; 3 | age: 2; 4 | } 5 | 6 | loki { 7 | name: 'loki'; 8 | age: 1; 9 | } 10 | -------------------------------------------------------------------------------- /test/cases/rules/output.css: -------------------------------------------------------------------------------- 1 | tobi { 2 | name: 'tobi'; 3 | age: 2; 4 | } 5 | 6 | loki { 7 | name: 'loki'; 8 | age: 1; 9 | } 10 | -------------------------------------------------------------------------------- /test/cases/selectors/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "rule", 7 | "selectors": [ 8 | "foo", 9 | "bar", 10 | "baz" 11 | ], 12 | "declarations": [ 13 | { 14 | "type": "declaration", 15 | "property": "color", 16 | "value": "'black'", 17 | "position": { 18 | "start": { 19 | "line": 4, 20 | "column": 3 21 | }, 22 | "end": { 23 | "line": 4, 24 | "column": 17 25 | }, 26 | "source": "input.css" 27 | } 28 | } 29 | ], 30 | "position": { 31 | "start": { 32 | "line": 1, 33 | "column": 1 34 | }, 35 | "end": { 36 | "line": 5, 37 | "column": 2 38 | }, 39 | "source": "input.css" 40 | } 41 | } 42 | ] 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /test/cases/selectors/compressed.css: -------------------------------------------------------------------------------- 1 | foo,bar,baz{color:'black';} 2 | -------------------------------------------------------------------------------- /test/cases/selectors/input.css: -------------------------------------------------------------------------------- 1 | foo, 2 | bar, 3 | baz { 4 | color: 'black'; 5 | } 6 | -------------------------------------------------------------------------------- /test/cases/selectors/output.css: -------------------------------------------------------------------------------- 1 | foo, 2 | bar, 3 | baz { 4 | color: 'black'; 5 | } 6 | -------------------------------------------------------------------------------- /test/cases/supports-linebreak/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "supports", 7 | "supports": "(display: flex)", 8 | "rules": [ 9 | { 10 | "type": "rule", 11 | "selectors": [ 12 | ".test" 13 | ], 14 | "declarations": [ 15 | { 16 | "type": "declaration", 17 | "property": "display", 18 | "value": "flex", 19 | "position": { 20 | "start": { 21 | "line": 4, 22 | "column": 17 23 | }, 24 | "end": { 25 | "line": 4, 26 | "column": 30 27 | }, 28 | "source": "input.css" 29 | } 30 | } 31 | ], 32 | "position": { 33 | "start": { 34 | "line": 4, 35 | "column": 9 36 | }, 37 | "end": { 38 | "line": 4, 39 | "column": 33 40 | }, 41 | "source": "input.css" 42 | } 43 | } 44 | ], 45 | "position": { 46 | "start": { 47 | "line": 1, 48 | "column": 1 49 | }, 50 | "end": { 51 | "line": 5, 52 | "column": 6 53 | }, 54 | "source": "input.css" 55 | } 56 | } 57 | ] 58 | } 59 | } -------------------------------------------------------------------------------- /test/cases/supports-linebreak/compressed.css: -------------------------------------------------------------------------------- 1 | @supports (display: flex){.test{display:flex;}} -------------------------------------------------------------------------------- /test/cases/supports-linebreak/input.css: -------------------------------------------------------------------------------- 1 | @supports 2 | (display: flex) 3 | { 4 | .test { display: flex; } 5 | } 6 | -------------------------------------------------------------------------------- /test/cases/supports-linebreak/output.css: -------------------------------------------------------------------------------- 1 | @supports (display: flex) { 2 | .test { 3 | display: flex; 4 | } 5 | } -------------------------------------------------------------------------------- /test/cases/supports/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "supports", 7 | "supports": "(display: flex) or (display: box)", 8 | "rules": [ 9 | { 10 | "type": "comment", 11 | "comment": " flex above ", 12 | "position": { 13 | "start": { 14 | "line": 2, 15 | "column": 3 16 | }, 17 | "end": { 18 | "line": 2, 19 | "column": 19 20 | }, 21 | "source": "input.css" 22 | } 23 | }, 24 | { 25 | "type": "rule", 26 | "selectors": [ 27 | ".flex" 28 | ], 29 | "declarations": [ 30 | { 31 | "type": "comment", 32 | "comment": " flex inside ", 33 | "position": { 34 | "start": { 35 | "line": 4, 36 | "column": 5 37 | }, 38 | "end": { 39 | "line": 4, 40 | "column": 22 41 | }, 42 | "source": "input.css" 43 | } 44 | }, 45 | { 46 | "type": "declaration", 47 | "property": "display", 48 | "value": "box", 49 | "position": { 50 | "start": { 51 | "line": 5, 52 | "column": 5 53 | }, 54 | "end": { 55 | "line": 5, 56 | "column": 17 57 | }, 58 | "source": "input.css" 59 | } 60 | }, 61 | { 62 | "type": "declaration", 63 | "property": "display", 64 | "value": "flex", 65 | "position": { 66 | "start": { 67 | "line": 6, 68 | "column": 5 69 | }, 70 | "end": { 71 | "line": 6, 72 | "column": 18 73 | }, 74 | "source": "input.css" 75 | } 76 | } 77 | ], 78 | "position": { 79 | "start": { 80 | "line": 3, 81 | "column": 3 82 | }, 83 | "end": { 84 | "line": 7, 85 | "column": 4 86 | }, 87 | "source": "input.css" 88 | } 89 | }, 90 | { 91 | "type": "rule", 92 | "selectors": [ 93 | "div" 94 | ], 95 | "declarations": [ 96 | { 97 | "type": "declaration", 98 | "property": "something", 99 | "value": "else", 100 | "position": { 101 | "start": { 102 | "line": 10, 103 | "column": 5 104 | }, 105 | "end": { 106 | "line": 10, 107 | "column": 20 108 | }, 109 | "source": "input.css" 110 | } 111 | } 112 | ], 113 | "position": { 114 | "start": { 115 | "line": 9, 116 | "column": 3 117 | }, 118 | "end": { 119 | "line": 11, 120 | "column": 4 121 | }, 122 | "source": "input.css" 123 | } 124 | } 125 | ], 126 | "position": { 127 | "start": { 128 | "line": 1, 129 | "column": 1 130 | }, 131 | "end": { 132 | "line": 12, 133 | "column": 2 134 | }, 135 | "source": "input.css" 136 | } 137 | } 138 | ] 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /test/cases/supports/compressed.css: -------------------------------------------------------------------------------- 1 | @supports (display: flex) or (display: box){.flex{display:box;display:flex;}div{something:else;}} 2 | -------------------------------------------------------------------------------- /test/cases/supports/input.css: -------------------------------------------------------------------------------- 1 | @supports (display: flex) or (display: box) { 2 | /* flex above */ 3 | .flex { 4 | /* flex inside */ 5 | display: box; 6 | display: flex; 7 | } 8 | 9 | div { 10 | something: else; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/cases/supports/output.css: -------------------------------------------------------------------------------- 1 | @supports (display: flex) or (display: box) { 2 | /* flex above */ 3 | 4 | .flex { 5 | /* flex inside */ 6 | display: box; 7 | display: flex; 8 | } 9 | 10 | div { 11 | something: else; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/cases/wtf/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "rule", 7 | "selectors": [ 8 | ".wtf" 9 | ], 10 | "declarations": [ 11 | { 12 | "type": "declaration", 13 | "property": "*overflow-x", 14 | "value": "hidden", 15 | "position": { 16 | "start": { 17 | "line": 2, 18 | "column": 3 19 | }, 20 | "end": { 21 | "line": 2, 22 | "column": 22 23 | }, 24 | "source": "input.css" 25 | } 26 | }, 27 | { 28 | "type": "declaration", 29 | "property": "//max-height", 30 | "value": "110px", 31 | "position": { 32 | "start": { 33 | "line": 3, 34 | "column": 3 35 | }, 36 | "end": { 37 | "line": 3, 38 | "column": 22 39 | }, 40 | "source": "input.css" 41 | } 42 | }, 43 | { 44 | "type": "declaration", 45 | "property": "#height", 46 | "value": "18px", 47 | "position": { 48 | "start": { 49 | "line": 4, 50 | "column": 3 51 | }, 52 | "end": { 53 | "line": 4, 54 | "column": 16 55 | }, 56 | "source": "input.css" 57 | } 58 | } 59 | ], 60 | "position": { 61 | "start": { 62 | "line": 1, 63 | "column": 1 64 | }, 65 | "end": { 66 | "line": 5, 67 | "column": 2 68 | }, 69 | "source": "input.css" 70 | } 71 | } 72 | ] 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /test/cases/wtf/compressed.css: -------------------------------------------------------------------------------- 1 | .wtf{*overflow-x:hidden;//max-height:110px;#height:18px;} 2 | -------------------------------------------------------------------------------- /test/cases/wtf/input.css: -------------------------------------------------------------------------------- 1 | .wtf { 2 | *overflow-x: hidden; 3 | //max-height: 110px; 4 | #height: 18px; 5 | } 6 | -------------------------------------------------------------------------------- /test/cases/wtf/output.css: -------------------------------------------------------------------------------- 1 | .wtf { 2 | *overflow-x: hidden; 3 | //max-height: 110px; 4 | #height: 18px; 5 | } 6 | -------------------------------------------------------------------------------- /test/parse.js: -------------------------------------------------------------------------------- 1 | var parse = require('../').parse; 2 | var should = require('should'); 3 | 4 | describe('parse(str)', function() { 5 | it('should save the filename and source', function() { 6 | var css = 'booty {\n size: large;\n}\n'; 7 | var ast = parse(css, { 8 | source: 'booty.css' 9 | }); 10 | 11 | ast.stylesheet.source.should.equal('booty.css'); 12 | 13 | var position = ast.stylesheet.rules[0].position; 14 | position.start.should.be.ok; 15 | position.end.should.be.ok; 16 | position.source.should.equal('booty.css'); 17 | position.content.should.equal(css); 18 | }); 19 | 20 | it('should throw when a selector is missing', function() { 21 | should(function() { 22 | parse('{size: large}'); 23 | }).throw(); 24 | 25 | should(function() { 26 | parse('b { color: red; }\n{ color: green; }\na { color: blue; }'); 27 | }).throw(); 28 | }); 29 | 30 | it('should throw when a broken comment is found', function () { 31 | should(function() { 32 | parse('thing { color: red; } /* b { color: blue; }'); 33 | }).throw(); 34 | 35 | should(function() { 36 | parse('/*'); 37 | }).throw(); 38 | 39 | /* Nested comments should be fine */ 40 | should(function() { 41 | parse('/* /* */'); 42 | }).not.throw(); 43 | }); 44 | 45 | it('should allow empty property value', function() { 46 | should(function() { 47 | parse('p { color:; }'); 48 | }).not.throw(); 49 | }); 50 | 51 | it('should not throw with silent option', function () { 52 | should(function() { 53 | parse('thing { color: red; } /* b { color: blue; }', { silent: true }); 54 | }).not.throw(); 55 | }); 56 | 57 | it('should list the parsing errors and continue parsing', function() { 58 | var result = parse('foo { color= red; } bar { color: blue; } baz {}} boo { display: none}', { 59 | silent: true, 60 | source: 'foo.css' 61 | }); 62 | 63 | var rules = result.stylesheet.rules; 64 | rules.length.should.be.above(2); 65 | 66 | var errors = result.stylesheet.parsingErrors; 67 | errors.length.should.equal(2); 68 | 69 | errors[0].should.have.a.property('message'); 70 | errors[0].should.have.a.property('reason'); 71 | errors[0].should.have.a.property('filename'); 72 | errors[0].filename.should.equal('foo.css'); 73 | errors[0].should.have.a.property('line'); 74 | errors[0].should.have.a.property('column'); 75 | errors[0].should.have.a.property('source'); 76 | 77 | }); 78 | 79 | it('should set parent property', function() { 80 | var result = parse( 81 | 'thing { test: value; }\n' + 82 | '@media (min-width: 100px) { thing { test: value; } }'); 83 | 84 | should(result.parent).equal(null); 85 | 86 | var rules = result.stylesheet.rules; 87 | rules.length.should.equal(2); 88 | 89 | var rule = rules[0]; 90 | rule.parent.should.equal(result); 91 | rule.declarations.length.should.equal(1); 92 | 93 | var decl = rule.declarations[0]; 94 | decl.parent.should.equal(rule); 95 | 96 | var media = rules[1]; 97 | media.parent.should.equal(result); 98 | media.rules.length.should.equal(1); 99 | 100 | rule = media.rules[0]; 101 | rule.parent.should.equal(media); 102 | 103 | rule.declarations.length.should.equal(1); 104 | decl = rule.declarations[0]; 105 | decl.parent.should.equal(rule); 106 | }); 107 | 108 | }); 109 | -------------------------------------------------------------------------------- /test/source-map/apply.css: -------------------------------------------------------------------------------- 1 | tobi { 2 | name: 'tobi'; } 3 | 4 | /*# sourceMappingURL=apply.css.map */ -------------------------------------------------------------------------------- /test/source-map/apply.css.map: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "file": "", 4 | "sources": ["apply.scss"], 5 | "names": [], 6 | "mappings": "AAAA;EAAO,MAAM" 7 | } -------------------------------------------------------------------------------- /test/source-map/apply.scss: -------------------------------------------------------------------------------- 1 | tobi { name: 'tobi'; } 2 | -------------------------------------------------------------------------------- /test/source-map/test.css: -------------------------------------------------------------------------------- 1 | tobi { 2 | name: 'tobi'; 3 | age: 2; 4 | } 5 | 6 | loki { 7 | name: 'loki'; 8 | age: 1; 9 | } 10 | 11 | @media screen { 12 | screen-only { 13 | display: block; 14 | } 15 | } 16 | 17 | /* comment */ 18 | -------------------------------------------------------------------------------- /test/stringify.js: -------------------------------------------------------------------------------- 1 | var stringify = require('../').stringify; 2 | var parse = require('../').parse; 3 | var path = require('path'); 4 | var read = require('fs').readFileSync; 5 | var SourceMapConsumer = require('source-map').SourceMapConsumer; 6 | var SourceMapGenerator = require('source-map').SourceMapGenerator; 7 | 8 | describe('stringify(obj, {sourcemap: true})', function() { 9 | var file = 'test/source-map/test.css'; 10 | var src = read(file, 'utf8'); 11 | var stylesheet = parse(src, { source: file }); 12 | function loc(line, column) { 13 | return { line: line, column: column, source: file, name: null }; 14 | } 15 | 16 | var locs = { 17 | tobiSelector: loc(1, 0), 18 | tobiNameName: loc(2, 2), 19 | tobiNameValue: loc(2, 2), 20 | mediaBlock: loc(11, 0), 21 | mediaOnly: loc(12, 2), 22 | comment: loc(17, 0), 23 | }; 24 | 25 | it('should generate source maps alongside when using identity compiler', function() { 26 | var result = stringify(stylesheet, { sourcemap: true }); 27 | result.should.have.property('code'); 28 | result.should.have.property('map'); 29 | var map = new SourceMapConsumer(result.map); 30 | map.originalPositionFor({ line: 1, column: 0 }).should.eql(locs.tobiSelector); 31 | map.originalPositionFor({ line: 2, column: 2 }).should.eql(locs.tobiNameName); 32 | map.originalPositionFor({ line: 2, column: 8 }).should.eql(locs.tobiNameValue); 33 | map.originalPositionFor({ line: 11, column: 0 }).should.eql(locs.mediaBlock); 34 | map.originalPositionFor({ line: 12, column: 2 }).should.eql(locs.mediaOnly); 35 | map.originalPositionFor({ line: 17, column: 0 }).should.eql(locs.comment); 36 | map.sourceContentFor(file).should.eql(src); 37 | }); 38 | 39 | it('should generate source maps alongside when using compress compiler', function() { 40 | var result = stringify(stylesheet, { compress: true, sourcemap: true }); 41 | result.should.have.property('code'); 42 | result.should.have.property('map'); 43 | var map = new SourceMapConsumer(result.map); 44 | map.originalPositionFor({ line: 1, column: 0 }).should.eql(locs.tobiSelector); 45 | map.originalPositionFor({ line: 1, column: 5 }).should.eql(locs.tobiNameName); 46 | map.originalPositionFor({ line: 1, column: 10 }).should.eql(locs.tobiNameValue); 47 | map.originalPositionFor({ line: 1, column: 50 }).should.eql(locs.mediaBlock); 48 | map.originalPositionFor({ line: 1, column: 64 }).should.eql(locs.mediaOnly); 49 | map.sourceContentFor(file).should.eql(src); 50 | }); 51 | 52 | it('should apply included source maps, with paths adjusted to CWD', function() { 53 | var file = 'test/source-map/apply.css'; 54 | var src = read(file, 'utf8'); 55 | var stylesheet = parse(src, { source: file }); 56 | var result = stringify(stylesheet, { sourcemap: true }); 57 | result.should.have.property('code'); 58 | result.should.have.property('map'); 59 | 60 | var map = new SourceMapConsumer(result.map); 61 | map.originalPositionFor({ line: 1, column: 0 }).should.eql({ 62 | column: 0, 63 | line: 1, 64 | name: null, 65 | source: 'test/source-map/apply.scss' 66 | }); 67 | 68 | map.originalPositionFor({ line: 2, column: 2 }).should.eql({ 69 | column: 7, 70 | line: 1, 71 | name: null, 72 | source: 'test/source-map/apply.scss' 73 | }); 74 | }); 75 | 76 | it('should not apply included source maps when inputSourcemap is false', function() { 77 | var file = 'test/source-map/apply.css'; 78 | var src = read(file, 'utf8'); 79 | var stylesheet = parse(src, { source: file }); 80 | var result = stringify(stylesheet, { sourcemap: true, inputSourcemaps: false }); 81 | 82 | var map = new SourceMapConsumer(result.map); 83 | map.originalPositionFor({ line: 1, column: 0 }).should.eql({ 84 | column: 0, 85 | line: 1, 86 | name: null, 87 | source: file 88 | }); 89 | }); 90 | 91 | it('should convert Windows-style paths to URLs', function() { 92 | var originalSep = path.sep; 93 | path.sep = '\\'; // Pretend we’re on Windows (if we aren’t already). 94 | 95 | var src = 'C:\\test\\source.css'; 96 | var css = 'a { color: black; }' 97 | var stylesheet = parse(css, { source: src }); 98 | var result = stringify(stylesheet, { sourcemap: true }); 99 | 100 | result.map.sources.should.eql(['/test/source.css']); 101 | 102 | path.sep = originalSep; 103 | }); 104 | 105 | it('should return source map generator when sourcemap: "generator"', function(){ 106 | var css = 'a { color: black; }'; 107 | var stylesheet = parse(css); 108 | var result = stringify(stylesheet, { sourcemap: 'generator' }); 109 | 110 | result.map.should.be.an.instanceOf(SourceMapGenerator); 111 | }); 112 | }); 113 | --------------------------------------------------------------------------------