style Dashboard
This commit is contained in:
325
node_modules/csso/HISTORY.md
generated
vendored
Executable file
325
node_modules/csso/HISTORY.md
generated
vendored
Executable file
@@ -0,0 +1,325 @@
|
||||
## 2.3.2 (March 11, 2016)
|
||||
|
||||
- Fix infinite loop on value parse (#328)
|
||||
|
||||
## 2.3.1 (January 6, 2016)
|
||||
|
||||
- Added `\0` IE hack support (#320)
|
||||
|
||||
## 2.3.0 (October 25, 2016)
|
||||
|
||||
- Added `beforeCompress` and `afterCompress` options support (#316)
|
||||
- Fixed crash on empty argument in function (#317)
|
||||
|
||||
## 2.2.1 (July 25, 2016)
|
||||
|
||||
- Fixed shorthand optimisation issue when value has a color value or something unknown (#311)
|
||||
- Fixed `cursor` broken fallback (#306)
|
||||
|
||||
## 2.2.0 (June 23, 2016)
|
||||
|
||||
- Implement AST cloning by adding `clone()` [function](https://github.com/css/csso#cloneast) and `clone` [option](https://github.com/css/csso#compressast-options) for `compress()` function (#296)
|
||||
- Fix parse and translate attribute selector with flags but w/o operator (i.e. `[attrName i]`)
|
||||
- Don't merge rules with flagged attribute selectors with others (#291)
|
||||
- Take in account functions when merge TRBL-properties (#297, thanks to @ArturAralin)
|
||||
- Improve partial merge (#304)
|
||||
- Tweak scanner, reduce code deoptimizations and other small improvements
|
||||
|
||||
## 2.1.1 (May 11, 2016)
|
||||
|
||||
- Fix wrong declaration with `\9` hack merge (#295)
|
||||
|
||||
## 2.1.0 (May 8, 2016)
|
||||
|
||||
- New option `comments` to specify what comments to left: `exclamation`, `first-exclamation` and `none`
|
||||
- Add `offset` to CSS parse error details
|
||||
- Fix token `offset` computation
|
||||
|
||||
## 2.0.0 (April 5, 2016)
|
||||
|
||||
- No more `gonzales` AST format and related code
|
||||
- `minify()` and `minifyBlock()` is always return an object as result now (i.e. `{ css: String, map: SourceMapGenerator or null }`)
|
||||
- `parse()`
|
||||
- Returns AST in new format (so called `internal`)
|
||||
- Dynamic scanner implemented
|
||||
- New AST format + dynamic scanner = performance boost and less memory consumption
|
||||
- No more `context` argument, context should be specified via `options`
|
||||
- Supported contexts now: `stylesheet`, `atrule`, `atruleExpression`, `ruleset`, `selector`, `simpleSelector`, `block`, `declaration` and `value`
|
||||
- Drop `needPositions` option, `positions` option should be used instead
|
||||
- Drop `needInfo` option, `info` object is attaching to nodes when some information is requested by `options`
|
||||
- `options` should be an object, otherwise it treats as empty object
|
||||
- `compress()`
|
||||
- No more AST converting (performance boost and less memory consumption)
|
||||
- Drop `outputAst` option
|
||||
- Returns an object as result instead of AST (i.e. `{ ast: Object }`)
|
||||
- Drop methods: `justDoIt()`, `stringify()`, `cleanInfo()`
|
||||
|
||||
## 1.8.1 (March 30, 2016)
|
||||
|
||||
- Don't remove spaces after function/braces/urls since unsafe (#289)
|
||||
|
||||
## 1.8.0 (March 24, 2016)
|
||||
|
||||
- Usage data support:
|
||||
- Filter rulesets by tag names, class names and ids white lists.
|
||||
- More aggressive ruleset moving using class name scopes information.
|
||||
- New CLI option `--usage` to pass usage data file.
|
||||
- Improve initial ruleset merge
|
||||
- Change order of ruleset processing, now it's left to right. Previously unmerged rulesets may prevent lookup and other rulesets merge.
|
||||
- Difference in pseudo signature just prevents ruleset merging, but don't stop lookup.
|
||||
- Simplify block comparison (performance).
|
||||
- New method `csso.minifyBlock()` for css block compression (e.g. `style` attribute content).
|
||||
- Ruleset merge improvement: at-rules with block (like `@media` or `@supports`) now can be skipped during ruleset merge lookup if doesn't contain something prevents it.
|
||||
- FIX: Add negation (`:not()`) to pseudo signature to avoid unsafe merge (old browsers doesn't support it).
|
||||
- FIX: Check nested parts of value when compute compatibility. It fixes unsafe property merging.
|
||||
|
||||
## 1.7.1 (March 16, 2016)
|
||||
|
||||
- pass block mode to tokenizer for correct parsing of declarations properties with `//` hack
|
||||
- fix wrongly `@import` and `@charset` removal on double exclamation comment
|
||||
|
||||
## 1.7.0 (March 10, 2016)
|
||||
|
||||
- support for [CSS Custom Properties](https://www.w3.org/TR/css-variables/) (#279)
|
||||
- rework RTBL properties merge – better merge for values with special units and don't merge values with CSS-wide keywords (#255)
|
||||
- remove redundant universal selectors (#178)
|
||||
- take in account `!important` when check for property overriding (#280)
|
||||
- don't merge `text-align` declarations with some values (#281)
|
||||
- add spaces around `/deep/` combinator on translate, since it together with universal selector can produce a comment
|
||||
- better keyword and property name resolving (tolerant to hacks and so on)
|
||||
- integration improvements
|
||||
- compression log function could be customized by `logger` option for `compress()` and `minify()`
|
||||
- make possible to set initial line and column for parser
|
||||
|
||||
## 1.6.4 (March 1, 2016)
|
||||
|
||||
- `npm` publish issue (#276)
|
||||
|
||||
## 1.6.3 (February 29, 2016)
|
||||
|
||||
- add `file` to generated source map since other tools can relay on it in source map transform chain
|
||||
|
||||
## 1.6.2 (February 29, 2016)
|
||||
|
||||
- tweak some parse error messages and their positions
|
||||
- fix `:not()` parsing and selector groups in `:not()` is supported now (#215)
|
||||
- `needPosition` parser option is deprecated, `positions` option should be used instead (`needPosition` is used still if `positions` option omitted)
|
||||
- expose internal AST API as `csso.internal.*`
|
||||
- `minify()` adds `sourcesContent` by default when source map is generated
|
||||
- bring back support for node.js `0.10` until major release (#275)
|
||||
|
||||
## 1.6.1 (February 28, 2016)
|
||||
|
||||
- fix exception on zero length dimension compress outside declaration (#273)
|
||||
|
||||
## 1.6.0 (February 27, 2016)
|
||||
|
||||
- **source maps support**
|
||||
- parser remake:
|
||||
- various parsing issues fixed
|
||||
- fix unicode sequence processing in ident (#191)
|
||||
- support for flags in attribute selector (#270)
|
||||
- position (line and column) of parse error (#109)
|
||||
- 4x performance boost, less memory consumption
|
||||
- compressor refactoring
|
||||
- internal AST is using doubly linked lists (with safe transformation support during iteration) instead of arrays
|
||||
- rename `restructuring` to `restructure` option for `minify()`/`compress()` (`restructuring` is alias for `restructure` now, with lower priority)
|
||||
- unquote urls when possible (#141, #60)
|
||||
- setup code coverage and a number of related fixes
|
||||
- add eslint to check unused things
|
||||
|
||||
## 1.5.4 (January 27, 2016)
|
||||
|
||||
- one more fix (in `restructRuleset` this time) with merge of rulesets when a ruleset with same specificity places between them (#264)
|
||||
- disable partial merge of rulesets in `@keyframes` rulesets (until sure it's correct)
|
||||
|
||||
## 1.5.3 (January 25, 2016)
|
||||
|
||||
- don't override display values with different browser support (#259)
|
||||
- fix publish issue (one of modules leak in development state)
|
||||
|
||||
## 1.5.2 (January 24, 2016)
|
||||
|
||||
- don't merge rulesets if between them a ruleset with same specificity (#264)
|
||||
|
||||
## 1.5.1 (January 14, 2016)
|
||||
|
||||
- ensure `-` is not used as an identifier in attribute selectors (thanks to @mathiasbynens)
|
||||
- fix broken `justDoIt()` function
|
||||
- various small fixes
|
||||
|
||||
## 1.5.0 (January 14, 2016)
|
||||
|
||||
### Parser
|
||||
|
||||
- attach minus to number
|
||||
|
||||
### Compressor
|
||||
|
||||
- split code base into small modules and related refactoring
|
||||
- introduce internal AST format for compressor (`gonzales`→`internal` and `internal`→`gonzales` convertors, walkers, translator)
|
||||
- various optimizations: no snapshots, using caches and indexes
|
||||
- sort selectors, merge selectors in alphabet order
|
||||
- compute selector's specificity
|
||||
- better ruleset restructuring, improve compression of partially equal blocks
|
||||
- better ruleset merge – not only closest but also disjoined by other rulesets when safe
|
||||
- join `@media` with same query
|
||||
- `outputAst` – new option to specify output AST format (`gonzales` by default for backward compatibility)
|
||||
- remove quotes surrounding attribute values in attribute selectors when possible (#73)
|
||||
- replace `from`→`0%` and `100%`→`to` at `@keyframes` (#205)
|
||||
- prevent partial merge of rulesets at `@keyframes` (#80, #197)
|
||||
|
||||
### API
|
||||
|
||||
- walker for `gonzales` AST was implemented
|
||||
|
||||
### CLI
|
||||
|
||||
- new option `--stat` (output stat in `stderr`)
|
||||
- new optional parameter `level` for `--debug` option
|
||||
|
||||
## 1.4.4 (December 10, 2015)
|
||||
|
||||
- prevent removal of spaces after braces that before identifier that breaking at-rules expressions (#258)
|
||||
|
||||
## 1.4.3 (December 4, 2015)
|
||||
|
||||
- fix unicode-range parsing that cause to wrong function detection (#250)
|
||||
|
||||
## 1.4.2 (November 9, 2015)
|
||||
|
||||
- allow spaces between `progid:` and rest part of value for IE's `filter` property as `autoprefixer` generates this kind of code (#249)
|
||||
- fixes for Windows:
|
||||
- correct processing new lines
|
||||
- normalize file content in test suite
|
||||
- fixes to work in strict mode (#252)
|
||||
- init compressor dictionaries for every css block (#248, #251)
|
||||
- bump uglify-js version
|
||||
|
||||
## 1.4.1 (October 20, 2015)
|
||||
|
||||
- allow merge for `display` property (#167, #244)
|
||||
- more accurate `rect` (`clip` property value) merge
|
||||
- fix typo when specifying options in cli (thanks to @Taritsyn)
|
||||
- fix safe unit values merge with keyword values (#244)
|
||||
- fix wrong descendant combinator removal (#246)
|
||||
- build browser version on `prepublish` (thanks to @silentroach)
|
||||
- parser: store whitespaces as single token (performance and reduce memory consumption)
|
||||
- rearrange compress tests layout
|
||||
|
||||
## 1.4 (October 16, 2015)
|
||||
|
||||
Bringing project back to life. Changed files structure, cleaned up and refactored most of sources.
|
||||
|
||||
### Common
|
||||
|
||||
- single code base (no more `src` folder)
|
||||
- build browser version with `browserify` (no more `make`, and `web` folder), browser version is available at `dist/csso-browser.js`
|
||||
- main file is `lib/index.js` now
|
||||
- minimal `node.js` version is `0.12` now
|
||||
- restrict file list to publish on npm (no more useless folders and files in package)
|
||||
- add `jscs` to control code style
|
||||
- automate `gh-pages` update
|
||||
- util functions reworked
|
||||
- translator reworked
|
||||
- test suite reworked
|
||||
- compressor refactored
|
||||
- initial parser refactoring
|
||||
|
||||
### API
|
||||
|
||||
- new method `minify(src, options)`, options:
|
||||
- `restructuring` – if set to `false`, disable structure optimisations (`true` by default)
|
||||
- `debug` - outputs intermediate state of CSS during compression (`false` by default)
|
||||
- deprecate `justDoIt()` method (use `minify` instead)
|
||||
- rename `treeToString()` method to `stringify()`
|
||||
- drop `printTree()` method
|
||||
- AST node info
|
||||
- `column` and `offset` added
|
||||
- `ln` renamed to `line`
|
||||
- fix line counting across multiple files and input with CR LF (#147)
|
||||
|
||||
### CLI
|
||||
|
||||
- completely reworked, use [clap](https://github.com/lahmatiy/clap) to parse argv
|
||||
- add support for input from stdin (#128)
|
||||
- drop undocumented and obsoleted options `--rule` and `--parser` (suppose nobody use it)
|
||||
- drop `-off` alias for `--restructure-off` as incorrect (only one letter options should starts with single `-`)
|
||||
- new option `--debug` that reflecting to `options.debug` for `minify`
|
||||
|
||||
### Parsing and optimizations
|
||||
|
||||
- keep all exclamation comments (#194)
|
||||
- add `/deep/` combinator support (#209)
|
||||
- attribute selector
|
||||
- allow colon in attribute name (#237)
|
||||
- support for namespaces (#233)
|
||||
- color
|
||||
- support all css/html colors
|
||||
- convert `hsla` to `rgba` and `hls` to `rgb`
|
||||
- convert `rgba` with 1 as alpha value to `rgb` (#122)
|
||||
- interpolate `rgb` and `rgba` percentage values to absolute values
|
||||
- replace percentage values in `rgba` for normalized/interpolated values
|
||||
- lowercase hex colors and color names (#169)
|
||||
- fix color minification when hex value replaced for color name (#176)
|
||||
- fit rgb values to 0..255 range (#181)
|
||||
- calc
|
||||
- remove spaces for multiple operator in calc
|
||||
- don't remove units inside calc (#222)
|
||||
- fix wrong white space removal around `+` and `-` (#228)
|
||||
- don't remove units in `flex` property as it could change value meaning (#200)
|
||||
- don't merge `\9` hack values (#231)
|
||||
- merge property values only if they have the same functions (#150, #227)
|
||||
- don't merge property values with some sort of units (#140, #161)
|
||||
- fix `!important` issue for `top-right-bottom-left` properties (#189)
|
||||
- fix `top-right-bottom-left` properties merge (#139, #175)
|
||||
- support for unicode-range (#148)
|
||||
- don't crash on ruleset with no selector (#135)
|
||||
- tolerant to class names that starts with digit (#99, #105)
|
||||
- fix background compressing (#170)
|
||||
|
||||
## 1.3.12 (October 8, 2015)
|
||||
|
||||
- Case insensitive check for `!important` (#187)
|
||||
- Fix problems with using `csso` as cli command on Windows (#83, #136, #142 and others)
|
||||
- Remove byte order marker (the UTF-8 BOM) from input
|
||||
- Don't strip space between funktion-funktion and funktion-vhash (#134)
|
||||
- Don't merge TRBL values having \9 (hack for IE8 in bootstrap) (#159, #214, #230, #231 and others)
|
||||
- Don't strip units off dimensions of non-length (#226, #229 and others)
|
||||
|
||||
## 1.3.7 (February 11, 2013)
|
||||
|
||||
- Gonzales 1.0.7.
|
||||
|
||||
## 1.3.6 (November 26, 2012)
|
||||
|
||||
- Gonzales 1.0.6.
|
||||
|
||||
## 1.3.5 (October 28, 2012)
|
||||
|
||||
- Gonzales 1.0.5.
|
||||
- Protecting copyright notices in CSS: https://github.com/css/csso/issues/92
|
||||
- Zero CSS throws an error: https://github.com/css/csso/issues/96
|
||||
- Don't minify the second `0s` in Firefox for animations: https://github.com/css/csso/issues/100
|
||||
- Japan manual
|
||||
- BEM ready documentation
|
||||
|
||||
## 1.3.4 (October 10, 2012)
|
||||
|
||||
- @page inside @media Causes Error: https://github.com/css/csso/issues/90
|
||||
|
||||
## 1.3.3 (October 9, 2012)
|
||||
|
||||
- CSSO 1.3.2 compresses ".t-1" and ".t-01" as identical classes: https://github.com/css/csso/issues/88
|
||||
|
||||
## 1.3.2 (October 8, 2012)
|
||||
|
||||
- filter + important breaks CSSO v1.3.1: https://github.com/css/csso/issues/87
|
||||
|
||||
## 1.3.1 (October 8, 2012)
|
||||
|
||||
- "filter" IE property breaks CSSO v1.3.0: https://github.com/css/csso/issues/86
|
||||
|
||||
## 1.3.0 (October 4, 2012)
|
||||
|
||||
- PeCode CSS parser replaced by Gonzales CSS parser
|
||||
19
node_modules/csso/LICENSE
generated
vendored
Executable file
19
node_modules/csso/LICENSE
generated
vendored
Executable file
@@ -0,0 +1,19 @@
|
||||
Copyright (C) 2011-2015 by Sergey Kryzhanovsky
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
407
node_modules/csso/README.md
generated
vendored
Executable file
407
node_modules/csso/README.md
generated
vendored
Executable file
@@ -0,0 +1,407 @@
|
||||
[](https://www.npmjs.com/package/csso)
|
||||
[](https://travis-ci.org/css/csso)
|
||||
[](https://coveralls.io/github/css/csso?branch=master)
|
||||
[](https://www.npmjs.com/package/csso)
|
||||
[](https://twitter.com/cssoptimizer)
|
||||
|
||||
CSSO (CSS Optimizer) is a CSS minifier. It performs three sort of transformations: cleaning (removing redundant), compression (replacement for shorter form) and restructuring (merge of declarations, rulesets and so on). As a result your CSS becomes much smaller.
|
||||
|
||||
[](https://www.yandex.com/)
|
||||
[](https://www.avito.ru/)
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
npm install -g csso
|
||||
```
|
||||
|
||||
Or try out CSSO [right in your browser](http://css.github.io/csso/csso.html) (web interface).
|
||||
|
||||
### Runners
|
||||
|
||||
- Gulp: [gulp-csso](https://github.com/ben-eb/gulp-csso)
|
||||
- Grunt: [grunt-csso](https://github.com/t32k/grunt-csso)
|
||||
- Broccoli: [broccoli-csso](https://github.com/sindresorhus/broccoli-csso)
|
||||
- PostCSS: [postcss-csso](https://github.com/lahmatiy/postcss-csso)
|
||||
- Webpack: [csso-loader](https://github.com/sandark7/csso-loader)
|
||||
|
||||
### Command line
|
||||
|
||||
```
|
||||
csso [input] [output] [options]
|
||||
|
||||
Options:
|
||||
|
||||
--comments <value> Comments to keep: exclamation (default), first-exclamation or none
|
||||
--debug [level] Output intermediate state of CSS during compression
|
||||
-h, --help Output usage information
|
||||
-i, --input <filename> Input file
|
||||
--input-map <source> Input source map: none, auto (default) or <filename>
|
||||
-m, --map <destination> Generate source map: none (default), inline, file or <filename>
|
||||
-o, --output <filename> Output file (result outputs to stdout if not set)
|
||||
--restructure-off Turns structure minimization off
|
||||
--stat Output statistics in stderr
|
||||
-u, --usage <filenane> Usage data file
|
||||
-v, --version Output version
|
||||
```
|
||||
|
||||
Some examples:
|
||||
|
||||
```
|
||||
> csso in.css
|
||||
...output result in stdout...
|
||||
|
||||
> csso in.css --output out.css
|
||||
|
||||
> echo '.test { color: #ff0000; }' | csso
|
||||
.test{color:red}
|
||||
|
||||
> cat source1.css source2.css | csso | gzip -9 -c > production.css.gz
|
||||
```
|
||||
|
||||
### Source maps
|
||||
|
||||
Source map doesn't generate by default. To generate map use `--map` CLI option, that can be:
|
||||
|
||||
- `none` (default) – don't generate source map
|
||||
- `inline` – add source map into result CSS (via `/*# sourceMappingURL=application/json;base64,... */`)
|
||||
- `file` – write source map into file with same name as output file, but with `.map` extension (in this case `--output` option is required)
|
||||
- any other values treat as filename for generated source map
|
||||
|
||||
Examples:
|
||||
|
||||
```
|
||||
> csso my.css --map inline
|
||||
> csso my.css --output my.min.css --map file
|
||||
> csso my.css --output my.min.css --map maps/my.min.map
|
||||
```
|
||||
|
||||
Use `--input-map` option to specify input source map if needed. Possible values for option:
|
||||
|
||||
- `auto` (default) - attempt to fetch input source map by follow steps:
|
||||
- try to fetch inline map from input
|
||||
- try to fetch source map filename from input and read its content
|
||||
- (when `--input` is specified) check file with same name as input file but with `.map` extension exists and read its content
|
||||
- `none` - don't use input source map; actually it's using to disable `auto`-fetching
|
||||
- any other values treat as filename for input source map
|
||||
|
||||
Generally you shouldn't care about input source map since defaults behaviour (`auto`) covers most use cases.
|
||||
|
||||
> NOTE: Input source map is using only if output source map is generating.
|
||||
|
||||
### Usage data
|
||||
|
||||
`CSSO` can use data about how `CSS` is using for better compression. File with this data (`JSON` format) can be set using `--usage` option. Usage data may contain follow sections:
|
||||
|
||||
- `tags` – white list of tags
|
||||
- `ids` – white list of ids
|
||||
- `classes` – white list of classes
|
||||
- `scopes` – groups of classes which never used with classes from other groups on single element
|
||||
|
||||
All sections are optional. Value of `tags`, `ids` and `classes` should be array of strings, value of `scopes` should be an array of arrays of strings. Other values are ignoring.
|
||||
|
||||
#### Selector filtering
|
||||
|
||||
`tags`, `ids` and `classes` are using on clean stage to filter selectors that contains something that not in list. Selectors are filtering only by those kind of simple selector which white list is specified. For example, if only `tags` list is specified then type selectors are checking, and if selector hasn't any type selector (or even any type selector) it isn't filter.
|
||||
|
||||
> `ids` and `classes` names are case sensitive, `tags` – is not.
|
||||
|
||||
Input CSS:
|
||||
|
||||
```css
|
||||
* { color: green; }
|
||||
ul, ol, li { color: blue; }
|
||||
UL.foo, span.bar { color: red; }
|
||||
```
|
||||
|
||||
Usage data:
|
||||
|
||||
```json
|
||||
{
|
||||
"tags": ["ul", "LI"]
|
||||
}
|
||||
```
|
||||
|
||||
Result CSS:
|
||||
|
||||
```css
|
||||
*{color:green}ul,li{color:blue}ul.foo{color:red}
|
||||
```
|
||||
|
||||
#### Scopes
|
||||
|
||||
Scopes is designed for CSS scope isolation solutions such as [css-modules](https://github.com/css-modules/css-modules). Scopes are similar to namespaces and defines lists of class names that exclusively used on some markup. This information allows the optimizer to move rulesets more agressive. Since it assumes selectors from different scopes can't to be matched on the same element. That leads to better ruleset merging.
|
||||
|
||||
Suppose we have a file:
|
||||
|
||||
```css
|
||||
.module1-foo { color: red; }
|
||||
.module1-bar { font-size: 1.5em; background: yellow; }
|
||||
|
||||
.module2-baz { color: red; }
|
||||
.module2-qux { font-size: 1.5em; background: yellow; width: 50px; }
|
||||
```
|
||||
|
||||
It can be assumed that first two rules never used with second two on the same markup. But we can't know that for sure without markup. The optimizer doesn't know it eather and will perform safe transformations only. The result will be the same as input but with no spaces and some semicolons:
|
||||
|
||||
```css
|
||||
.module1-foo{color:red}.module1-bar{font-size:1.5em;background:#ff0}.module2-baz{color:red}.module2-qux{font-size:1.5em;background:#ff0;width:50px}
|
||||
```
|
||||
|
||||
But with usage data `CSSO` can get better output. If follow usage data is provided:
|
||||
|
||||
```json
|
||||
{
|
||||
"scopes": [
|
||||
["module1-foo", "module1-bar"],
|
||||
["module2-baz", "module2-qux"]
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
New result (29 bytes extra saving):
|
||||
|
||||
```css
|
||||
.module1-foo,.module2-baz{color:red}.module1-bar,.module2-qux{font-size:1.5em;background:#ff0}.module2-qux{width:50px}
|
||||
```
|
||||
|
||||
If class name doesn't specified in `scopes` it belongs to default "scope". `scopes` doesn't affect `classes`. If class name presents in `scopes` but missed in `classes` (both sections specified) it will be filtered.
|
||||
|
||||
Note that class name can't be specified in several scopes. Also selector can't has classes from different scopes. In both cases an exception throws.
|
||||
|
||||
Currently the optimizer doesn't care about out-of-bounds selectors order changing safety (i.e. selectors that may be matched to elements with no class name of scope, e.g. `.scope div` or `.scope ~ :last-child`) since assumes scoped CSS modules doesn't relay on it's order. It may be fix in future if to be an issue.
|
||||
|
||||
### API
|
||||
|
||||
```js
|
||||
var csso = require('csso');
|
||||
|
||||
var compressedCss = csso.minify('.test { color: #ff0000; }').css;
|
||||
|
||||
console.log(compressedCss);
|
||||
// .test{color:red}
|
||||
```
|
||||
|
||||
You may minify CSS by yourself step by step:
|
||||
|
||||
```js
|
||||
var ast = csso.parse('.test { color: #ff0000; }');
|
||||
var compressResult = csso.compress(ast);
|
||||
var compressedCss = csso.translate(compressResult.ast);
|
||||
|
||||
console.log(compressedCss);
|
||||
// .test{color:red}
|
||||
```
|
||||
|
||||
Working with source maps:
|
||||
|
||||
```js
|
||||
var css = fs.readFileSync('path/to/my.css', 'utf8');
|
||||
var result = csso.minify(css, {
|
||||
filename: 'path/to/my.css', // will be added to source map as reference to source file
|
||||
sourceMap: true // generate source map
|
||||
});
|
||||
|
||||
console.log(result);
|
||||
// { css: '...minified...', map: SourceMapGenerator {} }
|
||||
|
||||
console.log(result.map.toString());
|
||||
// '{ .. source map content .. }'
|
||||
```
|
||||
|
||||
#### minify(source[, options])
|
||||
|
||||
Minify `source` CSS passed as `String`.
|
||||
|
||||
Options:
|
||||
|
||||
- sourceMap `Boolean` - generate source map if `true`
|
||||
- filename `String` - filename of input, uses for source map
|
||||
- debug `Boolean` - output debug information to `stderr`
|
||||
- beforeCompress `function|array<function>` - called right after parse is run. Callbacks arguments are `ast, options`.
|
||||
- afterCompress `function|array<function>` - called right after compress is run. Callbacks arguments are `compressResult, options`.
|
||||
- other options are the same as for `compress()`
|
||||
|
||||
Returns an object with properties:
|
||||
|
||||
- css `String` – resulting CSS
|
||||
- map `Object` – instance of `SourceMapGenerator` or `null`
|
||||
|
||||
```js
|
||||
var result = csso.minify('.test { color: #ff0000; }', {
|
||||
restructure: false, // don't change CSS structure, i.e. don't merge declarations, rulesets etc
|
||||
debug: true // show additional debug information:
|
||||
// true or number from 1 to 3 (greater number - more details)
|
||||
});
|
||||
|
||||
console.log(result.css);
|
||||
// > .test{color:red}
|
||||
```
|
||||
|
||||
#### minifyBlock(source[, options])
|
||||
|
||||
The same as `minify()` but for style block. Usualy it's a `style` attribute content.
|
||||
|
||||
```js
|
||||
var result = csso.minifyBlock('color: rgba(255, 0, 0, 1); color: #ff0000').css;
|
||||
|
||||
console.log(result.css);
|
||||
// > color:red
|
||||
```
|
||||
|
||||
#### parse(source[, options])
|
||||
|
||||
Parse CSS to AST.
|
||||
|
||||
> NOTE: Currenly parser omit redundant separators, spaces and comments (except exclamation comments, i.e. `/*! comment */`) on AST build, since those things are removing by compressor anyway.
|
||||
|
||||
Options:
|
||||
|
||||
- context `String` – parsing context, useful when some part of CSS is parsing (see below)
|
||||
- positions `Boolean` – should AST contains node position or not, store data in `info` property of nodes (`false` by default)
|
||||
- filename `String` – filename of source that adds to info when `positions` is true, uses for source map generation (`<unknown>` by default)
|
||||
- line `Number` – initial line number, useful when parse fragment of CSS to compute correct positions
|
||||
- column `Number` – initial column number, useful when parse fragment of CSS to compute correct positions
|
||||
|
||||
Contexts:
|
||||
|
||||
- `stylesheet` (default) – regular stylesheet, should be suitable in most cases
|
||||
- `atrule` – at-rule (e.g. `@media screen, print { ... }`)
|
||||
- `atruleExpression` – at-rule expression (`screen, print` for example above)
|
||||
- `ruleset` – rule (e.g. `.foo, .bar:hover { color: red; border: 1px solid black; }`)
|
||||
- `selector` – selector group (`.foo, .bar:hover` for ruleset example)
|
||||
- `simpleSelector` – selector (`.foo` or `.bar:hover` for ruleset example)
|
||||
- `block` – block content w/o curly braces (`color: red; border: 1px solid black;` for ruleset example)
|
||||
- `declaration` – declaration (`color: red` or `border: 1px solid black` for ruleset example)
|
||||
- `value` – declaration value (`red` or `1px solid black` for ruleset example)
|
||||
|
||||
```js
|
||||
// simple parsing with no options
|
||||
var ast = csso.parse('.example { color: red }');
|
||||
|
||||
// parse with options
|
||||
var ast = csso.parse('.foo.bar', {
|
||||
context: 'simpleSelector',
|
||||
positions: true
|
||||
});
|
||||
```
|
||||
|
||||
#### compress(ast[, options])
|
||||
|
||||
Does the main task – compress AST.
|
||||
|
||||
> NOTE: `compress` performs AST compression by transforming input AST by default (since AST cloning is expensive and needed in rare cases). Use `clone` option with truthy value in case you want to keep input AST untouched.
|
||||
|
||||
Options:
|
||||
|
||||
- restructure `Boolean` – do the structure optimisations or not (`true` by default)
|
||||
- clone `Boolean` - transform a copy of input AST if `true`, useful in case of AST reuse (`false` by default)
|
||||
- comments `String` or `Boolean` – specify what comments to left
|
||||
- `'exclamation'` or `true` (default) – left all exclamation comments (i.e. `/*! .. */`)
|
||||
- `'first-exclamation'` – remove every comments except first one
|
||||
- `false` – remove every comments
|
||||
- usage `Object` - usage data for advanced optimisations (see [Usage data](#usage-data) for details)
|
||||
- logger `Function` - function to track every step of transformations
|
||||
|
||||
#### clone(ast)
|
||||
|
||||
Make an AST node deep copy.
|
||||
|
||||
```js
|
||||
var orig = csso.parse('.test { color: red }');
|
||||
var copy = csso.clone(orig);
|
||||
|
||||
csso.walk(copy, function(node) {
|
||||
if (node.type === 'Class') {
|
||||
node.name = 'replaced';
|
||||
}
|
||||
});
|
||||
|
||||
console.log(csso.translate(orig));
|
||||
// .test{color:red}
|
||||
console.log(csso.translate(copy));
|
||||
// .replaced{color:red}
|
||||
```
|
||||
|
||||
#### translate(ast)
|
||||
|
||||
Converts AST to string.
|
||||
|
||||
```js
|
||||
var ast = csso.parse('.test { color: red }');
|
||||
console.log(csso.translate(ast));
|
||||
// > .test{color:red}
|
||||
```
|
||||
|
||||
#### translateWithSourceMap(ast)
|
||||
|
||||
The same as `translate()` but also generates source map (nodes should contain positions in `info` property).
|
||||
|
||||
```js
|
||||
var ast = csso.parse('.test { color: red }', {
|
||||
filename: 'my.css',
|
||||
positions: true
|
||||
});
|
||||
console.log(csso.translateWithSourceMap(ast));
|
||||
// { css: '.test{color:red}', map: SourceMapGenerator {} }
|
||||
```
|
||||
|
||||
#### walk(ast, handler)
|
||||
|
||||
Visit all nodes of AST and call handler for each one. `handler` receives three arguments:
|
||||
|
||||
- node – current AST node
|
||||
- item – node wrapper when node is a list member; this wrapper contains references to `prev` and `next` nodes in list
|
||||
- list – reference to list when node is a list member; it's useful for operations on list like `remove()` or `insert()`
|
||||
|
||||
Context for handler an object, that contains references to some parent nodes:
|
||||
|
||||
- root – refers to `ast` or root node
|
||||
- stylesheet – refers to closest `StyleSheet` node, it may be a top-level or at-rule block stylesheet
|
||||
- atruleExpression – refers to `AtruleExpression` node if current node inside at-rule expression
|
||||
- ruleset – refers to `Ruleset` node if current node inside a ruleset
|
||||
- selector – refers to `Selector` node if current node inside a selector
|
||||
- declaration – refers to `Declaration` node if current node inside a declaration
|
||||
- function – refers to closest `Function` or `FunctionalPseudo` node if current node inside one of them
|
||||
|
||||
```js
|
||||
// collect all urls in declarations
|
||||
var csso = require('./lib/index.js');
|
||||
var urls = [];
|
||||
var ast = csso.parse(`
|
||||
@import url(import.css);
|
||||
.foo { background: url('foo.jpg'); }
|
||||
.bar { background-image: url(bar.png); }
|
||||
`);
|
||||
|
||||
csso.walk(ast, function(node) {
|
||||
if (this.declaration !== null && node.type === 'Url') {
|
||||
var value = node.value;
|
||||
|
||||
if (value.type === 'Raw') {
|
||||
urls.push(value.value);
|
||||
} else {
|
||||
urls.push(value.value.substr(1, value.value.length - 2));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
console.log(urls);
|
||||
// [ 'foo.jpg', 'bar.png' ]
|
||||
```
|
||||
|
||||
#### walkRules(ast, handler)
|
||||
|
||||
Same as `walk()` but visits `Ruleset` and `Atrule` nodes only.
|
||||
|
||||
#### walkRulesRight(ast, handler)
|
||||
|
||||
Same as `walkRules()` but visits nodes in reverse order (from last to first).
|
||||
|
||||
## More reading
|
||||
|
||||
- [Debugging](docs/debugging.md)
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
16
node_modules/csso/bin/csso
generated
vendored
Executable file
16
node_modules/csso/bin/csso
generated
vendored
Executable file
@@ -0,0 +1,16 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
var cli = require('../lib/cli.js');
|
||||
|
||||
try {
|
||||
cli.run();
|
||||
} catch (e) {
|
||||
// output user frendly message if cli error
|
||||
if (cli.isCliError(e)) {
|
||||
console.error(e.message || e);
|
||||
process.exit(2);
|
||||
}
|
||||
|
||||
// otherwise re-throw exception
|
||||
throw e;
|
||||
}
|
||||
3
node_modules/csso/dist/csso-browser.js
generated
vendored
Executable file
3
node_modules/csso/dist/csso-browser.js
generated
vendored
Executable file
File diff suppressed because one or more lines are too long
338
node_modules/csso/lib/cli.js
generated
vendored
Executable file
338
node_modules/csso/lib/cli.js
generated
vendored
Executable file
@@ -0,0 +1,338 @@
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var cli = require('clap');
|
||||
var SourceMapConsumer = require('source-map').SourceMapConsumer;
|
||||
var csso = require('./index.js');
|
||||
|
||||
function readFromStream(stream, minify) {
|
||||
var buffer = [];
|
||||
|
||||
// FIXME: don't chain until node.js 0.10 drop, since setEncoding isn't chainable in 0.10
|
||||
stream.setEncoding('utf8');
|
||||
stream
|
||||
.on('data', function(chunk) {
|
||||
buffer.push(chunk);
|
||||
})
|
||||
.on('end', function() {
|
||||
minify(buffer.join(''));
|
||||
});
|
||||
}
|
||||
|
||||
function showStat(filename, source, result, inputMap, map, time, mem) {
|
||||
function fmt(size) {
|
||||
return String(size).split('').reverse().reduce(function(size, digit, idx) {
|
||||
if (idx && idx % 3 === 0) {
|
||||
size = ' ' + size;
|
||||
}
|
||||
return digit + size;
|
||||
}, '');
|
||||
}
|
||||
|
||||
map = map || 0;
|
||||
result -= map;
|
||||
|
||||
console.error('Source: ', filename === '<stdin>' ? filename : path.relative(process.cwd(), filename));
|
||||
if (inputMap) {
|
||||
console.error('Map source:', inputMap);
|
||||
}
|
||||
console.error('Original: ', fmt(source), 'bytes');
|
||||
console.error('Compressed:', fmt(result), 'bytes', '(' + (100 * result / source).toFixed(2) + '%)');
|
||||
console.error('Saving: ', fmt(source - result), 'bytes', '(' + (100 * (source - result) / source).toFixed(2) + '%)');
|
||||
if (map) {
|
||||
console.error('Source map:', fmt(map), 'bytes', '(' + (100 * map / (result + map)).toFixed(2) + '% of total)');
|
||||
console.error('Total: ', fmt(map + result), 'bytes');
|
||||
}
|
||||
console.error('Time: ', time, 'ms');
|
||||
console.error('Memory: ', (mem / (1024 * 1024)).toFixed(3), 'MB');
|
||||
}
|
||||
|
||||
function showParseError(source, filename, details, message) {
|
||||
function processLines(start, end) {
|
||||
return lines.slice(start, end).map(function(line, idx) {
|
||||
var num = String(start + idx + 1);
|
||||
|
||||
while (num.length < maxNumLength) {
|
||||
num = ' ' + num;
|
||||
}
|
||||
|
||||
return num + ' |' + line;
|
||||
}).join('\n');
|
||||
}
|
||||
|
||||
var lines = source.split(/\n|\r\n?|\f/);
|
||||
var column = details.column;
|
||||
var line = details.line;
|
||||
var startLine = Math.max(1, line - 2);
|
||||
var endLine = Math.min(line + 2, lines.length + 1);
|
||||
var maxNumLength = Math.max(4, String(endLine).length) + 1;
|
||||
|
||||
console.error('\nParse error ' + filename + ': ' + message);
|
||||
console.error(processLines(startLine - 1, line));
|
||||
console.error(new Array(column + maxNumLength + 2).join('-') + '^');
|
||||
console.error(processLines(line, endLine));
|
||||
console.error();
|
||||
}
|
||||
|
||||
function debugLevel(level) {
|
||||
// level is undefined when no param -> 1
|
||||
return isNaN(level) ? 1 : Math.max(Number(level), 0);
|
||||
}
|
||||
|
||||
function resolveSourceMap(source, inputMap, map, inputFile, outputFile) {
|
||||
var inputMapContent = null;
|
||||
var inputMapFile = null;
|
||||
var outputMapFile = null;
|
||||
|
||||
switch (map) {
|
||||
case 'none':
|
||||
// don't generate source map
|
||||
map = false;
|
||||
inputMap = 'none';
|
||||
break;
|
||||
|
||||
case 'inline':
|
||||
// nothing to do
|
||||
break;
|
||||
|
||||
case 'file':
|
||||
if (!outputFile) {
|
||||
console.error('Output filename should be specified when `--map file` is used');
|
||||
process.exit(2);
|
||||
}
|
||||
|
||||
outputMapFile = outputFile + '.map';
|
||||
break;
|
||||
|
||||
default:
|
||||
// process filename
|
||||
if (map) {
|
||||
// check path is reachable
|
||||
if (!fs.existsSync(path.dirname(map))) {
|
||||
console.error('Directory for map file should exists:', path.dirname(path.resolve(map)));
|
||||
process.exit(2);
|
||||
}
|
||||
|
||||
// resolve to absolute path
|
||||
outputMapFile = path.resolve(process.cwd(), map);
|
||||
}
|
||||
}
|
||||
|
||||
switch (inputMap) {
|
||||
case 'none':
|
||||
// nothing to do
|
||||
break;
|
||||
|
||||
case 'auto':
|
||||
if (map) {
|
||||
// try fetch source map from source
|
||||
var inputMapComment = source.match(/\/\*# sourceMappingURL=(\S+)\s*\*\/\s*$/);
|
||||
|
||||
if (inputFile === '<stdin>') {
|
||||
inputFile = false;
|
||||
}
|
||||
|
||||
if (inputMapComment) {
|
||||
// if comment found – value is filename or base64-encoded source map
|
||||
inputMapComment = inputMapComment[1];
|
||||
|
||||
if (inputMapComment.substr(0, 5) === 'data:') {
|
||||
// decode source map content from comment
|
||||
inputMapContent = new Buffer(inputMapComment.substr(inputMapComment.indexOf('base64,') + 7), 'base64').toString();
|
||||
} else {
|
||||
// value is filename – resolve it as absolute path
|
||||
if (inputFile) {
|
||||
inputMapFile = path.resolve(path.dirname(inputFile), inputMapComment);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// comment doesn't found - look up file with `.map` extension nearby input file
|
||||
if (inputFile && fs.existsSync(inputFile + '.map')) {
|
||||
inputMapFile = inputFile + '.map';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (inputMap) {
|
||||
inputMapFile = inputMap;
|
||||
}
|
||||
}
|
||||
|
||||
// source map placed in external file
|
||||
if (inputMapFile) {
|
||||
inputMapContent = fs.readFileSync(inputMapFile, 'utf8');
|
||||
}
|
||||
|
||||
return {
|
||||
input: inputMapContent,
|
||||
inputFile: inputMapFile || (inputMapContent ? '<inline>' : false),
|
||||
output: map,
|
||||
outputFile: outputMapFile
|
||||
};
|
||||
}
|
||||
|
||||
function processCommentsOption(value) {
|
||||
switch (value) {
|
||||
case 'exclamation':
|
||||
case 'first-exclamation':
|
||||
case 'none':
|
||||
return value;
|
||||
}
|
||||
|
||||
console.error('Wrong value for `comments` option: %s', value);
|
||||
process.exit(2);
|
||||
}
|
||||
|
||||
var command = cli.create('csso', '[input] [output]')
|
||||
.version(require('../package.json').version)
|
||||
.option('-i, --input <filename>', 'Input file')
|
||||
.option('-o, --output <filename>', 'Output file (result outputs to stdout if not set)')
|
||||
.option('-m, --map <destination>', 'Generate source map: none (default), inline, file or <filename>', 'none')
|
||||
.option('-u, --usage <filenane>', 'Usage data file')
|
||||
.option('--input-map <source>', 'Input source map: none, auto (default) or <filename>', 'auto')
|
||||
.option('--restructure-off', 'Turns structure minimization off')
|
||||
.option('--comments <value>', 'Comments to keep: exclamation (default), first-exclamation or none', 'exclamation')
|
||||
.option('--stat', 'Output statistics in stderr')
|
||||
.option('--debug [level]', 'Output intermediate state of CSS during compression', debugLevel, 0)
|
||||
.action(function(args) {
|
||||
var options = this.values;
|
||||
var inputFile = options.input || args[0];
|
||||
var outputFile = options.output || args[1];
|
||||
var usageFile = options.usage;
|
||||
var usageData = false;
|
||||
var map = options.map;
|
||||
var inputMap = options.inputMap;
|
||||
var structureOptimisationOff = options.restructureOff;
|
||||
var comments = processCommentsOption(options.comments);
|
||||
var debug = options.debug;
|
||||
var statistics = options.stat;
|
||||
var inputStream;
|
||||
|
||||
if (process.stdin.isTTY && !inputFile && !outputFile) {
|
||||
this.showHelp();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!inputFile) {
|
||||
inputFile = '<stdin>';
|
||||
inputStream = process.stdin;
|
||||
} else {
|
||||
inputFile = path.resolve(process.cwd(), inputFile);
|
||||
inputStream = fs.createReadStream(inputFile);
|
||||
}
|
||||
|
||||
if (outputFile) {
|
||||
outputFile = path.resolve(process.cwd(), outputFile);
|
||||
}
|
||||
|
||||
if (usageFile) {
|
||||
if (!fs.existsSync(usageFile)) {
|
||||
console.error('Usage data file doesn\'t found (%s)', usageFile);
|
||||
process.exit(2);
|
||||
}
|
||||
|
||||
usageData = fs.readFileSync(usageFile, 'utf-8');
|
||||
|
||||
try {
|
||||
usageData = JSON.parse(usageData);
|
||||
} catch (e) {
|
||||
console.error('Usage data parse error (%s)', usageFile);
|
||||
process.exit(2);
|
||||
}
|
||||
}
|
||||
|
||||
readFromStream(inputStream, function(source) {
|
||||
var time = process.hrtime();
|
||||
var mem = process.memoryUsage().heapUsed;
|
||||
var sourceMap = resolveSourceMap(source, inputMap, map, inputFile, outputFile);
|
||||
var sourceMapAnnotation = '';
|
||||
var result;
|
||||
|
||||
// main action
|
||||
try {
|
||||
result = csso.minify(source, {
|
||||
filename: inputFile,
|
||||
sourceMap: sourceMap.output,
|
||||
usage: usageData,
|
||||
restructure: !structureOptimisationOff,
|
||||
comments: comments,
|
||||
debug: debug
|
||||
});
|
||||
|
||||
// for backward capability minify returns a string
|
||||
if (typeof result === 'string') {
|
||||
result = {
|
||||
css: result,
|
||||
map: null
|
||||
};
|
||||
}
|
||||
} catch (e) {
|
||||
if (e.parseError) {
|
||||
showParseError(source, inputFile, e.parseError, e.message);
|
||||
if (!debug) {
|
||||
process.exit(2);
|
||||
}
|
||||
}
|
||||
|
||||
throw e;
|
||||
}
|
||||
|
||||
if (sourceMap.output && result.map) {
|
||||
// apply input map
|
||||
if (sourceMap.input) {
|
||||
result.map.applySourceMap(
|
||||
new SourceMapConsumer(sourceMap.input),
|
||||
inputFile
|
||||
);
|
||||
}
|
||||
|
||||
// add source map to result
|
||||
if (sourceMap.outputFile) {
|
||||
// write source map to file
|
||||
fs.writeFileSync(sourceMap.outputFile, result.map.toString(), 'utf-8');
|
||||
sourceMapAnnotation = '\n' +
|
||||
'/*# sourceMappingURL=' +
|
||||
path.relative(outputFile ? path.dirname(outputFile) : process.cwd(), sourceMap.outputFile) +
|
||||
' */';
|
||||
} else {
|
||||
// inline source map
|
||||
sourceMapAnnotation = '\n' +
|
||||
'/*# sourceMappingURL=data:application/json;base64,' +
|
||||
new Buffer(result.map.toString()).toString('base64') +
|
||||
' */';
|
||||
}
|
||||
|
||||
result.css += sourceMapAnnotation;
|
||||
}
|
||||
|
||||
// output result
|
||||
if (outputFile) {
|
||||
fs.writeFileSync(outputFile, result.css, 'utf-8');
|
||||
} else {
|
||||
console.log(result.css);
|
||||
}
|
||||
|
||||
// output statistics
|
||||
if (statistics) {
|
||||
var timeDiff = process.hrtime(time);
|
||||
showStat(
|
||||
path.relative(process.cwd(), inputFile),
|
||||
source.length,
|
||||
result.css.length,
|
||||
sourceMap.inputFile,
|
||||
sourceMapAnnotation.length,
|
||||
parseInt(timeDiff[0] * 1e3 + timeDiff[1] / 1e6),
|
||||
process.memoryUsage().heapUsed - mem
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
run: command.run.bind(command),
|
||||
isCliError: function(err) {
|
||||
return err instanceof cli.Error;
|
||||
}
|
||||
};
|
||||
54
node_modules/csso/lib/compressor/clean/Atrule.js
generated
vendored
Executable file
54
node_modules/csso/lib/compressor/clean/Atrule.js
generated
vendored
Executable file
@@ -0,0 +1,54 @@
|
||||
module.exports = function cleanAtrule(node, item, list) {
|
||||
if (node.block) {
|
||||
// otherwise removed at-rule don't prevent @import for removal
|
||||
this.root.firstAtrulesAllowed = false;
|
||||
|
||||
if (node.block.type === 'Block' && node.block.declarations.isEmpty()) {
|
||||
list.remove(item);
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.block.type === 'StyleSheet' && node.block.rules.isEmpty()) {
|
||||
list.remove(item);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch (node.name) {
|
||||
case 'charset':
|
||||
if (node.expression.sequence.isEmpty()) {
|
||||
list.remove(item);
|
||||
return;
|
||||
}
|
||||
|
||||
// if there is any rule before @charset -> remove it
|
||||
if (item.prev) {
|
||||
list.remove(item);
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'import':
|
||||
if (!this.root.firstAtrulesAllowed) {
|
||||
list.remove(item);
|
||||
return;
|
||||
}
|
||||
|
||||
// if there are some rules that not an @import or @charset before @import
|
||||
// remove it
|
||||
list.prevUntil(item.prev, function(rule) {
|
||||
if (rule.type === 'Atrule') {
|
||||
if (rule.name === 'import' || rule.name === 'charset') {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.root.firstAtrulesAllowed = false;
|
||||
list.remove(item);
|
||||
return true;
|
||||
}, this);
|
||||
|
||||
break;
|
||||
}
|
||||
};
|
||||
3
node_modules/csso/lib/compressor/clean/Comment.js
generated
vendored
Executable file
3
node_modules/csso/lib/compressor/clean/Comment.js
generated
vendored
Executable file
@@ -0,0 +1,3 @@
|
||||
module.exports = function cleanComment(data, item, list) {
|
||||
list.remove(item);
|
||||
};
|
||||
5
node_modules/csso/lib/compressor/clean/Declaration.js
generated
vendored
Executable file
5
node_modules/csso/lib/compressor/clean/Declaration.js
generated
vendored
Executable file
@@ -0,0 +1,5 @@
|
||||
module.exports = function cleanDeclartion(node, item, list) {
|
||||
if (node.value.sequence.isEmpty()) {
|
||||
list.remove(item);
|
||||
}
|
||||
};
|
||||
9
node_modules/csso/lib/compressor/clean/Identifier.js
generated
vendored
Executable file
9
node_modules/csso/lib/compressor/clean/Identifier.js
generated
vendored
Executable file
@@ -0,0 +1,9 @@
|
||||
module.exports = function cleanIdentifier(node, item, list) {
|
||||
// remove useless universal selector
|
||||
if (this.selector !== null && node.name === '*') {
|
||||
// remove when universal selector isn't last
|
||||
if (item.next && item.next.data.type !== 'Combinator') {
|
||||
list.remove(item);
|
||||
}
|
||||
}
|
||||
};
|
||||
39
node_modules/csso/lib/compressor/clean/Ruleset.js
generated
vendored
Executable file
39
node_modules/csso/lib/compressor/clean/Ruleset.js
generated
vendored
Executable file
@@ -0,0 +1,39 @@
|
||||
var hasOwnProperty = Object.prototype.hasOwnProperty;
|
||||
|
||||
function cleanUnused(node, usageData) {
|
||||
return node.selector.selectors.each(function(selector, item, list) {
|
||||
var hasUnused = selector.sequence.some(function(node) {
|
||||
switch (node.type) {
|
||||
case 'Class':
|
||||
return usageData.classes && !hasOwnProperty.call(usageData.classes, node.name);
|
||||
|
||||
case 'Id':
|
||||
return usageData.ids && !hasOwnProperty.call(usageData.ids, node.name);
|
||||
|
||||
case 'Identifier':
|
||||
// ignore universal selector
|
||||
if (node.name !== '*') {
|
||||
// TODO: remove toLowerCase when type selectors will be normalized
|
||||
return usageData.tags && !hasOwnProperty.call(usageData.tags, node.name.toLowerCase());
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
if (hasUnused) {
|
||||
list.remove(item);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = function cleanRuleset(node, item, list, usageData) {
|
||||
if (usageData) {
|
||||
cleanUnused(node, usageData);
|
||||
}
|
||||
|
||||
if (node.selector.selectors.isEmpty() ||
|
||||
node.block.declarations.isEmpty()) {
|
||||
list.remove(item);
|
||||
}
|
||||
};
|
||||
16
node_modules/csso/lib/compressor/clean/Space.js
generated
vendored
Executable file
16
node_modules/csso/lib/compressor/clean/Space.js
generated
vendored
Executable file
@@ -0,0 +1,16 @@
|
||||
function canCleanWhitespace(node) {
|
||||
if (node.type !== 'Operator') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return node.value !== '+' && node.value !== '-';
|
||||
}
|
||||
|
||||
module.exports = function cleanWhitespace(node, item, list) {
|
||||
var prev = item.prev && item.prev.data;
|
||||
var next = item.next && item.next.data;
|
||||
|
||||
if (canCleanWhitespace(prev) || canCleanWhitespace(next)) {
|
||||
list.remove(item);
|
||||
}
|
||||
};
|
||||
17
node_modules/csso/lib/compressor/clean/index.js
generated
vendored
Executable file
17
node_modules/csso/lib/compressor/clean/index.js
generated
vendored
Executable file
@@ -0,0 +1,17 @@
|
||||
var walk = require('../../utils/walk.js').all;
|
||||
var handlers = {
|
||||
Space: require('./Space.js'),
|
||||
Atrule: require('./Atrule.js'),
|
||||
Ruleset: require('./Ruleset.js'),
|
||||
Declaration: require('./Declaration.js'),
|
||||
Identifier: require('./Identifier.js'),
|
||||
Comment: require('./Comment.js')
|
||||
};
|
||||
|
||||
module.exports = function(ast, usageData) {
|
||||
walk(ast, function(node, item, list) {
|
||||
if (handlers.hasOwnProperty(node.type)) {
|
||||
handlers[node.type].call(this, node, item, list, usageData);
|
||||
}
|
||||
});
|
||||
};
|
||||
9
node_modules/csso/lib/compressor/compress/Atrule.js
generated
vendored
Executable file
9
node_modules/csso/lib/compressor/compress/Atrule.js
generated
vendored
Executable file
@@ -0,0 +1,9 @@
|
||||
var resolveKeyword = require('../../utils/names.js').keyword;
|
||||
var compressKeyframes = require('./atrule/keyframes.js');
|
||||
|
||||
module.exports = function(node) {
|
||||
// compress @keyframe selectors
|
||||
if (resolveKeyword(node.name).name === 'keyframes') {
|
||||
compressKeyframes(node);
|
||||
}
|
||||
};
|
||||
33
node_modules/csso/lib/compressor/compress/Attribute.js
generated
vendored
Executable file
33
node_modules/csso/lib/compressor/compress/Attribute.js
generated
vendored
Executable file
@@ -0,0 +1,33 @@
|
||||
// Can unquote attribute detection
|
||||
// Adopted implementation of Mathias Bynens
|
||||
// https://github.com/mathiasbynens/mothereff.in/blob/master/unquoted-attributes/eff.js
|
||||
var escapesRx = /\\([0-9A-Fa-f]{1,6})[ \t\n\f\r]?|\\./g;
|
||||
var blockUnquoteRx = /^(-?\d|--)|[\u0000-\u002c\u002e\u002f\u003A-\u0040\u005B-\u005E\u0060\u007B-\u009f]/;
|
||||
|
||||
function canUnquote(value) {
|
||||
if (value === '' || value === '-') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Escapes are valid, so replace them with a valid non-empty string
|
||||
value = value.replace(escapesRx, 'a');
|
||||
|
||||
return !blockUnquoteRx.test(value);
|
||||
}
|
||||
|
||||
module.exports = function(node) {
|
||||
var attrValue = node.value;
|
||||
|
||||
if (!attrValue || attrValue.type !== 'String') {
|
||||
return;
|
||||
}
|
||||
|
||||
var unquotedValue = attrValue.value.replace(/^(.)(.*)\1$/, '$2');
|
||||
if (canUnquote(unquotedValue)) {
|
||||
node.value = {
|
||||
type: 'Identifier',
|
||||
info: attrValue.info,
|
||||
name: unquotedValue
|
||||
};
|
||||
}
|
||||
};
|
||||
54
node_modules/csso/lib/compressor/compress/Dimension.js
generated
vendored
Executable file
54
node_modules/csso/lib/compressor/compress/Dimension.js
generated
vendored
Executable file
@@ -0,0 +1,54 @@
|
||||
var packNumber = require('./Number.js').pack;
|
||||
var LENGTH_UNIT = {
|
||||
// absolute length units
|
||||
'px': true,
|
||||
'mm': true,
|
||||
'cm': true,
|
||||
'in': true,
|
||||
'pt': true,
|
||||
'pc': true,
|
||||
|
||||
// relative length units
|
||||
'em': true,
|
||||
'ex': true,
|
||||
'ch': true,
|
||||
'rem': true,
|
||||
|
||||
// viewport-percentage lengths
|
||||
'vh': true,
|
||||
'vw': true,
|
||||
'vmin': true,
|
||||
'vmax': true,
|
||||
'vm': true
|
||||
};
|
||||
|
||||
module.exports = function compressDimension(node, item) {
|
||||
var value = packNumber(node.value);
|
||||
|
||||
node.value = value;
|
||||
|
||||
if (value === '0' && this.declaration) {
|
||||
var unit = node.unit.toLowerCase();
|
||||
|
||||
// only length values can be compressed
|
||||
if (!LENGTH_UNIT.hasOwnProperty(unit)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// issue #200: don't remove units in flex property as it could change value meaning
|
||||
if (this.declaration.property.name === 'flex') {
|
||||
return;
|
||||
}
|
||||
|
||||
// issue #222: don't remove units inside calc
|
||||
if (this['function'] && this['function'].name === 'calc') {
|
||||
return;
|
||||
}
|
||||
|
||||
item.data = {
|
||||
type: 'Number',
|
||||
info: node.info,
|
||||
value: value
|
||||
};
|
||||
}
|
||||
};
|
||||
22
node_modules/csso/lib/compressor/compress/Number.js
generated
vendored
Executable file
22
node_modules/csso/lib/compressor/compress/Number.js
generated
vendored
Executable file
@@ -0,0 +1,22 @@
|
||||
function packNumber(value) {
|
||||
// 100 -> '100'
|
||||
// 00100 -> '100'
|
||||
// +100 -> '100'
|
||||
// -100 -> '-100'
|
||||
// 0.123 -> '.123'
|
||||
// 0.12300 -> '.123'
|
||||
// 0.0 -> ''
|
||||
// 0 -> ''
|
||||
value = String(value).replace(/^(?:\+|(-))?0*(\d*)(?:\.0*|(\.\d*?)0*)?$/, '$1$2$3');
|
||||
|
||||
if (value.length === 0 || value === '-') {
|
||||
value = '0';
|
||||
}
|
||||
|
||||
return value;
|
||||
};
|
||||
|
||||
module.exports = function(node) {
|
||||
node.value = packNumber(node.value);
|
||||
};
|
||||
module.exports.pack = packNumber;
|
||||
12
node_modules/csso/lib/compressor/compress/String.js
generated
vendored
Executable file
12
node_modules/csso/lib/compressor/compress/String.js
generated
vendored
Executable file
@@ -0,0 +1,12 @@
|
||||
module.exports = function(node) {
|
||||
var value = node.value;
|
||||
|
||||
// remove escaped \n, i.e.
|
||||
// .a { content: "foo\
|
||||
// bar"}
|
||||
// ->
|
||||
// .a { content: "foobar" }
|
||||
value = value.replace(/\\\n/g, '');
|
||||
|
||||
node.value = value;
|
||||
};
|
||||
33
node_modules/csso/lib/compressor/compress/Url.js
generated
vendored
Executable file
33
node_modules/csso/lib/compressor/compress/Url.js
generated
vendored
Executable file
@@ -0,0 +1,33 @@
|
||||
var UNICODE = '\\\\[0-9a-f]{1,6}(\\r\\n|[ \\n\\r\\t\\f])?';
|
||||
var ESCAPE = '(' + UNICODE + '|\\\\[^\\n\\r\\f0-9a-fA-F])';
|
||||
var NONPRINTABLE = '\u0000\u0008\u000b\u000e-\u001f\u007f';
|
||||
var SAFE_URL = new RegExp('^(' + ESCAPE + '|[^\"\'\\(\\)\\\\\\s' + NONPRINTABLE + '])*$', 'i');
|
||||
|
||||
module.exports = function(node) {
|
||||
var value = node.value;
|
||||
|
||||
if (value.type !== 'String') {
|
||||
return;
|
||||
}
|
||||
|
||||
var quote = value.value[0];
|
||||
var url = value.value.substr(1, value.value.length - 2);
|
||||
|
||||
// convert `\\` to `/`
|
||||
url = url.replace(/\\\\/g, '/');
|
||||
|
||||
// remove quotes when safe
|
||||
// https://www.w3.org/TR/css-syntax-3/#url-unquoted-diagram
|
||||
if (SAFE_URL.test(url)) {
|
||||
node.value = {
|
||||
type: 'Raw',
|
||||
info: node.value.info,
|
||||
value: url
|
||||
};
|
||||
} else {
|
||||
// use double quotes if string has no double quotes
|
||||
// otherwise use original quotes
|
||||
// TODO: make better quote type selection
|
||||
node.value.value = url.indexOf('"') === -1 ? '"' + url + '"' : quote + url + quote;
|
||||
}
|
||||
};
|
||||
18
node_modules/csso/lib/compressor/compress/Value.js
generated
vendored
Executable file
18
node_modules/csso/lib/compressor/compress/Value.js
generated
vendored
Executable file
@@ -0,0 +1,18 @@
|
||||
var resolveName = require('../../utils/names.js').property;
|
||||
var handlers = {
|
||||
'font': require('./property/font.js'),
|
||||
'font-weight': require('./property/font-weight.js'),
|
||||
'background': require('./property/background.js')
|
||||
};
|
||||
|
||||
module.exports = function compressValue(node) {
|
||||
if (!this.declaration) {
|
||||
return;
|
||||
}
|
||||
|
||||
var property = resolveName(this.declaration.property.name);
|
||||
|
||||
if (handlers.hasOwnProperty(property.name)) {
|
||||
handlers[property.name](node);
|
||||
}
|
||||
};
|
||||
21
node_modules/csso/lib/compressor/compress/atrule/keyframes.js
generated
vendored
Executable file
21
node_modules/csso/lib/compressor/compress/atrule/keyframes.js
generated
vendored
Executable file
@@ -0,0 +1,21 @@
|
||||
module.exports = function(node) {
|
||||
node.block.rules.each(function(ruleset) {
|
||||
ruleset.selector.selectors.each(function(simpleselector) {
|
||||
simpleselector.sequence.each(function(data, item) {
|
||||
if (data.type === 'Percentage' && data.value === '100') {
|
||||
item.data = {
|
||||
type: 'Identifier',
|
||||
info: data.info,
|
||||
name: 'to'
|
||||
};
|
||||
} else if (data.type === 'Identifier' && data.name === 'from') {
|
||||
item.data = {
|
||||
type: 'Percentage',
|
||||
info: data.info,
|
||||
value: '0'
|
||||
};
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
489
node_modules/csso/lib/compressor/compress/color.js
generated
vendored
Executable file
489
node_modules/csso/lib/compressor/compress/color.js
generated
vendored
Executable file
@@ -0,0 +1,489 @@
|
||||
var List = require('../../utils/list.js');
|
||||
var packNumber = require('./Number.js').pack;
|
||||
|
||||
// http://www.w3.org/TR/css3-color/#svg-color
|
||||
var NAME_TO_HEX = {
|
||||
'aliceblue': 'f0f8ff',
|
||||
'antiquewhite': 'faebd7',
|
||||
'aqua': '0ff',
|
||||
'aquamarine': '7fffd4',
|
||||
'azure': 'f0ffff',
|
||||
'beige': 'f5f5dc',
|
||||
'bisque': 'ffe4c4',
|
||||
'black': '000',
|
||||
'blanchedalmond': 'ffebcd',
|
||||
'blue': '00f',
|
||||
'blueviolet': '8a2be2',
|
||||
'brown': 'a52a2a',
|
||||
'burlywood': 'deb887',
|
||||
'cadetblue': '5f9ea0',
|
||||
'chartreuse': '7fff00',
|
||||
'chocolate': 'd2691e',
|
||||
'coral': 'ff7f50',
|
||||
'cornflowerblue': '6495ed',
|
||||
'cornsilk': 'fff8dc',
|
||||
'crimson': 'dc143c',
|
||||
'cyan': '0ff',
|
||||
'darkblue': '00008b',
|
||||
'darkcyan': '008b8b',
|
||||
'darkgoldenrod': 'b8860b',
|
||||
'darkgray': 'a9a9a9',
|
||||
'darkgrey': 'a9a9a9',
|
||||
'darkgreen': '006400',
|
||||
'darkkhaki': 'bdb76b',
|
||||
'darkmagenta': '8b008b',
|
||||
'darkolivegreen': '556b2f',
|
||||
'darkorange': 'ff8c00',
|
||||
'darkorchid': '9932cc',
|
||||
'darkred': '8b0000',
|
||||
'darksalmon': 'e9967a',
|
||||
'darkseagreen': '8fbc8f',
|
||||
'darkslateblue': '483d8b',
|
||||
'darkslategray': '2f4f4f',
|
||||
'darkslategrey': '2f4f4f',
|
||||
'darkturquoise': '00ced1',
|
||||
'darkviolet': '9400d3',
|
||||
'deeppink': 'ff1493',
|
||||
'deepskyblue': '00bfff',
|
||||
'dimgray': '696969',
|
||||
'dimgrey': '696969',
|
||||
'dodgerblue': '1e90ff',
|
||||
'firebrick': 'b22222',
|
||||
'floralwhite': 'fffaf0',
|
||||
'forestgreen': '228b22',
|
||||
'fuchsia': 'f0f',
|
||||
'gainsboro': 'dcdcdc',
|
||||
'ghostwhite': 'f8f8ff',
|
||||
'gold': 'ffd700',
|
||||
'goldenrod': 'daa520',
|
||||
'gray': '808080',
|
||||
'grey': '808080',
|
||||
'green': '008000',
|
||||
'greenyellow': 'adff2f',
|
||||
'honeydew': 'f0fff0',
|
||||
'hotpink': 'ff69b4',
|
||||
'indianred': 'cd5c5c',
|
||||
'indigo': '4b0082',
|
||||
'ivory': 'fffff0',
|
||||
'khaki': 'f0e68c',
|
||||
'lavender': 'e6e6fa',
|
||||
'lavenderblush': 'fff0f5',
|
||||
'lawngreen': '7cfc00',
|
||||
'lemonchiffon': 'fffacd',
|
||||
'lightblue': 'add8e6',
|
||||
'lightcoral': 'f08080',
|
||||
'lightcyan': 'e0ffff',
|
||||
'lightgoldenrodyellow': 'fafad2',
|
||||
'lightgray': 'd3d3d3',
|
||||
'lightgrey': 'd3d3d3',
|
||||
'lightgreen': '90ee90',
|
||||
'lightpink': 'ffb6c1',
|
||||
'lightsalmon': 'ffa07a',
|
||||
'lightseagreen': '20b2aa',
|
||||
'lightskyblue': '87cefa',
|
||||
'lightslategray': '789',
|
||||
'lightslategrey': '789',
|
||||
'lightsteelblue': 'b0c4de',
|
||||
'lightyellow': 'ffffe0',
|
||||
'lime': '0f0',
|
||||
'limegreen': '32cd32',
|
||||
'linen': 'faf0e6',
|
||||
'magenta': 'f0f',
|
||||
'maroon': '800000',
|
||||
'mediumaquamarine': '66cdaa',
|
||||
'mediumblue': '0000cd',
|
||||
'mediumorchid': 'ba55d3',
|
||||
'mediumpurple': '9370db',
|
||||
'mediumseagreen': '3cb371',
|
||||
'mediumslateblue': '7b68ee',
|
||||
'mediumspringgreen': '00fa9a',
|
||||
'mediumturquoise': '48d1cc',
|
||||
'mediumvioletred': 'c71585',
|
||||
'midnightblue': '191970',
|
||||
'mintcream': 'f5fffa',
|
||||
'mistyrose': 'ffe4e1',
|
||||
'moccasin': 'ffe4b5',
|
||||
'navajowhite': 'ffdead',
|
||||
'navy': '000080',
|
||||
'oldlace': 'fdf5e6',
|
||||
'olive': '808000',
|
||||
'olivedrab': '6b8e23',
|
||||
'orange': 'ffa500',
|
||||
'orangered': 'ff4500',
|
||||
'orchid': 'da70d6',
|
||||
'palegoldenrod': 'eee8aa',
|
||||
'palegreen': '98fb98',
|
||||
'paleturquoise': 'afeeee',
|
||||
'palevioletred': 'db7093',
|
||||
'papayawhip': 'ffefd5',
|
||||
'peachpuff': 'ffdab9',
|
||||
'peru': 'cd853f',
|
||||
'pink': 'ffc0cb',
|
||||
'plum': 'dda0dd',
|
||||
'powderblue': 'b0e0e6',
|
||||
'purple': '800080',
|
||||
'rebeccapurple': '639',
|
||||
'red': 'f00',
|
||||
'rosybrown': 'bc8f8f',
|
||||
'royalblue': '4169e1',
|
||||
'saddlebrown': '8b4513',
|
||||
'salmon': 'fa8072',
|
||||
'sandybrown': 'f4a460',
|
||||
'seagreen': '2e8b57',
|
||||
'seashell': 'fff5ee',
|
||||
'sienna': 'a0522d',
|
||||
'silver': 'c0c0c0',
|
||||
'skyblue': '87ceeb',
|
||||
'slateblue': '6a5acd',
|
||||
'slategray': '708090',
|
||||
'slategrey': '708090',
|
||||
'snow': 'fffafa',
|
||||
'springgreen': '00ff7f',
|
||||
'steelblue': '4682b4',
|
||||
'tan': 'd2b48c',
|
||||
'teal': '008080',
|
||||
'thistle': 'd8bfd8',
|
||||
'tomato': 'ff6347',
|
||||
'turquoise': '40e0d0',
|
||||
'violet': 'ee82ee',
|
||||
'wheat': 'f5deb3',
|
||||
'white': 'fff',
|
||||
'whitesmoke': 'f5f5f5',
|
||||
'yellow': 'ff0',
|
||||
'yellowgreen': '9acd32'
|
||||
};
|
||||
|
||||
var HEX_TO_NAME = {
|
||||
'800000': 'maroon',
|
||||
'800080': 'purple',
|
||||
'808000': 'olive',
|
||||
'808080': 'gray',
|
||||
'00ffff': 'cyan',
|
||||
'f0ffff': 'azure',
|
||||
'f5f5dc': 'beige',
|
||||
'ffe4c4': 'bisque',
|
||||
'000000': 'black',
|
||||
'0000ff': 'blue',
|
||||
'a52a2a': 'brown',
|
||||
'ff7f50': 'coral',
|
||||
'ffd700': 'gold',
|
||||
'008000': 'green',
|
||||
'4b0082': 'indigo',
|
||||
'fffff0': 'ivory',
|
||||
'f0e68c': 'khaki',
|
||||
'00ff00': 'lime',
|
||||
'faf0e6': 'linen',
|
||||
'000080': 'navy',
|
||||
'ffa500': 'orange',
|
||||
'da70d6': 'orchid',
|
||||
'cd853f': 'peru',
|
||||
'ffc0cb': 'pink',
|
||||
'dda0dd': 'plum',
|
||||
'f00': 'red',
|
||||
'ff0000': 'red',
|
||||
'fa8072': 'salmon',
|
||||
'a0522d': 'sienna',
|
||||
'c0c0c0': 'silver',
|
||||
'fffafa': 'snow',
|
||||
'd2b48c': 'tan',
|
||||
'008080': 'teal',
|
||||
'ff6347': 'tomato',
|
||||
'ee82ee': 'violet',
|
||||
'f5deb3': 'wheat',
|
||||
'ffffff': 'white',
|
||||
'ffff00': 'yellow'
|
||||
};
|
||||
|
||||
function hueToRgb(p, q, t) {
|
||||
if (t < 0) {
|
||||
t += 1;
|
||||
}
|
||||
if (t > 1) {
|
||||
t -= 1;
|
||||
}
|
||||
if (t < 1 / 6) {
|
||||
return p + (q - p) * 6 * t;
|
||||
}
|
||||
if (t < 1 / 2) {
|
||||
return q;
|
||||
}
|
||||
if (t < 2 / 3) {
|
||||
return p + (q - p) * (2 / 3 - t) * 6;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
function hslToRgb(h, s, l, a) {
|
||||
var r;
|
||||
var g;
|
||||
var b;
|
||||
|
||||
if (s == 0) {
|
||||
r = g = b = l; // achromatic
|
||||
} else {
|
||||
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
||||
var p = 2 * l - q;
|
||||
|
||||
r = hueToRgb(p, q, h + 1 / 3);
|
||||
g = hueToRgb(p, q, h);
|
||||
b = hueToRgb(p, q, h - 1 / 3);
|
||||
}
|
||||
|
||||
return [
|
||||
Math.round(r * 255),
|
||||
Math.round(g * 255),
|
||||
Math.round(b * 255),
|
||||
a
|
||||
];
|
||||
}
|
||||
|
||||
function toHex(value) {
|
||||
value = value.toString(16);
|
||||
return value.length === 1 ? '0' + value : value;
|
||||
}
|
||||
|
||||
function parseFunctionArgs(functionArgs, count, rgb) {
|
||||
var argument = functionArgs.head;
|
||||
var args = [];
|
||||
|
||||
while (argument !== null) {
|
||||
var argumentPart = argument.data.sequence.head;
|
||||
var wasValue = false;
|
||||
|
||||
while (argumentPart !== null) {
|
||||
var value = argumentPart.data;
|
||||
var type = value.type;
|
||||
|
||||
switch (type) {
|
||||
case 'Number':
|
||||
case 'Percentage':
|
||||
if (wasValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
wasValue = true;
|
||||
args.push({
|
||||
type: type,
|
||||
value: Number(value.value)
|
||||
});
|
||||
break;
|
||||
|
||||
case 'Operator':
|
||||
if (wasValue || value.value !== '+') {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// something we couldn't understand
|
||||
return;
|
||||
}
|
||||
|
||||
argumentPart = argumentPart.next;
|
||||
}
|
||||
|
||||
argument = argument.next;
|
||||
}
|
||||
|
||||
if (args.length !== count) {
|
||||
// invalid arguments count
|
||||
// TODO: remove those tokens
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.length === 4) {
|
||||
if (args[3].type !== 'Number') {
|
||||
// 4th argument should be a number
|
||||
// TODO: remove those tokens
|
||||
return;
|
||||
}
|
||||
|
||||
args[3].type = 'Alpha';
|
||||
}
|
||||
|
||||
if (rgb) {
|
||||
if (args[0].type !== args[1].type || args[0].type !== args[2].type) {
|
||||
// invalid color, numbers and percentage shouldn't be mixed
|
||||
// TODO: remove those tokens
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (args[0].type !== 'Number' ||
|
||||
args[1].type !== 'Percentage' ||
|
||||
args[2].type !== 'Percentage') {
|
||||
// invalid color, for hsl values should be: number, percentage, percentage
|
||||
// TODO: remove those tokens
|
||||
return;
|
||||
}
|
||||
|
||||
args[0].type = 'Angle';
|
||||
}
|
||||
|
||||
return args.map(function(arg) {
|
||||
var value = Math.max(0, arg.value);
|
||||
|
||||
switch (arg.type) {
|
||||
case 'Number':
|
||||
// fit value to [0..255] range
|
||||
value = Math.min(value, 255);
|
||||
break;
|
||||
|
||||
case 'Percentage':
|
||||
// convert 0..100% to value in [0..255] range
|
||||
value = Math.min(value, 100) / 100;
|
||||
|
||||
if (!rgb) {
|
||||
return value;
|
||||
}
|
||||
|
||||
value = 255 * value;
|
||||
break;
|
||||
|
||||
case 'Angle':
|
||||
// fit value to (-360..360) range
|
||||
return (((value % 360) + 360) % 360) / 360;
|
||||
|
||||
case 'Alpha':
|
||||
// fit value to [0..1] range
|
||||
return Math.min(value, 1);
|
||||
}
|
||||
|
||||
return Math.round(value);
|
||||
});
|
||||
}
|
||||
|
||||
function compressFunction(node, item, list) {
|
||||
var functionName = node.name;
|
||||
var args;
|
||||
|
||||
if (functionName === 'rgba' || functionName === 'hsla') {
|
||||
args = parseFunctionArgs(node.arguments, 4, functionName === 'rgba');
|
||||
|
||||
if (!args) {
|
||||
// something went wrong
|
||||
return;
|
||||
}
|
||||
|
||||
if (functionName === 'hsla') {
|
||||
args = hslToRgb.apply(null, args);
|
||||
node.name = 'rgba';
|
||||
}
|
||||
|
||||
if (args[3] !== 1) {
|
||||
// replace argument values for normalized/interpolated
|
||||
node.arguments.each(function(argument) {
|
||||
var item = argument.sequence.head;
|
||||
|
||||
if (item.data.type === 'Operator') {
|
||||
item = item.next;
|
||||
}
|
||||
|
||||
argument.sequence = new List([{
|
||||
type: 'Number',
|
||||
info: item.data.info,
|
||||
value: packNumber(args.shift())
|
||||
}]);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// otherwise convert to rgb, i.e. rgba(255, 0, 0, 1) -> rgb(255, 0, 0)
|
||||
functionName = 'rgb';
|
||||
}
|
||||
|
||||
if (functionName === 'hsl') {
|
||||
args = args || parseFunctionArgs(node.arguments, 3, false);
|
||||
|
||||
if (!args) {
|
||||
// something went wrong
|
||||
return;
|
||||
}
|
||||
|
||||
// convert to rgb
|
||||
args = hslToRgb.apply(null, args);
|
||||
functionName = 'rgb';
|
||||
}
|
||||
|
||||
if (functionName === 'rgb') {
|
||||
args = args || parseFunctionArgs(node.arguments, 3, true);
|
||||
|
||||
if (!args) {
|
||||
// something went wrong
|
||||
return;
|
||||
}
|
||||
|
||||
// check if color is not at the end and not followed by space
|
||||
var next = item.next;
|
||||
if (next && next.data.type !== 'Space') {
|
||||
list.insert(list.createItem({
|
||||
type: 'Space'
|
||||
}), next);
|
||||
}
|
||||
|
||||
item.data = {
|
||||
type: 'Hash',
|
||||
info: node.info,
|
||||
value: toHex(args[0]) + toHex(args[1]) + toHex(args[2])
|
||||
};
|
||||
|
||||
compressHex(item.data, item);
|
||||
}
|
||||
}
|
||||
|
||||
function compressIdent(node, item) {
|
||||
if (this.declaration === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var color = node.name.toLowerCase();
|
||||
|
||||
if (NAME_TO_HEX.hasOwnProperty(color)) {
|
||||
var hex = NAME_TO_HEX[color];
|
||||
|
||||
if (hex.length + 1 <= color.length) {
|
||||
// replace for shorter hex value
|
||||
item.data = {
|
||||
type: 'Hash',
|
||||
info: node.info,
|
||||
value: hex
|
||||
};
|
||||
} else {
|
||||
// special case for consistent colors
|
||||
if (color === 'grey') {
|
||||
color = 'gray';
|
||||
}
|
||||
|
||||
// just replace value for lower cased name
|
||||
node.name = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function compressHex(node, item) {
|
||||
var color = node.value.toLowerCase();
|
||||
|
||||
// #112233 -> #123
|
||||
if (color.length === 6 &&
|
||||
color[0] === color[1] &&
|
||||
color[2] === color[3] &&
|
||||
color[4] === color[5]) {
|
||||
color = color[0] + color[2] + color[4];
|
||||
}
|
||||
|
||||
if (HEX_TO_NAME[color]) {
|
||||
item.data = {
|
||||
type: 'Identifier',
|
||||
info: node.info,
|
||||
name: HEX_TO_NAME[color]
|
||||
};
|
||||
} else {
|
||||
node.value = color;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
compressFunction: compressFunction,
|
||||
compressIdent: compressIdent,
|
||||
compressHex: compressHex
|
||||
};
|
||||
22
node_modules/csso/lib/compressor/compress/index.js
generated
vendored
Executable file
22
node_modules/csso/lib/compressor/compress/index.js
generated
vendored
Executable file
@@ -0,0 +1,22 @@
|
||||
var walk = require('../../utils/walk.js').all;
|
||||
var handlers = {
|
||||
Atrule: require('./Atrule.js'),
|
||||
Attribute: require('./Attribute.js'),
|
||||
Value: require('./Value.js'),
|
||||
Dimension: require('./Dimension.js'),
|
||||
Percentage: require('./Number.js'),
|
||||
Number: require('./Number.js'),
|
||||
String: require('./String.js'),
|
||||
Url: require('./Url.js'),
|
||||
Hash: require('./color.js').compressHex,
|
||||
Identifier: require('./color.js').compressIdent,
|
||||
Function: require('./color.js').compressFunction
|
||||
};
|
||||
|
||||
module.exports = function(ast) {
|
||||
walk(ast, function(node, item, list) {
|
||||
if (handlers.hasOwnProperty(node.type)) {
|
||||
handlers[node.type].call(this, node, item, list);
|
||||
}
|
||||
});
|
||||
};
|
||||
66
node_modules/csso/lib/compressor/compress/property/background.js
generated
vendored
Executable file
66
node_modules/csso/lib/compressor/compress/property/background.js
generated
vendored
Executable file
@@ -0,0 +1,66 @@
|
||||
var List = require('../../../utils/list.js');
|
||||
|
||||
module.exports = function compressBackground(node) {
|
||||
function lastType() {
|
||||
if (buffer.length) {
|
||||
return buffer[buffer.length - 1].type;
|
||||
}
|
||||
}
|
||||
|
||||
function flush() {
|
||||
if (lastType() === 'Space') {
|
||||
buffer.pop();
|
||||
}
|
||||
|
||||
if (!buffer.length) {
|
||||
buffer.unshift(
|
||||
{
|
||||
type: 'Number',
|
||||
value: '0'
|
||||
},
|
||||
{
|
||||
type: 'Space'
|
||||
},
|
||||
{
|
||||
type: 'Number',
|
||||
value: '0'
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
newValue.push.apply(newValue, buffer);
|
||||
|
||||
buffer = [];
|
||||
}
|
||||
|
||||
var newValue = [];
|
||||
var buffer = [];
|
||||
|
||||
node.sequence.each(function(node) {
|
||||
if (node.type === 'Operator' && node.value === ',') {
|
||||
flush();
|
||||
newValue.push(node);
|
||||
return;
|
||||
}
|
||||
|
||||
// remove defaults
|
||||
if (node.type === 'Identifier') {
|
||||
if (node.name === 'transparent' ||
|
||||
node.name === 'none' ||
|
||||
node.name === 'repeat' ||
|
||||
node.name === 'scroll') {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// don't add redundant spaces
|
||||
if (node.type === 'Space' && (!buffer.length || lastType() === 'Space')) {
|
||||
return;
|
||||
}
|
||||
|
||||
buffer.push(node);
|
||||
});
|
||||
|
||||
flush();
|
||||
node.sequence = new List(newValue);
|
||||
};
|
||||
22
node_modules/csso/lib/compressor/compress/property/font-weight.js
generated
vendored
Executable file
22
node_modules/csso/lib/compressor/compress/property/font-weight.js
generated
vendored
Executable file
@@ -0,0 +1,22 @@
|
||||
module.exports = function compressFontWeight(node) {
|
||||
var value = node.sequence.head.data;
|
||||
|
||||
if (value.type === 'Identifier') {
|
||||
switch (value.name) {
|
||||
case 'normal':
|
||||
node.sequence.head.data = {
|
||||
type: 'Number',
|
||||
info: value.info,
|
||||
value: '400'
|
||||
};
|
||||
break;
|
||||
case 'bold':
|
||||
node.sequence.head.data = {
|
||||
type: 'Number',
|
||||
info: value.info,
|
||||
value: '700'
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
45
node_modules/csso/lib/compressor/compress/property/font.js
generated
vendored
Executable file
45
node_modules/csso/lib/compressor/compress/property/font.js
generated
vendored
Executable file
@@ -0,0 +1,45 @@
|
||||
module.exports = function compressFont(node) {
|
||||
var list = node.sequence;
|
||||
|
||||
list.eachRight(function(node, item) {
|
||||
if (node.type === 'Identifier') {
|
||||
if (node.name === 'bold') {
|
||||
item.data = {
|
||||
type: 'Number',
|
||||
info: node.info,
|
||||
value: '700'
|
||||
};
|
||||
} else if (node.name === 'normal') {
|
||||
var prev = item.prev;
|
||||
|
||||
if (prev && prev.data.type === 'Operator' && prev.data.value === '/') {
|
||||
this.remove(prev);
|
||||
}
|
||||
|
||||
this.remove(item);
|
||||
} else if (node.name === 'medium') {
|
||||
var next = item.next;
|
||||
|
||||
if (!next || next.data.type !== 'Operator') {
|
||||
this.remove(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// remove redundant spaces
|
||||
list.each(function(node, item) {
|
||||
if (node.type === 'Space') {
|
||||
if (!item.prev || !item.next || item.next.data.type === 'Space') {
|
||||
this.remove(item);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (list.isEmpty()) {
|
||||
list.insert(list.createItem({
|
||||
type: 'Identifier',
|
||||
name: 'normal'
|
||||
}));
|
||||
}
|
||||
};
|
||||
186
node_modules/csso/lib/compressor/index.js
generated
vendored
Executable file
186
node_modules/csso/lib/compressor/index.js
generated
vendored
Executable file
@@ -0,0 +1,186 @@
|
||||
var List = require('../utils/list');
|
||||
var clone = require('../utils/clone');
|
||||
var usageUtils = require('./usage');
|
||||
var clean = require('./clean');
|
||||
var compress = require('./compress');
|
||||
var restructureBlock = require('./restructure');
|
||||
var walkRules = require('../utils/walk').rules;
|
||||
|
||||
function readRulesChunk(rules, specialComments) {
|
||||
var buffer = new List();
|
||||
var nonSpaceTokenInBuffer = false;
|
||||
var protectedComment;
|
||||
|
||||
rules.nextUntil(rules.head, function(node, item, list) {
|
||||
if (node.type === 'Comment') {
|
||||
if (!specialComments || node.value.charAt(0) !== '!') {
|
||||
list.remove(item);
|
||||
return;
|
||||
}
|
||||
|
||||
if (nonSpaceTokenInBuffer || protectedComment) {
|
||||
return true;
|
||||
}
|
||||
|
||||
list.remove(item);
|
||||
protectedComment = node;
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.type !== 'Space') {
|
||||
nonSpaceTokenInBuffer = true;
|
||||
}
|
||||
|
||||
buffer.insert(list.remove(item));
|
||||
});
|
||||
|
||||
return {
|
||||
comment: protectedComment,
|
||||
stylesheet: {
|
||||
type: 'StyleSheet',
|
||||
info: null,
|
||||
rules: buffer
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function compressChunk(ast, firstAtrulesAllowed, usageData, num, logger) {
|
||||
logger('Compress block #' + num, null, true);
|
||||
|
||||
var seed = 1;
|
||||
walkRules(ast, function markStylesheets() {
|
||||
if ('id' in this.stylesheet === false) {
|
||||
this.stylesheet.firstAtrulesAllowed = firstAtrulesAllowed;
|
||||
this.stylesheet.id = seed++;
|
||||
}
|
||||
});
|
||||
logger('init', ast);
|
||||
|
||||
// remove redundant
|
||||
clean(ast, usageData);
|
||||
logger('clean', ast);
|
||||
|
||||
// compress nodes
|
||||
compress(ast, usageData);
|
||||
logger('compress', ast);
|
||||
|
||||
return ast;
|
||||
}
|
||||
|
||||
function getCommentsOption(options) {
|
||||
var comments = 'comments' in options ? options.comments : 'exclamation';
|
||||
|
||||
if (typeof comments === 'boolean') {
|
||||
comments = comments ? 'exclamation' : false;
|
||||
} else if (comments !== 'exclamation' && comments !== 'first-exclamation') {
|
||||
comments = false;
|
||||
}
|
||||
|
||||
return comments;
|
||||
}
|
||||
|
||||
function getRestructureOption(options) {
|
||||
return 'restructure' in options ? options.restructure :
|
||||
'restructuring' in options ? options.restructuring :
|
||||
true;
|
||||
}
|
||||
|
||||
function wrapBlock(block) {
|
||||
return new List([{
|
||||
type: 'Ruleset',
|
||||
selector: {
|
||||
type: 'Selector',
|
||||
selectors: new List([{
|
||||
type: 'SimpleSelector',
|
||||
sequence: new List([{
|
||||
type: 'Identifier',
|
||||
name: 'x'
|
||||
}])
|
||||
}])
|
||||
},
|
||||
block: block
|
||||
}]);
|
||||
}
|
||||
|
||||
module.exports = function compress(ast, options) {
|
||||
ast = ast || { type: 'StyleSheet', info: null, rules: new List() };
|
||||
options = options || {};
|
||||
|
||||
var logger = typeof options.logger === 'function' ? options.logger : Function();
|
||||
var specialComments = getCommentsOption(options);
|
||||
var restructuring = getRestructureOption(options);
|
||||
var firstAtrulesAllowed = true;
|
||||
var usageData = false;
|
||||
var inputRules;
|
||||
var outputRules = new List();
|
||||
var chunk;
|
||||
var chunkNum = 1;
|
||||
var chunkRules;
|
||||
|
||||
if (options.clone) {
|
||||
ast = clone(ast);
|
||||
}
|
||||
|
||||
if (ast.type === 'StyleSheet') {
|
||||
inputRules = ast.rules;
|
||||
ast.rules = outputRules;
|
||||
} else {
|
||||
inputRules = wrapBlock(ast);
|
||||
}
|
||||
|
||||
if (options.usage) {
|
||||
usageData = usageUtils.buildIndex(options.usage);
|
||||
}
|
||||
|
||||
do {
|
||||
chunk = readRulesChunk(inputRules, Boolean(specialComments));
|
||||
|
||||
compressChunk(chunk.stylesheet, firstAtrulesAllowed, usageData, chunkNum++, logger);
|
||||
|
||||
// structure optimisations
|
||||
if (restructuring) {
|
||||
restructureBlock(chunk.stylesheet, usageData, logger);
|
||||
}
|
||||
|
||||
chunkRules = chunk.stylesheet.rules;
|
||||
|
||||
if (chunk.comment) {
|
||||
// add \n before comment if there is another content in outputRules
|
||||
if (!outputRules.isEmpty()) {
|
||||
outputRules.insert(List.createItem({
|
||||
type: 'Raw',
|
||||
value: '\n'
|
||||
}));
|
||||
}
|
||||
|
||||
outputRules.insert(List.createItem(chunk.comment));
|
||||
|
||||
// add \n after comment if chunk is not empty
|
||||
if (!chunkRules.isEmpty()) {
|
||||
outputRules.insert(List.createItem({
|
||||
type: 'Raw',
|
||||
value: '\n'
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
if (firstAtrulesAllowed && !chunkRules.isEmpty()) {
|
||||
var lastRule = chunkRules.last();
|
||||
|
||||
if (lastRule.type !== 'Atrule' ||
|
||||
(lastRule.name !== 'import' && lastRule.name !== 'charset')) {
|
||||
firstAtrulesAllowed = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (specialComments !== 'exclamation') {
|
||||
specialComments = false;
|
||||
}
|
||||
|
||||
outputRules.appendList(chunkRules);
|
||||
} while (!inputRules.isEmpty());
|
||||
|
||||
return {
|
||||
ast: ast
|
||||
};
|
||||
};
|
||||
48
node_modules/csso/lib/compressor/restructure/1-initialMergeRuleset.js
generated
vendored
Executable file
48
node_modules/csso/lib/compressor/restructure/1-initialMergeRuleset.js
generated
vendored
Executable file
@@ -0,0 +1,48 @@
|
||||
var utils = require('./utils.js');
|
||||
var walkRules = require('../../utils/walk.js').rules;
|
||||
|
||||
function processRuleset(node, item, list) {
|
||||
var selectors = node.selector.selectors;
|
||||
var declarations = node.block.declarations;
|
||||
|
||||
list.prevUntil(item.prev, function(prev) {
|
||||
// skip non-ruleset node if safe
|
||||
if (prev.type !== 'Ruleset') {
|
||||
return utils.unsafeToSkipNode.call(selectors, prev);
|
||||
}
|
||||
|
||||
var prevSelectors = prev.selector.selectors;
|
||||
var prevDeclarations = prev.block.declarations;
|
||||
|
||||
// try to join rulesets with equal pseudo signature
|
||||
if (node.pseudoSignature === prev.pseudoSignature) {
|
||||
// try to join by selectors
|
||||
if (utils.isEqualLists(prevSelectors, selectors)) {
|
||||
prevDeclarations.appendList(declarations);
|
||||
list.remove(item);
|
||||
return true;
|
||||
}
|
||||
|
||||
// try to join by declarations
|
||||
if (utils.isEqualDeclarations(declarations, prevDeclarations)) {
|
||||
utils.addSelectors(prevSelectors, selectors);
|
||||
list.remove(item);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// go to prev ruleset if has no selector similarities
|
||||
return utils.hasSimilarSelectors(selectors, prevSelectors);
|
||||
});
|
||||
};
|
||||
|
||||
// NOTE: direction should be left to right, since rulesets merge to left
|
||||
// ruleset. When direction right to left unmerged rulesets may prevent lookup
|
||||
// TODO: remove initial merge
|
||||
module.exports = function initialMergeRuleset(ast) {
|
||||
walkRules(ast, function(node, item, list) {
|
||||
if (node.type === 'Ruleset') {
|
||||
processRuleset(node, item, list);
|
||||
}
|
||||
});
|
||||
};
|
||||
35
node_modules/csso/lib/compressor/restructure/2-mergeAtrule.js
generated
vendored
Executable file
35
node_modules/csso/lib/compressor/restructure/2-mergeAtrule.js
generated
vendored
Executable file
@@ -0,0 +1,35 @@
|
||||
var walkRulesRight = require('../../utils/walk.js').rulesRight;
|
||||
|
||||
function isMediaRule(node) {
|
||||
return node.type === 'Atrule' && node.name === 'media';
|
||||
}
|
||||
|
||||
function processAtrule(node, item, list) {
|
||||
if (!isMediaRule(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var prev = item.prev && item.prev.data;
|
||||
|
||||
if (!prev || !isMediaRule(prev)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// merge @media with same query
|
||||
if (node.expression.id === prev.expression.id) {
|
||||
prev.block.rules.appendList(node.block.rules);
|
||||
prev.info = {
|
||||
primary: prev.info,
|
||||
merged: node.info
|
||||
};
|
||||
list.remove(item);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = function rejoinAtrule(ast) {
|
||||
walkRulesRight(ast, function(node, item, list) {
|
||||
if (node.type === 'Atrule') {
|
||||
processAtrule(node, item, list);
|
||||
}
|
||||
});
|
||||
};
|
||||
42
node_modules/csso/lib/compressor/restructure/3-disjoinRuleset.js
generated
vendored
Executable file
42
node_modules/csso/lib/compressor/restructure/3-disjoinRuleset.js
generated
vendored
Executable file
@@ -0,0 +1,42 @@
|
||||
var List = require('../../utils/list.js');
|
||||
var walkRulesRight = require('../../utils/walk.js').rulesRight;
|
||||
|
||||
function processRuleset(node, item, list) {
|
||||
var selectors = node.selector.selectors;
|
||||
|
||||
// generate new rule sets:
|
||||
// .a, .b { color: red; }
|
||||
// ->
|
||||
// .a { color: red; }
|
||||
// .b { color: red; }
|
||||
|
||||
// while there are more than 1 simple selector split for rulesets
|
||||
while (selectors.head !== selectors.tail) {
|
||||
var newSelectors = new List();
|
||||
newSelectors.insert(selectors.remove(selectors.head));
|
||||
|
||||
list.insert(list.createItem({
|
||||
type: 'Ruleset',
|
||||
info: node.info,
|
||||
pseudoSignature: node.pseudoSignature,
|
||||
selector: {
|
||||
type: 'Selector',
|
||||
info: node.selector.info,
|
||||
selectors: newSelectors
|
||||
},
|
||||
block: {
|
||||
type: 'Block',
|
||||
info: node.block.info,
|
||||
declarations: node.block.declarations.copy()
|
||||
}
|
||||
}), item);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = function disjoinRuleset(ast) {
|
||||
walkRulesRight(ast, function(node, item, list) {
|
||||
if (node.type === 'Ruleset') {
|
||||
processRuleset(node, item, list);
|
||||
}
|
||||
});
|
||||
};
|
||||
430
node_modules/csso/lib/compressor/restructure/4-restructShorthand.js
generated
vendored
Executable file
430
node_modules/csso/lib/compressor/restructure/4-restructShorthand.js
generated
vendored
Executable file
@@ -0,0 +1,430 @@
|
||||
var List = require('../../utils/list.js');
|
||||
var translate = require('../../utils/translate.js');
|
||||
var walkRulesRight = require('../../utils/walk.js').rulesRight;
|
||||
|
||||
var REPLACE = 1;
|
||||
var REMOVE = 2;
|
||||
var TOP = 0;
|
||||
var RIGHT = 1;
|
||||
var BOTTOM = 2;
|
||||
var LEFT = 3;
|
||||
var SIDES = ['top', 'right', 'bottom', 'left'];
|
||||
var SIDE = {
|
||||
'margin-top': 'top',
|
||||
'margin-right': 'right',
|
||||
'margin-bottom': 'bottom',
|
||||
'margin-left': 'left',
|
||||
|
||||
'padding-top': 'top',
|
||||
'padding-right': 'right',
|
||||
'padding-bottom': 'bottom',
|
||||
'padding-left': 'left',
|
||||
|
||||
'border-top-color': 'top',
|
||||
'border-right-color': 'right',
|
||||
'border-bottom-color': 'bottom',
|
||||
'border-left-color': 'left',
|
||||
'border-top-width': 'top',
|
||||
'border-right-width': 'right',
|
||||
'border-bottom-width': 'bottom',
|
||||
'border-left-width': 'left',
|
||||
'border-top-style': 'top',
|
||||
'border-right-style': 'right',
|
||||
'border-bottom-style': 'bottom',
|
||||
'border-left-style': 'left'
|
||||
};
|
||||
var MAIN_PROPERTY = {
|
||||
'margin': 'margin',
|
||||
'margin-top': 'margin',
|
||||
'margin-right': 'margin',
|
||||
'margin-bottom': 'margin',
|
||||
'margin-left': 'margin',
|
||||
|
||||
'padding': 'padding',
|
||||
'padding-top': 'padding',
|
||||
'padding-right': 'padding',
|
||||
'padding-bottom': 'padding',
|
||||
'padding-left': 'padding',
|
||||
|
||||
'border-color': 'border-color',
|
||||
'border-top-color': 'border-color',
|
||||
'border-right-color': 'border-color',
|
||||
'border-bottom-color': 'border-color',
|
||||
'border-left-color': 'border-color',
|
||||
'border-width': 'border-width',
|
||||
'border-top-width': 'border-width',
|
||||
'border-right-width': 'border-width',
|
||||
'border-bottom-width': 'border-width',
|
||||
'border-left-width': 'border-width',
|
||||
'border-style': 'border-style',
|
||||
'border-top-style': 'border-style',
|
||||
'border-right-style': 'border-style',
|
||||
'border-bottom-style': 'border-style',
|
||||
'border-left-style': 'border-style'
|
||||
};
|
||||
|
||||
function TRBL(name) {
|
||||
this.name = name;
|
||||
this.info = null;
|
||||
this.iehack = undefined;
|
||||
this.sides = {
|
||||
'top': null,
|
||||
'right': null,
|
||||
'bottom': null,
|
||||
'left': null
|
||||
};
|
||||
}
|
||||
|
||||
TRBL.prototype.getValueSequence = function(value, count) {
|
||||
var values = [];
|
||||
var iehack = '';
|
||||
var hasBadValues = value.sequence.some(function(child) {
|
||||
var special = false;
|
||||
|
||||
switch (child.type) {
|
||||
case 'Identifier':
|
||||
switch (child.name) {
|
||||
case '\\0':
|
||||
case '\\9':
|
||||
iehack = child.name;
|
||||
return;
|
||||
|
||||
case 'inherit':
|
||||
case 'initial':
|
||||
case 'unset':
|
||||
case 'revert':
|
||||
special = child.name;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'Dimension':
|
||||
switch (child.unit) {
|
||||
// is not supported until IE11
|
||||
case 'rem':
|
||||
|
||||
// v* units is too buggy across browsers and better
|
||||
// don't merge values with those units
|
||||
case 'vw':
|
||||
case 'vh':
|
||||
case 'vmin':
|
||||
case 'vmax':
|
||||
case 'vm': // IE9 supporting "vm" instead of "vmin".
|
||||
special = child.unit;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'Hash': // color
|
||||
case 'Number':
|
||||
case 'Percentage':
|
||||
break;
|
||||
|
||||
case 'Function':
|
||||
special = child.name;
|
||||
break;
|
||||
|
||||
case 'Space':
|
||||
return false; // ignore space
|
||||
|
||||
default:
|
||||
return true; // bad value
|
||||
}
|
||||
|
||||
values.push({
|
||||
node: child,
|
||||
special: special,
|
||||
important: value.important
|
||||
});
|
||||
});
|
||||
|
||||
if (hasBadValues || values.length > count) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof this.iehack === 'string' && this.iehack !== iehack) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.iehack = iehack; // move outside
|
||||
|
||||
return values;
|
||||
};
|
||||
|
||||
TRBL.prototype.canOverride = function(side, value) {
|
||||
var currentValue = this.sides[side];
|
||||
|
||||
return !currentValue || (value.important && !currentValue.important);
|
||||
};
|
||||
|
||||
TRBL.prototype.add = function(name, value, info) {
|
||||
function attemptToAdd() {
|
||||
var sides = this.sides;
|
||||
var side = SIDE[name];
|
||||
|
||||
if (side) {
|
||||
if (side in sides === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var values = this.getValueSequence(value, 1);
|
||||
|
||||
if (!values || !values.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// can mix only if specials are equal
|
||||
for (var key in sides) {
|
||||
if (sides[key] !== null && sides[key].special !== values[0].special) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.canOverride(side, values[0])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
sides[side] = values[0];
|
||||
return true;
|
||||
} else if (name === this.name) {
|
||||
var values = this.getValueSequence(value, 4);
|
||||
|
||||
if (!values || !values.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (values.length) {
|
||||
case 1:
|
||||
values[RIGHT] = values[TOP];
|
||||
values[BOTTOM] = values[TOP];
|
||||
values[LEFT] = values[TOP];
|
||||
break;
|
||||
|
||||
case 2:
|
||||
values[BOTTOM] = values[TOP];
|
||||
values[LEFT] = values[RIGHT];
|
||||
break;
|
||||
|
||||
case 3:
|
||||
values[LEFT] = values[RIGHT];
|
||||
break;
|
||||
}
|
||||
|
||||
// can mix only if specials are equal
|
||||
for (var i = 0; i < 4; i++) {
|
||||
for (var key in sides) {
|
||||
if (sides[key] !== null && sides[key].special !== values[i].special) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < 4; i++) {
|
||||
if (this.canOverride(SIDES[i], values[i])) {
|
||||
sides[SIDES[i]] = values[i];
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!attemptToAdd.call(this)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.info) {
|
||||
this.info = {
|
||||
primary: this.info,
|
||||
merged: info
|
||||
};
|
||||
} else {
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
TRBL.prototype.isOkToMinimize = function() {
|
||||
var top = this.sides.top;
|
||||
var right = this.sides.right;
|
||||
var bottom = this.sides.bottom;
|
||||
var left = this.sides.left;
|
||||
|
||||
if (top && right && bottom && left) {
|
||||
var important =
|
||||
top.important +
|
||||
right.important +
|
||||
bottom.important +
|
||||
left.important;
|
||||
|
||||
return important === 0 || important === 4;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
TRBL.prototype.getValue = function() {
|
||||
var result = [];
|
||||
var sides = this.sides;
|
||||
var values = [
|
||||
sides.top,
|
||||
sides.right,
|
||||
sides.bottom,
|
||||
sides.left
|
||||
];
|
||||
var stringValues = [
|
||||
translate(sides.top.node),
|
||||
translate(sides.right.node),
|
||||
translate(sides.bottom.node),
|
||||
translate(sides.left.node)
|
||||
];
|
||||
|
||||
if (stringValues[LEFT] === stringValues[RIGHT]) {
|
||||
values.pop();
|
||||
if (stringValues[BOTTOM] === stringValues[TOP]) {
|
||||
values.pop();
|
||||
if (stringValues[RIGHT] === stringValues[TOP]) {
|
||||
values.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < values.length; i++) {
|
||||
if (i) {
|
||||
result.push({ type: 'Space' });
|
||||
}
|
||||
|
||||
result.push(values[i].node);
|
||||
}
|
||||
|
||||
if (this.iehack) {
|
||||
result.push({ type: 'Space' }, {
|
||||
type: 'Identifier',
|
||||
info: {},
|
||||
name: this.iehack
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'Value',
|
||||
info: {},
|
||||
important: sides.top.important,
|
||||
sequence: new List(result)
|
||||
};
|
||||
};
|
||||
|
||||
TRBL.prototype.getProperty = function() {
|
||||
return {
|
||||
type: 'Property',
|
||||
info: {},
|
||||
name: this.name
|
||||
};
|
||||
};
|
||||
|
||||
function processRuleset(ruleset, shorts, shortDeclarations, lastShortSelector) {
|
||||
var declarations = ruleset.block.declarations;
|
||||
var selector = ruleset.selector.selectors.first().id;
|
||||
|
||||
ruleset.block.declarations.eachRight(function(declaration, item) {
|
||||
var property = declaration.property.name;
|
||||
|
||||
if (!MAIN_PROPERTY.hasOwnProperty(property)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var key = MAIN_PROPERTY[property];
|
||||
var shorthand;
|
||||
var operation;
|
||||
|
||||
if (!lastShortSelector || selector === lastShortSelector) {
|
||||
if (key in shorts) {
|
||||
operation = REMOVE;
|
||||
shorthand = shorts[key];
|
||||
}
|
||||
}
|
||||
|
||||
if (!shorthand || !shorthand.add(property, declaration.value, declaration.info)) {
|
||||
operation = REPLACE;
|
||||
shorthand = new TRBL(key);
|
||||
|
||||
// if can't parse value ignore it and break shorthand sequence
|
||||
if (!shorthand.add(property, declaration.value, declaration.info)) {
|
||||
lastShortSelector = null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
shorts[key] = shorthand;
|
||||
shortDeclarations.push({
|
||||
operation: operation,
|
||||
block: declarations,
|
||||
item: item,
|
||||
shorthand: shorthand
|
||||
});
|
||||
|
||||
lastShortSelector = selector;
|
||||
});
|
||||
|
||||
return lastShortSelector;
|
||||
};
|
||||
|
||||
function processShorthands(shortDeclarations, markDeclaration) {
|
||||
shortDeclarations.forEach(function(item) {
|
||||
var shorthand = item.shorthand;
|
||||
|
||||
if (!shorthand.isOkToMinimize()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (item.operation === REPLACE) {
|
||||
item.item.data = markDeclaration({
|
||||
type: 'Declaration',
|
||||
info: shorthand.info,
|
||||
property: shorthand.getProperty(),
|
||||
value: shorthand.getValue(),
|
||||
id: 0,
|
||||
length: 0,
|
||||
fingerprint: null
|
||||
});
|
||||
} else {
|
||||
item.block.remove(item.item);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = function restructBlock(ast, indexer) {
|
||||
var stylesheetMap = {};
|
||||
var shortDeclarations = [];
|
||||
|
||||
walkRulesRight(ast, function(node) {
|
||||
if (node.type !== 'Ruleset') {
|
||||
return;
|
||||
}
|
||||
|
||||
var stylesheet = this.stylesheet;
|
||||
var rulesetId = (node.pseudoSignature || '') + '|' + node.selector.selectors.first().id;
|
||||
var rulesetMap;
|
||||
var shorts;
|
||||
|
||||
if (!stylesheetMap.hasOwnProperty(stylesheet.id)) {
|
||||
rulesetMap = {
|
||||
lastShortSelector: null
|
||||
};
|
||||
stylesheetMap[stylesheet.id] = rulesetMap;
|
||||
} else {
|
||||
rulesetMap = stylesheetMap[stylesheet.id];
|
||||
}
|
||||
|
||||
if (rulesetMap.hasOwnProperty(rulesetId)) {
|
||||
shorts = rulesetMap[rulesetId];
|
||||
} else {
|
||||
shorts = {};
|
||||
rulesetMap[rulesetId] = shorts;
|
||||
}
|
||||
|
||||
rulesetMap.lastShortSelector = processRuleset.call(this, node, shorts, shortDeclarations, rulesetMap.lastShortSelector);
|
||||
});
|
||||
|
||||
processShorthands(shortDeclarations, indexer.declaration);
|
||||
};
|
||||
261
node_modules/csso/lib/compressor/restructure/6-restructBlock.js
generated
vendored
Executable file
261
node_modules/csso/lib/compressor/restructure/6-restructBlock.js
generated
vendored
Executable file
@@ -0,0 +1,261 @@
|
||||
var resolveProperty = require('../../utils/names.js').property;
|
||||
var resolveKeyword = require('../../utils/names.js').keyword;
|
||||
var walkRulesRight = require('../../utils/walk.js').rulesRight;
|
||||
var translate = require('../../utils/translate.js');
|
||||
var dontRestructure = {
|
||||
'src': 1 // https://github.com/afelix/csso/issues/50
|
||||
};
|
||||
|
||||
var DONT_MIX_VALUE = {
|
||||
// https://developer.mozilla.org/en-US/docs/Web/CSS/display#Browser_compatibility
|
||||
'display': /table|ruby|flex|-(flex)?box$|grid|contents|run-in/i,
|
||||
// https://developer.mozilla.org/en/docs/Web/CSS/text-align
|
||||
'text-align': /^(start|end|match-parent|justify-all)$/i
|
||||
};
|
||||
|
||||
var CURSOR_SAFE_VALUE = [
|
||||
'auto', 'crosshair', 'default', 'move', 'text', 'wait', 'help',
|
||||
'n-resize', 'e-resize', 's-resize', 'w-resize',
|
||||
'ne-resize', 'nw-resize', 'se-resize', 'sw-resize',
|
||||
'pointer', 'progress', 'not-allowed', 'no-drop', 'vertical-text', 'all-scroll',
|
||||
'col-resize', 'row-resize'
|
||||
];
|
||||
|
||||
var NEEDLESS_TABLE = {
|
||||
'border-width': ['border'],
|
||||
'border-style': ['border'],
|
||||
'border-color': ['border'],
|
||||
'border-top': ['border'],
|
||||
'border-right': ['border'],
|
||||
'border-bottom': ['border'],
|
||||
'border-left': ['border'],
|
||||
'border-top-width': ['border-top', 'border-width', 'border'],
|
||||
'border-right-width': ['border-right', 'border-width', 'border'],
|
||||
'border-bottom-width': ['border-bottom', 'border-width', 'border'],
|
||||
'border-left-width': ['border-left', 'border-width', 'border'],
|
||||
'border-top-style': ['border-top', 'border-style', 'border'],
|
||||
'border-right-style': ['border-right', 'border-style', 'border'],
|
||||
'border-bottom-style': ['border-bottom', 'border-style', 'border'],
|
||||
'border-left-style': ['border-left', 'border-style', 'border'],
|
||||
'border-top-color': ['border-top', 'border-color', 'border'],
|
||||
'border-right-color': ['border-right', 'border-color', 'border'],
|
||||
'border-bottom-color': ['border-bottom', 'border-color', 'border'],
|
||||
'border-left-color': ['border-left', 'border-color', 'border'],
|
||||
'margin-top': ['margin'],
|
||||
'margin-right': ['margin'],
|
||||
'margin-bottom': ['margin'],
|
||||
'margin-left': ['margin'],
|
||||
'padding-top': ['padding'],
|
||||
'padding-right': ['padding'],
|
||||
'padding-bottom': ['padding'],
|
||||
'padding-left': ['padding'],
|
||||
'font-style': ['font'],
|
||||
'font-variant': ['font'],
|
||||
'font-weight': ['font'],
|
||||
'font-size': ['font'],
|
||||
'font-family': ['font'],
|
||||
'list-style-type': ['list-style'],
|
||||
'list-style-position': ['list-style'],
|
||||
'list-style-image': ['list-style']
|
||||
};
|
||||
|
||||
function getPropertyFingerprint(propertyName, declaration, fingerprints) {
|
||||
var realName = resolveProperty(propertyName).name;
|
||||
|
||||
if (realName === 'background' ||
|
||||
(realName === 'filter' && declaration.value.sequence.first().type === 'Progid')) {
|
||||
return propertyName + ':' + translate(declaration.value);
|
||||
}
|
||||
|
||||
var declarationId = declaration.id;
|
||||
var fingerprint = fingerprints[declarationId];
|
||||
|
||||
if (!fingerprint) {
|
||||
var vendorId = '';
|
||||
var iehack = '';
|
||||
var special = {};
|
||||
|
||||
declaration.value.sequence.each(function walk(node) {
|
||||
switch (node.type) {
|
||||
case 'Argument':
|
||||
case 'Value':
|
||||
case 'Braces':
|
||||
node.sequence.each(walk);
|
||||
break;
|
||||
|
||||
case 'Identifier':
|
||||
var name = node.name;
|
||||
|
||||
if (!vendorId) {
|
||||
vendorId = resolveKeyword(name).vendor;
|
||||
}
|
||||
|
||||
if (/\\[09]/.test(name)) {
|
||||
iehack = RegExp.lastMatch;
|
||||
}
|
||||
|
||||
if (realName === 'cursor') {
|
||||
if (CURSOR_SAFE_VALUE.indexOf(name) === -1) {
|
||||
special[name] = true;
|
||||
}
|
||||
} else if (DONT_MIX_VALUE.hasOwnProperty(realName)) {
|
||||
if (DONT_MIX_VALUE[realName].test(name)) {
|
||||
special[name] = true;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'Function':
|
||||
var name = node.name;
|
||||
|
||||
if (!vendorId) {
|
||||
vendorId = resolveKeyword(name).vendor;
|
||||
}
|
||||
|
||||
if (name === 'rect') {
|
||||
// there are 2 forms of rect:
|
||||
// rect(<top>, <right>, <bottom>, <left>) - standart
|
||||
// rect(<top> <right> <bottom> <left>) – backwards compatible syntax
|
||||
// only the same form values can be merged
|
||||
if (node.arguments.size < 4) {
|
||||
name = 'rect-backward';
|
||||
}
|
||||
}
|
||||
|
||||
special[name + '()'] = true;
|
||||
|
||||
// check nested tokens too
|
||||
node.arguments.each(walk);
|
||||
|
||||
break;
|
||||
|
||||
case 'Dimension':
|
||||
var unit = node.unit;
|
||||
|
||||
switch (unit) {
|
||||
// is not supported until IE11
|
||||
case 'rem':
|
||||
|
||||
// v* units is too buggy across browsers and better
|
||||
// don't merge values with those units
|
||||
case 'vw':
|
||||
case 'vh':
|
||||
case 'vmin':
|
||||
case 'vmax':
|
||||
case 'vm': // IE9 supporting "vm" instead of "vmin".
|
||||
special[unit] = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
fingerprint = '|' + Object.keys(special).sort() + '|' + iehack + vendorId;
|
||||
|
||||
fingerprints[declarationId] = fingerprint;
|
||||
}
|
||||
|
||||
return propertyName + fingerprint;
|
||||
}
|
||||
|
||||
function needless(props, declaration, fingerprints) {
|
||||
var property = resolveProperty(declaration.property.name);
|
||||
|
||||
if (NEEDLESS_TABLE.hasOwnProperty(property.name)) {
|
||||
var table = NEEDLESS_TABLE[property.name];
|
||||
|
||||
for (var i = 0; i < table.length; i++) {
|
||||
var ppre = getPropertyFingerprint(property.prefix + table[i], declaration, fingerprints);
|
||||
var prev = props[ppre];
|
||||
|
||||
if (prev && (!declaration.value.important || prev.item.data.value.important)) {
|
||||
return prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function processRuleset(ruleset, item, list, props, fingerprints) {
|
||||
var declarations = ruleset.block.declarations;
|
||||
|
||||
declarations.eachRight(function(declaration, declarationItem) {
|
||||
var property = declaration.property.name;
|
||||
var fingerprint = getPropertyFingerprint(property, declaration, fingerprints);
|
||||
var prev = props[fingerprint];
|
||||
|
||||
if (prev && !dontRestructure.hasOwnProperty(property)) {
|
||||
if (declaration.value.important && !prev.item.data.value.important) {
|
||||
props[fingerprint] = {
|
||||
block: declarations,
|
||||
item: declarationItem
|
||||
};
|
||||
|
||||
prev.block.remove(prev.item);
|
||||
declaration.info = {
|
||||
primary: declaration.info,
|
||||
merged: prev.item.data.info
|
||||
};
|
||||
} else {
|
||||
declarations.remove(declarationItem);
|
||||
prev.item.data.info = {
|
||||
primary: prev.item.data.info,
|
||||
merged: declaration.info
|
||||
};
|
||||
}
|
||||
} else {
|
||||
var prev = needless(props, declaration, fingerprints);
|
||||
|
||||
if (prev) {
|
||||
declarations.remove(declarationItem);
|
||||
prev.item.data.info = {
|
||||
primary: prev.item.data.info,
|
||||
merged: declaration.info
|
||||
};
|
||||
} else {
|
||||
declaration.fingerprint = fingerprint;
|
||||
|
||||
props[fingerprint] = {
|
||||
block: declarations,
|
||||
item: declarationItem
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (declarations.isEmpty()) {
|
||||
list.remove(item);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = function restructBlock(ast) {
|
||||
var stylesheetMap = {};
|
||||
var fingerprints = Object.create(null);
|
||||
|
||||
walkRulesRight(ast, function(node, item, list) {
|
||||
if (node.type !== 'Ruleset') {
|
||||
return;
|
||||
}
|
||||
|
||||
var stylesheet = this.stylesheet;
|
||||
var rulesetId = (node.pseudoSignature || '') + '|' + node.selector.selectors.first().id;
|
||||
var rulesetMap;
|
||||
var props;
|
||||
|
||||
if (!stylesheetMap.hasOwnProperty(stylesheet.id)) {
|
||||
rulesetMap = {};
|
||||
stylesheetMap[stylesheet.id] = rulesetMap;
|
||||
} else {
|
||||
rulesetMap = stylesheetMap[stylesheet.id];
|
||||
}
|
||||
|
||||
if (rulesetMap.hasOwnProperty(rulesetId)) {
|
||||
props = rulesetMap[rulesetId];
|
||||
} else {
|
||||
props = {};
|
||||
rulesetMap[rulesetId] = props;
|
||||
}
|
||||
|
||||
processRuleset.call(this, node, item, list, props, fingerprints);
|
||||
});
|
||||
};
|
||||
87
node_modules/csso/lib/compressor/restructure/7-mergeRuleset.js
generated
vendored
Executable file
87
node_modules/csso/lib/compressor/restructure/7-mergeRuleset.js
generated
vendored
Executable file
@@ -0,0 +1,87 @@
|
||||
var utils = require('./utils.js');
|
||||
var walkRules = require('../../utils/walk.js').rules;
|
||||
|
||||
/*
|
||||
At this step all rules has single simple selector. We try to join by equal
|
||||
declaration blocks to first rule, e.g.
|
||||
|
||||
.a { color: red }
|
||||
b { ... }
|
||||
.b { color: red }
|
||||
->
|
||||
.a, .b { color: red }
|
||||
b { ... }
|
||||
*/
|
||||
|
||||
function processRuleset(node, item, list) {
|
||||
var selectors = node.selector.selectors;
|
||||
var declarations = node.block.declarations;
|
||||
var nodeCompareMarker = selectors.first().compareMarker;
|
||||
var skippedCompareMarkers = {};
|
||||
|
||||
list.nextUntil(item.next, function(next, nextItem) {
|
||||
// skip non-ruleset node if safe
|
||||
if (next.type !== 'Ruleset') {
|
||||
return utils.unsafeToSkipNode.call(selectors, next);
|
||||
}
|
||||
|
||||
if (node.pseudoSignature !== next.pseudoSignature) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var nextFirstSelector = next.selector.selectors.head;
|
||||
var nextDeclarations = next.block.declarations;
|
||||
var nextCompareMarker = nextFirstSelector.data.compareMarker;
|
||||
|
||||
// if next ruleset has same marked as one of skipped then stop joining
|
||||
if (nextCompareMarker in skippedCompareMarkers) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// try to join by selectors
|
||||
if (selectors.head === selectors.tail) {
|
||||
if (selectors.first().id === nextFirstSelector.data.id) {
|
||||
declarations.appendList(nextDeclarations);
|
||||
list.remove(nextItem);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// try to join by properties
|
||||
if (utils.isEqualDeclarations(declarations, nextDeclarations)) {
|
||||
var nextStr = nextFirstSelector.data.id;
|
||||
|
||||
selectors.some(function(data, item) {
|
||||
var curStr = data.id;
|
||||
|
||||
if (nextStr < curStr) {
|
||||
selectors.insert(nextFirstSelector, item);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!item.next) {
|
||||
selectors.insert(nextFirstSelector);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
list.remove(nextItem);
|
||||
return;
|
||||
}
|
||||
|
||||
// go to next ruleset if current one can be skipped (has no equal specificity nor element selector)
|
||||
if (nextCompareMarker === nodeCompareMarker) {
|
||||
return true;
|
||||
}
|
||||
|
||||
skippedCompareMarkers[nextCompareMarker] = true;
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = function mergeRuleset(ast) {
|
||||
walkRules(ast, function(node, item, list) {
|
||||
if (node.type === 'Ruleset') {
|
||||
processRuleset(node, item, list);
|
||||
}
|
||||
});
|
||||
};
|
||||
157
node_modules/csso/lib/compressor/restructure/8-restructRuleset.js
generated
vendored
Executable file
157
node_modules/csso/lib/compressor/restructure/8-restructRuleset.js
generated
vendored
Executable file
@@ -0,0 +1,157 @@
|
||||
var List = require('../../utils/list.js');
|
||||
var utils = require('./utils.js');
|
||||
var walkRulesRight = require('../../utils/walk.js').rulesRight;
|
||||
|
||||
function calcSelectorLength(list) {
|
||||
var length = 0;
|
||||
|
||||
list.each(function(data) {
|
||||
length += data.id.length + 1;
|
||||
});
|
||||
|
||||
return length - 1;
|
||||
}
|
||||
|
||||
function calcDeclarationsLength(tokens) {
|
||||
var length = 0;
|
||||
|
||||
for (var i = 0; i < tokens.length; i++) {
|
||||
length += tokens[i].length;
|
||||
}
|
||||
|
||||
return (
|
||||
length + // declarations
|
||||
tokens.length - 1 // delimeters
|
||||
);
|
||||
}
|
||||
|
||||
function processRuleset(node, item, list) {
|
||||
var avoidRulesMerge = this.stylesheet.avoidRulesMerge;
|
||||
var selectors = node.selector.selectors;
|
||||
var block = node.block;
|
||||
var disallowDownMarkers = Object.create(null);
|
||||
var allowMergeUp = true;
|
||||
var allowMergeDown = true;
|
||||
|
||||
list.prevUntil(item.prev, function(prev, prevItem) {
|
||||
// skip non-ruleset node if safe
|
||||
if (prev.type !== 'Ruleset') {
|
||||
return utils.unsafeToSkipNode.call(selectors, prev);
|
||||
}
|
||||
|
||||
var prevSelectors = prev.selector.selectors;
|
||||
var prevBlock = prev.block;
|
||||
|
||||
if (node.pseudoSignature !== prev.pseudoSignature) {
|
||||
return true;
|
||||
}
|
||||
|
||||
allowMergeDown = !prevSelectors.some(function(selector) {
|
||||
return selector.compareMarker in disallowDownMarkers;
|
||||
});
|
||||
|
||||
// try prev ruleset if simpleselectors has no equal specifity and element selector
|
||||
if (!allowMergeDown && !allowMergeUp) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// try to join by selectors
|
||||
if (allowMergeUp && utils.isEqualLists(prevSelectors, selectors)) {
|
||||
prevBlock.declarations.appendList(block.declarations);
|
||||
list.remove(item);
|
||||
return true;
|
||||
}
|
||||
|
||||
// try to join by properties
|
||||
var diff = utils.compareDeclarations(block.declarations, prevBlock.declarations);
|
||||
|
||||
// console.log(diff.eq, diff.ne1, diff.ne2);
|
||||
|
||||
if (diff.eq.length) {
|
||||
if (!diff.ne1.length && !diff.ne2.length) {
|
||||
// equal blocks
|
||||
if (allowMergeDown) {
|
||||
utils.addSelectors(selectors, prevSelectors);
|
||||
list.remove(prevItem);
|
||||
}
|
||||
|
||||
return true;
|
||||
} else if (!avoidRulesMerge) { /* probably we don't need to prevent those merges for @keyframes
|
||||
TODO: need to be checked */
|
||||
|
||||
if (diff.ne1.length && !diff.ne2.length) {
|
||||
// prevBlock is subset block
|
||||
var selectorLength = calcSelectorLength(selectors);
|
||||
var blockLength = calcDeclarationsLength(diff.eq); // declarations length
|
||||
|
||||
if (allowMergeUp && selectorLength < blockLength) {
|
||||
utils.addSelectors(prevSelectors, selectors);
|
||||
block.declarations = new List(diff.ne1);
|
||||
}
|
||||
} else if (!diff.ne1.length && diff.ne2.length) {
|
||||
// node is subset of prevBlock
|
||||
var selectorLength = calcSelectorLength(prevSelectors);
|
||||
var blockLength = calcDeclarationsLength(diff.eq); // declarations length
|
||||
|
||||
if (allowMergeDown && selectorLength < blockLength) {
|
||||
utils.addSelectors(selectors, prevSelectors);
|
||||
prevBlock.declarations = new List(diff.ne2);
|
||||
}
|
||||
} else {
|
||||
// diff.ne1.length && diff.ne2.length
|
||||
// extract equal block
|
||||
var newSelector = {
|
||||
type: 'Selector',
|
||||
info: {},
|
||||
selectors: utils.addSelectors(prevSelectors.copy(), selectors)
|
||||
};
|
||||
var newBlockLength = calcSelectorLength(newSelector.selectors) + 2; // selectors length + curly braces length
|
||||
var blockLength = calcDeclarationsLength(diff.eq); // declarations length
|
||||
|
||||
// create new ruleset if declarations length greater than
|
||||
// ruleset description overhead
|
||||
if (allowMergeDown && blockLength >= newBlockLength) {
|
||||
var newRuleset = {
|
||||
type: 'Ruleset',
|
||||
info: {},
|
||||
pseudoSignature: node.pseudoSignature,
|
||||
selector: newSelector,
|
||||
block: {
|
||||
type: 'Block',
|
||||
info: {},
|
||||
declarations: new List(diff.eq)
|
||||
}
|
||||
};
|
||||
|
||||
block.declarations = new List(diff.ne1);
|
||||
prevBlock.declarations = new List(diff.ne2.concat(diff.ne2overrided));
|
||||
list.insert(list.createItem(newRuleset), prevItem);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (allowMergeUp) {
|
||||
// TODO: disallow up merge only if any property interception only (i.e. diff.ne2overrided.length > 0);
|
||||
// await property families to find property interception correctly
|
||||
allowMergeUp = !prevSelectors.some(function(prevSelector) {
|
||||
return selectors.some(function(selector) {
|
||||
return selector.compareMarker === prevSelector.compareMarker;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
prevSelectors.each(function(data) {
|
||||
disallowDownMarkers[data.compareMarker] = true;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = function restructRuleset(ast) {
|
||||
walkRulesRight(ast, function(node, item, list) {
|
||||
if (node.type === 'Ruleset') {
|
||||
processRuleset.call(this, node, item, list);
|
||||
}
|
||||
});
|
||||
};
|
||||
35
node_modules/csso/lib/compressor/restructure/index.js
generated
vendored
Executable file
35
node_modules/csso/lib/compressor/restructure/index.js
generated
vendored
Executable file
@@ -0,0 +1,35 @@
|
||||
var prepare = require('./prepare/index.js');
|
||||
var initialMergeRuleset = require('./1-initialMergeRuleset.js');
|
||||
var mergeAtrule = require('./2-mergeAtrule.js');
|
||||
var disjoinRuleset = require('./3-disjoinRuleset.js');
|
||||
var restructShorthand = require('./4-restructShorthand.js');
|
||||
var restructBlock = require('./6-restructBlock.js');
|
||||
var mergeRuleset = require('./7-mergeRuleset.js');
|
||||
var restructRuleset = require('./8-restructRuleset.js');
|
||||
|
||||
module.exports = function(ast, usageData, debug) {
|
||||
// prepare ast for restructing
|
||||
var indexer = prepare(ast, usageData);
|
||||
debug('prepare', ast);
|
||||
|
||||
initialMergeRuleset(ast);
|
||||
debug('initialMergeRuleset', ast);
|
||||
|
||||
mergeAtrule(ast);
|
||||
debug('mergeAtrule', ast);
|
||||
|
||||
disjoinRuleset(ast);
|
||||
debug('disjoinRuleset', ast);
|
||||
|
||||
restructShorthand(ast, indexer);
|
||||
debug('restructShorthand', ast);
|
||||
|
||||
restructBlock(ast);
|
||||
debug('restructBlock', ast);
|
||||
|
||||
mergeRuleset(ast);
|
||||
debug('mergeRuleset', ast);
|
||||
|
||||
restructRuleset(ast);
|
||||
debug('restructRuleset', ast);
|
||||
};
|
||||
32
node_modules/csso/lib/compressor/restructure/prepare/createDeclarationIndexer.js
generated
vendored
Executable file
32
node_modules/csso/lib/compressor/restructure/prepare/createDeclarationIndexer.js
generated
vendored
Executable file
@@ -0,0 +1,32 @@
|
||||
var translate = require('../../../utils/translate.js');
|
||||
|
||||
function Index() {
|
||||
this.seed = 0;
|
||||
this.map = Object.create(null);
|
||||
}
|
||||
|
||||
Index.prototype.resolve = function(str) {
|
||||
var index = this.map[str];
|
||||
|
||||
if (!index) {
|
||||
index = ++this.seed;
|
||||
this.map[str] = index;
|
||||
}
|
||||
|
||||
return index;
|
||||
};
|
||||
|
||||
module.exports = function createDeclarationIndexer() {
|
||||
var names = new Index();
|
||||
var values = new Index();
|
||||
|
||||
return function markDeclaration(node) {
|
||||
var property = node.property.name;
|
||||
var value = translate(node.value);
|
||||
|
||||
node.id = names.resolve(property) + (values.resolve(value) << 12);
|
||||
node.length = property.length + 1 + value.length;
|
||||
|
||||
return node;
|
||||
};
|
||||
};
|
||||
44
node_modules/csso/lib/compressor/restructure/prepare/index.js
generated
vendored
Executable file
44
node_modules/csso/lib/compressor/restructure/prepare/index.js
generated
vendored
Executable file
@@ -0,0 +1,44 @@
|
||||
var resolveKeyword = require('../../../utils/names.js').keyword;
|
||||
var walkRules = require('../../../utils/walk.js').rules;
|
||||
var translate = require('../../../utils/translate.js');
|
||||
var createDeclarationIndexer = require('./createDeclarationIndexer.js');
|
||||
var processSelector = require('./processSelector.js');
|
||||
|
||||
function walk(node, markDeclaration, usageData) {
|
||||
switch (node.type) {
|
||||
case 'Ruleset':
|
||||
node.block.declarations.each(markDeclaration);
|
||||
processSelector(node, usageData);
|
||||
break;
|
||||
|
||||
case 'Atrule':
|
||||
if (node.expression) {
|
||||
node.expression.id = translate(node.expression);
|
||||
}
|
||||
|
||||
// compare keyframe selectors by its values
|
||||
// NOTE: still no clarification about problems with keyframes selector grouping (issue #197)
|
||||
if (resolveKeyword(node.name).name === 'keyframes') {
|
||||
node.block.avoidRulesMerge = true; /* probably we don't need to prevent those merges for @keyframes
|
||||
TODO: need to be checked */
|
||||
node.block.rules.each(function(ruleset) {
|
||||
ruleset.selector.selectors.each(function(simpleselector) {
|
||||
simpleselector.compareMarker = simpleselector.id;
|
||||
});
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = function prepare(ast, usageData) {
|
||||
var markDeclaration = createDeclarationIndexer();
|
||||
|
||||
walkRules(ast, function(node) {
|
||||
walk(node, markDeclaration, usageData);
|
||||
});
|
||||
|
||||
return {
|
||||
declaration: markDeclaration
|
||||
};
|
||||
};
|
||||
99
node_modules/csso/lib/compressor/restructure/prepare/processSelector.js
generated
vendored
Executable file
99
node_modules/csso/lib/compressor/restructure/prepare/processSelector.js
generated
vendored
Executable file
@@ -0,0 +1,99 @@
|
||||
var translate = require('../../../utils/translate.js');
|
||||
var specificity = require('./specificity.js');
|
||||
|
||||
var nonFreezePseudoElements = {
|
||||
'first-letter': true,
|
||||
'first-line': true,
|
||||
'after': true,
|
||||
'before': true
|
||||
};
|
||||
var nonFreezePseudoClasses = {
|
||||
'link': true,
|
||||
'visited': true,
|
||||
'hover': true,
|
||||
'active': true,
|
||||
'first-letter': true,
|
||||
'first-line': true,
|
||||
'after': true,
|
||||
'before': true
|
||||
};
|
||||
|
||||
module.exports = function freeze(node, usageData) {
|
||||
var pseudos = Object.create(null);
|
||||
var hasPseudo = false;
|
||||
|
||||
node.selector.selectors.each(function(simpleSelector) {
|
||||
var tagName = '*';
|
||||
var scope = 0;
|
||||
|
||||
simpleSelector.sequence.some(function(node) {
|
||||
switch (node.type) {
|
||||
case 'Class':
|
||||
if (usageData && usageData.scopes) {
|
||||
var classScope = usageData.scopes[node.name] || 0;
|
||||
|
||||
if (scope !== 0 && classScope !== scope) {
|
||||
throw new Error('Selector can\'t has classes from different scopes: ' + translate(simpleSelector));
|
||||
}
|
||||
|
||||
scope = classScope;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'PseudoClass':
|
||||
if (!nonFreezePseudoClasses.hasOwnProperty(node.name)) {
|
||||
pseudos[node.name] = true;
|
||||
hasPseudo = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'PseudoElement':
|
||||
if (!nonFreezePseudoElements.hasOwnProperty(node.name)) {
|
||||
pseudos[node.name] = true;
|
||||
hasPseudo = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'FunctionalPseudo':
|
||||
pseudos[node.name] = true;
|
||||
hasPseudo = true;
|
||||
break;
|
||||
|
||||
case 'Negation':
|
||||
pseudos.not = true;
|
||||
hasPseudo = true;
|
||||
break;
|
||||
|
||||
case 'Identifier':
|
||||
tagName = node.name;
|
||||
break;
|
||||
|
||||
case 'Attribute':
|
||||
if (node.flags) {
|
||||
pseudos['[' + node.flags + ']'] = true;
|
||||
hasPseudo = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'Combinator':
|
||||
tagName = '*';
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
simpleSelector.id = translate(simpleSelector);
|
||||
simpleSelector.compareMarker = specificity(simpleSelector).toString();
|
||||
|
||||
if (scope) {
|
||||
simpleSelector.compareMarker += ':' + scope;
|
||||
}
|
||||
|
||||
if (tagName !== '*') {
|
||||
simpleSelector.compareMarker += ',' + tagName;
|
||||
}
|
||||
});
|
||||
|
||||
if (hasPseudo) {
|
||||
node.pseudoSignature = Object.keys(pseudos).sort().join(',');
|
||||
}
|
||||
};
|
||||
48
node_modules/csso/lib/compressor/restructure/prepare/specificity.js
generated
vendored
Executable file
48
node_modules/csso/lib/compressor/restructure/prepare/specificity.js
generated
vendored
Executable file
@@ -0,0 +1,48 @@
|
||||
module.exports = function specificity(simpleSelector) {
|
||||
var A = 0;
|
||||
var B = 0;
|
||||
var C = 0;
|
||||
|
||||
simpleSelector.sequence.each(function walk(data) {
|
||||
switch (data.type) {
|
||||
case 'SimpleSelector':
|
||||
case 'Negation':
|
||||
data.sequence.each(walk);
|
||||
break;
|
||||
|
||||
case 'Id':
|
||||
A++;
|
||||
break;
|
||||
|
||||
case 'Class':
|
||||
case 'Attribute':
|
||||
case 'FunctionalPseudo':
|
||||
B++;
|
||||
break;
|
||||
|
||||
case 'Identifier':
|
||||
if (data.name !== '*') {
|
||||
C++;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'PseudoElement':
|
||||
C++;
|
||||
break;
|
||||
|
||||
case 'PseudoClass':
|
||||
var name = data.name.toLowerCase();
|
||||
if (name === 'before' ||
|
||||
name === 'after' ||
|
||||
name === 'first-line' ||
|
||||
name === 'first-letter') {
|
||||
C++;
|
||||
} else {
|
||||
B++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
return [A, B, C];
|
||||
};
|
||||
141
node_modules/csso/lib/compressor/restructure/utils.js
generated
vendored
Executable file
141
node_modules/csso/lib/compressor/restructure/utils.js
generated
vendored
Executable file
@@ -0,0 +1,141 @@
|
||||
var hasOwnProperty = Object.prototype.hasOwnProperty;
|
||||
|
||||
function isEqualLists(a, b) {
|
||||
var cursor1 = a.head;
|
||||
var cursor2 = b.head;
|
||||
|
||||
while (cursor1 !== null && cursor2 !== null && cursor1.data.id === cursor2.data.id) {
|
||||
cursor1 = cursor1.next;
|
||||
cursor2 = cursor2.next;
|
||||
}
|
||||
|
||||
return cursor1 === null && cursor2 === null;
|
||||
}
|
||||
|
||||
function isEqualDeclarations(a, b) {
|
||||
var cursor1 = a.head;
|
||||
var cursor2 = b.head;
|
||||
|
||||
while (cursor1 !== null && cursor2 !== null && cursor1.data.id === cursor2.data.id) {
|
||||
cursor1 = cursor1.next;
|
||||
cursor2 = cursor2.next;
|
||||
}
|
||||
|
||||
return cursor1 === null && cursor2 === null;
|
||||
}
|
||||
|
||||
function compareDeclarations(declarations1, declarations2) {
|
||||
var result = {
|
||||
eq: [],
|
||||
ne1: [],
|
||||
ne2: [],
|
||||
ne2overrided: []
|
||||
};
|
||||
|
||||
var fingerprints = Object.create(null);
|
||||
var declarations2hash = Object.create(null);
|
||||
|
||||
for (var cursor = declarations2.head; cursor; cursor = cursor.next) {
|
||||
declarations2hash[cursor.data.id] = true;
|
||||
}
|
||||
|
||||
for (var cursor = declarations1.head; cursor; cursor = cursor.next) {
|
||||
var data = cursor.data;
|
||||
|
||||
if (data.fingerprint) {
|
||||
fingerprints[data.fingerprint] = data.value.important;
|
||||
}
|
||||
|
||||
if (declarations2hash[data.id]) {
|
||||
declarations2hash[data.id] = false;
|
||||
result.eq.push(data);
|
||||
} else {
|
||||
result.ne1.push(data);
|
||||
}
|
||||
}
|
||||
|
||||
for (var cursor = declarations2.head; cursor; cursor = cursor.next) {
|
||||
var data = cursor.data;
|
||||
|
||||
if (declarations2hash[data.id]) {
|
||||
// if declarations1 has overriding declaration, this is not a difference
|
||||
// but take in account !important - prev should be equal or greater than follow
|
||||
if (hasOwnProperty.call(fingerprints, data.fingerprint) &&
|
||||
Number(fingerprints[data.fingerprint]) >= Number(data.value.important)) {
|
||||
result.ne2overrided.push(data);
|
||||
} else {
|
||||
result.ne2.push(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function addSelectors(dest, source) {
|
||||
source.each(function(sourceData) {
|
||||
var newStr = sourceData.id;
|
||||
var cursor = dest.head;
|
||||
|
||||
while (cursor) {
|
||||
var nextStr = cursor.data.id;
|
||||
|
||||
if (nextStr === newStr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (nextStr > newStr) {
|
||||
break;
|
||||
}
|
||||
|
||||
cursor = cursor.next;
|
||||
}
|
||||
|
||||
dest.insert(dest.createItem(sourceData), cursor);
|
||||
});
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
// check if simpleselectors has no equal specificity and element selector
|
||||
function hasSimilarSelectors(selectors1, selectors2) {
|
||||
return selectors1.some(function(a) {
|
||||
return selectors2.some(function(b) {
|
||||
return a.compareMarker === b.compareMarker;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// test node can't to be skipped
|
||||
function unsafeToSkipNode(node) {
|
||||
switch (node.type) {
|
||||
case 'Ruleset':
|
||||
// unsafe skip ruleset with selector similarities
|
||||
return hasSimilarSelectors(node.selector.selectors, this);
|
||||
|
||||
case 'Atrule':
|
||||
// can skip at-rules with blocks
|
||||
if (node.block) {
|
||||
// non-stylesheet blocks are safe to skip since have no selectors
|
||||
if (node.block.type !== 'StyleSheet') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// unsafe skip at-rule if block contains something unsafe to skip
|
||||
return node.block.rules.some(unsafeToSkipNode, this);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// unsafe by default
|
||||
return true;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
isEqualLists: isEqualLists,
|
||||
isEqualDeclarations: isEqualDeclarations,
|
||||
compareDeclarations: compareDeclarations,
|
||||
addSelectors: addSelectors,
|
||||
hasSimilarSelectors: hasSimilarSelectors,
|
||||
unsafeToSkipNode: unsafeToSkipNode
|
||||
};
|
||||
58
node_modules/csso/lib/compressor/usage.js
generated
vendored
Executable file
58
node_modules/csso/lib/compressor/usage.js
generated
vendored
Executable file
@@ -0,0 +1,58 @@
|
||||
var hasOwnProperty = Object.prototype.hasOwnProperty;
|
||||
|
||||
function buildMap(list, caseInsensitive) {
|
||||
var map = Object.create(null);
|
||||
|
||||
if (!Array.isArray(list)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
var name = list[i];
|
||||
|
||||
if (caseInsensitive) {
|
||||
name = name.toLowerCase();
|
||||
}
|
||||
|
||||
map[name] = true;
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
function buildIndex(data) {
|
||||
var scopes = false;
|
||||
|
||||
if (data.scopes && Array.isArray(data.scopes)) {
|
||||
scopes = Object.create(null);
|
||||
|
||||
for (var i = 0; i < data.scopes.length; i++) {
|
||||
var list = data.scopes[i];
|
||||
|
||||
if (!list || !Array.isArray(list)) {
|
||||
throw new Error('Wrong usage format');
|
||||
}
|
||||
|
||||
for (var j = 0; j < list.length; j++) {
|
||||
var name = list[j];
|
||||
|
||||
if (hasOwnProperty.call(scopes, name)) {
|
||||
throw new Error('Class can\'t be used for several scopes: ' + name);
|
||||
}
|
||||
|
||||
scopes[name] = i + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
tags: buildMap(data.tags, true),
|
||||
ids: buildMap(data.ids),
|
||||
classes: buildMap(data.classes),
|
||||
scopes: scopes
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
buildIndex: buildIndex
|
||||
};
|
||||
156
node_modules/csso/lib/index.js
generated
vendored
Executable file
156
node_modules/csso/lib/index.js
generated
vendored
Executable file
@@ -0,0 +1,156 @@
|
||||
var parse = require('./parser');
|
||||
var compress = require('./compressor');
|
||||
var translate = require('./utils/translate');
|
||||
var translateWithSourceMap = require('./utils/translateWithSourceMap');
|
||||
var walkers = require('./utils/walk');
|
||||
var clone = require('./utils/clone');
|
||||
var List = require('./utils/list');
|
||||
|
||||
function debugOutput(name, options, startTime, data) {
|
||||
if (options.debug) {
|
||||
console.error('## ' + name + ' done in %d ms\n', Date.now() - startTime);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
function createDefaultLogger(level) {
|
||||
var lastDebug;
|
||||
|
||||
return function logger(title, ast) {
|
||||
var line = title;
|
||||
|
||||
if (ast) {
|
||||
line = '[' + ((Date.now() - lastDebug) / 1000).toFixed(3) + 's] ' + line;
|
||||
}
|
||||
|
||||
if (level > 1 && ast) {
|
||||
var css = translate(ast, true);
|
||||
|
||||
// when level 2, limit css to 256 symbols
|
||||
if (level === 2 && css.length > 256) {
|
||||
css = css.substr(0, 256) + '...';
|
||||
}
|
||||
|
||||
line += '\n ' + css + '\n';
|
||||
}
|
||||
|
||||
console.error(line);
|
||||
lastDebug = Date.now();
|
||||
};
|
||||
}
|
||||
|
||||
function copy(obj) {
|
||||
var result = {};
|
||||
|
||||
for (var key in obj) {
|
||||
result[key] = obj[key];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function buildCompressOptions(options) {
|
||||
options = copy(options);
|
||||
|
||||
if (typeof options.logger !== 'function' && options.debug) {
|
||||
options.logger = createDefaultLogger(options.debug);
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
function runHandler(ast, options, handlers) {
|
||||
if (!Array.isArray(handlers)) {
|
||||
handlers = [handlers];
|
||||
}
|
||||
|
||||
handlers.forEach(function(fn) {
|
||||
fn(ast, options);
|
||||
});
|
||||
}
|
||||
|
||||
function minify(context, source, options) {
|
||||
options = options || {};
|
||||
|
||||
var filename = options.filename || '<unknown>';
|
||||
var result;
|
||||
|
||||
// parse
|
||||
var ast = debugOutput('parsing', options, Date.now(),
|
||||
parse(source, {
|
||||
context: context,
|
||||
filename: filename,
|
||||
positions: Boolean(options.sourceMap)
|
||||
})
|
||||
);
|
||||
|
||||
// before compress handlers
|
||||
if (options.beforeCompress) {
|
||||
debugOutput('beforeCompress', options, Date.now(),
|
||||
runHandler(ast, options, options.beforeCompress)
|
||||
);
|
||||
}
|
||||
|
||||
// compress
|
||||
var compressResult = debugOutput('compress', options, Date.now(),
|
||||
compress(ast, buildCompressOptions(options))
|
||||
);
|
||||
|
||||
// after compress handlers
|
||||
if (options.afterCompress) {
|
||||
debugOutput('afterCompress', options, Date.now(),
|
||||
runHandler(compressResult, options, options.afterCompress)
|
||||
);
|
||||
}
|
||||
|
||||
// translate
|
||||
if (options.sourceMap) {
|
||||
result = debugOutput('translateWithSourceMap', options, Date.now(), (function() {
|
||||
var tmp = translateWithSourceMap(compressResult.ast);
|
||||
tmp.map._file = filename; // since other tools can relay on file in source map transform chain
|
||||
tmp.map.setSourceContent(filename, source);
|
||||
return tmp;
|
||||
})());
|
||||
} else {
|
||||
result = debugOutput('translate', options, Date.now(), {
|
||||
css: translate(compressResult.ast),
|
||||
map: null
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function minifyStylesheet(source, options) {
|
||||
return minify('stylesheet', source, options);
|
||||
};
|
||||
|
||||
function minifyBlock(source, options) {
|
||||
return minify('block', source, options);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
version: require('../package.json').version,
|
||||
|
||||
// classes
|
||||
List: List,
|
||||
|
||||
// main methods
|
||||
minify: minifyStylesheet,
|
||||
minifyBlock: minifyBlock,
|
||||
|
||||
// step by step
|
||||
parse: parse,
|
||||
compress: compress,
|
||||
translate: translate,
|
||||
translateWithSourceMap: translateWithSourceMap,
|
||||
|
||||
// walkers
|
||||
walk: walkers.all,
|
||||
walkRules: walkers.rules,
|
||||
walkRulesRight: walkers.rulesRight,
|
||||
|
||||
// utils
|
||||
clone: clone
|
||||
};
|
||||
46
node_modules/csso/lib/parser/const.js
generated
vendored
Executable file
46
node_modules/csso/lib/parser/const.js
generated
vendored
Executable file
@@ -0,0 +1,46 @@
|
||||
exports.TokenType = {
|
||||
String: 'String',
|
||||
Comment: 'Comment',
|
||||
Unknown: 'Unknown',
|
||||
Newline: 'Newline',
|
||||
Space: 'Space',
|
||||
Tab: 'Tab',
|
||||
ExclamationMark: 'ExclamationMark', // !
|
||||
QuotationMark: 'QuotationMark', // "
|
||||
NumberSign: 'NumberSign', // #
|
||||
DollarSign: 'DollarSign', // $
|
||||
PercentSign: 'PercentSign', // %
|
||||
Ampersand: 'Ampersand', // &
|
||||
Apostrophe: 'Apostrophe', // '
|
||||
LeftParenthesis: 'LeftParenthesis', // (
|
||||
RightParenthesis: 'RightParenthesis', // )
|
||||
Asterisk: 'Asterisk', // *
|
||||
PlusSign: 'PlusSign', // +
|
||||
Comma: 'Comma', // ,
|
||||
HyphenMinus: 'HyphenMinus', // -
|
||||
FullStop: 'FullStop', // .
|
||||
Solidus: 'Solidus', // /
|
||||
Colon: 'Colon', // :
|
||||
Semicolon: 'Semicolon', // ;
|
||||
LessThanSign: 'LessThanSign', // <
|
||||
EqualsSign: 'EqualsSign', // =
|
||||
GreaterThanSign: 'GreaterThanSign', // >
|
||||
QuestionMark: 'QuestionMark', // ?
|
||||
CommercialAt: 'CommercialAt', // @
|
||||
LeftSquareBracket: 'LeftSquareBracket', // [
|
||||
ReverseSolidus: 'ReverseSolidus', // \
|
||||
RightSquareBracket: 'RightSquareBracket', // ]
|
||||
CircumflexAccent: 'CircumflexAccent', // ^
|
||||
LowLine: 'LowLine', // _
|
||||
LeftCurlyBracket: 'LeftCurlyBracket', // {
|
||||
VerticalLine: 'VerticalLine', // |
|
||||
RightCurlyBracket: 'RightCurlyBracket', // }
|
||||
Tilde: 'Tilde', // ~
|
||||
Identifier: 'Identifier',
|
||||
DecimalNumber: 'DecimalNumber'
|
||||
};
|
||||
|
||||
// var i = 1;
|
||||
// for (var key in exports.TokenType) {
|
||||
// exports.TokenType[key] = i++;
|
||||
// }
|
||||
1870
node_modules/csso/lib/parser/index.js
generated
vendored
Executable file
1870
node_modules/csso/lib/parser/index.js
generated
vendored
Executable file
File diff suppressed because it is too large
Load Diff
380
node_modules/csso/lib/parser/scanner.js
generated
vendored
Executable file
380
node_modules/csso/lib/parser/scanner.js
generated
vendored
Executable file
@@ -0,0 +1,380 @@
|
||||
'use strict';
|
||||
|
||||
var TokenType = require('./const.js').TokenType;
|
||||
|
||||
var TAB = 9;
|
||||
var N = 10;
|
||||
var F = 12;
|
||||
var R = 13;
|
||||
var SPACE = 32;
|
||||
var DOUBLE_QUOTE = 34;
|
||||
var QUOTE = 39;
|
||||
var RIGHT_PARENTHESIS = 41;
|
||||
var STAR = 42;
|
||||
var SLASH = 47;
|
||||
var BACK_SLASH = 92;
|
||||
var UNDERSCORE = 95;
|
||||
var LEFT_CURLY_BRACE = 123;
|
||||
var RIGHT_CURLY_BRACE = 125;
|
||||
|
||||
var WHITESPACE = 1;
|
||||
var PUNCTUATOR = 2;
|
||||
var DIGIT = 3;
|
||||
var STRING = 4;
|
||||
|
||||
var PUNCTUATION = {
|
||||
9: TokenType.Tab, // '\t'
|
||||
10: TokenType.Newline, // '\n'
|
||||
13: TokenType.Newline, // '\r'
|
||||
32: TokenType.Space, // ' '
|
||||
33: TokenType.ExclamationMark, // '!'
|
||||
34: TokenType.QuotationMark, // '"'
|
||||
35: TokenType.NumberSign, // '#'
|
||||
36: TokenType.DollarSign, // '$'
|
||||
37: TokenType.PercentSign, // '%'
|
||||
38: TokenType.Ampersand, // '&'
|
||||
39: TokenType.Apostrophe, // '\''
|
||||
40: TokenType.LeftParenthesis, // '('
|
||||
41: TokenType.RightParenthesis, // ')'
|
||||
42: TokenType.Asterisk, // '*'
|
||||
43: TokenType.PlusSign, // '+'
|
||||
44: TokenType.Comma, // ','
|
||||
45: TokenType.HyphenMinus, // '-'
|
||||
46: TokenType.FullStop, // '.'
|
||||
47: TokenType.Solidus, // '/'
|
||||
58: TokenType.Colon, // ':'
|
||||
59: TokenType.Semicolon, // ';'
|
||||
60: TokenType.LessThanSign, // '<'
|
||||
61: TokenType.EqualsSign, // '='
|
||||
62: TokenType.GreaterThanSign, // '>'
|
||||
63: TokenType.QuestionMark, // '?'
|
||||
64: TokenType.CommercialAt, // '@'
|
||||
91: TokenType.LeftSquareBracket, // '['
|
||||
93: TokenType.RightSquareBracket, // ']'
|
||||
94: TokenType.CircumflexAccent, // '^'
|
||||
95: TokenType.LowLine, // '_'
|
||||
123: TokenType.LeftCurlyBracket, // '{'
|
||||
124: TokenType.VerticalLine, // '|'
|
||||
125: TokenType.RightCurlyBracket, // '}'
|
||||
126: TokenType.Tilde // '~'
|
||||
};
|
||||
var SYMBOL_CATEGORY_LENGTH = Math.max.apply(null, Object.keys(PUNCTUATION)) + 1;
|
||||
var SYMBOL_CATEGORY = new Uint32Array(SYMBOL_CATEGORY_LENGTH);
|
||||
var IS_PUNCTUATOR = new Uint32Array(SYMBOL_CATEGORY_LENGTH);
|
||||
|
||||
// fill categories
|
||||
Object.keys(PUNCTUATION).forEach(function(key) {
|
||||
SYMBOL_CATEGORY[Number(key)] = PUNCTUATOR;
|
||||
IS_PUNCTUATOR[Number(key)] = PUNCTUATOR;
|
||||
}, SYMBOL_CATEGORY);
|
||||
|
||||
// don't treat as punctuator
|
||||
IS_PUNCTUATOR[UNDERSCORE] = 0;
|
||||
|
||||
for (var i = 48; i <= 57; i++) {
|
||||
SYMBOL_CATEGORY[i] = DIGIT;
|
||||
}
|
||||
|
||||
SYMBOL_CATEGORY[SPACE] = WHITESPACE;
|
||||
SYMBOL_CATEGORY[TAB] = WHITESPACE;
|
||||
SYMBOL_CATEGORY[N] = WHITESPACE;
|
||||
SYMBOL_CATEGORY[R] = WHITESPACE;
|
||||
SYMBOL_CATEGORY[F] = WHITESPACE;
|
||||
|
||||
SYMBOL_CATEGORY[QUOTE] = STRING;
|
||||
SYMBOL_CATEGORY[DOUBLE_QUOTE] = STRING;
|
||||
|
||||
//
|
||||
// scanner
|
||||
//
|
||||
|
||||
var Scanner = function(source, initBlockMode, initLine, initColumn) {
|
||||
this.source = source;
|
||||
|
||||
this.pos = source.charCodeAt(0) === 0xFEFF ? 1 : 0;
|
||||
this.eof = this.pos === this.source.length;
|
||||
this.line = typeof initLine === 'undefined' ? 1 : initLine;
|
||||
this.lineStartPos = typeof initColumn === 'undefined' ? -1 : -initColumn;
|
||||
|
||||
this.minBlockMode = initBlockMode ? 1 : 0;
|
||||
this.blockMode = this.minBlockMode;
|
||||
this.urlMode = false;
|
||||
|
||||
this.prevToken = null;
|
||||
this.token = null;
|
||||
this.buffer = [];
|
||||
};
|
||||
|
||||
Scanner.prototype = {
|
||||
lookup: function(offset) {
|
||||
if (offset === 0) {
|
||||
return this.token;
|
||||
}
|
||||
|
||||
for (var i = this.buffer.length; !this.eof && i < offset; i++) {
|
||||
this.buffer.push(this.getToken());
|
||||
}
|
||||
|
||||
return offset <= this.buffer.length ? this.buffer[offset - 1] : null;
|
||||
},
|
||||
lookupType: function(offset, type) {
|
||||
var token = this.lookup(offset);
|
||||
|
||||
return token !== null && token.type === type;
|
||||
},
|
||||
next: function() {
|
||||
var newToken = null;
|
||||
|
||||
if (this.buffer.length !== 0) {
|
||||
newToken = this.buffer.shift();
|
||||
} else if (!this.eof) {
|
||||
newToken = this.getToken();
|
||||
}
|
||||
|
||||
this.prevToken = this.token;
|
||||
this.token = newToken;
|
||||
|
||||
return newToken;
|
||||
},
|
||||
|
||||
tokenize: function() {
|
||||
var tokens = [];
|
||||
|
||||
for (; this.pos < this.source.length; this.pos++) {
|
||||
tokens.push(this.getToken());
|
||||
}
|
||||
|
||||
return tokens;
|
||||
},
|
||||
|
||||
getToken: function() {
|
||||
var code = this.source.charCodeAt(this.pos);
|
||||
var line = this.line;
|
||||
var column = this.pos - this.lineStartPos;
|
||||
var offset = this.pos;
|
||||
var next;
|
||||
var type;
|
||||
var value;
|
||||
|
||||
switch (code < SYMBOL_CATEGORY_LENGTH ? SYMBOL_CATEGORY[code] : 0) {
|
||||
case DIGIT:
|
||||
type = TokenType.DecimalNumber;
|
||||
value = this.readDecimalNumber();
|
||||
break;
|
||||
|
||||
case STRING:
|
||||
type = TokenType.String;
|
||||
value = this.readString(code);
|
||||
break;
|
||||
|
||||
case WHITESPACE:
|
||||
type = TokenType.Space;
|
||||
value = this.readSpaces();
|
||||
break;
|
||||
|
||||
case PUNCTUATOR:
|
||||
if (code === SLASH) {
|
||||
next = this.pos + 1 < this.source.length ? this.source.charCodeAt(this.pos + 1) : 0;
|
||||
|
||||
if (next === STAR) { // /*
|
||||
type = TokenType.Comment;
|
||||
value = this.readComment();
|
||||
break;
|
||||
} else if (next === SLASH && !this.urlMode) { // //
|
||||
if (this.blockMode > 0) {
|
||||
var skip = 2;
|
||||
|
||||
while (this.source.charCodeAt(this.pos + 2) === SLASH) {
|
||||
skip++;
|
||||
}
|
||||
|
||||
type = TokenType.Identifier;
|
||||
value = this.readIdentifier(skip);
|
||||
|
||||
this.urlMode = this.urlMode || value === 'url';
|
||||
} else {
|
||||
type = TokenType.Unknown;
|
||||
value = this.readUnknown();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
type = PUNCTUATION[code];
|
||||
value = String.fromCharCode(code);
|
||||
this.pos++;
|
||||
|
||||
if (code === RIGHT_PARENTHESIS) {
|
||||
this.urlMode = false;
|
||||
} else if (code === LEFT_CURLY_BRACE) {
|
||||
this.blockMode++;
|
||||
} else if (code === RIGHT_CURLY_BRACE) {
|
||||
if (this.blockMode > this.minBlockMode) {
|
||||
this.blockMode--;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
type = TokenType.Identifier;
|
||||
value = this.readIdentifier(0);
|
||||
|
||||
this.urlMode = this.urlMode || value === 'url';
|
||||
}
|
||||
|
||||
this.eof = this.pos === this.source.length;
|
||||
|
||||
return {
|
||||
type: type,
|
||||
value: value,
|
||||
|
||||
offset: offset,
|
||||
line: line,
|
||||
column: column
|
||||
};
|
||||
},
|
||||
|
||||
isNewline: function(code) {
|
||||
if (code === N || code === F || code === R) {
|
||||
if (code === R && this.pos + 1 < this.source.length && this.source.charCodeAt(this.pos + 1) === N) {
|
||||
this.pos++;
|
||||
}
|
||||
|
||||
this.line++;
|
||||
this.lineStartPos = this.pos;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
readSpaces: function() {
|
||||
var start = this.pos;
|
||||
|
||||
for (; this.pos < this.source.length; this.pos++) {
|
||||
var code = this.source.charCodeAt(this.pos);
|
||||
|
||||
if (!this.isNewline(code) && code !== SPACE && code !== TAB) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return this.source.substring(start, this.pos);
|
||||
},
|
||||
|
||||
readComment: function() {
|
||||
var start = this.pos;
|
||||
|
||||
for (this.pos += 2; this.pos < this.source.length; this.pos++) {
|
||||
var code = this.source.charCodeAt(this.pos);
|
||||
|
||||
if (code === STAR) { // */
|
||||
if (this.source.charCodeAt(this.pos + 1) === SLASH) {
|
||||
this.pos += 2;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
this.isNewline(code);
|
||||
}
|
||||
}
|
||||
|
||||
return this.source.substring(start, this.pos);
|
||||
},
|
||||
|
||||
readUnknown: function() {
|
||||
var start = this.pos;
|
||||
|
||||
for (this.pos += 2; this.pos < this.source.length; this.pos++) {
|
||||
if (this.isNewline(this.source.charCodeAt(this.pos), this.source)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return this.source.substring(start, this.pos);
|
||||
},
|
||||
|
||||
readString: function(quote) {
|
||||
var start = this.pos;
|
||||
var res = '';
|
||||
|
||||
for (this.pos++; this.pos < this.source.length; this.pos++) {
|
||||
var code = this.source.charCodeAt(this.pos);
|
||||
|
||||
if (code === BACK_SLASH) {
|
||||
var end = this.pos++;
|
||||
|
||||
if (this.isNewline(this.source.charCodeAt(this.pos), this.source)) {
|
||||
res += this.source.substring(start, end);
|
||||
start = this.pos + 1;
|
||||
}
|
||||
} else if (code === quote) {
|
||||
this.pos++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return res + this.source.substring(start, this.pos);
|
||||
},
|
||||
|
||||
readDecimalNumber: function() {
|
||||
var start = this.pos;
|
||||
var code;
|
||||
|
||||
for (this.pos++; this.pos < this.source.length; this.pos++) {
|
||||
code = this.source.charCodeAt(this.pos);
|
||||
|
||||
if (code < 48 || code > 57) { // 0 .. 9
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return this.source.substring(start, this.pos);
|
||||
},
|
||||
|
||||
readIdentifier: function(skip) {
|
||||
var start = this.pos;
|
||||
|
||||
for (this.pos += skip; this.pos < this.source.length; this.pos++) {
|
||||
var code = this.source.charCodeAt(this.pos);
|
||||
|
||||
if (code === BACK_SLASH) {
|
||||
this.pos++;
|
||||
|
||||
// skip escaped unicode sequence that can ends with space
|
||||
// [0-9a-f]{1,6}(\r\n|[ \n\r\t\f])?
|
||||
for (var i = 0; i < 7 && this.pos + i < this.source.length; i++) {
|
||||
code = this.source.charCodeAt(this.pos + i);
|
||||
|
||||
if (i !== 6) {
|
||||
if ((code >= 48 && code <= 57) || // 0 .. 9
|
||||
(code >= 65 && code <= 70) || // A .. F
|
||||
(code >= 97 && code <= 102)) { // a .. f
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (i > 0) {
|
||||
this.pos += i - 1;
|
||||
if (code === SPACE || code === TAB || this.isNewline(code)) {
|
||||
this.pos++;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
} else if (code < SYMBOL_CATEGORY_LENGTH &&
|
||||
IS_PUNCTUATOR[code] === PUNCTUATOR) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return this.source.substring(start, this.pos);
|
||||
}
|
||||
};
|
||||
|
||||
// warm up tokenizer to elimitate code branches that never execute
|
||||
// fix soft deoptimizations (insufficient type feedback)
|
||||
new Scanner('\n\r\r\n\f//""\'\'/**/1a;.{url(a)}').lookup(1e3);
|
||||
|
||||
module.exports = Scanner;
|
||||
23
node_modules/csso/lib/utils/clone.js
generated
vendored
Executable file
23
node_modules/csso/lib/utils/clone.js
generated
vendored
Executable file
@@ -0,0 +1,23 @@
|
||||
var List = require('./list');
|
||||
|
||||
module.exports = function clone(node) {
|
||||
var result = {};
|
||||
|
||||
for (var key in node) {
|
||||
var value = node[key];
|
||||
|
||||
if (value) {
|
||||
if (Array.isArray(value)) {
|
||||
value = value.slice(0);
|
||||
} else if (value instanceof List) {
|
||||
value = new List(value.map(clone));
|
||||
} else if (value.constructor === Object) {
|
||||
value = clone(value);
|
||||
}
|
||||
}
|
||||
|
||||
result[key] = value;
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
389
node_modules/csso/lib/utils/list.js
generated
vendored
Executable file
389
node_modules/csso/lib/utils/list.js
generated
vendored
Executable file
@@ -0,0 +1,389 @@
|
||||
//
|
||||
// item item item item
|
||||
// /------\ /------\ /------\ /------\
|
||||
// | data | | data | | data | | data |
|
||||
// null <--+-prev |<---+-prev |<---+-prev |<---+-prev |
|
||||
// | next-+--->| next-+--->| next-+--->| next-+--> null
|
||||
// \------/ \------/ \------/ \------/
|
||||
// ^ ^
|
||||
// | list |
|
||||
// | /------\ |
|
||||
// \--------------+-head | |
|
||||
// | tail-+--------------/
|
||||
// \------/
|
||||
//
|
||||
|
||||
function createItem(data) {
|
||||
return {
|
||||
data: data,
|
||||
next: null,
|
||||
prev: null
|
||||
};
|
||||
}
|
||||
|
||||
var List = function(values) {
|
||||
this.cursor = null;
|
||||
this.head = null;
|
||||
this.tail = null;
|
||||
|
||||
if (Array.isArray(values)) {
|
||||
var cursor = null;
|
||||
|
||||
for (var i = 0; i < values.length; i++) {
|
||||
var item = createItem(values[i]);
|
||||
|
||||
if (cursor !== null) {
|
||||
cursor.next = item;
|
||||
} else {
|
||||
this.head = item;
|
||||
}
|
||||
|
||||
item.prev = cursor;
|
||||
cursor = item;
|
||||
}
|
||||
|
||||
this.tail = cursor;
|
||||
}
|
||||
};
|
||||
|
||||
Object.defineProperty(List.prototype, 'size', {
|
||||
get: function() {
|
||||
var size = 0;
|
||||
var cursor = this.head;
|
||||
|
||||
while (cursor) {
|
||||
size++;
|
||||
cursor = cursor.next;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
});
|
||||
|
||||
List.createItem = createItem;
|
||||
List.prototype.createItem = createItem;
|
||||
|
||||
List.prototype.toArray = function() {
|
||||
var cursor = this.head;
|
||||
var result = [];
|
||||
|
||||
while (cursor) {
|
||||
result.push(cursor.data);
|
||||
cursor = cursor.next;
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
List.prototype.toJSON = function() {
|
||||
return this.toArray();
|
||||
};
|
||||
|
||||
List.prototype.isEmpty = function() {
|
||||
return this.head === null;
|
||||
};
|
||||
|
||||
List.prototype.first = function() {
|
||||
return this.head && this.head.data;
|
||||
};
|
||||
|
||||
List.prototype.last = function() {
|
||||
return this.tail && this.tail.data;
|
||||
};
|
||||
|
||||
List.prototype.each = function(fn, context) {
|
||||
var item;
|
||||
var cursor = {
|
||||
prev: null,
|
||||
next: this.head,
|
||||
cursor: this.cursor
|
||||
};
|
||||
|
||||
if (context === undefined) {
|
||||
context = this;
|
||||
}
|
||||
|
||||
// push cursor
|
||||
this.cursor = cursor;
|
||||
|
||||
while (cursor.next !== null) {
|
||||
item = cursor.next;
|
||||
cursor.next = item.next;
|
||||
|
||||
fn.call(context, item.data, item, this);
|
||||
}
|
||||
|
||||
// pop cursor
|
||||
this.cursor = this.cursor.cursor;
|
||||
};
|
||||
|
||||
List.prototype.eachRight = function(fn, context) {
|
||||
var item;
|
||||
var cursor = {
|
||||
prev: this.tail,
|
||||
next: null,
|
||||
cursor: this.cursor
|
||||
};
|
||||
|
||||
if (context === undefined) {
|
||||
context = this;
|
||||
}
|
||||
|
||||
// push cursor
|
||||
this.cursor = cursor;
|
||||
|
||||
while (cursor.prev !== null) {
|
||||
item = cursor.prev;
|
||||
cursor.prev = item.prev;
|
||||
|
||||
fn.call(context, item.data, item, this);
|
||||
}
|
||||
|
||||
// pop cursor
|
||||
this.cursor = this.cursor.cursor;
|
||||
};
|
||||
|
||||
List.prototype.nextUntil = function(start, fn, context) {
|
||||
if (start === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var item;
|
||||
var cursor = {
|
||||
prev: null,
|
||||
next: start,
|
||||
cursor: this.cursor
|
||||
};
|
||||
|
||||
if (context === undefined) {
|
||||
context = this;
|
||||
}
|
||||
|
||||
// push cursor
|
||||
this.cursor = cursor;
|
||||
|
||||
while (cursor.next !== null) {
|
||||
item = cursor.next;
|
||||
cursor.next = item.next;
|
||||
|
||||
if (fn.call(context, item.data, item, this)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// pop cursor
|
||||
this.cursor = this.cursor.cursor;
|
||||
};
|
||||
|
||||
List.prototype.prevUntil = function(start, fn, context) {
|
||||
if (start === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var item;
|
||||
var cursor = {
|
||||
prev: start,
|
||||
next: null,
|
||||
cursor: this.cursor
|
||||
};
|
||||
|
||||
if (context === undefined) {
|
||||
context = this;
|
||||
}
|
||||
|
||||
// push cursor
|
||||
this.cursor = cursor;
|
||||
|
||||
while (cursor.prev !== null) {
|
||||
item = cursor.prev;
|
||||
cursor.prev = item.prev;
|
||||
|
||||
if (fn.call(context, item.data, item, this)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// pop cursor
|
||||
this.cursor = this.cursor.cursor;
|
||||
};
|
||||
|
||||
List.prototype.some = function(fn, context) {
|
||||
var cursor = this.head;
|
||||
|
||||
if (context === undefined) {
|
||||
context = this;
|
||||
}
|
||||
|
||||
while (cursor !== null) {
|
||||
if (fn.call(context, cursor.data, cursor, this)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
cursor = cursor.next;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
List.prototype.map = function(fn, context) {
|
||||
var result = [];
|
||||
var cursor = this.head;
|
||||
|
||||
if (context === undefined) {
|
||||
context = this;
|
||||
}
|
||||
|
||||
while (cursor !== null) {
|
||||
result.push(fn.call(context, cursor.data, cursor, this));
|
||||
cursor = cursor.next;
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
List.prototype.copy = function() {
|
||||
var result = new List();
|
||||
var cursor = this.head;
|
||||
|
||||
while (cursor !== null) {
|
||||
result.insert(createItem(cursor.data));
|
||||
cursor = cursor.next;
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
List.prototype.updateCursors = function(prevOld, prevNew, nextOld, nextNew) {
|
||||
var cursor = this.cursor;
|
||||
|
||||
while (cursor !== null) {
|
||||
if (prevNew === true || cursor.prev === prevOld) {
|
||||
cursor.prev = prevNew;
|
||||
}
|
||||
|
||||
if (nextNew === true || cursor.next === nextOld) {
|
||||
cursor.next = nextNew;
|
||||
}
|
||||
|
||||
cursor = cursor.cursor;
|
||||
}
|
||||
};
|
||||
|
||||
List.prototype.insert = function(item, before) {
|
||||
if (before !== undefined && before !== null) {
|
||||
// prev before
|
||||
// ^
|
||||
// item
|
||||
this.updateCursors(before.prev, item, before, item);
|
||||
|
||||
if (before.prev === null) {
|
||||
// insert to the beginning of list
|
||||
if (this.head !== before) {
|
||||
throw new Error('before doesn\'t below to list');
|
||||
}
|
||||
|
||||
// since head points to before therefore list doesn't empty
|
||||
// no need to check tail
|
||||
this.head = item;
|
||||
before.prev = item;
|
||||
item.next = before;
|
||||
|
||||
this.updateCursors(null, item);
|
||||
} else {
|
||||
|
||||
// insert between two items
|
||||
before.prev.next = item;
|
||||
item.prev = before.prev;
|
||||
|
||||
before.prev = item;
|
||||
item.next = before;
|
||||
}
|
||||
} else {
|
||||
// tail
|
||||
// ^
|
||||
// item
|
||||
this.updateCursors(this.tail, item, null, item);
|
||||
|
||||
// insert to end of the list
|
||||
if (this.tail !== null) {
|
||||
// if list has a tail, then it also has a head, but head doesn't change
|
||||
|
||||
// last item -> new item
|
||||
this.tail.next = item;
|
||||
|
||||
// last item <- new item
|
||||
item.prev = this.tail;
|
||||
} else {
|
||||
// if list has no a tail, then it also has no a head
|
||||
// in this case points head to new item
|
||||
this.head = item;
|
||||
}
|
||||
|
||||
// tail always start point to new item
|
||||
this.tail = item;
|
||||
}
|
||||
};
|
||||
|
||||
List.prototype.remove = function(item) {
|
||||
// item
|
||||
// ^
|
||||
// prev next
|
||||
this.updateCursors(item, item.prev, item, item.next);
|
||||
|
||||
if (item.prev !== null) {
|
||||
item.prev.next = item.next;
|
||||
} else {
|
||||
if (this.head !== item) {
|
||||
throw new Error('item doesn\'t below to list');
|
||||
}
|
||||
|
||||
this.head = item.next;
|
||||
}
|
||||
|
||||
if (item.next !== null) {
|
||||
item.next.prev = item.prev;
|
||||
} else {
|
||||
if (this.tail !== item) {
|
||||
throw new Error('item doesn\'t below to list');
|
||||
}
|
||||
|
||||
this.tail = item.prev;
|
||||
}
|
||||
|
||||
item.prev = null;
|
||||
item.next = null;
|
||||
|
||||
return item;
|
||||
};
|
||||
|
||||
List.prototype.appendList = function(list) {
|
||||
// ignore empty lists
|
||||
if (list.head === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.updateCursors(this.tail, list.tail, null, list.head);
|
||||
|
||||
// insert to end of the list
|
||||
if (this.tail !== null) {
|
||||
// if destination list has a tail, then it also has a head,
|
||||
// but head doesn't change
|
||||
|
||||
// dest tail -> source head
|
||||
this.tail.next = list.head;
|
||||
|
||||
// dest tail <- source head
|
||||
list.head.prev = this.tail;
|
||||
} else {
|
||||
// if list has no a tail, then it also has no a head
|
||||
// in this case points head to new item
|
||||
this.head = list.head;
|
||||
}
|
||||
|
||||
// tail always start point to new item
|
||||
this.tail = list.tail;
|
||||
|
||||
list.head = null;
|
||||
list.tail = null;
|
||||
};
|
||||
|
||||
module.exports = List;
|
||||
73
node_modules/csso/lib/utils/names.js
generated
vendored
Executable file
73
node_modules/csso/lib/utils/names.js
generated
vendored
Executable file
@@ -0,0 +1,73 @@
|
||||
var hasOwnProperty = Object.prototype.hasOwnProperty;
|
||||
var knownKeywords = Object.create(null);
|
||||
var knownProperties = Object.create(null);
|
||||
|
||||
function getVendorPrefix(string) {
|
||||
if (string[0] === '-') {
|
||||
// skip 2 chars to avoid wrong match with variables names
|
||||
var secondDashIndex = string.indexOf('-', 2);
|
||||
|
||||
if (secondDashIndex !== -1) {
|
||||
return string.substr(0, secondDashIndex + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
function getKeywordInfo(keyword) {
|
||||
if (hasOwnProperty.call(knownKeywords, keyword)) {
|
||||
return knownKeywords[keyword];
|
||||
}
|
||||
|
||||
var lowerCaseKeyword = keyword.toLowerCase();
|
||||
var vendor = getVendorPrefix(lowerCaseKeyword);
|
||||
var name = lowerCaseKeyword;
|
||||
|
||||
if (vendor) {
|
||||
name = name.substr(vendor.length);
|
||||
}
|
||||
|
||||
return knownKeywords[keyword] = Object.freeze({
|
||||
vendor: vendor,
|
||||
prefix: vendor,
|
||||
name: name
|
||||
});
|
||||
}
|
||||
|
||||
function getPropertyInfo(property) {
|
||||
if (hasOwnProperty.call(knownProperties, property)) {
|
||||
return knownProperties[property];
|
||||
}
|
||||
|
||||
var lowerCaseProperty = property.toLowerCase();
|
||||
var hack = lowerCaseProperty[0];
|
||||
|
||||
if (hack === '*' || hack === '_' || hack === '$') {
|
||||
lowerCaseProperty = lowerCaseProperty.substr(1);
|
||||
} else if (hack === '/' && property[1] === '/') {
|
||||
hack = '//';
|
||||
lowerCaseProperty = lowerCaseProperty.substr(2);
|
||||
} else {
|
||||
hack = '';
|
||||
}
|
||||
|
||||
var vendor = getVendorPrefix(lowerCaseProperty);
|
||||
var name = lowerCaseProperty;
|
||||
|
||||
if (vendor) {
|
||||
name = name.substr(vendor.length);
|
||||
}
|
||||
|
||||
return knownProperties[property] = Object.freeze({
|
||||
hack: hack,
|
||||
vendor: vendor,
|
||||
prefix: hack + vendor,
|
||||
name: name
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
keyword: getKeywordInfo,
|
||||
property: getPropertyInfo
|
||||
};
|
||||
178
node_modules/csso/lib/utils/translate.js
generated
vendored
Executable file
178
node_modules/csso/lib/utils/translate.js
generated
vendored
Executable file
@@ -0,0 +1,178 @@
|
||||
function each(list) {
|
||||
if (list.head === null) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (list.head === list.tail) {
|
||||
return translate(list.head.data);
|
||||
}
|
||||
|
||||
return list.map(translate).join('');
|
||||
}
|
||||
|
||||
function eachDelim(list, delimeter) {
|
||||
if (list.head === null) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (list.head === list.tail) {
|
||||
return translate(list.head.data);
|
||||
}
|
||||
|
||||
return list.map(translate).join(delimeter);
|
||||
}
|
||||
|
||||
function translate(node) {
|
||||
switch (node.type) {
|
||||
case 'StyleSheet':
|
||||
return each(node.rules);
|
||||
|
||||
case 'Atrule':
|
||||
var nodes = ['@', node.name];
|
||||
|
||||
if (node.expression && !node.expression.sequence.isEmpty()) {
|
||||
nodes.push(' ', translate(node.expression));
|
||||
}
|
||||
|
||||
if (node.block) {
|
||||
nodes.push('{', translate(node.block), '}');
|
||||
} else {
|
||||
nodes.push(';');
|
||||
}
|
||||
|
||||
return nodes.join('');
|
||||
|
||||
case 'Ruleset':
|
||||
return translate(node.selector) + '{' + translate(node.block) + '}';
|
||||
|
||||
case 'Selector':
|
||||
return eachDelim(node.selectors, ',');
|
||||
|
||||
case 'SimpleSelector':
|
||||
var nodes = node.sequence.map(function(node) {
|
||||
// add extra spaces around /deep/ combinator since comment beginning/ending may to be produced
|
||||
if (node.type === 'Combinator' && node.name === '/deep/') {
|
||||
return ' ' + translate(node) + ' ';
|
||||
}
|
||||
|
||||
return translate(node);
|
||||
});
|
||||
|
||||
return nodes.join('');
|
||||
|
||||
case 'Block':
|
||||
return eachDelim(node.declarations, ';');
|
||||
|
||||
case 'Declaration':
|
||||
return translate(node.property) + ':' + translate(node.value);
|
||||
|
||||
case 'Property':
|
||||
return node.name;
|
||||
|
||||
case 'Value':
|
||||
return node.important
|
||||
? each(node.sequence) + '!important'
|
||||
: each(node.sequence);
|
||||
|
||||
case 'Attribute':
|
||||
var result = translate(node.name);
|
||||
var flagsPrefix = ' ';
|
||||
|
||||
if (node.operator !== null) {
|
||||
result += node.operator;
|
||||
|
||||
if (node.value !== null) {
|
||||
result += translate(node.value);
|
||||
|
||||
// space between string and flags is not required
|
||||
if (node.value.type === 'String') {
|
||||
flagsPrefix = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (node.flags !== null) {
|
||||
result += flagsPrefix + node.flags;
|
||||
}
|
||||
|
||||
return '[' + result + ']';
|
||||
|
||||
case 'FunctionalPseudo':
|
||||
return ':' + node.name + '(' + eachDelim(node.arguments, ',') + ')';
|
||||
|
||||
case 'Function':
|
||||
return node.name + '(' + eachDelim(node.arguments, ',') + ')';
|
||||
|
||||
case 'Negation':
|
||||
return ':not(' + eachDelim(node.sequence, ',') + ')';
|
||||
|
||||
case 'Braces':
|
||||
return node.open + each(node.sequence) + node.close;
|
||||
|
||||
case 'Argument':
|
||||
case 'AtruleExpression':
|
||||
return each(node.sequence);
|
||||
|
||||
case 'Url':
|
||||
return 'url(' + translate(node.value) + ')';
|
||||
|
||||
case 'Progid':
|
||||
return translate(node.value);
|
||||
|
||||
case 'Combinator':
|
||||
return node.name;
|
||||
|
||||
case 'Identifier':
|
||||
return node.name;
|
||||
|
||||
case 'PseudoClass':
|
||||
return ':' + node.name;
|
||||
|
||||
case 'PseudoElement':
|
||||
return '::' + node.name;
|
||||
|
||||
case 'Class':
|
||||
return '.' + node.name;
|
||||
|
||||
case 'Id':
|
||||
return '#' + node.name;
|
||||
|
||||
case 'Hash':
|
||||
return '#' + node.value;
|
||||
|
||||
case 'Dimension':
|
||||
return node.value + node.unit;
|
||||
|
||||
case 'Nth':
|
||||
return node.value;
|
||||
|
||||
case 'Number':
|
||||
return node.value;
|
||||
|
||||
case 'String':
|
||||
return node.value;
|
||||
|
||||
case 'Operator':
|
||||
return node.value;
|
||||
|
||||
case 'Raw':
|
||||
return node.value;
|
||||
|
||||
case 'Unknown':
|
||||
return node.value;
|
||||
|
||||
case 'Percentage':
|
||||
return node.value + '%';
|
||||
|
||||
case 'Space':
|
||||
return ' ';
|
||||
|
||||
case 'Comment':
|
||||
return '/*' + node.value + '*/';
|
||||
|
||||
default:
|
||||
throw new Error('Unknown node type: ' + node.type);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = translate;
|
||||
291
node_modules/csso/lib/utils/translateWithSourceMap.js
generated
vendored
Executable file
291
node_modules/csso/lib/utils/translateWithSourceMap.js
generated
vendored
Executable file
@@ -0,0 +1,291 @@
|
||||
var SourceMapGenerator = require('source-map').SourceMapGenerator;
|
||||
var SourceNode = require('source-map').SourceNode;
|
||||
|
||||
// Our own implementation of SourceNode#toStringWithSourceMap,
|
||||
// since SourceNode doesn't allow multiple references to original source.
|
||||
// Also, as we know structure of result we could be optimize generation
|
||||
// (currently it's ~40% faster).
|
||||
function walk(node, fn) {
|
||||
for (var chunk, i = 0; i < node.children.length; i++) {
|
||||
chunk = node.children[i];
|
||||
|
||||
if (chunk instanceof SourceNode) {
|
||||
// this is a hack, because source maps doesn't support for 1(generated):N(original)
|
||||
// if (chunk.merged) {
|
||||
// fn('', chunk);
|
||||
// }
|
||||
|
||||
walk(chunk, fn);
|
||||
} else {
|
||||
fn(chunk, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function generateSourceMap(root) {
|
||||
var map = new SourceMapGenerator();
|
||||
var css = '';
|
||||
var sourceMappingActive = false;
|
||||
var lastOriginalLine = null;
|
||||
var lastOriginalColumn = null;
|
||||
var lastIndexOfNewline;
|
||||
var generated = {
|
||||
line: 1,
|
||||
column: 0
|
||||
};
|
||||
var activatedMapping = {
|
||||
generated: generated
|
||||
};
|
||||
|
||||
walk(root, function(chunk, original) {
|
||||
if (original.line !== null &&
|
||||
original.column !== null) {
|
||||
if (lastOriginalLine !== original.line ||
|
||||
lastOriginalColumn !== original.column) {
|
||||
map.addMapping({
|
||||
source: original.source,
|
||||
original: original,
|
||||
generated: generated
|
||||
});
|
||||
}
|
||||
|
||||
lastOriginalLine = original.line;
|
||||
lastOriginalColumn = original.column;
|
||||
sourceMappingActive = true;
|
||||
} else if (sourceMappingActive) {
|
||||
map.addMapping(activatedMapping);
|
||||
sourceMappingActive = false;
|
||||
}
|
||||
|
||||
css += chunk;
|
||||
|
||||
lastIndexOfNewline = chunk.lastIndexOf('\n');
|
||||
if (lastIndexOfNewline !== -1) {
|
||||
generated.line += chunk.match(/\n/g).length;
|
||||
generated.column = chunk.length - lastIndexOfNewline - 1;
|
||||
} else {
|
||||
generated.column += chunk.length;
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
css: css,
|
||||
map: map
|
||||
};
|
||||
}
|
||||
|
||||
function createAnonymousSourceNode(children) {
|
||||
return new SourceNode(
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
children
|
||||
);
|
||||
}
|
||||
|
||||
function createSourceNode(info, children) {
|
||||
if (info.primary) {
|
||||
// special marker node to add several references to original
|
||||
// var merged = createSourceNode(info.merged, []);
|
||||
// merged.merged = true;
|
||||
// children.unshift(merged);
|
||||
|
||||
// use recursion, because primary can also has a primary/merged info
|
||||
return createSourceNode(info.primary, children);
|
||||
}
|
||||
|
||||
return new SourceNode(
|
||||
info.line,
|
||||
info.column - 1,
|
||||
info.source,
|
||||
children
|
||||
);
|
||||
}
|
||||
|
||||
function each(list) {
|
||||
if (list.head === null) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (list.head === list.tail) {
|
||||
return translate(list.head.data);
|
||||
}
|
||||
|
||||
return list.map(translate).join('');
|
||||
}
|
||||
|
||||
function eachDelim(list, delimeter) {
|
||||
if (list.head === null) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (list.head === list.tail) {
|
||||
return translate(list.head.data);
|
||||
}
|
||||
|
||||
return list.map(translate).join(delimeter);
|
||||
}
|
||||
|
||||
function translate(node) {
|
||||
switch (node.type) {
|
||||
case 'StyleSheet':
|
||||
return createAnonymousSourceNode(node.rules.map(translate));
|
||||
|
||||
case 'Atrule':
|
||||
var nodes = ['@', node.name];
|
||||
|
||||
if (node.expression && !node.expression.sequence.isEmpty()) {
|
||||
nodes.push(' ', translate(node.expression));
|
||||
}
|
||||
|
||||
if (node.block) {
|
||||
nodes.push('{', translate(node.block), '}');
|
||||
} else {
|
||||
nodes.push(';');
|
||||
}
|
||||
|
||||
return createSourceNode(node.info, nodes);
|
||||
|
||||
case 'Ruleset':
|
||||
return createAnonymousSourceNode([
|
||||
translate(node.selector), '{', translate(node.block), '}'
|
||||
]);
|
||||
|
||||
case 'Selector':
|
||||
return createAnonymousSourceNode(node.selectors.map(translate)).join(',');
|
||||
|
||||
case 'SimpleSelector':
|
||||
var nodes = node.sequence.map(function(node) {
|
||||
// add extra spaces around /deep/ combinator since comment beginning/ending may to be produced
|
||||
if (node.type === 'Combinator' && node.name === '/deep/') {
|
||||
return ' ' + translate(node) + ' ';
|
||||
}
|
||||
|
||||
return translate(node);
|
||||
});
|
||||
|
||||
return createSourceNode(node.info, nodes);
|
||||
|
||||
case 'Block':
|
||||
return createAnonymousSourceNode(node.declarations.map(translate)).join(';');
|
||||
|
||||
case 'Declaration':
|
||||
return createSourceNode(
|
||||
node.info,
|
||||
[translate(node.property), ':', translate(node.value)]
|
||||
);
|
||||
|
||||
case 'Property':
|
||||
return node.name;
|
||||
|
||||
case 'Value':
|
||||
return node.important
|
||||
? each(node.sequence) + '!important'
|
||||
: each(node.sequence);
|
||||
|
||||
case 'Attribute':
|
||||
var result = translate(node.name);
|
||||
var flagsPrefix = ' ';
|
||||
|
||||
if (node.operator !== null) {
|
||||
result += node.operator;
|
||||
|
||||
if (node.value !== null) {
|
||||
result += translate(node.value);
|
||||
|
||||
// space between string and flags is not required
|
||||
if (node.value.type === 'String') {
|
||||
flagsPrefix = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (node.flags !== null) {
|
||||
result += flagsPrefix + node.flags;
|
||||
}
|
||||
|
||||
return '[' + result + ']';
|
||||
|
||||
case 'FunctionalPseudo':
|
||||
return ':' + node.name + '(' + eachDelim(node.arguments, ',') + ')';
|
||||
|
||||
case 'Function':
|
||||
return node.name + '(' + eachDelim(node.arguments, ',') + ')';
|
||||
|
||||
case 'Negation':
|
||||
return ':not(' + eachDelim(node.sequence, ',') + ')';
|
||||
|
||||
case 'Braces':
|
||||
return node.open + each(node.sequence) + node.close;
|
||||
|
||||
case 'Argument':
|
||||
case 'AtruleExpression':
|
||||
return each(node.sequence);
|
||||
|
||||
case 'Url':
|
||||
return 'url(' + translate(node.value) + ')';
|
||||
|
||||
case 'Progid':
|
||||
return translate(node.value);
|
||||
|
||||
case 'Combinator':
|
||||
return node.name;
|
||||
|
||||
case 'Identifier':
|
||||
return node.name;
|
||||
|
||||
case 'PseudoClass':
|
||||
return ':' + node.name;
|
||||
|
||||
case 'PseudoElement':
|
||||
return '::' + node.name;
|
||||
|
||||
case 'Class':
|
||||
return '.' + node.name;
|
||||
|
||||
case 'Id':
|
||||
return '#' + node.name;
|
||||
|
||||
case 'Hash':
|
||||
return '#' + node.value;
|
||||
|
||||
case 'Dimension':
|
||||
return node.value + node.unit;
|
||||
|
||||
case 'Nth':
|
||||
return node.value;
|
||||
|
||||
case 'Number':
|
||||
return node.value;
|
||||
|
||||
case 'String':
|
||||
return node.value;
|
||||
|
||||
case 'Operator':
|
||||
return node.value;
|
||||
|
||||
case 'Raw':
|
||||
return node.value;
|
||||
|
||||
case 'Unknown':
|
||||
return node.value;
|
||||
|
||||
case 'Percentage':
|
||||
return node.value + '%';
|
||||
|
||||
case 'Space':
|
||||
return ' ';
|
||||
|
||||
case 'Comment':
|
||||
return '/*' + node.value + '*/';
|
||||
|
||||
default:
|
||||
throw new Error('Unknown node type: ' + node.type);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = function(node) {
|
||||
return generateSourceMap(
|
||||
createAnonymousSourceNode(translate(node))
|
||||
);
|
||||
};
|
||||
189
node_modules/csso/lib/utils/walk.js
generated
vendored
Executable file
189
node_modules/csso/lib/utils/walk.js
generated
vendored
Executable file
@@ -0,0 +1,189 @@
|
||||
function walkRules(node, item, list) {
|
||||
switch (node.type) {
|
||||
case 'StyleSheet':
|
||||
var oldStylesheet = this.stylesheet;
|
||||
this.stylesheet = node;
|
||||
|
||||
node.rules.each(walkRules, this);
|
||||
|
||||
this.stylesheet = oldStylesheet;
|
||||
break;
|
||||
|
||||
case 'Atrule':
|
||||
if (node.block !== null) {
|
||||
walkRules.call(this, node.block);
|
||||
}
|
||||
|
||||
this.fn(node, item, list);
|
||||
break;
|
||||
|
||||
case 'Ruleset':
|
||||
this.fn(node, item, list);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function walkRulesRight(node, item, list) {
|
||||
switch (node.type) {
|
||||
case 'StyleSheet':
|
||||
var oldStylesheet = this.stylesheet;
|
||||
this.stylesheet = node;
|
||||
|
||||
node.rules.eachRight(walkRulesRight, this);
|
||||
|
||||
this.stylesheet = oldStylesheet;
|
||||
break;
|
||||
|
||||
case 'Atrule':
|
||||
if (node.block !== null) {
|
||||
walkRulesRight.call(this, node.block);
|
||||
}
|
||||
|
||||
this.fn(node, item, list);
|
||||
break;
|
||||
|
||||
case 'Ruleset':
|
||||
this.fn(node, item, list);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function walkAll(node, item, list) {
|
||||
switch (node.type) {
|
||||
case 'StyleSheet':
|
||||
var oldStylesheet = this.stylesheet;
|
||||
this.stylesheet = node;
|
||||
|
||||
node.rules.each(walkAll, this);
|
||||
|
||||
this.stylesheet = oldStylesheet;
|
||||
break;
|
||||
|
||||
case 'Atrule':
|
||||
if (node.expression !== null) {
|
||||
walkAll.call(this, node.expression);
|
||||
}
|
||||
if (node.block !== null) {
|
||||
walkAll.call(this, node.block);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'Ruleset':
|
||||
this.ruleset = node;
|
||||
|
||||
if (node.selector !== null) {
|
||||
walkAll.call(this, node.selector);
|
||||
}
|
||||
walkAll.call(this, node.block);
|
||||
|
||||
this.ruleset = null;
|
||||
break;
|
||||
|
||||
case 'Selector':
|
||||
var oldSelector = this.selector;
|
||||
this.selector = node;
|
||||
|
||||
node.selectors.each(walkAll, this);
|
||||
|
||||
this.selector = oldSelector;
|
||||
break;
|
||||
|
||||
case 'Block':
|
||||
node.declarations.each(walkAll, this);
|
||||
break;
|
||||
|
||||
case 'Declaration':
|
||||
this.declaration = node;
|
||||
|
||||
walkAll.call(this, node.property);
|
||||
walkAll.call(this, node.value);
|
||||
|
||||
this.declaration = null;
|
||||
break;
|
||||
|
||||
case 'Attribute':
|
||||
walkAll.call(this, node.name);
|
||||
if (node.value !== null) {
|
||||
walkAll.call(this, node.value);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'FunctionalPseudo':
|
||||
case 'Function':
|
||||
this['function'] = node;
|
||||
|
||||
node.arguments.each(walkAll, this);
|
||||
|
||||
this['function'] = null;
|
||||
break;
|
||||
|
||||
case 'AtruleExpression':
|
||||
this.atruleExpression = node;
|
||||
|
||||
node.sequence.each(walkAll, this);
|
||||
|
||||
this.atruleExpression = null;
|
||||
break;
|
||||
|
||||
case 'Value':
|
||||
case 'Argument':
|
||||
case 'SimpleSelector':
|
||||
case 'Braces':
|
||||
case 'Negation':
|
||||
node.sequence.each(walkAll, this);
|
||||
break;
|
||||
|
||||
case 'Url':
|
||||
case 'Progid':
|
||||
walkAll.call(this, node.value);
|
||||
break;
|
||||
|
||||
// nothig to do with
|
||||
// case 'Property':
|
||||
// case 'Combinator':
|
||||
// case 'Dimension':
|
||||
// case 'Hash':
|
||||
// case 'Identifier':
|
||||
// case 'Nth':
|
||||
// case 'Class':
|
||||
// case 'Id':
|
||||
// case 'Percentage':
|
||||
// case 'PseudoClass':
|
||||
// case 'PseudoElement':
|
||||
// case 'Space':
|
||||
// case 'Number':
|
||||
// case 'String':
|
||||
// case 'Operator':
|
||||
// case 'Raw':
|
||||
}
|
||||
|
||||
this.fn(node, item, list);
|
||||
}
|
||||
|
||||
function createContext(root, fn) {
|
||||
var context = {
|
||||
fn: fn,
|
||||
root: root,
|
||||
stylesheet: null,
|
||||
atruleExpression: null,
|
||||
ruleset: null,
|
||||
selector: null,
|
||||
declaration: null,
|
||||
function: null
|
||||
};
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
all: function(root, fn) {
|
||||
walkAll.call(createContext(root, fn), root);
|
||||
},
|
||||
rules: function(root, fn) {
|
||||
walkRules.call(createContext(root, fn), root);
|
||||
},
|
||||
rulesRight: function(root, fn) {
|
||||
walkRulesRight.call(createContext(root, fn), root);
|
||||
}
|
||||
};
|
||||
118
node_modules/csso/package.json
generated
vendored
Executable file
118
node_modules/csso/package.json
generated
vendored
Executable file
@@ -0,0 +1,118 @@
|
||||
{
|
||||
"_args": [
|
||||
[
|
||||
"csso@2.3.2",
|
||||
"/Applications/XAMPP/xamppfiles/htdocs/wordpress/latehome"
|
||||
]
|
||||
],
|
||||
"_from": "csso@2.3.2",
|
||||
"_id": "csso@2.3.2",
|
||||
"_inBundle": false,
|
||||
"_integrity": "sha1-3dUsWHAz9J6Utx/FVWnyUuj/X4U=",
|
||||
"_location": "/csso",
|
||||
"_phantomChildren": {},
|
||||
"_requested": {
|
||||
"type": "version",
|
||||
"registry": true,
|
||||
"raw": "csso@2.3.2",
|
||||
"name": "csso",
|
||||
"escapedName": "csso",
|
||||
"rawSpec": "2.3.2",
|
||||
"saveSpec": null,
|
||||
"fetchSpec": "2.3.2"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/svgo"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/csso/-/csso-2.3.2.tgz",
|
||||
"_spec": "2.3.2",
|
||||
"_where": "/Applications/XAMPP/xamppfiles/htdocs/wordpress/latehome",
|
||||
"author": {
|
||||
"name": "Sergey Kryzhanovsky",
|
||||
"email": "skryzhanovsky@ya.ru",
|
||||
"url": "https://github.com/afelix"
|
||||
},
|
||||
"bin": {
|
||||
"csso": "./bin/csso"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/css/csso/issues"
|
||||
},
|
||||
"dependencies": {
|
||||
"clap": "^1.0.9",
|
||||
"source-map": "^0.5.3"
|
||||
},
|
||||
"description": "CSSO (CSS Optimizer) is a CSS minifier with structural optimisations",
|
||||
"devDependencies": {
|
||||
"browserify": "^13.0.0",
|
||||
"coveralls": "^2.11.6",
|
||||
"eslint": "^2.2.0",
|
||||
"istanbul": "^0.4.2",
|
||||
"jscs": "~2.10.0",
|
||||
"mocha": "~2.4.2",
|
||||
"uglify-js": "^2.6.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"env": {
|
||||
"node": true,
|
||||
"mocha": true,
|
||||
"es6": true
|
||||
},
|
||||
"rules": {
|
||||
"no-duplicate-case": 2,
|
||||
"no-undef": 2,
|
||||
"no-unused-vars": [
|
||||
2,
|
||||
{
|
||||
"vars": "all",
|
||||
"args": "after-used"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"bin",
|
||||
"dist/csso-browser.js",
|
||||
"lib",
|
||||
"HISTORY.md",
|
||||
"LICENSE",
|
||||
"README.md"
|
||||
],
|
||||
"homepage": "https://github.com/css/csso",
|
||||
"keywords": [
|
||||
"css",
|
||||
"minifier",
|
||||
"minify",
|
||||
"compress",
|
||||
"optimisation"
|
||||
],
|
||||
"license": "MIT",
|
||||
"main": "./lib/index",
|
||||
"maintainers": [
|
||||
{
|
||||
"name": "Roman Dvornov",
|
||||
"email": "rdvornov@gmail.com"
|
||||
}
|
||||
],
|
||||
"name": "csso",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/css/csso.git"
|
||||
},
|
||||
"scripts": {
|
||||
"browserify": "browserify --standalone csso lib/index.js | uglifyjs --compress --mangle -o dist/csso-browser.js",
|
||||
"codestyle": "jscs lib && eslint lib test",
|
||||
"codestyle-and-test": "npm run codestyle && npm test",
|
||||
"coverage": "istanbul cover _mocha -- -R dot",
|
||||
"coveralls": "istanbul cover _mocha --report lcovonly -- -R dot && cat ./coverage/lcov.info | coveralls",
|
||||
"gh-pages": "git clone -b gh-pages https://github.com/css/csso.git .gh-pages && npm run browserify && cp dist/csso-browser.js .gh-pages/ && cd .gh-pages && git commit -am \"update\" && git push && cd .. && rm -rf .gh-pages",
|
||||
"hydrogen": "node --trace-hydrogen --trace-phase=Z --trace-deopt --code-comments --hydrogen-track-positions --redirect-code-traces --redirect-code-traces-to=code.asm --trace_hydrogen_file=code.cfg --print-opt-code bin/csso --stat -o /dev/null",
|
||||
"prepublish": "npm run browserify",
|
||||
"test": "mocha --reporter dot",
|
||||
"travis": "npm run codestyle-and-test && npm run coveralls"
|
||||
},
|
||||
"version": "2.3.2"
|
||||
}
|
||||
Reference in New Issue
Block a user