├── .gitattributes ├── .gitignore ├── .travis.yml ├── Makefile ├── README.md ├── bin ├── css.ml └── dune ├── css.opam ├── docs ├── README.md ├── camel-train.4e48f6b0.png ├── codemirror.c7cb63f8.css ├── codemirror.c7cb63f8.map ├── index.html ├── party-camel.0684fd20.jpeg ├── src.46f26b8e.map ├── src.c4c495dd.js ├── src │ ├── css.js │ ├── docs.html │ ├── images │ │ ├── .DS_Store │ │ ├── camel-train.png │ │ └── party-camel.jpeg │ ├── index.html │ ├── index.js │ ├── lib │ │ ├── code-mirror-modes │ │ │ ├── css.js │ │ │ └── javascript.js │ │ ├── codemirror.css │ │ ├── codemirror.js │ │ └── css-parser.js │ ├── package.json │ ├── styles.css │ └── yarn.lock ├── styles.a142ff0e.css └── styles.a142ff0e.map ├── dune ├── dune-project ├── esy.lock.json ├── js_export ├── Index.ml └── dune ├── lib ├── Index.ml ├── Lexer.mll ├── Parser.mly ├── Printer.ml ├── Types.ml └── dune ├── package.json └── test ├── cases.test.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 ├── 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 ├── selector-compound │ ├── ast.json │ ├── compressed.css │ ├── input.css │ └── output.css ├── selector-space │ ├── 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 ├── dune ├── parse.js ├── stringify.js └── test.ml /.gitattributes: -------------------------------------------------------------------------------- 1 | *.lock.json binary 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | npm-debug.log 2 | .merlin 3 | yarn-error.log 4 | node_modules/ 5 | _build 6 | _esybuild 7 | _esyinstall 8 | _release 9 | *.byte 10 | *.native 11 | *.install 12 | esy.lock 13 | Parser.mli 14 | Parser.ml 15 | Lexer.ml 16 | Parser.automaton 17 | Parser.conflicts 18 | .cache 19 | dist 20 | _esy 21 | node_modules 22 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 6 4 | - 8 5 | os: 6 | - linux 7 | - osx 8 | install: 9 | - npm install --global esy@latest 10 | - esy install 11 | script: 12 | - esy build 13 | - make test 14 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | build: lexer #parser 2 | @esy build 3 | 4 | test: build 5 | ./_build/install/default/bin/test 6 | 7 | lexer: 8 | @ocamllex -q ./lib/Lexer.mll 9 | 10 | parser: 11 | #@esy menhir --table --trace --explain --dump ./lib/Parser.mly 12 | @esy menhir --table --explain ./lib/Parser.mly 13 | 14 | release: 15 | @esy release 16 | 17 | format: 18 | @esy dune build @fmt --auto-promote 19 | 20 | clean: 21 | rm -rf ./lib/Lexer.ml ./lib/Parser.mli ./lib/Parser.ml _build _release -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # css-parse 2 | [](https://travis-ci.org/samouri/ocaml-css) 3 | 4 | parse, detect errors, and pretty-print css directly in terminal, natively in OCaml, or even from JavaScript. 5 | 6 | **this is under active development, please do not use yet** 7 | 8 | ### Overview 9 | 10 | `css-parse` is written in OCaml and utilizes ocamllex and [menhir](http://gallium.inria.fr/~fpottier/menhir/manual.html) for lexer and parser generation. A pretty good introduction and explanation of the tools can be found in [Real World Ocaml](https://v1.realworldocaml.org/v1/en/html/parsing-with-ocamllex-and-menhir.html). 11 | We generate a binary as well that can be run from the command line. 12 | 13 | ### Development 14 | 15 | You'll need to install esy as well as menhir. 16 | To bootstrap the project run: 17 | ``` 18 | esy install 19 | make 20 | ``` 21 | 22 | ### Testing Done 23 | 24 | In order to test this module, I've stolen test cases from the very well tested [reworkcss](https://github.com/reworkcss/css). 25 | All of the test cases are run through OUnit and can be executed with: 26 | 27 | ``` 28 | make test 29 | ``` 30 | -------------------------------------------------------------------------------- /bin/css.ml: -------------------------------------------------------------------------------- 1 | (* open Lib.Types *) 2 | open Lib.Index 3 | open Cmdliner 4 | 5 | type output_t = Pretty | Errors | AST 6 | 7 | exception ArgException of string 8 | 9 | let str_of_output = function 10 | | Pretty -> "pretty" 11 | | Errors -> "errors" 12 | | AST -> "ast" 13 | 14 | let output_of_str o = 15 | match String.lowercase_ascii o with 16 | | "pretty" -> Pretty 17 | | "errors" -> Errors 18 | | "ast" -> AST 19 | | s -> 20 | raise 21 | (ArgException (Printf.sprintf "invalid string for output type: %s" s)) 22 | 23 | let output = 24 | let doc = 25 | "Pick what ocaml-css should do: pretty print, astprint, or check for errors" 26 | in 27 | Arg.(value & opt string "pretty" & info ["o"; "output"] ~docv:"OUTPUT" ~doc) 28 | 29 | let file = 30 | let doc = "The file " in 31 | Arg.(required & pos 0 (some string) None & info [] ~docv:"FILE" ~doc) 32 | 33 | let info = 34 | let doc = "parse a css document in order to detect errors" in 35 | let man = 36 | [ `S Manpage.s_bugs 37 | ; `P 38 | "Open bug reports as issues on the GitHub repo at \ 39 | https://github.com/samouri/ocaml-css." ] 40 | in 41 | Term.info "css" ~version:"%%VERSION%%" ~doc ~exits:Term.default_exits ~man 42 | 43 | let load_file f = 44 | let ic = open_in f in 45 | let n = in_channel_length ic in 46 | let s = Bytes.create n in 47 | really_input ic s 0 n ; close_in ic ; Bytes.to_string s 48 | 49 | let run file output_str = 50 | let parsed = parse ~fp:file (load_file file) in 51 | let output_flag = output_of_str output_str in 52 | (* learn how to make the proper CMDLiner converter for this *) 53 | let output = 54 | if output_flag = Pretty then print parsed else astPrint parsed 55 | in 56 | print_endline output 57 | 58 | let css_t = Term.(const run $ file $ output) 59 | 60 | let () = Term.exit @@ Term.eval (css_t, Term.info "css-parse") 61 | -------------------------------------------------------------------------------- /bin/dune: -------------------------------------------------------------------------------- 1 | (executable 2 | (name css) 3 | (public_name css-parse) 4 | (libraries lib cmdliner yojson) 5 | (preprocess (pps ppx_deriving.std ppx_deriving_yojson)) 6 | ) 7 | -------------------------------------------------------------------------------- /css.opam: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samouri/ocaml-css/5fbc3482b1e665dc134eba0c8fb0a1558c9943e0/css.opam -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # css-parse-explorer 2 | 3 | [css-parse-explorer](https://samouri.github.io/ocaml-css/) is a tool to help individuals explore the AST generated by css-parse as well as to prove the viability of using an OCaml generated library in the browser. 4 | 5 | ### Development 6 | 7 | ```bash 8 | cd src 9 | npm install 10 | npm start 11 | ``` 12 | 13 | ## Deployment 14 | 15 | the current process is a hack. 16 | 17 | 1. delete all web files (keep src and this README) 18 | 2. run `npm run build` from within the `src` directory which should build the app and `mv` the new web files here. 19 | 3. commit and push! [GitHub Pages](https://pages.github.com/) should pick up the changes within seconds. -------------------------------------------------------------------------------- /docs/camel-train.4e48f6b0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samouri/ocaml-css/5fbc3482b1e665dc134eba0c8fb0a1558c9943e0/docs/camel-train.4e48f6b0.png -------------------------------------------------------------------------------- /docs/codemirror.c7cb63f8.css: -------------------------------------------------------------------------------- 1 | .CodeMirror{color:#000;direction:ltr;font-family:monospace;height:300px}.CodeMirror-lines{padding:4px 0}.CodeMirror pre{padding:0 4px}.CodeMirror-gutter-filler,.CodeMirror-scrollbar-filler{background-color:#fff}.CodeMirror-gutters{background-color:#f7f7f7;border-right:1px solid #ddd;white-space:nowrap}.CodeMirror-linenumber{color:#999;min-width:20px;padding:0 3px 0 5px;text-align:right;white-space:nowrap}.CodeMirror-guttermarker{color:#000}.CodeMirror-guttermarker-subtle{color:#999}.CodeMirror-cursor{border-left:1px solid #000;border-right:none;width:0}.CodeMirror div.CodeMirror-secondarycursor{border-left:1px solid silver}.cm-fat-cursor .CodeMirror-cursor{background:#7e7;border:0!important;width:auto}.cm-fat-cursor div.CodeMirror-cursors{z-index:1}.cm-fat-cursor-mark{background-color:rgba(20,255,20,.5)}.cm-animate-fat-cursor,.cm-fat-cursor-mark{-moz-animation:blink 1.06s steps(1) infinite;-webkit-animation:blink 1.06s steps(1) infinite;animation:blink 1.06s steps(1) infinite}.cm-animate-fat-cursor{background-color:#7e7;border:0;width:auto}@-moz-keyframes blink{50%{background-color:transparent}}@-webkit-keyframes blink{50%{background-color:transparent}}@keyframes blink{50%{background-color:transparent}}.cm-tab{display:inline-block;text-decoration:inherit}.CodeMirror-rulers{bottom:-20px;left:0;overflow:hidden;position:absolute;right:0;top:-50px}.CodeMirror-ruler{border-left:1px solid #ccc;bottom:0;position:absolute;top:0}.cm-s-default .cm-header{color:#00f}.cm-s-default .cm-quote{color:#090}.cm-negative{color:#d44}.cm-positive{color:#292}.cm-header,.cm-strong{font-weight:700}.cm-em{font-style:italic}.cm-link{text-decoration:underline}.cm-strikethrough{text-decoration:line-through}.cm-s-default .cm-keyword{color:#708}.cm-s-default .cm-atom{color:#219}.cm-s-default .cm-number{color:#164}.cm-s-default .cm-def{color:#00f}.cm-s-default .cm-variable-2{color:#05a}.cm-s-default .cm-type,.cm-s-default .cm-variable-3{color:#085}.cm-s-default .cm-comment{color:#a50}.cm-s-default .cm-string{color:#a11}.cm-s-default .cm-string-2{color:#f50}.cm-s-default .cm-meta,.cm-s-default .cm-qualifier{color:#555}.cm-s-default .cm-builtin{color:#30a}.cm-s-default .cm-bracket{color:#997}.cm-s-default .cm-tag{color:#170}.cm-s-default .cm-attribute{color:#00c}.cm-s-default .cm-hr{color:#999}.cm-s-default .cm-link{color:#00c}.cm-invalidchar,.cm-s-default .cm-error{color:red}.CodeMirror-composing{border-bottom:2px solid}div.CodeMirror span.CodeMirror-matchingbracket{color:#0b0}div.CodeMirror span.CodeMirror-nonmatchingbracket{color:#a22}.CodeMirror-matchingtag{background:rgba(255,150,0,.3)}.CodeMirror-activeline-background{background:#e8f2ff}.CodeMirror{background:#fff;overflow:hidden;position:relative}.CodeMirror-scroll{height:100%;margin-bottom:-30px;margin-right:-30px;outline:none;overflow:scroll!important;padding-bottom:30px;position:relative}.CodeMirror-sizer{border-right:30px solid transparent;position:relative}.CodeMirror-gutter-filler,.CodeMirror-hscrollbar,.CodeMirror-scrollbar-filler,.CodeMirror-vscrollbar{display:none;position:absolute;z-index:6}.CodeMirror-vscrollbar{overflow-x:hidden;overflow-y:scroll;right:0;top:0}.CodeMirror-hscrollbar{bottom:0;left:0;overflow-x:scroll;overflow-y:hidden}.CodeMirror-scrollbar-filler{bottom:0;right:0}.CodeMirror-gutter-filler{bottom:0;left:0}.CodeMirror-gutters{left:0;min-height:100%;position:absolute;top:0;z-index:3}.CodeMirror-gutter{display:inline-block;height:100%;margin-bottom:-30px;vertical-align:top;white-space:normal}.CodeMirror-gutter-wrapper{background:none!important;border:none!important;position:absolute;z-index:4}.CodeMirror-gutter-background{bottom:0;position:absolute;top:0;z-index:4}.CodeMirror-gutter-elt{cursor:default;position:absolute;z-index:4}.CodeMirror-gutter-wrapper ::selection{background-color:transparent}.CodeMirror-gutter-wrapper ::-moz-selection{background-color:transparent}.CodeMirror-lines{cursor:text;min-height:1px}.CodeMirror pre{-moz-border-radius:0;-webkit-border-radius:0;-webkit-font-variant-ligatures:contextual;-webkit-tap-highlight-color:transparent;background:transparent;border-radius:0;border-width:0;color:inherit;font-family:inherit;font-size:inherit;font-variant-ligatures:contextual;line-height:inherit;margin:0;overflow:visible;position:relative;white-space:pre;word-wrap:normal;z-index:2}.CodeMirror-wrap pre{white-space:pre-wrap;word-break:normal;word-wrap:break-word}.CodeMirror-linebackground{bottom:0;left:0;position:absolute;right:0;top:0;z-index:0}.CodeMirror-linewidget{padding:.1px;position:relative;z-index:2}.CodeMirror-rtl pre{direction:rtl}.CodeMirror-code{outline:none}.CodeMirror-gutter,.CodeMirror-gutters,.CodeMirror-linenumber,.CodeMirror-scroll,.CodeMirror-sizer{-moz-box-sizing:content-box;box-sizing:content-box}.CodeMirror-measure{height:0;overflow:hidden;position:absolute;visibility:hidden;width:100%}.CodeMirror-cursor{pointer-events:none;position:absolute}.CodeMirror-measure pre{position:static}div.CodeMirror-cursors{position:relative;visibility:hidden;z-index:3}.CodeMirror-focused div.CodeMirror-cursors,div.CodeMirror-dragcursors{visibility:visible}.CodeMirror-selected{background:#d9d9d9}.CodeMirror-focused .CodeMirror-selected{background:#d7d4f0}.CodeMirror-crosshair{cursor:crosshair}.CodeMirror-line::selection,.CodeMirror-line>span::selection,.CodeMirror-line>span>span::selection{background:#d7d4f0}.CodeMirror-line::-moz-selection,.CodeMirror-line>span::-moz-selection,.CodeMirror-line>span>span::-moz-selection{background:#d7d4f0}.cm-searching{background-color:#ffa;background-color:rgba(255,255,0,.4)}.cm-force-border{padding-right:.1px}@media print{.CodeMirror div.CodeMirror-cursors{visibility:hidden}}.cm-tab-wrap-hack:after{content:""}span.CodeMirror-selectedtext{background:none} -------------------------------------------------------------------------------- /docs/codemirror.c7cb63f8.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":[],"names":[],"mappings":"","file":"codemirror.c7cb63f8.map","sourceRoot":".."} -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 |
{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) 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) screen; 2 | -------------------------------------------------------------------------------- /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"; 2 | -------------------------------------------------------------------------------- /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": 4, 38 | "column": 32 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 | } 42 | } -------------------------------------------------------------------------------- /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 | } 4 | -------------------------------------------------------------------------------- /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/selector-compound/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "rule", 7 | "selectors": [ "foo.bar" ], 8 | "declarations": [ 9 | { 10 | "type": "declaration", 11 | "property": "color", 12 | "value": "'black'", 13 | "position": { 14 | "start": { "line": 2, "column": 3 }, 15 | "end": { "line": 2, "column": 17 }, 16 | "source": "input.css" 17 | } 18 | } 19 | ], 20 | "position": { 21 | "start": { "line": 1, "column": 1 }, 22 | "end": { "line": 3, "column": 2 }, 23 | "source": "input.css" 24 | } 25 | } 26 | ] 27 | } 28 | } -------------------------------------------------------------------------------- /test/cases/selector-compound/compressed.css: -------------------------------------------------------------------------------- 1 | foo,bar,baz{color:'black';} 2 | -------------------------------------------------------------------------------- /test/cases/selector-compound/input.css: -------------------------------------------------------------------------------- 1 | foo.bar { 2 | color: 'black'; 3 | } 4 | -------------------------------------------------------------------------------- /test/cases/selector-compound/output.css: -------------------------------------------------------------------------------- 1 | foo.bar { 2 | color: 'black'; 3 | } 4 | -------------------------------------------------------------------------------- /test/cases/selector-space/ast.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "stylesheet", 3 | "stylesheet": { 4 | "rules": [ 5 | { 6 | "type": "rule", 7 | "selectors": [ "foo bar" ], 8 | "declarations": [ 9 | { 10 | "type": "declaration", 11 | "property": "color", 12 | "value": "'black'", 13 | "position": { 14 | "start": { "line": 2, "column": 3 }, 15 | "end": { "line": 2, "column": 17 }, 16 | "source": "input.css" 17 | } 18 | } 19 | ], 20 | "position": { 21 | "start": { "line": 1, "column": 1 }, 22 | "end": { "line": 3, "column": 2 }, 23 | "source": "input.css" 24 | } 25 | } 26 | ] 27 | } 28 | } -------------------------------------------------------------------------------- /test/cases/selector-space/compressed.css: -------------------------------------------------------------------------------- 1 | foo bar{color:'black';} 2 | -------------------------------------------------------------------------------- /test/cases/selector-space/input.css: -------------------------------------------------------------------------------- 1 | foo bar { 2 | color: 'black'; 3 | } 4 | -------------------------------------------------------------------------------- /test/cases/selector-space/output.css: -------------------------------------------------------------------------------- 1 | foo bar { 2 | color: 'black'; 3 | } 4 | -------------------------------------------------------------------------------- /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/dune: -------------------------------------------------------------------------------- 1 | (executable 2 | (name test) 3 | (public_name test) 4 | (libraries lib cmdliner yojson ounit) 5 | (preprocess (pps ppx_deriving.std ppx_deriving_yojson)) 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/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 | -------------------------------------------------------------------------------- /test/test.ml: -------------------------------------------------------------------------------- 1 | open Lib.Index 2 | open OUnit2 3 | 4 | let dir_contents dir = Sys.readdir dir |> Array.to_list 5 | 6 | let load_file f = 7 | let ic = open_in f in 8 | let n = in_channel_length ic in 9 | let s = Bytes.create n in 10 | really_input ic s 0 n ; close_in ic ; Bytes.to_string s 11 | 12 | let rec printlst = function 13 | | [] -> () 14 | | hd :: tl -> print_endline hd ; printlst tl 15 | 16 | let test_path = "./test/cases" 17 | 18 | let test_dirs = dir_contents test_path 19 | 20 | let get_test_for_dir dir = 21 | let filename = test_path ^ "/" ^ dir ^ "/input.css" in 22 | let inputStr = load_file filename in 23 | let expectedStr = load_file (test_path ^ "/" ^ dir ^ "/output.css") in 24 | let expectedAst = 25 | Yojson.Safe.prettify (load_file (test_path ^ "/" ^ dir ^ "/ast.json")) 26 | in 27 | dir 28 | >:: fun _ -> 29 | let actualAst = astPrint (parse ~fp:filename inputStr) in 30 | let actualStr = print (parse ~fp:filename inputStr) in 31 | assert_equal ~msg:"pretty-print" ~printer:(fun x -> x) expectedStr actualStr ; 32 | assert_equal ~msg:"ast-print" ~printer:(fun x -> x) expectedAst actualAst 33 | 34 | let suite = 35 | "suite" 36 | >::: List.map 37 | (fun dir -> get_test_for_dir dir) 38 | [ "at-namespace" 39 | ; "charset" 40 | ; "charset-linebreak" 41 | ; "colon-space" 42 | ; "comma-attribute" 43 | ; "comma-selector-function" 44 | ; "comment" 45 | ; "comment-in" 46 | ; "comment-url" 47 | (* ; "custom-media" 48 | ; "custom-media-linebreak" 49 | ; "document" 50 | ; "document-linebreak" *) 51 | ; "empty" 52 | (* ; "escapes" 53 | ; "font-face" 54 | ; "font-face-linebreak" 55 | ; "hose-linebreak" 56 | ; "host" *) 57 | ; "import" 58 | ; "import-linebreak" 59 | ; "import-messed" 60 | (* ; "keyframes" 61 | ; "keyframes-advanced" 62 | ; "keyframes-complex" 63 | ; "keyframes-linebreak" 64 | ; "keyframes-messed" 65 | ; "keyframes-vendor" 66 | ; "media" 67 | ; "media-linebreak" 68 | ; "media-messed" 69 | ; "messed-up" *) 70 | ; "namespace" 71 | ; "namespace-linebreak" 72 | ; "no-semi" 73 | (* ; "page-linebreak" 74 | ; "paged-media" *) 75 | ; "props" 76 | ; "quote-escape" 77 | ; "quoted" 78 | ; "rule" 79 | ; "rules" 80 | ; "selectors" 81 | ; "selector-space" 82 | ; "selector-compound" 83 | (* ; "supports" 84 | ; "supports-linebreak" 85 | ; "wtf" *) 86 | ] 87 | 88 | ;; 89 | run_test_tt_main suite 90 | --------------------------------------------------------------------------------