schnee effeckt und fehler Korektur
This commit is contained in:
133
node_modules/csso/HISTORY.md → node_modules/csso/CHANGELOG.md
generated
vendored
133
node_modules/csso/HISTORY.md → node_modules/csso/CHANGELOG.md
generated
vendored
@@ -1,3 +1,136 @@
|
||||
## 4.2.0 (November 26, 2020)
|
||||
|
||||
- Trim Custom Property values when possible (#393)
|
||||
- Fixed removing unit for zero-length dimentions in `min()`, `max()` and `clamp()` functions (#426)
|
||||
- Fixed crash on bad value in TRBL declaration value (#412)
|
||||
|
||||
## 4.1.1 (November 15, 2020)
|
||||
|
||||
- Fixed build setup to exclude full `mdn/data` that reduced the lib size:
|
||||
* dist/csso.js: 794.5Kb -> 255.2Kb
|
||||
* dist/csso.min.js: 394.4Kb -> 194.2Kb
|
||||
* package size: 237.8 kB -> 156.1 kB
|
||||
* package unpacked size: 1.3 MB -> 586.8 kB
|
||||
|
||||
## 4.1.0 (October 27, 2020)
|
||||
|
||||
- Bumped [CSSTree](https://github.com/csstree/csstree) to `^1.0.0`
|
||||
- Fixed wrongly merging of TRBL values when one of them contains `var()` (#420)
|
||||
- Fixed wrongly merging of pseudo class and element with the same name, e.g. `:-ms-input-placeholder` and `::-ms-input-placeholder` (#383, #416)
|
||||
- Fixed wrongly merging of `overflow` fallback (#415)
|
||||
|
||||
## 4.0.3 (March 24, 2020)
|
||||
|
||||
- Prevented percent sign removal in `flex`/`-ms-flex` (#410)
|
||||
- Fixed restructuring optimisation in some cases (@charlessuh & @chsuh, #358, #411)
|
||||
- Bumped dependencies (@AviVahl, #409)
|
||||
|
||||
## 4.0.2 (October 28, 2019)
|
||||
|
||||
- Fixed clean stage to avoid exceptions when source has unparsed or bad parts (#380)
|
||||
- Fixed wrong percentage sign removal for zero values (#395)
|
||||
|
||||
## 4.0.1 (October 22, 2019)
|
||||
|
||||
- Bumped CSSTree to [`1.0.0-alpha.37`](https://github.com/csstree/csstree/releases/tag/v1.0.0-alpha.37) to avoid source map generation inconsistency across Node.js versions
|
||||
|
||||
## 4.0.0 (October 21, 2019)
|
||||
|
||||
- Dropped support for Node.js < 8
|
||||
- Refreshed dev dependencies and scripts
|
||||
- Bumped [CSSTree](https://github.com/csstree/csstree) to `1.0.0-alpha.36` (#399)
|
||||
- Changed bundle files: `dist/csso.js` and `dist/csso.min.js` instead single `dist/csso-browser.js` (min version)
|
||||
- Expose `compress()` as `syntax.compress()`
|
||||
|
||||
## 3.5.1 (June 7, 2018)
|
||||
|
||||
- Bumped [CSSTree](https://github.com/csstree/csstree) to `1.0.0-alpha.29` (fixes some issues)
|
||||
|
||||
## 3.5.0 (January 14, 2018)
|
||||
|
||||
- Migrated to [CSSTree](https://github.com/csstree/csstree) `1.0.0-alpha.27`
|
||||
|
||||
## 3.4.0 (November 3, 2017)
|
||||
|
||||
- Added percent sign removal for zero percentages for some properties that is safe (@RubaXa, #286)
|
||||
- Removed unit removal for zero values in `-ms-flex` due it breaks flex in IE10/11 (#362)
|
||||
- Improved performance of selectors comparison (@smelukov, #343)
|
||||
|
||||
## 3.3.1 (October 17, 2017)
|
||||
|
||||
- Fixed merge of `position` declarations when `sticky` fallback is using (@gruzzilkin, #356)
|
||||
|
||||
## 3.3.0 (October 12, 2017)
|
||||
|
||||
- Migrated to [CSSTree](https://github.com/csstree/csstree) `1.0.0-alpha25`
|
||||
- Changed AST format (see [CSSTree change log](https://github.com/csstree/csstree/blob/master/HISTORY.md) for details)
|
||||
- Fixed performance issue when generate CSS with source map (quadratic increase in time depending on the size of the CSS)
|
||||
|
||||
## 3.2.0 (September 10, 2017)
|
||||
|
||||
- Fixed named color compression to apply only when an identifier is guaranteed to be a color
|
||||
- Added lifting of `@keyframes` to the beginning of style sheet (chunk), but after `@charset` and `@import` rules
|
||||
- Added removal of `@keyframes`, `@media` and `@supports` with no prelude
|
||||
- Added removal of duplicate `@keyframes` (#202)
|
||||
- Added new option `forceMediaMerge` to force media rules merging. It's unsafe in general, but works fine in many cases. Use it on your own risk (#350)
|
||||
- Bumped `CSSTree` to `1.0.0-alpha23`
|
||||
|
||||
## 3.1.1 (April 25, 2017)
|
||||
|
||||
- Fixed crash on a number processing when it used not in a list (#335)
|
||||
|
||||
## 3.1.0 (April 24, 2017)
|
||||
|
||||
- Implemented optimisation for `none` keyword in `border` and `outline` properties (@zoobestik, #41)
|
||||
- Implemented replacing `rgba(x, x, x, 0)` to `transparent`
|
||||
- Fixed plus sign omitting for numbers following identifier, hex color, number or unicode range, since it can change the meaning of CSS (e.g. `calc(1px+2px)` has been optimized to `calc(1px2px)` before, now it stays the same)
|
||||
- Improved usage filtering for nested selectors (i.e. for `:nth-*()`, `:has()`, `:matches` and other pseudos)
|
||||
- Implemented `blacklist` filtering in usage (#334, see [Black list filtering](https://github.com/css/csso#black-list-filtering))
|
||||
- Improved white space removing, now white spaces are removing in the beginning and at the ending of sequences, and between stylesheet and block nodes
|
||||
- Bumped `CSSTree` to `1.0.0-alpha19`
|
||||
|
||||
## 3.0.1 (March 14, 2017)
|
||||
|
||||
- Fixed declaration merging when declaration contains an `!important`
|
||||
|
||||
## 3.0.0 (March 13, 2017)
|
||||
|
||||
- Migrated to [CSSTree](https://github.com/csstree/csstree) as AST backend and exposed its API behind `syntax` property
|
||||
- Extracted CLI into standalone package [css/csso-cli](https://github.com/css/csso-cli)
|
||||
|
||||
## 2.3.1 (January 6, 2017)
|
||||
|
||||
- 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
|
||||
1
node_modules/csso/LICENSE
generated
vendored
1
node_modules/csso/LICENSE
generated
vendored
@@ -1,3 +1,4 @@
|
||||
Copyright (C) 2015-2019 by Roman Dvornov
|
||||
Copyright (C) 2011-2015 by Sergey Kryzhanovsky
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
|
||||
532
node_modules/csso/README.md
generated
vendored
532
node_modules/csso/README.md
generated
vendored
@@ -9,100 +9,258 @@ CSSO (CSS Optimizer) is a CSS minifier. It performs three sort of transformation
|
||||
[](https://www.yandex.com/)
|
||||
[](https://www.avito.ru/)
|
||||
|
||||
## Usage
|
||||
## Ready to use
|
||||
|
||||
- [Web interface](http://css.github.io/csso/csso.html)
|
||||
- [csso-cli](https://github.com/css/csso-cli) – command line interface
|
||||
- [gulp-csso](https://github.com/ben-eb/gulp-csso) – `Gulp` plugin
|
||||
- [grunt-csso](https://github.com/t32k/grunt-csso) – `Grunt` plugin
|
||||
- [broccoli-csso](https://github.com/sindresorhus/broccoli-csso) – `Broccoli` plugin
|
||||
- [postcss-csso](https://github.com/lahmatiy/postcss-csso) – `PostCSS` plugin
|
||||
- [csso-loader](https://github.com/sandark7/csso-loader) – `webpack` loader
|
||||
- [csso-webpack-plugin](https://github.com/zoobestik/csso-webpack-plugin) – `webpack` plugin
|
||||
- [CSSO Visual Studio Code plugin](https://marketplace.visualstudio.com/items?itemName=Aneryu.csso)
|
||||
|
||||
## Install
|
||||
|
||||
```
|
||||
npm install -g csso
|
||||
npm install csso
|
||||
```
|
||||
|
||||
Or try out CSSO [right in your browser](http://css.github.io/csso/csso.html) (web interface).
|
||||
## API
|
||||
|
||||
### Runners
|
||||
<!-- TOC depthfrom:3 -->
|
||||
|
||||
- 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)
|
||||
- [minify(source[, options])](#minifysource-options)
|
||||
- [minifyBlock(source[, options])](#minifyblocksource-options)
|
||||
- [syntax.compress(ast[, options])](#syntaxcompressast-options)
|
||||
- [Source maps](#source-maps)
|
||||
- [Usage data](#usage-data)
|
||||
- [White list filtering](#white-list-filtering)
|
||||
- [Black list filtering](#black-list-filtering)
|
||||
- [Scopes](#scopes)
|
||||
|
||||
### Command line
|
||||
<!-- /TOC -->
|
||||
|
||||
Basic usage:
|
||||
|
||||
```js
|
||||
var csso = require('csso');
|
||||
|
||||
var minifiedCss = csso.minify('.test { color: #ff0000; }').css;
|
||||
|
||||
console.log(minifiedCss);
|
||||
// .test{color:red}
|
||||
```
|
||||
csso [input] [output] [options]
|
||||
|
||||
CSSO is based on [CSSTree](https://github.com/csstree/csstree) to parse CSS into AST, AST traversal and to generate AST back to CSS. All `CSSTree` API is available behind `syntax` field. You may minify CSS step by step:
|
||||
|
||||
```js
|
||||
var csso = require('csso');
|
||||
var ast = csso.syntax.parse('.test { color: #ff0000; }');
|
||||
var compressedAst = csso.syntax.compress(ast).ast;
|
||||
var minifiedCss = csso.syntax.generate(compressedAst);
|
||||
|
||||
console.log(minifiedCss);
|
||||
// .test{color:red}
|
||||
```
|
||||
|
||||
> Warning: CSSO uses early versions of CSSTree that still in active development. CSSO doesn't guarantee API behind `syntax` field or AST format will not change in future releases of CSSO, since it's subject to change in CSSTree. Be careful with CSSO updates if you use `syntax` API until this warning removal.
|
||||
|
||||
### minify(source[, options])
|
||||
|
||||
Minify `source` CSS passed as `String`.
|
||||
|
||||
```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}
|
||||
```
|
||||
|
||||
Returns an object with properties:
|
||||
|
||||
- css `String` – resulting CSS
|
||||
- map `Object` – instance of [`SourceMapGenerator`](https://github.com/mozilla/source-map#sourcemapgenerator) or `null`
|
||||
|
||||
Options:
|
||||
|
||||
--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
|
||||
- sourceMap
|
||||
|
||||
Type: `Boolean`
|
||||
Default: `false`
|
||||
|
||||
Generate a source map when `true`.
|
||||
|
||||
- filename
|
||||
|
||||
Type: `String`
|
||||
Default: `'<unknown>'`
|
||||
|
||||
Filename of input CSS, uses for source map generation.
|
||||
|
||||
- debug
|
||||
|
||||
Type: `Boolean`
|
||||
Default: `false`
|
||||
|
||||
Output debug information to `stderr`.
|
||||
|
||||
- beforeCompress
|
||||
|
||||
Type: `function(ast, options)` or `Array<function(ast, options)>` or `null`
|
||||
Default: `null`
|
||||
|
||||
Called right after parse is run.
|
||||
|
||||
- afterCompress
|
||||
|
||||
Type: `function(compressResult, options)` or `Array<function(compressResult, options)>` or `null`
|
||||
Default: `null`
|
||||
|
||||
Called right after [`syntax.compress()`](#syntaxcompressast-options) is run.
|
||||
|
||||
- Other options are the same as for [`syntax.compress()`](#syntaxcompressast-options) function.
|
||||
|
||||
### minifyBlock(source[, options])
|
||||
|
||||
The same as `minify()` but for list of declarations. Usually it's a `style` attribute value.
|
||||
|
||||
```js
|
||||
var result = csso.minifyBlock('color: rgba(255, 0, 0, 1); color: #ff0000');
|
||||
|
||||
console.log(result.css);
|
||||
// > color:red
|
||||
```
|
||||
|
||||
Some examples:
|
||||
### syntax.compress(ast[, options])
|
||||
|
||||
```
|
||||
> csso in.css
|
||||
...output result in stdout...
|
||||
Does the main task – compress an AST. This is CSSO's extension in CSSTree syntax API.
|
||||
|
||||
> csso in.css --output out.css
|
||||
> NOTE: `syntax.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.
|
||||
|
||||
> echo '.test { color: #ff0000; }' | csso
|
||||
.test{color:red}
|
||||
Returns an object with properties:
|
||||
|
||||
> cat source1.css source2.css | csso | gzip -9 -c > production.css.gz
|
||||
```
|
||||
- ast `Object` – resulting AST
|
||||
|
||||
Options:
|
||||
|
||||
- restructure
|
||||
|
||||
Type: `Boolean`
|
||||
Default: `true`
|
||||
|
||||
Disable or enable a structure optimisations.
|
||||
|
||||
- forceMediaMerge
|
||||
|
||||
Type: `Boolean`
|
||||
Default: `false`
|
||||
|
||||
Enables merging of `@media` rules with the same media query by splitted by other rules. The optimisation is unsafe in general, but should work fine in most cases. Use it on your own risk.
|
||||
|
||||
- clone
|
||||
|
||||
Type: `Boolean`
|
||||
Default: `false`
|
||||
|
||||
Transform a copy of input AST if `true`. Useful in case of AST reuse.
|
||||
|
||||
- comments
|
||||
|
||||
Type: `String` or `Boolean`
|
||||
Default: `true`
|
||||
|
||||
Specify what comments to leave:
|
||||
|
||||
- `'exclamation'` or `true` – leave all exclamation comments (i.e. `/*! .. */`)
|
||||
- `'first-exclamation'` – remove every comment except first one
|
||||
- `false` – remove all comments
|
||||
|
||||
- usage
|
||||
|
||||
Type: `Object` or `null`
|
||||
Default: `null`
|
||||
|
||||
Usage data for advanced optimisations (see [Usage data](#usage-data) for details)
|
||||
|
||||
- logger
|
||||
|
||||
Type: `Function` or `null`
|
||||
Default: `null`
|
||||
|
||||
Function to track every step of transformation.
|
||||
|
||||
### Source maps
|
||||
|
||||
Source map doesn't generate by default. To generate map use `--map` CLI option, that can be:
|
||||
To get a source map set `true` for `sourceMap` option. Additianaly `filename` option can be passed to specify source file. When `sourceMap` option is `true`, `map` field of result object will contain a [`SourceMapGenerator`](https://github.com/mozilla/source-map#sourcemapgenerator) instance. This object can be mixed with another source map or translated to string.
|
||||
|
||||
- `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
|
||||
```js
|
||||
var csso = require('csso');
|
||||
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
|
||||
});
|
||||
|
||||
Examples:
|
||||
console.log(result);
|
||||
// { css: '...minified...', map: SourceMapGenerator {} }
|
||||
|
||||
```
|
||||
> 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
|
||||
console.log(result.map.toString());
|
||||
// '{ .. source map content .. }'
|
||||
```
|
||||
|
||||
Use `--input-map` option to specify input source map if needed. Possible values for option:
|
||||
Example of generating source map with respect of source map from input CSS:
|
||||
|
||||
- `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
|
||||
```js
|
||||
var require('source-map');
|
||||
var csso = require('csso');
|
||||
var inputFile = 'path/to/my.css';
|
||||
var input = fs.readFileSync(inputFile, 'utf8');
|
||||
var inputMap = input.match(/\/\*# sourceMappingURL=(\S+)\s*\*\/\s*$/);
|
||||
var output = csso.minify(input, {
|
||||
filename: inputFile,
|
||||
sourceMap: true
|
||||
});
|
||||
|
||||
Generally you shouldn't care about input source map since defaults behaviour (`auto`) covers most use cases.
|
||||
// apply input source map to output
|
||||
if (inputMap) {
|
||||
output.map.applySourceMap(
|
||||
new SourceMapConsumer(inputMap[1]),
|
||||
inputFile
|
||||
)
|
||||
}
|
||||
|
||||
> NOTE: Input source map is using only if output source map is generating.
|
||||
// result CSS with source map
|
||||
console.log(
|
||||
output.css +
|
||||
'/*# sourceMappingURL=data:application/json;base64,' +
|
||||
new Buffer(output.map.toString()).toString('base64') +
|
||||
' */'
|
||||
);
|
||||
```
|
||||
|
||||
### 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:
|
||||
`CSSO` can use data about how `CSS` is used in a markup for better compression. File with this data (`JSON`) can be set using `usage` option. Usage data may contain following sections:
|
||||
|
||||
- `blacklist` – a set of black lists (see [Black list filtering](#black-list-filtering))
|
||||
- `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
|
||||
- `scopes` – groups of classes which never used with classes from other groups on the same 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.
|
||||
All sections are optional. Value of `tags`, `ids` and `classes` should be an array of a string, value of `scopes` should be an array of arrays of strings. Other values are ignoring.
|
||||
|
||||
#### Selector filtering
|
||||
#### White list 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.
|
||||
`tags`, `ids` and `classes` are using on clean stage to filter selectors that contain something not in the lists. 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 all type selectors in selector present in list or selector has no any type selector it isn't filter.
|
||||
|
||||
> `ids` and `classes` names are case sensitive, `tags` – is not.
|
||||
> `ids` and `classes` are case sensitive, `tags` – is not.
|
||||
|
||||
Input CSS:
|
||||
|
||||
@@ -120,15 +278,59 @@ Usage data:
|
||||
}
|
||||
```
|
||||
|
||||
Result CSS:
|
||||
Resulting CSS:
|
||||
|
||||
```css
|
||||
*{color:green}ul,li{color:blue}ul.foo{color:red}
|
||||
```
|
||||
|
||||
Filtering performs for nested selectors too. `:not()` pseudos content is ignoring since the result of matching is unpredictable. Example for the same usage data as above:
|
||||
|
||||
```css
|
||||
:nth-child(2n of ul, ol) { color: red }
|
||||
:nth-child(3n + 1 of img) { color: yellow }
|
||||
:not(div, ol, ul) { color: green }
|
||||
:has(:matches(ul, ol), ul, ol) { color: blue }
|
||||
```
|
||||
|
||||
Turns into:
|
||||
|
||||
```css
|
||||
:nth-child(2n of ul){color:red}:not(div,ol,ul){color:green}:has(:matches(ul),ul){color:blue}
|
||||
```
|
||||
|
||||
#### Black list filtering
|
||||
|
||||
Black list filtering performs the same as white list filtering, but filters things that mentioned in the lists. `blacklist` can contain the lists `tags`, `ids` and `classes`.
|
||||
|
||||
Black list has a higher priority, so when something mentioned in the white list and in the black list then white list occurrence is ignoring. The `:not()` pseudos content ignoring as well.
|
||||
|
||||
```css
|
||||
* { color: green; }
|
||||
ul, ol, li { color: blue; }
|
||||
UL.foo, li.bar { color: red; }
|
||||
```
|
||||
|
||||
Usage data:
|
||||
|
||||
```json
|
||||
{
|
||||
"blacklist": {
|
||||
"tags": ["ul"]
|
||||
},
|
||||
"tags": ["ul", "LI"]
|
||||
}
|
||||
```
|
||||
|
||||
Resulting CSS:
|
||||
|
||||
```css
|
||||
*{color:green}li{color:blue}li.bar{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.
|
||||
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 define lists of class names that exclusively used on some markup. This information allows the optimizer to move rules more agressive. Since it assumes selectors from different scopes don't match for the same element. This can improve rule merging.
|
||||
|
||||
Suppose we have a file:
|
||||
|
||||
@@ -140,13 +342,13 @@ Suppose we have a file:
|
||||
.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:
|
||||
It can be assumed that first two rules are never used with the second two on the same markup. But we can't say that for sure without a markup review. The optimizer doesn't know it either 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:
|
||||
With usage data `CSSO` can produce better output. If follow usage data is provided:
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -157,220 +359,14 @@ But with usage data `CSSO` can get better output. If follow usage data is provid
|
||||
}
|
||||
```
|
||||
|
||||
New result (29 bytes extra saving):
|
||||
The result will be (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.
|
||||
If class name isn't mentioned in the `scopes` it belongs to default scope. `scopes` data doesn't affect `classes` whitelist. If class name mentioned in `scopes` but missed in `classes` (both sections are 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.
|
||||
Note that class name can't be set for several scopes. Also a selector can't have class names from different scopes. In both cases an exception will thrown.
|
||||
|
||||
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`
|
||||
- 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])
|
||||
|
||||
Do the main task – compress AST.
|
||||
|
||||
Options:
|
||||
|
||||
- restructure `Boolean` – do the structure optimisations or not (`true` by default)
|
||||
- usage `Object` - usage data for advanced optimisations (see [Usage data](#usage-data) for details)
|
||||
- logger `Function` - function to track every step of transformations
|
||||
|
||||
#### 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
|
||||
Currently the optimizer doesn't care about changing order safety for out-of-bounds selectors (i.e. selectors that match to elements without class name, e.g. `.scope div` or `.scope ~ :last-child`). It assumes that scoped CSS modules doesn't relay on it's order. It may be fix in future if to be an issue.
|
||||
|
||||
16
node_modules/csso/bin/csso
generated
vendored
16
node_modules/csso/bin/csso
generated
vendored
@@ -1,16 +0,0 @@
|
||||
#!/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
3
node_modules/csso/dist/csso-browser.js
generated
vendored
File diff suppressed because one or more lines are too long
3322
node_modules/csso/dist/csso.js
generated
vendored
Normal file
3322
node_modules/csso/dist/csso.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1
node_modules/csso/dist/csso.min.js
generated
vendored
Normal file
1
node_modules/csso/dist/csso.min.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
28
node_modules/csso/lib/compressor/clean/Atrule.js → node_modules/csso/lib/clean/Atrule.js
generated
vendored
28
node_modules/csso/lib/compressor/clean/Atrule.js → node_modules/csso/lib/clean/Atrule.js
generated
vendored
@@ -1,14 +1,14 @@
|
||||
var resolveKeyword = require('css-tree').keyword;
|
||||
var { hasNoChildren } = require('./utils');
|
||||
|
||||
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 (this.stylesheet !== null) {
|
||||
this.stylesheet.firstAtrulesAllowed = false;
|
||||
}
|
||||
|
||||
if (node.block.type === 'StyleSheet' && node.block.rules.isEmpty()) {
|
||||
if (hasNoChildren(node.block)) {
|
||||
list.remove(item);
|
||||
return;
|
||||
}
|
||||
@@ -16,7 +16,7 @@ module.exports = function cleanAtrule(node, item, list) {
|
||||
|
||||
switch (node.name) {
|
||||
case 'charset':
|
||||
if (node.expression.sequence.isEmpty()) {
|
||||
if (hasNoChildren(node.prelude)) {
|
||||
list.remove(item);
|
||||
return;
|
||||
}
|
||||
@@ -30,7 +30,7 @@ module.exports = function cleanAtrule(node, item, list) {
|
||||
break;
|
||||
|
||||
case 'import':
|
||||
if (!this.root.firstAtrulesAllowed) {
|
||||
if (this.stylesheet === null || !this.stylesheet.firstAtrulesAllowed) {
|
||||
list.remove(item);
|
||||
return;
|
||||
}
|
||||
@@ -50,5 +50,17 @@ module.exports = function cleanAtrule(node, item, list) {
|
||||
}, this);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
var name = resolveKeyword(node.name).basename;
|
||||
if (name === 'keyframes' ||
|
||||
name === 'media' ||
|
||||
name === 'supports') {
|
||||
|
||||
// drop at-rule with no prelude
|
||||
if (hasNoChildren(node.prelude) || hasNoChildren(node.block)) {
|
||||
list.remove(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
14
node_modules/csso/lib/clean/Declaration.js
generated
vendored
Normal file
14
node_modules/csso/lib/clean/Declaration.js
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
var property = require('css-tree').property;
|
||||
|
||||
module.exports = function cleanDeclartion(node, item, list) {
|
||||
if (node.value.children && node.value.children.isEmpty()) {
|
||||
list.remove(item);
|
||||
return;
|
||||
}
|
||||
|
||||
if (property(node.property).custom) {
|
||||
if (/\S/.test(node.value.value)) {
|
||||
node.value.value = node.value.value.trim();
|
||||
}
|
||||
}
|
||||
};
|
||||
9
node_modules/csso/lib/clean/Raw.js
generated
vendored
Normal file
9
node_modules/csso/lib/clean/Raw.js
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
var { isNodeChildrenList } = require('./utils');
|
||||
|
||||
module.exports = function cleanRaw(node, item, list) {
|
||||
// raw in stylesheet or block children
|
||||
if (isNodeChildrenList(this.stylesheet, list) ||
|
||||
isNodeChildrenList(this.block, list)) {
|
||||
list.remove(item);
|
||||
}
|
||||
};
|
||||
93
node_modules/csso/lib/clean/Rule.js
generated
vendored
Normal file
93
node_modules/csso/lib/clean/Rule.js
generated
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
var hasOwnProperty = Object.prototype.hasOwnProperty;
|
||||
var walk = require('css-tree').walk;
|
||||
var { hasNoChildren } = require('./utils');
|
||||
|
||||
function cleanUnused(selectorList, usageData) {
|
||||
selectorList.children.each(function(selector, item, list) {
|
||||
var shouldRemove = false;
|
||||
|
||||
walk(selector, function(node) {
|
||||
// ignore nodes in nested selectors
|
||||
if (this.selector === null || this.selector === selectorList) {
|
||||
switch (node.type) {
|
||||
case 'SelectorList':
|
||||
// TODO: remove toLowerCase when pseudo selectors will be normalized
|
||||
// ignore selectors inside :not()
|
||||
if (this.function === null || this.function.name.toLowerCase() !== 'not') {
|
||||
if (cleanUnused(node, usageData)) {
|
||||
shouldRemove = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'ClassSelector':
|
||||
if (usageData.whitelist !== null &&
|
||||
usageData.whitelist.classes !== null &&
|
||||
!hasOwnProperty.call(usageData.whitelist.classes, node.name)) {
|
||||
shouldRemove = true;
|
||||
}
|
||||
if (usageData.blacklist !== null &&
|
||||
usageData.blacklist.classes !== null &&
|
||||
hasOwnProperty.call(usageData.blacklist.classes, node.name)) {
|
||||
shouldRemove = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'IdSelector':
|
||||
if (usageData.whitelist !== null &&
|
||||
usageData.whitelist.ids !== null &&
|
||||
!hasOwnProperty.call(usageData.whitelist.ids, node.name)) {
|
||||
shouldRemove = true;
|
||||
}
|
||||
if (usageData.blacklist !== null &&
|
||||
usageData.blacklist.ids !== null &&
|
||||
hasOwnProperty.call(usageData.blacklist.ids, node.name)) {
|
||||
shouldRemove = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'TypeSelector':
|
||||
// TODO: remove toLowerCase when type selectors will be normalized
|
||||
// ignore universal selectors
|
||||
if (node.name.charAt(node.name.length - 1) !== '*') {
|
||||
if (usageData.whitelist !== null &&
|
||||
usageData.whitelist.tags !== null &&
|
||||
!hasOwnProperty.call(usageData.whitelist.tags, node.name.toLowerCase())) {
|
||||
shouldRemove = true;
|
||||
}
|
||||
if (usageData.blacklist !== null &&
|
||||
usageData.blacklist.tags !== null &&
|
||||
hasOwnProperty.call(usageData.blacklist.tags, node.name.toLowerCase())) {
|
||||
shouldRemove = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (shouldRemove) {
|
||||
list.remove(item);
|
||||
}
|
||||
});
|
||||
|
||||
return selectorList.children.isEmpty();
|
||||
}
|
||||
|
||||
module.exports = function cleanRule(node, item, list, options) {
|
||||
if (hasNoChildren(node.prelude) || hasNoChildren(node.block)) {
|
||||
list.remove(item);
|
||||
return;
|
||||
}
|
||||
|
||||
var usageData = options.usage;
|
||||
|
||||
if (usageData && (usageData.whitelist !== null || usageData.blacklist !== null)) {
|
||||
cleanUnused(node.prelude, usageData);
|
||||
|
||||
if (hasNoChildren(node.prelude)) {
|
||||
list.remove(item);
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
19
node_modules/csso/lib/clean/TypeSelector.js
generated
vendored
Normal file
19
node_modules/csso/lib/clean/TypeSelector.js
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
// remove useless universal selector
|
||||
module.exports = function cleanTypeSelector(node, item, list) {
|
||||
var name = item.data.name;
|
||||
|
||||
// check it's a non-namespaced universal selector
|
||||
if (name !== '*') {
|
||||
return;
|
||||
}
|
||||
|
||||
// remove when universal selector before other selectors
|
||||
var nextType = item.next && item.next.data.type;
|
||||
if (nextType === 'IdSelector' ||
|
||||
nextType === 'ClassSelector' ||
|
||||
nextType === 'AttributeSelector' ||
|
||||
nextType === 'PseudoClassSelector' ||
|
||||
nextType === 'PseudoElementSelector') {
|
||||
list.remove(item);
|
||||
}
|
||||
};
|
||||
30
node_modules/csso/lib/clean/WhiteSpace.js
generated
vendored
Normal file
30
node_modules/csso/lib/clean/WhiteSpace.js
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
var { isNodeChildrenList } = require('./utils');
|
||||
|
||||
function isSafeOperator(node) {
|
||||
return node.type === 'Operator' && node.value !== '+' && node.value !== '-';
|
||||
}
|
||||
|
||||
module.exports = function cleanWhitespace(node, item, list) {
|
||||
// remove when first or last item in sequence
|
||||
if (item.next === null || item.prev === null) {
|
||||
list.remove(item);
|
||||
return;
|
||||
}
|
||||
|
||||
// white space in stylesheet or block children
|
||||
if (isNodeChildrenList(this.stylesheet, list) ||
|
||||
isNodeChildrenList(this.block, list)) {
|
||||
list.remove(item);
|
||||
return;
|
||||
}
|
||||
|
||||
if (item.next.data.type === 'WhiteSpace') {
|
||||
list.remove(item);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isSafeOperator(item.prev.data) || isSafeOperator(item.next.data)) {
|
||||
list.remove(item);
|
||||
return;
|
||||
}
|
||||
};
|
||||
20
node_modules/csso/lib/clean/index.js
generated
vendored
Normal file
20
node_modules/csso/lib/clean/index.js
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
var walk = require('css-tree').walk;
|
||||
var handlers = {
|
||||
Atrule: require('./Atrule'),
|
||||
Comment: require('./Comment'),
|
||||
Declaration: require('./Declaration'),
|
||||
Raw: require('./Raw'),
|
||||
Rule: require('./Rule'),
|
||||
TypeSelector: require('./TypeSelector'),
|
||||
WhiteSpace: require('./WhiteSpace')
|
||||
};
|
||||
|
||||
module.exports = function(ast, options) {
|
||||
walk(ast, {
|
||||
leave: function(node, item, list) {
|
||||
if (handlers.hasOwnProperty(node.type)) {
|
||||
handlers[node.type].call(this, node, item, list, options);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
8
node_modules/csso/lib/clean/utils.js
generated
vendored
Normal file
8
node_modules/csso/lib/clean/utils.js
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
module.exports = {
|
||||
hasNoChildren: function(node) {
|
||||
return !node || !node.children || node.children.isEmpty();
|
||||
},
|
||||
isNodeChildrenList: function(node, list) {
|
||||
return node !== null && node.children === list;
|
||||
}
|
||||
};
|
||||
323
node_modules/csso/lib/cli.js
generated
vendored
323
node_modules/csso/lib/cli.js
generated
vendored
@@ -1,323 +0,0 @@
|
||||
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
|
||||
};
|
||||
}
|
||||
|
||||
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('--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 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,
|
||||
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;
|
||||
}
|
||||
};
|
||||
197
node_modules/csso/lib/compress.js
generated
vendored
Normal file
197
node_modules/csso/lib/compress.js
generated
vendored
Normal file
@@ -0,0 +1,197 @@
|
||||
var List = require('css-tree').List;
|
||||
var clone = require('css-tree').clone;
|
||||
var usageUtils = require('./usage');
|
||||
var clean = require('./clean');
|
||||
var replace = require('./replace');
|
||||
var restructure = require('./restructure');
|
||||
var walk = require('css-tree').walk;
|
||||
|
||||
function readChunk(children, specialComments) {
|
||||
var buffer = new List();
|
||||
var nonSpaceTokenInBuffer = false;
|
||||
var protectedComment;
|
||||
|
||||
children.nextUntil(children.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 !== 'WhiteSpace') {
|
||||
nonSpaceTokenInBuffer = true;
|
||||
}
|
||||
|
||||
buffer.insert(list.remove(item));
|
||||
});
|
||||
|
||||
return {
|
||||
comment: protectedComment,
|
||||
stylesheet: {
|
||||
type: 'StyleSheet',
|
||||
loc: null,
|
||||
children: buffer
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function compressChunk(ast, firstAtrulesAllowed, num, options) {
|
||||
options.logger('Compress block #' + num, null, true);
|
||||
|
||||
var seed = 1;
|
||||
|
||||
if (ast.type === 'StyleSheet') {
|
||||
ast.firstAtrulesAllowed = firstAtrulesAllowed;
|
||||
ast.id = seed++;
|
||||
}
|
||||
|
||||
walk(ast, {
|
||||
visit: 'Atrule',
|
||||
enter: function markScopes(node) {
|
||||
if (node.block !== null) {
|
||||
node.block.id = seed++;
|
||||
}
|
||||
}
|
||||
});
|
||||
options.logger('init', ast);
|
||||
|
||||
// remove redundant
|
||||
clean(ast, options);
|
||||
options.logger('clean', ast);
|
||||
|
||||
// replace nodes for shortened forms
|
||||
replace(ast, options);
|
||||
options.logger('replace', ast);
|
||||
|
||||
// structure optimisations
|
||||
if (options.restructuring) {
|
||||
restructure(ast, options);
|
||||
}
|
||||
|
||||
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) {
|
||||
if ('restructure' in options) {
|
||||
return options.restructure;
|
||||
}
|
||||
|
||||
return 'restructuring' in options ? options.restructuring : true;
|
||||
}
|
||||
|
||||
function wrapBlock(block) {
|
||||
return new List().appendData({
|
||||
type: 'Rule',
|
||||
loc: null,
|
||||
prelude: {
|
||||
type: 'SelectorList',
|
||||
loc: null,
|
||||
children: new List().appendData({
|
||||
type: 'Selector',
|
||||
loc: null,
|
||||
children: new List().appendData({
|
||||
type: 'TypeSelector',
|
||||
loc: null,
|
||||
name: 'x'
|
||||
})
|
||||
})
|
||||
},
|
||||
block: block
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = function compress(ast, options) {
|
||||
ast = ast || { type: 'StyleSheet', loc: null, children: new List() };
|
||||
options = options || {};
|
||||
|
||||
var compressOptions = {
|
||||
logger: typeof options.logger === 'function' ? options.logger : function() {},
|
||||
restructuring: getRestructureOption(options),
|
||||
forceMediaMerge: Boolean(options.forceMediaMerge),
|
||||
usage: options.usage ? usageUtils.buildIndex(options.usage) : false
|
||||
};
|
||||
var specialComments = getCommentsOption(options);
|
||||
var firstAtrulesAllowed = true;
|
||||
var input;
|
||||
var output = new List();
|
||||
var chunk;
|
||||
var chunkNum = 1;
|
||||
var chunkChildren;
|
||||
|
||||
if (options.clone) {
|
||||
ast = clone(ast);
|
||||
}
|
||||
|
||||
if (ast.type === 'StyleSheet') {
|
||||
input = ast.children;
|
||||
ast.children = output;
|
||||
} else {
|
||||
input = wrapBlock(ast);
|
||||
}
|
||||
|
||||
do {
|
||||
chunk = readChunk(input, Boolean(specialComments));
|
||||
compressChunk(chunk.stylesheet, firstAtrulesAllowed, chunkNum++, compressOptions);
|
||||
chunkChildren = chunk.stylesheet.children;
|
||||
|
||||
if (chunk.comment) {
|
||||
// add \n before comment if there is another content in output
|
||||
if (!output.isEmpty()) {
|
||||
output.insert(List.createItem({
|
||||
type: 'Raw',
|
||||
value: '\n'
|
||||
}));
|
||||
}
|
||||
|
||||
output.insert(List.createItem(chunk.comment));
|
||||
|
||||
// add \n after comment if chunk is not empty
|
||||
if (!chunkChildren.isEmpty()) {
|
||||
output.insert(List.createItem({
|
||||
type: 'Raw',
|
||||
value: '\n'
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
if (firstAtrulesAllowed && !chunkChildren.isEmpty()) {
|
||||
var lastRule = chunkChildren.last();
|
||||
|
||||
if (lastRule.type !== 'Atrule' ||
|
||||
(lastRule.name !== 'import' && lastRule.name !== 'charset')) {
|
||||
firstAtrulesAllowed = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (specialComments !== 'exclamation') {
|
||||
specialComments = false;
|
||||
}
|
||||
|
||||
output.appendList(chunkChildren);
|
||||
} while (!input.isEmpty());
|
||||
|
||||
return {
|
||||
ast: ast
|
||||
};
|
||||
};
|
||||
5
node_modules/csso/lib/compressor/clean/Declaration.js
generated
vendored
5
node_modules/csso/lib/compressor/clean/Declaration.js
generated
vendored
@@ -1,5 +0,0 @@
|
||||
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
9
node_modules/csso/lib/compressor/clean/Identifier.js
generated
vendored
@@ -1,9 +0,0 @@
|
||||
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
39
node_modules/csso/lib/compressor/clean/Ruleset.js
generated
vendored
@@ -1,39 +0,0 @@
|
||||
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
16
node_modules/csso/lib/compressor/clean/Space.js
generated
vendored
@@ -1,16 +0,0 @@
|
||||
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
17
node_modules/csso/lib/compressor/clean/index.js
generated
vendored
@@ -1,17 +0,0 @@
|
||||
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
9
node_modules/csso/lib/compressor/compress/Atrule.js
generated
vendored
@@ -1,9 +0,0 @@
|
||||
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);
|
||||
}
|
||||
};
|
||||
22
node_modules/csso/lib/compressor/compress/Number.js
generated
vendored
22
node_modules/csso/lib/compressor/compress/Number.js
generated
vendored
@@ -1,22 +0,0 @@
|
||||
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;
|
||||
18
node_modules/csso/lib/compressor/compress/Value.js
generated
vendored
18
node_modules/csso/lib/compressor/compress/Value.js
generated
vendored
@@ -1,18 +0,0 @@
|
||||
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);
|
||||
}
|
||||
};
|
||||
22
node_modules/csso/lib/compressor/compress/index.js
generated
vendored
22
node_modules/csso/lib/compressor/compress/index.js
generated
vendored
@@ -1,22 +0,0 @@
|
||||
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);
|
||||
}
|
||||
});
|
||||
};
|
||||
168
node_modules/csso/lib/compressor/index.js
generated
vendored
168
node_modules/csso/lib/compressor/index.js
generated
vendored
@@ -1,168 +0,0 @@
|
||||
var List = require('../utils/list');
|
||||
var usageUtils = require('./usage');
|
||||
var clean = require('./clean');
|
||||
var compress = require('./compress');
|
||||
var restructureBlock = require('./restructure');
|
||||
var walkRules = require('../utils/walk').rules;
|
||||
|
||||
function readBlock(stylesheet) {
|
||||
var buffer = new List();
|
||||
var nonSpaceTokenInBuffer = false;
|
||||
var protectedComment;
|
||||
|
||||
stylesheet.rules.nextUntil(stylesheet.rules.head, function(node, item, list) {
|
||||
if (node.type === 'Comment' && node.value.charAt(0) === '!') {
|
||||
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',
|
||||
rules: buffer
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function compressBlock(ast, usageData, num, logger) {
|
||||
logger('Compress block #' + num, null, true);
|
||||
|
||||
var seed = 1;
|
||||
ast.firstAtrulesAllowed = ast.firstAtrulesAllowed;
|
||||
walkRules(ast, function() {
|
||||
if (!this.stylesheet.id) {
|
||||
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;
|
||||
}
|
||||
|
||||
module.exports = function compress(ast, options) {
|
||||
options = options || {};
|
||||
ast = ast || { type: 'StyleSheet', rules: new List() };
|
||||
|
||||
var logger = typeof options.logger === 'function' ? options.logger : Function();
|
||||
var restructuring =
|
||||
'restructure' in options ? options.restructure :
|
||||
'restructuring' in options ? options.restructuring :
|
||||
true;
|
||||
var result = new List();
|
||||
var block;
|
||||
var firstAtrulesAllowed = true;
|
||||
var blockNum = 1;
|
||||
var blockRules;
|
||||
var blockMode = false;
|
||||
var usageData = false;
|
||||
var info = ast.info || null;
|
||||
|
||||
if (ast.type !== 'StyleSheet') {
|
||||
blockMode = true;
|
||||
ast = {
|
||||
type: 'StyleSheet',
|
||||
rules: new List([{
|
||||
type: 'Ruleset',
|
||||
selector: {
|
||||
type: 'Selector',
|
||||
selectors: new List([{
|
||||
type: 'SimpleSelector',
|
||||
sequence: new List([{
|
||||
type: 'Identifier',
|
||||
name: 'x'
|
||||
}])
|
||||
}])
|
||||
},
|
||||
block: ast
|
||||
}])
|
||||
};
|
||||
}
|
||||
|
||||
if (options.usage) {
|
||||
usageData = usageUtils.buildIndex(options.usage);
|
||||
}
|
||||
|
||||
do {
|
||||
block = readBlock(ast);
|
||||
// console.log(JSON.stringify(block.stylesheet, null, 2));
|
||||
block.stylesheet.firstAtrulesAllowed = firstAtrulesAllowed;
|
||||
block.stylesheet = compressBlock(block.stylesheet, usageData, blockNum++, logger);
|
||||
|
||||
// structure optimisations
|
||||
if (restructuring) {
|
||||
restructureBlock(block.stylesheet, usageData, logger);
|
||||
}
|
||||
|
||||
blockRules = block.stylesheet.rules;
|
||||
|
||||
if (block.comment) {
|
||||
// add \n before comment if there is another content in result
|
||||
if (!result.isEmpty()) {
|
||||
result.insert(List.createItem({
|
||||
type: 'Raw',
|
||||
value: '\n'
|
||||
}));
|
||||
}
|
||||
|
||||
result.insert(List.createItem(block.comment));
|
||||
|
||||
// add \n after comment if block is not empty
|
||||
if (!blockRules.isEmpty()) {
|
||||
result.insert(List.createItem({
|
||||
type: 'Raw',
|
||||
value: '\n'
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
if (firstAtrulesAllowed && !blockRules.isEmpty()) {
|
||||
var lastRule = blockRules.last();
|
||||
|
||||
if (lastRule.type !== 'Atrule' ||
|
||||
(lastRule.name !== 'import' && lastRule.name !== 'charset')) {
|
||||
firstAtrulesAllowed = false;
|
||||
}
|
||||
}
|
||||
|
||||
result.appendList(blockRules);
|
||||
} while (!ast.rules.isEmpty());
|
||||
|
||||
if (blockMode) {
|
||||
result = !result.isEmpty() ? result.first().block : {
|
||||
type: 'Block',
|
||||
info: info,
|
||||
declarations: new List()
|
||||
};
|
||||
} else {
|
||||
result = {
|
||||
type: 'StyleSheet',
|
||||
info: info,
|
||||
rules: result
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
ast: result
|
||||
};
|
||||
};
|
||||
35
node_modules/csso/lib/compressor/restructure/2-mergeAtrule.js
generated
vendored
35
node_modules/csso/lib/compressor/restructure/2-mergeAtrule.js
generated
vendored
@@ -1,35 +0,0 @@
|
||||
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
42
node_modules/csso/lib/compressor/restructure/3-disjoinRuleset.js
generated
vendored
@@ -1,42 +0,0 @@
|
||||
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);
|
||||
}
|
||||
});
|
||||
};
|
||||
248
node_modules/csso/lib/compressor/restructure/6-restructBlock.js
generated
vendored
248
node_modules/csso/lib/compressor/restructure/6-restructBlock.js
generated
vendored
@@ -1,248 +0,0 @@
|
||||
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 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 hack9 = '';
|
||||
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 (name === '\\9') {
|
||||
hack9 = name;
|
||||
}
|
||||
|
||||
if (DONT_MIX_VALUE.hasOwnProperty(realName) &&
|
||||
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() + '|' + hack9 + 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);
|
||||
});
|
||||
};
|
||||
142
node_modules/csso/lib/compressor/restructure/8-restructRuleset.js
generated
vendored
142
node_modules/csso/lib/compressor/restructure/8-restructRuleset.js
generated
vendored
@@ -1,142 +0,0 @@
|
||||
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 inList(selector) {
|
||||
return selector.compareMarker in this;
|
||||
}
|
||||
|
||||
function processRuleset(node, item, list) {
|
||||
var avoidRulesMerge = this.stylesheet.avoidRulesMerge;
|
||||
var selectors = node.selector.selectors;
|
||||
var block = node.block;
|
||||
var skippedCompareMarkers = Object.create(null);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// try prev ruleset if simpleselectors has no equal specifity and element selector
|
||||
if (prevSelectors.some(inList, skippedCompareMarkers)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// try to join by selectors
|
||||
if (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
|
||||
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 (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 (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 (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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
prevSelectors.each(function(data) {
|
||||
skippedCompareMarkers[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
35
node_modules/csso/lib/compressor/restructure/index.js
generated
vendored
@@ -1,35 +0,0 @@
|
||||
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);
|
||||
};
|
||||
44
node_modules/csso/lib/compressor/restructure/prepare/index.js
generated
vendored
44
node_modules/csso/lib/compressor/restructure/prepare/index.js
generated
vendored
@@ -1,44 +0,0 @@
|
||||
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
|
||||
};
|
||||
};
|
||||
48
node_modules/csso/lib/compressor/restructure/prepare/specificity.js
generated
vendored
48
node_modules/csso/lib/compressor/restructure/prepare/specificity.js
generated
vendored
@@ -1,48 +0,0 @@
|
||||
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];
|
||||
};
|
||||
65
node_modules/csso/lib/index.js
generated
vendored
65
node_modules/csso/lib/index.js
generated
vendored
@@ -1,8 +1,7 @@
|
||||
var parse = require('./parser');
|
||||
var compress = require('./compressor');
|
||||
var translate = require('./utils/translate');
|
||||
var translateWithSourceMap = require('./utils/translateWithSourceMap');
|
||||
var walkers = require('./utils/walk');
|
||||
var csstree = require('css-tree');
|
||||
var parse = csstree.parse;
|
||||
var compress = require('./compress');
|
||||
var generate = csstree.generate;
|
||||
|
||||
function debugOutput(name, options, startTime, data) {
|
||||
if (options.debug) {
|
||||
@@ -23,7 +22,7 @@ function createDefaultLogger(level) {
|
||||
}
|
||||
|
||||
if (level > 1 && ast) {
|
||||
var css = translate(ast, true);
|
||||
var css = generate(ast);
|
||||
|
||||
// when level 2, limit css to 256 symbols
|
||||
if (level === 2 && css.length > 256) {
|
||||
@@ -58,6 +57,16 @@ function buildCompressOptions(options) {
|
||||
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 || {};
|
||||
|
||||
@@ -73,22 +82,36 @@ function minify(context, source, options) {
|
||||
})
|
||||
);
|
||||
|
||||
// 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))
|
||||
);
|
||||
|
||||
// translate
|
||||
// after compress handlers
|
||||
if (options.afterCompress) {
|
||||
debugOutput('afterCompress', options, Date.now(),
|
||||
runHandler(compressResult, options, options.afterCompress)
|
||||
);
|
||||
}
|
||||
|
||||
// generate
|
||||
if (options.sourceMap) {
|
||||
result = debugOutput('translateWithSourceMap', options, Date.now(), (function() {
|
||||
var tmp = translateWithSourceMap(compressResult.ast);
|
||||
result = debugOutput('generate(sourceMap: true)', options, Date.now(), (function() {
|
||||
var tmp = generate(compressResult.ast, { sourceMap: true });
|
||||
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),
|
||||
result = debugOutput('generate', options, Date.now(), {
|
||||
css: generate(compressResult.ast),
|
||||
map: null
|
||||
});
|
||||
}
|
||||
@@ -98,10 +121,10 @@ function minify(context, source, options) {
|
||||
|
||||
function minifyStylesheet(source, options) {
|
||||
return minify('stylesheet', source, options);
|
||||
};
|
||||
}
|
||||
|
||||
function minifyBlock(source, options) {
|
||||
return minify('block', source, options);
|
||||
return minify('declarationList', source, options);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
@@ -111,14 +134,8 @@ module.exports = {
|
||||
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
|
||||
// css syntax parser/walkers/generator/etc
|
||||
syntax: Object.assign({
|
||||
compress: compress
|
||||
}, csstree)
|
||||
};
|
||||
|
||||
46
node_modules/csso/lib/parser/const.js
generated
vendored
46
node_modules/csso/lib/parser/const.js
generated
vendored
@@ -1,46 +0,0 @@
|
||||
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++;
|
||||
// }
|
||||
1856
node_modules/csso/lib/parser/index.js
generated
vendored
1856
node_modules/csso/lib/parser/index.js
generated
vendored
File diff suppressed because it is too large
Load Diff
380
node_modules/csso/lib/parser/scanner.js
generated
vendored
380
node_modules/csso/lib/parser/scanner.js
generated
vendored
@@ -1,380 +0,0 @@
|
||||
'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_SQ = 4;
|
||||
var STRING_DQ = 5;
|
||||
|
||||
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_SQ;
|
||||
SYMBOL_CATEGORY[DOUBLE_QUOTE] = STRING_DQ;
|
||||
|
||||
//
|
||||
// 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.lastPos = this.pos;
|
||||
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() {
|
||||
this.prevToken = this.token;
|
||||
|
||||
if (this.buffer.length !== 0) {
|
||||
this.token = this.buffer.shift();
|
||||
} else if (!this.eof) {
|
||||
this.token = this.getToken();
|
||||
} else {
|
||||
this.token = null;
|
||||
}
|
||||
|
||||
return this.token;
|
||||
},
|
||||
|
||||
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 lastPos;
|
||||
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_SQ:
|
||||
case STRING_DQ:
|
||||
type = TokenType.String;
|
||||
value = this.readString(code);
|
||||
break;
|
||||
|
||||
case WHITESPACE:
|
||||
type = TokenType.Space;
|
||||
value = this.readSpaces();
|
||||
break;
|
||||
|
||||
case PUNCTUATOR:
|
||||
if (code === SLASH) {
|
||||
next = this.source.charCodeAt(this.pos + 1);
|
||||
|
||||
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';
|
||||
}
|
||||
|
||||
lastPos = this.lastPos === 0 ? this.lastPos : this.lastPos - 1;
|
||||
this.lastPos = this.pos;
|
||||
this.eof = this.pos === this.source.length;
|
||||
|
||||
return {
|
||||
type: type,
|
||||
value: value,
|
||||
|
||||
offset: lastPos,
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = Scanner;
|
||||
9
node_modules/csso/lib/replace/Atrule.js
generated
vendored
Normal file
9
node_modules/csso/lib/replace/Atrule.js
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
var resolveKeyword = require('css-tree').keyword;
|
||||
var compressKeyframes = require('./atrule/keyframes');
|
||||
|
||||
module.exports = function(node) {
|
||||
// compress @keyframe selectors
|
||||
if (resolveKeyword(node.name).basename === 'keyframes') {
|
||||
compressKeyframes(node);
|
||||
}
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
// 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 escapesRx = /\\([0-9A-Fa-f]{1,6})(\r\n|[ \t\n\f\r])?|\\./g;
|
||||
var blockUnquoteRx = /^(-?\d|--)|[\u0000-\u002c\u002e\u002f\u003A-\u0040\u005B-\u005E\u0060\u007B-\u009f]/;
|
||||
|
||||
function canUnquote(value) {
|
||||
@@ -26,7 +26,7 @@ module.exports = function(node) {
|
||||
if (canUnquote(unquotedValue)) {
|
||||
node.value = {
|
||||
type: 'Identifier',
|
||||
info: attrValue.info,
|
||||
loc: attrValue.loc,
|
||||
name: unquotedValue
|
||||
};
|
||||
}
|
||||
@@ -1,4 +1,10 @@
|
||||
var packNumber = require('./Number.js').pack;
|
||||
var packNumber = require('./Number').pack;
|
||||
var MATH_FUNCTIONS = {
|
||||
'calc': true,
|
||||
'min': true,
|
||||
'max': true,
|
||||
'clamp': true
|
||||
};
|
||||
var LENGTH_UNIT = {
|
||||
// absolute length units
|
||||
'px': true,
|
||||
@@ -23,11 +29,11 @@ var LENGTH_UNIT = {
|
||||
};
|
||||
|
||||
module.exports = function compressDimension(node, item) {
|
||||
var value = packNumber(node.value);
|
||||
var value = packNumber(node.value, item);
|
||||
|
||||
node.value = value;
|
||||
|
||||
if (value === '0' && this.declaration) {
|
||||
if (value === '0' && this.declaration !== null && this.atrulePrelude === null) {
|
||||
var unit = node.unit.toLowerCase();
|
||||
|
||||
// only length values can be compressed
|
||||
@@ -35,19 +41,21 @@ module.exports = function compressDimension(node, item) {
|
||||
return;
|
||||
}
|
||||
|
||||
// issue #200: don't remove units in flex property as it could change value meaning
|
||||
if (this.declaration.property.name === 'flex') {
|
||||
// issue #362: shouldn't remove unit in -ms-flex since it breaks flex in IE10/11
|
||||
// issue #200: shouldn't remove unit in flex since it breaks flex in IE10/11
|
||||
if (this.declaration.property === '-ms-flex' ||
|
||||
this.declaration.property === 'flex') {
|
||||
return;
|
||||
}
|
||||
|
||||
// issue #222: don't remove units inside calc
|
||||
if (this['function'] && this['function'].name === 'calc') {
|
||||
if (this.function && MATH_FUNCTIONS.hasOwnProperty(this.function.name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
item.data = {
|
||||
type: 'Number',
|
||||
info: node.info,
|
||||
loc: node.loc,
|
||||
value: value
|
||||
};
|
||||
}
|
||||
39
node_modules/csso/lib/replace/Number.js
generated
vendored
Normal file
39
node_modules/csso/lib/replace/Number.js
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
var OMIT_PLUSSIGN = /^(?:\+|(-))?0*(\d*)(?:\.0*|(\.\d*?)0*)?$/;
|
||||
var KEEP_PLUSSIGN = /^([\+\-])?0*(\d*)(?:\.0*|(\.\d*?)0*)?$/;
|
||||
var unsafeToRemovePlusSignAfter = {
|
||||
Dimension: true,
|
||||
Hash: true,
|
||||
Identifier: true,
|
||||
Number: true,
|
||||
Raw: true,
|
||||
UnicodeRange: true
|
||||
};
|
||||
|
||||
function packNumber(value, item) {
|
||||
// omit plus sign only if no prev or prev is safe type
|
||||
var regexp = item && item.prev !== null && unsafeToRemovePlusSignAfter.hasOwnProperty(item.prev.data.type)
|
||||
? KEEP_PLUSSIGN
|
||||
: OMIT_PLUSSIGN;
|
||||
|
||||
// 100 -> '100'
|
||||
// 00100 -> '100'
|
||||
// +100 -> '100' (only when safe, e.g. omitting plus sign for 1px+1px leads to single dimension instead of two)
|
||||
// -100 -> '-100'
|
||||
// 0.123 -> '.123'
|
||||
// 0.12300 -> '.123'
|
||||
// 0.0 -> ''
|
||||
// 0 -> ''
|
||||
// -0 -> '-'
|
||||
value = String(value).replace(regexp, '$1$2$3');
|
||||
|
||||
if (value === '' || value === '-') {
|
||||
value = '0';
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
module.exports = function(node, item) {
|
||||
node.value = packNumber(node.value, item);
|
||||
};
|
||||
module.exports.pack = packNumber;
|
||||
36
node_modules/csso/lib/replace/Percentage.js
generated
vendored
Normal file
36
node_modules/csso/lib/replace/Percentage.js
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
var lexer = require('css-tree').lexer;
|
||||
var packNumber = require('./Number').pack;
|
||||
var blacklist = new Set([
|
||||
// see https://github.com/jakubpawlowicz/clean-css/issues/957
|
||||
'width',
|
||||
'min-width',
|
||||
'max-width',
|
||||
'height',
|
||||
'min-height',
|
||||
'max-height',
|
||||
|
||||
// issue #410: Don’t remove units in flex-basis value for (-ms-)flex shorthand
|
||||
// issue #362: shouldn't remove unit in -ms-flex since it breaks flex in IE10/11
|
||||
// issue #200: shouldn't remove unit in flex since it breaks flex in IE10/11
|
||||
'flex',
|
||||
'-ms-flex'
|
||||
]);
|
||||
|
||||
module.exports = function compressPercentage(node, item) {
|
||||
node.value = packNumber(node.value, item);
|
||||
|
||||
if (node.value === '0' && this.declaration && !blacklist.has(this.declaration.property)) {
|
||||
// try to convert a number
|
||||
item.data = {
|
||||
type: 'Number',
|
||||
loc: node.loc,
|
||||
value: node.value
|
||||
};
|
||||
|
||||
// that's ok only when new value matches on length
|
||||
if (!lexer.matchDeclaration(this.declaration).isType(item.data, 'length')) {
|
||||
// otherwise rollback changes
|
||||
item.data = node;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,12 +1,12 @@
|
||||
module.exports = function(node) {
|
||||
var value = node.value;
|
||||
|
||||
// remove escaped \n, i.e.
|
||||
// remove escaped newlines, i.e.
|
||||
// .a { content: "foo\
|
||||
// bar"}
|
||||
// ->
|
||||
// .a { content: "foobar" }
|
||||
value = value.replace(/\\\n/g, '');
|
||||
value = value.replace(/\\(\r\n|\r|\n|\f)/g, '');
|
||||
|
||||
node.value = value;
|
||||
};
|
||||
@@ -21,7 +21,7 @@ module.exports = function(node) {
|
||||
if (SAFE_URL.test(url)) {
|
||||
node.value = {
|
||||
type: 'Raw',
|
||||
info: node.value.info,
|
||||
loc: node.value.loc,
|
||||
value: url
|
||||
};
|
||||
} else {
|
||||
20
node_modules/csso/lib/replace/Value.js
generated
vendored
Normal file
20
node_modules/csso/lib/replace/Value.js
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
var resolveName = require('css-tree').property;
|
||||
var handlers = {
|
||||
'font': require('./property/font'),
|
||||
'font-weight': require('./property/font-weight'),
|
||||
'background': require('./property/background'),
|
||||
'border': require('./property/border'),
|
||||
'outline': require('./property/border')
|
||||
};
|
||||
|
||||
module.exports = function compressValue(node) {
|
||||
if (!this.declaration) {
|
||||
return;
|
||||
}
|
||||
|
||||
var property = resolveName(this.declaration.property);
|
||||
|
||||
if (handlers.hasOwnProperty(property.basename)) {
|
||||
handlers[property.basename](node);
|
||||
}
|
||||
};
|
||||
@@ -1,17 +1,17 @@
|
||||
module.exports = function(node) {
|
||||
node.block.rules.each(function(ruleset) {
|
||||
ruleset.selector.selectors.each(function(simpleselector) {
|
||||
simpleselector.sequence.each(function(data, item) {
|
||||
node.block.children.each(function(rule) {
|
||||
rule.prelude.children.each(function(simpleselector) {
|
||||
simpleselector.children.each(function(data, item) {
|
||||
if (data.type === 'Percentage' && data.value === '100') {
|
||||
item.data = {
|
||||
type: 'Identifier',
|
||||
info: data.info,
|
||||
type: 'TypeSelector',
|
||||
loc: data.loc,
|
||||
name: 'to'
|
||||
};
|
||||
} else if (data.type === 'Identifier' && data.name === 'from') {
|
||||
} else if (data.type === 'TypeSelector' && data.name === 'from') {
|
||||
item.data = {
|
||||
type: 'Percentage',
|
||||
info: data.info,
|
||||
loc: data.loc,
|
||||
value: '0'
|
||||
};
|
||||
}
|
||||
129
node_modules/csso/lib/compressor/compress/color.js → node_modules/csso/lib/replace/color.js
generated
vendored
129
node_modules/csso/lib/compressor/compress/color.js → node_modules/csso/lib/replace/color.js
generated
vendored
@@ -1,5 +1,5 @@
|
||||
var List = require('../../utils/list.js');
|
||||
var packNumber = require('./Number.js').pack;
|
||||
var lexer = require('css-tree').lexer;
|
||||
var packNumber = require('./Number').pack;
|
||||
|
||||
// http://www.w3.org/TR/css3-color/#svg-color
|
||||
var NAME_TO_HEX = {
|
||||
@@ -218,7 +218,7 @@ function hslToRgb(h, s, l, a) {
|
||||
var g;
|
||||
var b;
|
||||
|
||||
if (s == 0) {
|
||||
if (s === 0) {
|
||||
r = g = b = l; // achromatic
|
||||
} else {
|
||||
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
||||
@@ -243,46 +243,45 @@ function toHex(value) {
|
||||
}
|
||||
|
||||
function parseFunctionArgs(functionArgs, count, rgb) {
|
||||
var argument = functionArgs.head;
|
||||
var cursor = functionArgs.head;
|
||||
var args = [];
|
||||
var wasValue = false;
|
||||
|
||||
while (argument !== null) {
|
||||
var argumentPart = argument.data.sequence.head;
|
||||
var wasValue = false;
|
||||
while (cursor !== null) {
|
||||
var node = cursor.data;
|
||||
var type = node.type;
|
||||
|
||||
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
|
||||
switch (type) {
|
||||
case 'Number':
|
||||
case 'Percentage':
|
||||
if (wasValue) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
argumentPart = argumentPart.next;
|
||||
wasValue = true;
|
||||
args.push({
|
||||
type: type,
|
||||
value: Number(node.value)
|
||||
});
|
||||
break;
|
||||
|
||||
case 'Operator':
|
||||
if (node.value === ',') {
|
||||
if (!wasValue) {
|
||||
return;
|
||||
}
|
||||
wasValue = false;
|
||||
} else if (wasValue || node.value !== '+') {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// something we couldn't understand
|
||||
return;
|
||||
}
|
||||
|
||||
argument = argument.next;
|
||||
cursor = cursor.next;
|
||||
}
|
||||
|
||||
if (args.length !== count) {
|
||||
@@ -357,7 +356,7 @@ function compressFunction(node, item, list) {
|
||||
var args;
|
||||
|
||||
if (functionName === 'rgba' || functionName === 'hsla') {
|
||||
args = parseFunctionArgs(node.arguments, 4, functionName === 'rgba');
|
||||
args = parseFunctionArgs(node.children, 4, functionName === 'rgba');
|
||||
|
||||
if (!args) {
|
||||
// something went wrong
|
||||
@@ -369,20 +368,40 @@ function compressFunction(node, item, list) {
|
||||
node.name = 'rgba';
|
||||
}
|
||||
|
||||
if (args[3] === 0) {
|
||||
// try to replace `rgba(x, x, x, 0)` to `transparent`
|
||||
// always replace `rgba(0, 0, 0, 0)` to `transparent`
|
||||
// otherwise avoid replacement in gradients since it may break color transition
|
||||
// http://stackoverflow.com/questions/11829410/css3-gradient-rendering-issues-from-transparent-to-white
|
||||
var scopeFunctionName = this.function && this.function.name;
|
||||
if ((args[0] === 0 && args[1] === 0 && args[2] === 0) ||
|
||||
!/^(?:to|from|color-stop)$|gradient$/i.test(scopeFunctionName)) {
|
||||
|
||||
item.data = {
|
||||
type: 'Identifier',
|
||||
loc: node.loc,
|
||||
name: 'transparent'
|
||||
};
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
node.children.each(function(node, item, list) {
|
||||
if (node.type === 'Operator') {
|
||||
if (node.value !== ',') {
|
||||
list.remove(item);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
argument.sequence = new List([{
|
||||
item.data = {
|
||||
type: 'Number',
|
||||
info: item.data.info,
|
||||
value: packNumber(args.shift())
|
||||
}]);
|
||||
loc: node.loc,
|
||||
value: packNumber(args.shift(), null)
|
||||
};
|
||||
});
|
||||
|
||||
return;
|
||||
@@ -393,7 +412,7 @@ function compressFunction(node, item, list) {
|
||||
}
|
||||
|
||||
if (functionName === 'hsl') {
|
||||
args = args || parseFunctionArgs(node.arguments, 3, false);
|
||||
args = args || parseFunctionArgs(node.children, 3, false);
|
||||
|
||||
if (!args) {
|
||||
// something went wrong
|
||||
@@ -406,7 +425,7 @@ function compressFunction(node, item, list) {
|
||||
}
|
||||
|
||||
if (functionName === 'rgb') {
|
||||
args = args || parseFunctionArgs(node.arguments, 3, true);
|
||||
args = args || parseFunctionArgs(node.children, 3, true);
|
||||
|
||||
if (!args) {
|
||||
// something went wrong
|
||||
@@ -415,15 +434,16 @@ function compressFunction(node, item, list) {
|
||||
|
||||
// check if color is not at the end and not followed by space
|
||||
var next = item.next;
|
||||
if (next && next.data.type !== 'Space') {
|
||||
if (next && next.data.type !== 'WhiteSpace') {
|
||||
list.insert(list.createItem({
|
||||
type: 'Space'
|
||||
type: 'WhiteSpace',
|
||||
value: ' '
|
||||
}), next);
|
||||
}
|
||||
|
||||
item.data = {
|
||||
type: 'Hash',
|
||||
info: node.info,
|
||||
loc: node.loc,
|
||||
value: toHex(args[0]) + toHex(args[1]) + toHex(args[2])
|
||||
};
|
||||
|
||||
@@ -438,14 +458,15 @@ function compressIdent(node, item) {
|
||||
|
||||
var color = node.name.toLowerCase();
|
||||
|
||||
if (NAME_TO_HEX.hasOwnProperty(color)) {
|
||||
if (NAME_TO_HEX.hasOwnProperty(color) &&
|
||||
lexer.matchDeclaration(this.declaration).isType(node, '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,
|
||||
loc: node.loc,
|
||||
value: hex
|
||||
};
|
||||
} else {
|
||||
@@ -474,7 +495,7 @@ function compressHex(node, item) {
|
||||
if (HEX_TO_NAME[color]) {
|
||||
item.data = {
|
||||
type: 'Identifier',
|
||||
info: node.info,
|
||||
loc: node.loc,
|
||||
name: HEX_TO_NAME[color]
|
||||
};
|
||||
} else {
|
||||
24
node_modules/csso/lib/replace/index.js
generated
vendored
Normal file
24
node_modules/csso/lib/replace/index.js
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
var walk = require('css-tree').walk;
|
||||
var handlers = {
|
||||
Atrule: require('./Atrule'),
|
||||
AttributeSelector: require('./AttributeSelector'),
|
||||
Value: require('./Value'),
|
||||
Dimension: require('./Dimension'),
|
||||
Percentage: require('./Percentage'),
|
||||
Number: require('./Number'),
|
||||
String: require('./String'),
|
||||
Url: require('./Url'),
|
||||
Hash: require('./color').compressHex,
|
||||
Identifier: require('./color').compressIdent,
|
||||
Function: require('./color').compressFunction
|
||||
};
|
||||
|
||||
module.exports = function(ast) {
|
||||
walk(ast, {
|
||||
leave: function(node, item, list) {
|
||||
if (handlers.hasOwnProperty(node.type)) {
|
||||
handlers[node.type].call(this, node, item, list);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
var List = require('../../../utils/list.js');
|
||||
var List = require('css-tree').List;
|
||||
|
||||
module.exports = function compressBackground(node) {
|
||||
function lastType() {
|
||||
@@ -8,7 +8,7 @@ module.exports = function compressBackground(node) {
|
||||
}
|
||||
|
||||
function flush() {
|
||||
if (lastType() === 'Space') {
|
||||
if (lastType() === 'WhiteSpace') {
|
||||
buffer.pop();
|
||||
}
|
||||
|
||||
@@ -16,13 +16,16 @@ module.exports = function compressBackground(node) {
|
||||
buffer.unshift(
|
||||
{
|
||||
type: 'Number',
|
||||
loc: null,
|
||||
value: '0'
|
||||
},
|
||||
{
|
||||
type: 'Space'
|
||||
type: 'WhiteSpace',
|
||||
value: ' '
|
||||
},
|
||||
{
|
||||
type: 'Number',
|
||||
loc: null,
|
||||
value: '0'
|
||||
}
|
||||
);
|
||||
@@ -36,7 +39,7 @@ module.exports = function compressBackground(node) {
|
||||
var newValue = [];
|
||||
var buffer = [];
|
||||
|
||||
node.sequence.each(function(node) {
|
||||
node.children.each(function(node) {
|
||||
if (node.type === 'Operator' && node.value === ',') {
|
||||
flush();
|
||||
newValue.push(node);
|
||||
@@ -54,7 +57,7 @@ module.exports = function compressBackground(node) {
|
||||
}
|
||||
|
||||
// don't add redundant spaces
|
||||
if (node.type === 'Space' && (!buffer.length || lastType() === 'Space')) {
|
||||
if (node.type === 'WhiteSpace' && (!buffer.length || lastType() === 'WhiteSpace')) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -62,5 +65,5 @@ module.exports = function compressBackground(node) {
|
||||
});
|
||||
|
||||
flush();
|
||||
node.sequence = new List(newValue);
|
||||
node.children = new List().fromArray(newValue);
|
||||
};
|
||||
31
node_modules/csso/lib/replace/property/border.js
generated
vendored
Normal file
31
node_modules/csso/lib/replace/property/border.js
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
function removeItemAndRedundantWhiteSpace(list, item) {
|
||||
var prev = item.prev;
|
||||
var next = item.next;
|
||||
|
||||
if (next !== null) {
|
||||
if (next.data.type === 'WhiteSpace' && (prev === null || prev.data.type === 'WhiteSpace')) {
|
||||
list.remove(next);
|
||||
}
|
||||
} else if (prev !== null && prev.data.type === 'WhiteSpace') {
|
||||
list.remove(prev);
|
||||
}
|
||||
|
||||
list.remove(item);
|
||||
}
|
||||
|
||||
module.exports = function compressBorder(node) {
|
||||
node.children.each(function(node, item, list) {
|
||||
if (node.type === 'Identifier' && node.name.toLowerCase() === 'none') {
|
||||
if (list.head === list.tail) {
|
||||
// replace `none` for zero when `none` is a single term
|
||||
item.data = {
|
||||
type: 'Number',
|
||||
loc: node.loc,
|
||||
value: '0'
|
||||
};
|
||||
} else {
|
||||
removeItemAndRedundantWhiteSpace(list, item);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -1,19 +1,19 @@
|
||||
module.exports = function compressFontWeight(node) {
|
||||
var value = node.sequence.head.data;
|
||||
var value = node.children.head.data;
|
||||
|
||||
if (value.type === 'Identifier') {
|
||||
switch (value.name) {
|
||||
case 'normal':
|
||||
node.sequence.head.data = {
|
||||
node.children.head.data = {
|
||||
type: 'Number',
|
||||
info: value.info,
|
||||
loc: value.loc,
|
||||
value: '400'
|
||||
};
|
||||
break;
|
||||
case 'bold':
|
||||
node.sequence.head.data = {
|
||||
node.children.head.data = {
|
||||
type: 'Number',
|
||||
info: value.info,
|
||||
loc: value.loc,
|
||||
value: '700'
|
||||
};
|
||||
break;
|
||||
@@ -1,12 +1,12 @@
|
||||
module.exports = function compressFont(node) {
|
||||
var list = node.sequence;
|
||||
var list = node.children;
|
||||
|
||||
list.eachRight(function(node, item) {
|
||||
if (node.type === 'Identifier') {
|
||||
if (node.name === 'bold') {
|
||||
item.data = {
|
||||
type: 'Number',
|
||||
info: node.info,
|
||||
loc: node.loc,
|
||||
value: '700'
|
||||
};
|
||||
} else if (node.name === 'normal') {
|
||||
@@ -29,8 +29,8 @@ module.exports = function compressFont(node) {
|
||||
|
||||
// remove redundant spaces
|
||||
list.each(function(node, item) {
|
||||
if (node.type === 'Space') {
|
||||
if (!item.prev || !item.next || item.next.data.type === 'Space') {
|
||||
if (node.type === 'WhiteSpace') {
|
||||
if (!item.prev || !item.next || item.next.data.type === 'WhiteSpace') {
|
||||
this.remove(item);
|
||||
}
|
||||
}
|
||||
107
node_modules/csso/lib/restructure/1-mergeAtrule.js
generated
vendored
Normal file
107
node_modules/csso/lib/restructure/1-mergeAtrule.js
generated
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
var List = require('css-tree').List;
|
||||
var resolveKeyword = require('css-tree').keyword;
|
||||
var hasOwnProperty = Object.prototype.hasOwnProperty;
|
||||
var walk = require('css-tree').walk;
|
||||
|
||||
function addRuleToMap(map, item, list, single) {
|
||||
var node = item.data;
|
||||
var name = resolveKeyword(node.name).basename;
|
||||
var id = node.name.toLowerCase() + '/' + (node.prelude ? node.prelude.id : null);
|
||||
|
||||
if (!hasOwnProperty.call(map, name)) {
|
||||
map[name] = Object.create(null);
|
||||
}
|
||||
|
||||
if (single) {
|
||||
delete map[name][id];
|
||||
}
|
||||
|
||||
if (!hasOwnProperty.call(map[name], id)) {
|
||||
map[name][id] = new List();
|
||||
}
|
||||
|
||||
map[name][id].append(list.remove(item));
|
||||
}
|
||||
|
||||
function relocateAtrules(ast, options) {
|
||||
var collected = Object.create(null);
|
||||
var topInjectPoint = null;
|
||||
|
||||
ast.children.each(function(node, item, list) {
|
||||
if (node.type === 'Atrule') {
|
||||
var name = resolveKeyword(node.name).basename;
|
||||
|
||||
switch (name) {
|
||||
case 'keyframes':
|
||||
addRuleToMap(collected, item, list, true);
|
||||
return;
|
||||
|
||||
case 'media':
|
||||
if (options.forceMediaMerge) {
|
||||
addRuleToMap(collected, item, list, false);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (topInjectPoint === null &&
|
||||
name !== 'charset' &&
|
||||
name !== 'import') {
|
||||
topInjectPoint = item;
|
||||
}
|
||||
} else {
|
||||
if (topInjectPoint === null) {
|
||||
topInjectPoint = item;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for (var atrule in collected) {
|
||||
for (var id in collected[atrule]) {
|
||||
ast.children.insertList(
|
||||
collected[atrule][id],
|
||||
atrule === 'media' ? null : topInjectPoint
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
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.prelude &&
|
||||
prev.prelude &&
|
||||
node.prelude.id === prev.prelude.id) {
|
||||
prev.block.children.appendList(node.block.children);
|
||||
list.remove(item);
|
||||
|
||||
// TODO: use it when we can refer to several points in source
|
||||
// prev.loc = {
|
||||
// primary: prev.loc,
|
||||
// merged: node.loc
|
||||
// };
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = function rejoinAtrule(ast, options) {
|
||||
relocateAtrules(ast, options);
|
||||
|
||||
walk(ast, {
|
||||
visit: 'Atrule',
|
||||
reverse: true,
|
||||
enter: processAtrule
|
||||
});
|
||||
};
|
||||
@@ -1,23 +1,23 @@
|
||||
var utils = require('./utils.js');
|
||||
var walkRules = require('../../utils/walk.js').rules;
|
||||
var walk = require('css-tree').walk;
|
||||
var utils = require('./utils');
|
||||
|
||||
function processRuleset(node, item, list) {
|
||||
var selectors = node.selector.selectors;
|
||||
var declarations = node.block.declarations;
|
||||
function processRule(node, item, list) {
|
||||
var selectors = node.prelude.children;
|
||||
var declarations = node.block.children;
|
||||
|
||||
list.prevUntil(item.prev, function(prev) {
|
||||
// skip non-ruleset node if safe
|
||||
if (prev.type !== 'Ruleset') {
|
||||
if (prev.type !== 'Rule') {
|
||||
return utils.unsafeToSkipNode.call(selectors, prev);
|
||||
}
|
||||
|
||||
var prevSelectors = prev.selector.selectors;
|
||||
var prevDeclarations = prev.block.declarations;
|
||||
var prevSelectors = prev.prelude.children;
|
||||
var prevDeclarations = prev.block.children;
|
||||
|
||||
// try to join rulesets with equal pseudo signature
|
||||
if (node.pseudoSignature === prev.pseudoSignature) {
|
||||
// try to join by selectors
|
||||
if (utils.isEqualLists(prevSelectors, selectors)) {
|
||||
if (utils.isEqualSelectors(prevSelectors, selectors)) {
|
||||
prevDeclarations.appendList(declarations);
|
||||
list.remove(item);
|
||||
return true;
|
||||
@@ -34,15 +34,14 @@ function processRuleset(node, item, list) {
|
||||
// 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);
|
||||
}
|
||||
module.exports = function initialMergeRule(ast) {
|
||||
walk(ast, {
|
||||
visit: 'Rule',
|
||||
enter: processRule
|
||||
});
|
||||
};
|
||||
42
node_modules/csso/lib/restructure/3-disjoinRuleset.js
generated
vendored
Normal file
42
node_modules/csso/lib/restructure/3-disjoinRuleset.js
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
var List = require('css-tree').List;
|
||||
var walk = require('css-tree').walk;
|
||||
|
||||
function processRule(node, item, list) {
|
||||
var selectors = node.prelude.children;
|
||||
|
||||
// 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: 'Rule',
|
||||
loc: node.loc,
|
||||
prelude: {
|
||||
type: 'SelectorList',
|
||||
loc: node.prelude.loc,
|
||||
children: newSelectors
|
||||
},
|
||||
block: {
|
||||
type: 'Block',
|
||||
loc: node.block.loc,
|
||||
children: node.block.children.copy()
|
||||
},
|
||||
pseudoSignature: node.pseudoSignature
|
||||
}), item);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = function disjoinRule(ast) {
|
||||
walk(ast, {
|
||||
visit: 'Rule',
|
||||
reverse: true,
|
||||
enter: processRule
|
||||
});
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
var List = require('../../utils/list.js');
|
||||
var translate = require('../../utils/translate.js');
|
||||
var walkRulesRight = require('../../utils/walk.js').rulesRight;
|
||||
var List = require('css-tree').List;
|
||||
var generate = require('css-tree').generate;
|
||||
var walk = require('css-tree').walk;
|
||||
|
||||
var REPLACE = 1;
|
||||
var REMOVE = 2;
|
||||
@@ -65,7 +65,7 @@ var MAIN_PROPERTY = {
|
||||
|
||||
function TRBL(name) {
|
||||
this.name = name;
|
||||
this.info = null;
|
||||
this.loc = null;
|
||||
this.iehack = undefined;
|
||||
this.sides = {
|
||||
'top': null,
|
||||
@@ -75,17 +75,18 @@ function TRBL(name) {
|
||||
};
|
||||
}
|
||||
|
||||
TRBL.prototype.getValueSequence = function(value, count) {
|
||||
TRBL.prototype.getValueSequence = function(declaration, count) {
|
||||
var values = [];
|
||||
var iehack = false;
|
||||
var hasBadValues = value.sequence.some(function(child) {
|
||||
var iehack = '';
|
||||
var hasBadValues = declaration.value.type !== 'Value' || declaration.value.children.some(function(child) {
|
||||
var special = false;
|
||||
|
||||
switch (child.type) {
|
||||
case 'Identifier':
|
||||
switch (child.name) {
|
||||
case '\\0':
|
||||
case '\\9':
|
||||
iehack = true;
|
||||
iehack = child.name;
|
||||
return;
|
||||
|
||||
case 'inherit':
|
||||
@@ -114,11 +115,20 @@ TRBL.prototype.getValueSequence = function(value, count) {
|
||||
}
|
||||
break;
|
||||
|
||||
case 'Hash': // color
|
||||
case 'Number':
|
||||
case 'Percentage':
|
||||
break;
|
||||
|
||||
case 'Space':
|
||||
case 'Function':
|
||||
if (child.name === 'var') {
|
||||
return true;
|
||||
}
|
||||
|
||||
special = child.name;
|
||||
break;
|
||||
|
||||
case 'WhiteSpace':
|
||||
return false; // ignore space
|
||||
|
||||
default:
|
||||
@@ -128,7 +138,7 @@ TRBL.prototype.getValueSequence = function(value, count) {
|
||||
values.push({
|
||||
node: child,
|
||||
special: special,
|
||||
important: value.important
|
||||
important: declaration.important
|
||||
});
|
||||
});
|
||||
|
||||
@@ -136,7 +146,7 @@ TRBL.prototype.getValueSequence = function(value, count) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof this.iehack === 'boolean' && this.iehack !== iehack) {
|
||||
if (typeof this.iehack === 'string' && this.iehack !== iehack) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -151,35 +161,37 @@ TRBL.prototype.canOverride = function(side, value) {
|
||||
return !currentValue || (value.important && !currentValue.important);
|
||||
};
|
||||
|
||||
TRBL.prototype.add = function(name, value, info) {
|
||||
TRBL.prototype.add = function(name, declaration) {
|
||||
function attemptToAdd() {
|
||||
var sides = this.sides;
|
||||
var side = SIDE[name];
|
||||
|
||||
if (side) {
|
||||
if (side in sides) {
|
||||
var values = this.getValueSequence(value, 1);
|
||||
if (side in sides === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!values || !values.length) {
|
||||
var values = this.getValueSequence(declaration, 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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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];
|
||||
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);
|
||||
var values = this.getValueSequence(declaration, 4);
|
||||
|
||||
if (!values || !values.length) {
|
||||
return false;
|
||||
@@ -225,13 +237,17 @@ TRBL.prototype.add = function(name, value, info) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.info) {
|
||||
this.info = {
|
||||
primary: this.info,
|
||||
merged: info
|
||||
};
|
||||
} else {
|
||||
this.info = info;
|
||||
// TODO: use it when we can refer to several points in source
|
||||
// if (this.loc) {
|
||||
// this.loc = {
|
||||
// primary: this.loc,
|
||||
// merged: declaration.loc
|
||||
// };
|
||||
// } else {
|
||||
// this.loc = declaration.loc;
|
||||
// }
|
||||
if (!this.loc) {
|
||||
this.loc = declaration.loc;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -257,7 +273,7 @@ TRBL.prototype.isOkToMinimize = function() {
|
||||
};
|
||||
|
||||
TRBL.prototype.getValue = function() {
|
||||
var result = [];
|
||||
var result = new List();
|
||||
var sides = this.sides;
|
||||
var values = [
|
||||
sides.top,
|
||||
@@ -266,10 +282,10 @@ TRBL.prototype.getValue = function() {
|
||||
sides.left
|
||||
];
|
||||
var stringValues = [
|
||||
translate(sides.top.node),
|
||||
translate(sides.right.node),
|
||||
translate(sides.bottom.node),
|
||||
translate(sides.left.node)
|
||||
generate(sides.top.node),
|
||||
generate(sides.right.node),
|
||||
generate(sides.bottom.node),
|
||||
generate(sides.left.node)
|
||||
];
|
||||
|
||||
if (stringValues[LEFT] === stringValues[RIGHT]) {
|
||||
@@ -284,42 +300,44 @@ TRBL.prototype.getValue = function() {
|
||||
|
||||
for (var i = 0; i < values.length; i++) {
|
||||
if (i) {
|
||||
result.push({ type: 'Space' });
|
||||
result.appendData({ type: 'WhiteSpace', value: ' ' });
|
||||
}
|
||||
|
||||
result.push(values[i].node);
|
||||
result.appendData(values[i].node);
|
||||
}
|
||||
|
||||
if (this.iehack) {
|
||||
result.push({ type: 'Space' }, {
|
||||
result.appendData({ type: 'WhiteSpace', value: ' ' });
|
||||
result.appendData({
|
||||
type: 'Identifier',
|
||||
info: {},
|
||||
name: '\\9'
|
||||
loc: null,
|
||||
name: this.iehack
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'Value',
|
||||
info: {},
|
||||
important: sides.top.important,
|
||||
sequence: new List(result)
|
||||
loc: null,
|
||||
children: result
|
||||
};
|
||||
};
|
||||
|
||||
TRBL.prototype.getProperty = function() {
|
||||
TRBL.prototype.getDeclaration = function() {
|
||||
return {
|
||||
type: 'Property',
|
||||
info: {},
|
||||
name: this.name
|
||||
type: 'Declaration',
|
||||
loc: this.loc,
|
||||
important: this.sides.top.important,
|
||||
property: this.name,
|
||||
value: this.getValue()
|
||||
};
|
||||
};
|
||||
|
||||
function processRuleset(ruleset, shorts, shortDeclarations, lastShortSelector) {
|
||||
var declarations = ruleset.block.declarations;
|
||||
var selector = ruleset.selector.selectors.first().id;
|
||||
function processRule(rule, shorts, shortDeclarations, lastShortSelector) {
|
||||
var declarations = rule.block.children;
|
||||
var selector = rule.prelude.children.first().id;
|
||||
|
||||
ruleset.block.declarations.eachRight(function(declaration, item) {
|
||||
var property = declaration.property.name;
|
||||
rule.block.children.eachRight(function(declaration, item) {
|
||||
var property = declaration.property;
|
||||
|
||||
if (!MAIN_PROPERTY.hasOwnProperty(property)) {
|
||||
return;
|
||||
@@ -336,10 +354,15 @@ function processRuleset(ruleset, shorts, shortDeclarations, lastShortSelector) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!shorthand || !shorthand.add(property, declaration.value, declaration.info)) {
|
||||
if (!shorthand || !shorthand.add(property, declaration)) {
|
||||
operation = REPLACE;
|
||||
shorthand = new TRBL(key);
|
||||
shorthand.add(property, declaration.value, declaration.info);
|
||||
|
||||
// if can't parse value ignore it and break shorthand children
|
||||
if (!shorthand.add(property, declaration)) {
|
||||
lastShortSelector = null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
shorts[key] = shorthand;
|
||||
@@ -354,7 +377,7 @@ function processRuleset(ruleset, shorts, shortDeclarations, lastShortSelector) {
|
||||
});
|
||||
|
||||
return lastShortSelector;
|
||||
};
|
||||
}
|
||||
|
||||
function processShorthands(shortDeclarations, markDeclaration) {
|
||||
shortDeclarations.forEach(function(item) {
|
||||
@@ -365,52 +388,44 @@ function processShorthands(shortDeclarations, markDeclaration) {
|
||||
}
|
||||
|
||||
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
|
||||
});
|
||||
item.item.data = markDeclaration(shorthand.getDeclaration());
|
||||
} 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;
|
||||
walk(ast, {
|
||||
visit: 'Rule',
|
||||
reverse: true,
|
||||
enter: function(node) {
|
||||
var stylesheet = this.block || this.stylesheet;
|
||||
var ruleId = (node.pseudoSignature || '') + '|' + node.prelude.children.first().id;
|
||||
var ruleMap;
|
||||
var shorts;
|
||||
|
||||
if (!stylesheetMap.hasOwnProperty(stylesheet.id)) {
|
||||
ruleMap = {
|
||||
lastShortSelector: null
|
||||
};
|
||||
stylesheetMap[stylesheet.id] = ruleMap;
|
||||
} else {
|
||||
ruleMap = stylesheetMap[stylesheet.id];
|
||||
}
|
||||
|
||||
if (ruleMap.hasOwnProperty(ruleId)) {
|
||||
shorts = ruleMap[ruleId];
|
||||
} else {
|
||||
shorts = {};
|
||||
ruleMap[ruleId] = shorts;
|
||||
}
|
||||
|
||||
ruleMap.lastShortSelector = processRule.call(this, node, shorts, shortDeclarations, ruleMap.lastShortSelector);
|
||||
}
|
||||
|
||||
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);
|
||||
300
node_modules/csso/lib/restructure/6-restructBlock.js
generated
vendored
Normal file
300
node_modules/csso/lib/restructure/6-restructBlock.js
generated
vendored
Normal file
@@ -0,0 +1,300 @@
|
||||
var resolveProperty = require('css-tree').property;
|
||||
var resolveKeyword = require('css-tree').keyword;
|
||||
var walk = require('css-tree').walk;
|
||||
var generate = require('css-tree').generate;
|
||||
var fingerprintId = 1;
|
||||
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 SAFE_VALUES = {
|
||||
cursor: [
|
||||
'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'
|
||||
],
|
||||
overflow: [
|
||||
'hidden', 'visible', 'scroll', 'auto'
|
||||
],
|
||||
position: [
|
||||
'static', 'relative', 'absolute', 'fixed'
|
||||
]
|
||||
};
|
||||
|
||||
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).basename;
|
||||
|
||||
if (realName === 'background') {
|
||||
return propertyName + ':' + generate(declaration.value);
|
||||
}
|
||||
|
||||
var declarationId = declaration.id;
|
||||
var fingerprint = fingerprints[declarationId];
|
||||
|
||||
if (!fingerprint) {
|
||||
switch (declaration.value.type) {
|
||||
case 'Value':
|
||||
var vendorId = '';
|
||||
var iehack = '';
|
||||
var special = {};
|
||||
var raw = false;
|
||||
|
||||
declaration.value.children.each(function walk(node) {
|
||||
switch (node.type) {
|
||||
case 'Value':
|
||||
case 'Brackets':
|
||||
case 'Parentheses':
|
||||
node.children.each(walk);
|
||||
break;
|
||||
|
||||
case 'Raw':
|
||||
raw = true;
|
||||
break;
|
||||
|
||||
case 'Identifier':
|
||||
var name = node.name;
|
||||
|
||||
if (!vendorId) {
|
||||
vendorId = resolveKeyword(name).vendor;
|
||||
}
|
||||
|
||||
if (/\\[09]/.test(name)) {
|
||||
iehack = RegExp.lastMatch;
|
||||
}
|
||||
|
||||
if (SAFE_VALUES.hasOwnProperty(realName)) {
|
||||
if (SAFE_VALUES[realName].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
|
||||
var hasComma = node.children.some(function(node) {
|
||||
return node.type === 'Operator' && node.value === ',';
|
||||
});
|
||||
if (!hasComma) {
|
||||
name = 'rect-backward';
|
||||
}
|
||||
}
|
||||
|
||||
special[name + '()'] = true;
|
||||
|
||||
// check nested tokens too
|
||||
node.children.each(walk);
|
||||
|
||||
break;
|
||||
|
||||
case 'Dimension':
|
||||
var unit = node.unit;
|
||||
|
||||
if (/\\[09]/.test(unit)) {
|
||||
iehack = RegExp.lastMatch;
|
||||
}
|
||||
|
||||
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 = raw
|
||||
? '!' + fingerprintId++
|
||||
: '!' + Object.keys(special).sort() + '|' + iehack + vendorId;
|
||||
break;
|
||||
|
||||
case 'Raw':
|
||||
fingerprint = '!' + declaration.value.value;
|
||||
break;
|
||||
|
||||
default:
|
||||
fingerprint = generate(declaration.value);
|
||||
}
|
||||
|
||||
fingerprints[declarationId] = fingerprint;
|
||||
}
|
||||
|
||||
return propertyName + fingerprint;
|
||||
}
|
||||
|
||||
function needless(props, declaration, fingerprints) {
|
||||
var property = resolveProperty(declaration.property);
|
||||
|
||||
if (NEEDLESS_TABLE.hasOwnProperty(property.basename)) {
|
||||
var table = NEEDLESS_TABLE[property.basename];
|
||||
|
||||
for (var i = 0; i < table.length; i++) {
|
||||
var ppre = getPropertyFingerprint(property.prefix + table[i], declaration, fingerprints);
|
||||
var prev = props.hasOwnProperty(ppre) ? props[ppre] : null;
|
||||
|
||||
if (prev && (!declaration.important || prev.item.data.important)) {
|
||||
return prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function processRule(rule, item, list, props, fingerprints) {
|
||||
var declarations = rule.block.children;
|
||||
|
||||
declarations.eachRight(function(declaration, declarationItem) {
|
||||
var property = declaration.property;
|
||||
var fingerprint = getPropertyFingerprint(property, declaration, fingerprints);
|
||||
var prev = props[fingerprint];
|
||||
|
||||
if (prev && !dontRestructure.hasOwnProperty(property)) {
|
||||
if (declaration.important && !prev.item.data.important) {
|
||||
props[fingerprint] = {
|
||||
block: declarations,
|
||||
item: declarationItem
|
||||
};
|
||||
|
||||
prev.block.remove(prev.item);
|
||||
|
||||
// TODO: use it when we can refer to several points in source
|
||||
// declaration.loc = {
|
||||
// primary: declaration.loc,
|
||||
// merged: prev.item.data.loc
|
||||
// };
|
||||
} else {
|
||||
declarations.remove(declarationItem);
|
||||
|
||||
// TODO: use it when we can refer to several points in source
|
||||
// prev.item.data.loc = {
|
||||
// primary: prev.item.data.loc,
|
||||
// merged: declaration.loc
|
||||
// };
|
||||
}
|
||||
} else {
|
||||
var prev = needless(props, declaration, fingerprints);
|
||||
|
||||
if (prev) {
|
||||
declarations.remove(declarationItem);
|
||||
|
||||
// TODO: use it when we can refer to several points in source
|
||||
// prev.item.data.loc = {
|
||||
// primary: prev.item.data.loc,
|
||||
// merged: declaration.loc
|
||||
// };
|
||||
} 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);
|
||||
|
||||
walk(ast, {
|
||||
visit: 'Rule',
|
||||
reverse: true,
|
||||
enter: function(node, item, list) {
|
||||
var stylesheet = this.block || this.stylesheet;
|
||||
var ruleId = (node.pseudoSignature || '') + '|' + node.prelude.children.first().id;
|
||||
var ruleMap;
|
||||
var props;
|
||||
|
||||
if (!stylesheetMap.hasOwnProperty(stylesheet.id)) {
|
||||
ruleMap = {};
|
||||
stylesheetMap[stylesheet.id] = ruleMap;
|
||||
} else {
|
||||
ruleMap = stylesheetMap[stylesheet.id];
|
||||
}
|
||||
|
||||
if (ruleMap.hasOwnProperty(ruleId)) {
|
||||
props = ruleMap[ruleId];
|
||||
} else {
|
||||
props = {};
|
||||
ruleMap[ruleId] = props;
|
||||
}
|
||||
|
||||
processRule.call(this, node, item, list, props, fingerprints);
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -1,5 +1,5 @@
|
||||
var utils = require('./utils.js');
|
||||
var walkRules = require('../../utils/walk.js').rules;
|
||||
var walk = require('css-tree').walk;
|
||||
var utils = require('./utils');
|
||||
|
||||
/*
|
||||
At this step all rules has single simple selector. We try to join by equal
|
||||
@@ -13,15 +13,15 @@ var walkRules = require('../../utils/walk.js').rules;
|
||||
b { ... }
|
||||
*/
|
||||
|
||||
function processRuleset(node, item, list) {
|
||||
var selectors = node.selector.selectors;
|
||||
var declarations = node.block.declarations;
|
||||
function processRule(node, item, list) {
|
||||
var selectors = node.prelude.children;
|
||||
var declarations = node.block.children;
|
||||
var nodeCompareMarker = selectors.first().compareMarker;
|
||||
var skippedCompareMarkers = {};
|
||||
|
||||
list.nextUntil(item.next, function(next, nextItem) {
|
||||
// skip non-ruleset node if safe
|
||||
if (next.type !== 'Ruleset') {
|
||||
if (next.type !== 'Rule') {
|
||||
return utils.unsafeToSkipNode.call(selectors, next);
|
||||
}
|
||||
|
||||
@@ -29,8 +29,8 @@ function processRuleset(node, item, list) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var nextFirstSelector = next.selector.selectors.head;
|
||||
var nextDeclarations = next.block.declarations;
|
||||
var nextFirstSelector = next.prelude.children.head;
|
||||
var nextDeclarations = next.block.children;
|
||||
var nextCompareMarker = nextFirstSelector.data.compareMarker;
|
||||
|
||||
// if next ruleset has same marked as one of skipped then stop joining
|
||||
@@ -76,12 +76,11 @@ function processRuleset(node, item, list) {
|
||||
|
||||
skippedCompareMarkers[nextCompareMarker] = true;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = function mergeRuleset(ast) {
|
||||
walkRules(ast, function(node, item, list) {
|
||||
if (node.type === 'Ruleset') {
|
||||
processRuleset(node, item, list);
|
||||
}
|
||||
module.exports = function mergeRule(ast) {
|
||||
walk(ast, {
|
||||
visit: 'Rule',
|
||||
enter: processRule
|
||||
});
|
||||
};
|
||||
177
node_modules/csso/lib/restructure/8-restructRuleset.js
generated
vendored
Normal file
177
node_modules/csso/lib/restructure/8-restructRuleset.js
generated
vendored
Normal file
@@ -0,0 +1,177 @@
|
||||
var List = require('css-tree').List;
|
||||
var walk = require('css-tree').walk;
|
||||
var utils = require('./utils');
|
||||
|
||||
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 processRule(node, item, list) {
|
||||
var avoidRulesMerge = this.block !== null ? this.block.avoidRulesMerge : false;
|
||||
var selectors = node.prelude.children;
|
||||
var block = node.block;
|
||||
var disallowDownMarkers = Object.create(null);
|
||||
var allowMergeUp = true;
|
||||
var allowMergeDown = true;
|
||||
|
||||
list.prevUntil(item.prev, function(prev, prevItem) {
|
||||
var prevBlock = prev.block;
|
||||
var prevType = prev.type;
|
||||
|
||||
if (prevType !== 'Rule') {
|
||||
var unsafe = utils.unsafeToSkipNode.call(selectors, prev);
|
||||
|
||||
if (!unsafe && prevType === 'Atrule' && prevBlock) {
|
||||
walk(prevBlock, {
|
||||
visit: 'Rule',
|
||||
enter: function(node) {
|
||||
node.prelude.children.each(function(data) {
|
||||
disallowDownMarkers[data.compareMarker] = true;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return unsafe;
|
||||
}
|
||||
|
||||
var prevSelectors = prev.prelude.children;
|
||||
|
||||
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.isEqualSelectors(prevSelectors, selectors)) {
|
||||
prevBlock.children.appendList(block.children);
|
||||
list.remove(item);
|
||||
return true;
|
||||
}
|
||||
|
||||
// try to join by properties
|
||||
var diff = utils.compareDeclarations(block.children, prevBlock.children);
|
||||
|
||||
// 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.children = new List().fromArray(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.children = new List().fromArray(diff.ne2);
|
||||
}
|
||||
} else {
|
||||
// diff.ne1.length && diff.ne2.length
|
||||
// extract equal block
|
||||
var newSelector = {
|
||||
type: 'SelectorList',
|
||||
loc: null,
|
||||
children: utils.addSelectors(prevSelectors.copy(), selectors)
|
||||
};
|
||||
var newBlockLength = calcSelectorLength(newSelector.children) + 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 (blockLength >= newBlockLength) {
|
||||
var newItem = list.createItem({
|
||||
type: 'Rule',
|
||||
loc: null,
|
||||
prelude: newSelector,
|
||||
block: {
|
||||
type: 'Block',
|
||||
loc: null,
|
||||
children: new List().fromArray(diff.eq)
|
||||
},
|
||||
pseudoSignature: node.pseudoSignature
|
||||
});
|
||||
|
||||
block.children = new List().fromArray(diff.ne1);
|
||||
prevBlock.children = new List().fromArray(diff.ne2overrided);
|
||||
|
||||
if (allowMergeUp) {
|
||||
list.insert(newItem, prevItem);
|
||||
} else {
|
||||
list.insert(newItem, item);
|
||||
}
|
||||
|
||||
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 restructRule(ast) {
|
||||
walk(ast, {
|
||||
visit: 'Rule',
|
||||
reverse: true,
|
||||
enter: processRule
|
||||
});
|
||||
};
|
||||
35
node_modules/csso/lib/restructure/index.js
generated
vendored
Normal file
35
node_modules/csso/lib/restructure/index.js
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
var prepare = require('./prepare/index');
|
||||
var mergeAtrule = require('./1-mergeAtrule');
|
||||
var initialMergeRuleset = require('./2-initialMergeRuleset');
|
||||
var disjoinRuleset = require('./3-disjoinRuleset');
|
||||
var restructShorthand = require('./4-restructShorthand');
|
||||
var restructBlock = require('./6-restructBlock');
|
||||
var mergeRuleset = require('./7-mergeRuleset');
|
||||
var restructRuleset = require('./8-restructRuleset');
|
||||
|
||||
module.exports = function(ast, options) {
|
||||
// prepare ast for restructing
|
||||
var indexer = prepare(ast, options);
|
||||
options.logger('prepare', ast);
|
||||
|
||||
mergeAtrule(ast, options);
|
||||
options.logger('mergeAtrule', ast);
|
||||
|
||||
initialMergeRuleset(ast);
|
||||
options.logger('initialMergeRuleset', ast);
|
||||
|
||||
disjoinRuleset(ast);
|
||||
options.logger('disjoinRuleset', ast);
|
||||
|
||||
restructShorthand(ast, indexer);
|
||||
options.logger('restructShorthand', ast);
|
||||
|
||||
restructBlock(ast);
|
||||
options.logger('restructBlock', ast);
|
||||
|
||||
mergeRuleset(ast);
|
||||
options.logger('mergeRuleset', ast);
|
||||
|
||||
restructRuleset(ast);
|
||||
options.logger('restructRuleset', ast);
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
var translate = require('../../../utils/translate.js');
|
||||
var generate = require('css-tree').generate;
|
||||
|
||||
function Index() {
|
||||
this.seed = 0;
|
||||
@@ -17,15 +17,14 @@ Index.prototype.resolve = function(str) {
|
||||
};
|
||||
|
||||
module.exports = function createDeclarationIndexer() {
|
||||
var names = new Index();
|
||||
var values = new Index();
|
||||
var ids = new Index();
|
||||
|
||||
return function markDeclaration(node) {
|
||||
var property = node.property.name;
|
||||
var value = translate(node.value);
|
||||
var id = generate(node);
|
||||
|
||||
node.id = names.resolve(property) + (values.resolve(value) << 12);
|
||||
node.length = property.length + 1 + value.length;
|
||||
node.id = ids.resolve(id);
|
||||
node.length = id.length;
|
||||
node.fingerprint = null;
|
||||
|
||||
return node;
|
||||
};
|
||||
43
node_modules/csso/lib/restructure/prepare/index.js
generated
vendored
Normal file
43
node_modules/csso/lib/restructure/prepare/index.js
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
var resolveKeyword = require('css-tree').keyword;
|
||||
var walk = require('css-tree').walk;
|
||||
var generate = require('css-tree').generate;
|
||||
var createDeclarationIndexer = require('./createDeclarationIndexer');
|
||||
var processSelector = require('./processSelector');
|
||||
|
||||
module.exports = function prepare(ast, options) {
|
||||
var markDeclaration = createDeclarationIndexer();
|
||||
|
||||
walk(ast, {
|
||||
visit: 'Rule',
|
||||
enter: function processRule(node) {
|
||||
node.block.children.each(markDeclaration);
|
||||
processSelector(node, options.usage);
|
||||
}
|
||||
});
|
||||
|
||||
walk(ast, {
|
||||
visit: 'Atrule',
|
||||
enter: function(node) {
|
||||
if (node.prelude) {
|
||||
node.prelude.id = null; // pre-init property to avoid multiple hidden class for generate
|
||||
node.prelude.id = generate(node.prelude);
|
||||
}
|
||||
|
||||
// compare keyframe selectors by its values
|
||||
// NOTE: still no clarification about problems with keyframes selector grouping (issue #197)
|
||||
if (resolveKeyword(node.name).basename === 'keyframes') {
|
||||
node.block.avoidRulesMerge = true; /* probably we don't need to prevent those merges for @keyframes
|
||||
TODO: need to be checked */
|
||||
node.block.children.each(function(rule) {
|
||||
rule.prelude.children.each(function(simpleselector) {
|
||||
simpleselector.compareMarker = simpleselector.id;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
declaration: markDeclaration
|
||||
};
|
||||
};
|
||||
@@ -1,5 +1,5 @@
|
||||
var translate = require('../../../utils/translate.js');
|
||||
var specificity = require('./specificity.js');
|
||||
var generate = require('css-tree').generate;
|
||||
var specificity = require('./specificity');
|
||||
|
||||
var nonFreezePseudoElements = {
|
||||
'first-letter': true,
|
||||
@@ -22,60 +22,63 @@ module.exports = function freeze(node, usageData) {
|
||||
var pseudos = Object.create(null);
|
||||
var hasPseudo = false;
|
||||
|
||||
node.selector.selectors.each(function(simpleSelector) {
|
||||
node.prelude.children.each(function(simpleSelector) {
|
||||
var tagName = '*';
|
||||
var scope = 0;
|
||||
|
||||
simpleSelector.sequence.some(function(node) {
|
||||
simpleSelector.children.each(function(node) {
|
||||
switch (node.type) {
|
||||
case 'Class':
|
||||
case 'ClassSelector':
|
||||
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));
|
||||
throw new Error('Selector can\'t has classes from different scopes: ' + generate(simpleSelector));
|
||||
}
|
||||
|
||||
scope = classScope;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'PseudoClass':
|
||||
if (!nonFreezePseudoClasses.hasOwnProperty(node.name)) {
|
||||
pseudos[node.name] = true;
|
||||
case 'PseudoClassSelector':
|
||||
var name = node.name.toLowerCase();
|
||||
|
||||
if (!nonFreezePseudoClasses.hasOwnProperty(name)) {
|
||||
pseudos[':' + name] = true;
|
||||
hasPseudo = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'PseudoElement':
|
||||
if (!nonFreezePseudoElements.hasOwnProperty(node.name)) {
|
||||
pseudos[node.name] = true;
|
||||
case 'PseudoElementSelector':
|
||||
var name = node.name.toLowerCase();
|
||||
|
||||
if (!nonFreezePseudoElements.hasOwnProperty(name)) {
|
||||
pseudos['::' + name] = true;
|
||||
hasPseudo = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'FunctionalPseudo':
|
||||
pseudos[node.name] = true;
|
||||
hasPseudo = true;
|
||||
case 'TypeSelector':
|
||||
tagName = node.name.toLowerCase();
|
||||
break;
|
||||
|
||||
case 'Negation':
|
||||
pseudos.not = true;
|
||||
hasPseudo = true;
|
||||
break;
|
||||
|
||||
case 'Identifier':
|
||||
tagName = node.name;
|
||||
case 'AttributeSelector':
|
||||
if (node.flags) {
|
||||
pseudos['[' + node.flags.toLowerCase() + ']'] = true;
|
||||
hasPseudo = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'WhiteSpace':
|
||||
case 'Combinator':
|
||||
tagName = '*';
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
simpleSelector.id = translate(simpleSelector);
|
||||
simpleSelector.compareMarker = specificity(simpleSelector).toString();
|
||||
simpleSelector.id = null; // pre-init property to avoid multiple hidden class
|
||||
simpleSelector.id = generate(simpleSelector);
|
||||
|
||||
if (scope) {
|
||||
simpleSelector.compareMarker += ':' + scope;
|
||||
@@ -86,7 +89,6 @@ module.exports = function freeze(node, usageData) {
|
||||
}
|
||||
});
|
||||
|
||||
if (hasPseudo) {
|
||||
node.pseudoSignature = Object.keys(pseudos).sort().join(',');
|
||||
}
|
||||
// add property to all rule nodes to avoid multiple hidden class
|
||||
node.pseudoSignature = hasPseudo && Object.keys(pseudos).sort().join(',');
|
||||
};
|
||||
56
node_modules/csso/lib/restructure/prepare/specificity.js
generated
vendored
Normal file
56
node_modules/csso/lib/restructure/prepare/specificity.js
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
module.exports = function specificity(simpleSelector) {
|
||||
var A = 0;
|
||||
var B = 0;
|
||||
var C = 0;
|
||||
|
||||
simpleSelector.children.each(function walk(node) {
|
||||
switch (node.type) {
|
||||
case 'SelectorList':
|
||||
case 'Selector':
|
||||
node.children.each(walk);
|
||||
break;
|
||||
|
||||
case 'IdSelector':
|
||||
A++;
|
||||
break;
|
||||
|
||||
case 'ClassSelector':
|
||||
case 'AttributeSelector':
|
||||
B++;
|
||||
break;
|
||||
|
||||
case 'PseudoClassSelector':
|
||||
switch (node.name.toLowerCase()) {
|
||||
case 'not':
|
||||
node.children.each(walk);
|
||||
break;
|
||||
|
||||
case 'before':
|
||||
case 'after':
|
||||
case 'first-line':
|
||||
case 'first-letter':
|
||||
C++;
|
||||
break;
|
||||
|
||||
// TODO: support for :nth-*(.. of <SelectorList>), :matches(), :has()
|
||||
default:
|
||||
B++;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'PseudoElementSelector':
|
||||
C++;
|
||||
break;
|
||||
|
||||
case 'TypeSelector':
|
||||
// ignore universal selector
|
||||
if (node.name.charAt(node.name.length - 1) !== '*') {
|
||||
C++;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
return [A, B, C];
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
var hasOwnProperty = Object.prototype.hasOwnProperty;
|
||||
|
||||
function isEqualLists(a, b) {
|
||||
function isEqualSelectors(a, b) {
|
||||
var cursor1 = a.head;
|
||||
var cursor2 = b.head;
|
||||
|
||||
@@ -43,7 +43,7 @@ function compareDeclarations(declarations1, declarations2) {
|
||||
var data = cursor.data;
|
||||
|
||||
if (data.fingerprint) {
|
||||
fingerprints[data.fingerprint] = data.value.important;
|
||||
fingerprints[data.fingerprint] = data.important;
|
||||
}
|
||||
|
||||
if (declarations2hash[data.id]) {
|
||||
@@ -58,14 +58,14 @@ function compareDeclarations(declarations1, declarations2) {
|
||||
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 {
|
||||
// when declarations1 has an overriding declaration, this is not a difference
|
||||
// unless no !important is used on prev and !important is used on the following
|
||||
if (!hasOwnProperty.call(fingerprints, data.fingerprint) ||
|
||||
(!fingerprints[data.fingerprint] && data.important)) {
|
||||
result.ne2.push(data);
|
||||
}
|
||||
|
||||
result.ne2overrided.push(data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,32 +99,42 @@ function addSelectors(dest, source) {
|
||||
|
||||
// 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;
|
||||
});
|
||||
});
|
||||
var cursor1 = selectors1.head;
|
||||
|
||||
while (cursor1 !== null) {
|
||||
var cursor2 = selectors2.head;
|
||||
|
||||
while (cursor2 !== null) {
|
||||
if (cursor1.data.compareMarker === cursor2.data.compareMarker) {
|
||||
return true;
|
||||
}
|
||||
|
||||
cursor2 = cursor2.next;
|
||||
}
|
||||
|
||||
cursor1 = cursor1.next;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// test node can't to be skipped
|
||||
function unsafeToSkipNode(node) {
|
||||
switch (node.type) {
|
||||
case 'Ruleset':
|
||||
case 'Rule':
|
||||
// unsafe skip ruleset with selector similarities
|
||||
return hasSimilarSelectors(node.selector.selectors, this);
|
||||
return hasSimilarSelectors(node.prelude.children, 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);
|
||||
return node.block.children.some(unsafeToSkipNode, this);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'Declaration':
|
||||
return false;
|
||||
}
|
||||
|
||||
// unsafe by default
|
||||
@@ -132,7 +142,7 @@ function unsafeToSkipNode(node) {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
isEqualLists: isEqualLists,
|
||||
isEqualSelectors: isEqualSelectors,
|
||||
isEqualDeclarations: isEqualDeclarations,
|
||||
compareDeclarations: compareDeclarations,
|
||||
addSelectors: addSelectors,
|
||||
29
node_modules/csso/lib/compressor/usage.js → node_modules/csso/lib/usage.js
generated
vendored
29
node_modules/csso/lib/compressor/usage.js → node_modules/csso/lib/usage.js
generated
vendored
@@ -4,7 +4,7 @@ function buildMap(list, caseInsensitive) {
|
||||
var map = Object.create(null);
|
||||
|
||||
if (!Array.isArray(list)) {
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
@@ -20,6 +20,28 @@ function buildMap(list, caseInsensitive) {
|
||||
return map;
|
||||
}
|
||||
|
||||
function buildList(data) {
|
||||
if (!data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var tags = buildMap(data.tags, true);
|
||||
var ids = buildMap(data.ids);
|
||||
var classes = buildMap(data.classes);
|
||||
|
||||
if (tags === null &&
|
||||
ids === null &&
|
||||
classes === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
tags: tags,
|
||||
ids: ids,
|
||||
classes: classes
|
||||
};
|
||||
}
|
||||
|
||||
function buildIndex(data) {
|
||||
var scopes = false;
|
||||
|
||||
@@ -46,9 +68,8 @@ function buildIndex(data) {
|
||||
}
|
||||
|
||||
return {
|
||||
tags: buildMap(data.tags, true),
|
||||
ids: buildMap(data.ids),
|
||||
classes: buildMap(data.classes),
|
||||
whitelist: buildList(data),
|
||||
blacklist: buildList(data.blacklist),
|
||||
scopes: scopes
|
||||
};
|
||||
}
|
||||
389
node_modules/csso/lib/utils/list.js
generated
vendored
389
node_modules/csso/lib/utils/list.js
generated
vendored
@@ -1,389 +0,0 @@
|
||||
//
|
||||
// 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
73
node_modules/csso/lib/utils/names.js
generated
vendored
@@ -1,73 +0,0 @@
|
||||
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
|
||||
};
|
||||
168
node_modules/csso/lib/utils/translate.js
generated
vendored
168
node_modules/csso/lib/utils/translate.js
generated
vendored
@@ -1,168 +0,0 @@
|
||||
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 result = '@' + node.name;
|
||||
|
||||
if (node.expression && !node.expression.sequence.isEmpty()) {
|
||||
result += ' ' + translate(node.expression);
|
||||
}
|
||||
|
||||
if (node.block) {
|
||||
return result + '{' + translate(node.block) + '}';
|
||||
} else {
|
||||
return result + ';';
|
||||
}
|
||||
|
||||
case 'Ruleset':
|
||||
return translate(node.selector) + '{' + translate(node.block) + '}';
|
||||
|
||||
case 'Selector':
|
||||
return eachDelim(node.selectors, ',');
|
||||
|
||||
case 'SimpleSelector':
|
||||
return 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);
|
||||
}).join('');
|
||||
|
||||
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);
|
||||
|
||||
if (node.operator !== null) {
|
||||
result += node.operator;
|
||||
|
||||
if (node.value !== null) {
|
||||
result += translate(node.value);
|
||||
|
||||
if (node.flags !== null) {
|
||||
result += (node.value.type !== 'String' ? ' ' : '') + node.flags;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return '[' + result + ']';
|
||||
|
||||
case 'FunctionalPseudo':
|
||||
return ':' + node.name + '(' + eachDelim(node.arguments, ',') + ')';
|
||||
|
||||
case 'Function':
|
||||
return node.name + '(' + eachDelim(node.arguments, ',') + ')';
|
||||
|
||||
case 'Block':
|
||||
return eachDelim(node.declarations, ';');
|
||||
|
||||
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;
|
||||
284
node_modules/csso/lib/utils/translateWithSourceMap.js
generated
vendored
284
node_modules/csso/lib/utils/translateWithSourceMap.js
generated
vendored
@@ -1,284 +0,0 @@
|
||||
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 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 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 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':
|
||||
return createSourceNode(node.info, 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);
|
||||
}));
|
||||
|
||||
case 'Block':
|
||||
return createAnonymousSourceNode(node.declarations.map(translate)).join(';');
|
||||
|
||||
case 'Declaration':
|
||||
return createSourceNode(
|
||||
node.info,
|
||||
[translate(node.property), ':', translate(node.value)]
|
||||
);
|
||||
|
||||
case 'Value':
|
||||
return node.important
|
||||
? each(node.sequence) + '!important'
|
||||
: each(node.sequence);
|
||||
|
||||
case 'Attribute':
|
||||
var result = translate(node.name);
|
||||
|
||||
if (node.operator !== null) {
|
||||
result += node.operator;
|
||||
|
||||
if (node.value !== null) {
|
||||
result += translate(node.value);
|
||||
|
||||
if (node.flags !== null) {
|
||||
result += (node.value.type !== 'String' ? ' ' : '') + 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 'Property':
|
||||
return node.name;
|
||||
|
||||
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
189
node_modules/csso/lib/utils/walk.js
generated
vendored
@@ -1,189 +0,0 @@
|
||||
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);
|
||||
}
|
||||
};
|
||||
83
node_modules/csso/package.json
generated
vendored
83
node_modules/csso/package.json
generated
vendored
@@ -1,14 +1,7 @@
|
||||
{
|
||||
"name": "csso",
|
||||
"version": "2.0.0",
|
||||
"description": "CSSO (CSS Optimizer) is a CSS minifier with structural optimisations",
|
||||
"keywords": [
|
||||
"css",
|
||||
"minifier",
|
||||
"minify",
|
||||
"compress",
|
||||
"optimisation"
|
||||
],
|
||||
"version": "4.2.0",
|
||||
"description": "CSS minifier with structural optimisations",
|
||||
"homepage": "https://github.com/css/csso",
|
||||
"author": "Sergey Kryzhanovsky <skryzhanovsky@ya.ru> (https://github.com/afelix)",
|
||||
"maintainers": [
|
||||
@@ -23,56 +16,50 @@
|
||||
"bugs": {
|
||||
"url": "https://github.com/css/csso/issues"
|
||||
},
|
||||
"bin": {
|
||||
"csso": "./bin/csso"
|
||||
},
|
||||
"keywords": [
|
||||
"css",
|
||||
"compress",
|
||||
"minifier",
|
||||
"minify",
|
||||
"optimise",
|
||||
"optimisation",
|
||||
"csstree"
|
||||
],
|
||||
"main": "./lib/index",
|
||||
"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"}]
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"test": "mocha --reporter dot",
|
||||
"codestyle": "jscs lib && eslint lib test",
|
||||
"codestyle-and-test": "npm run codestyle && npm test",
|
||||
"lint": "eslint lib test",
|
||||
"lint-and-test": "npm run lint && npm test",
|
||||
"build": "rollup --config && terser dist/csso.js --compress --mangle -o dist/csso.min.js",
|
||||
"coverage": "nyc npm test",
|
||||
"coveralls": "nyc report --reporter=text-lcov | coveralls",
|
||||
"travis": "nyc npm run lint-and-test && npm run coveralls",
|
||||
"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",
|
||||
"coverage": "istanbul cover _mocha -- -R dot",
|
||||
"coveralls": "istanbul cover _mocha --report lcovonly -- -R dot && cat ./coverage/lcov.info | coveralls",
|
||||
"travis": "npm run codestyle-and-test && npm run coveralls",
|
||||
"browserify": "browserify --standalone csso lib/index.js | uglifyjs --compress --mangle -o dist/csso-browser.js",
|
||||
"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",
|
||||
"prepublish": "npm run browserify"
|
||||
"prepublishOnly": "npm run build"
|
||||
},
|
||||
"dependencies": {
|
||||
"clap": "^1.0.9",
|
||||
"source-map": "^0.5.3"
|
||||
"css-tree": "^1.1.2"
|
||||
},
|
||||
"browser": {
|
||||
"css-tree": "css-tree/dist/csstree.min.js"
|
||||
},
|
||||
"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"
|
||||
"@rollup/plugin-commonjs": "^11.0.1",
|
||||
"@rollup/plugin-json": "^4.0.1",
|
||||
"@rollup/plugin-node-resolve": "^7.0.0",
|
||||
"coveralls": "^3.0.11",
|
||||
"eslint": "^6.8.0",
|
||||
"mocha": "^7.1.1",
|
||||
"nyc": "^15.0.0",
|
||||
"rollup": "^1.29.0",
|
||||
"source-map": "^0.6.1",
|
||||
"terser": "^4.6.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
"node": ">=8.0.0"
|
||||
},
|
||||
"files": [
|
||||
"bin",
|
||||
"dist/csso-browser.js",
|
||||
"lib",
|
||||
"HISTORY.md",
|
||||
"LICENSE",
|
||||
"README.md"
|
||||
"dist",
|
||||
"lib"
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user