Socket
Socket
Sign inDemoInstall

csso

Package Overview
Dependencies
Maintainers
3
Versions
82
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

csso - npm Package Compare versions

Comparing version 2.1.1 to 2.2.0

lib/utils/clone.js

9

HISTORY.md

@@ -0,1 +1,10 @@

## 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)

@@ -2,0 +11,0 @@

122

lib/compressor/index.js
var List = require('../utils/list');
var clone = require('../utils/clone');
var usageUtils = require('./usage');

@@ -8,3 +9,3 @@ var clean = require('./clean');

function readBlock(stylesheet, specialComments) {
function readRulesChunk(rules, specialComments) {
var buffer = new List();

@@ -14,3 +15,3 @@ var nonSpaceTokenInBuffer = false;

stylesheet.rules.nextUntil(stylesheet.rules.head, function(node, item, list) {
rules.nextUntil(rules.head, function(node, item, list) {
if (node.type === 'Comment') {

@@ -42,2 +43,3 @@ if (!specialComments || node.value.charAt(0) !== '!') {

type: 'StyleSheet',
info: null,
rules: buffer

@@ -48,9 +50,9 @@ }

function compressBlock(ast, usageData, num, logger) {
function compressChunk(ast, firstAtrulesAllowed, usageData, num, logger) {
logger('Compress block #' + num, null, true);
var seed = 1;
ast.firstAtrulesAllowed = ast.firstAtrulesAllowed;
walkRules(ast, function() {
if (!this.stylesheet.id) {
walkRules(ast, function markStylesheets() {
if ('id' in this.stylesheet === false) {
this.stylesheet.firstAtrulesAllowed = firstAtrulesAllowed;
this.stylesheet.id = seed++;

@@ -90,5 +92,22 @@ }

function wrapBlock(block) {
return new List([{
type: 'Ruleset',
selector: {
type: 'Selector',
selectors: new List([{
type: 'SimpleSelector',
sequence: new List([{
type: 'Identifier',
name: 'x'
}])
}])
},
block: block
}]);
}
module.exports = function compress(ast, options) {
ast = ast || { type: 'StyleSheet', info: null, rules: new List() };
options = options || {};
ast = ast || { type: 'StyleSheet', rules: new List() };

@@ -98,32 +117,21 @@ var logger = typeof options.logger === 'function' ? options.logger : Function();

var restructuring = getRestructureOption(options);
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;
var inputRules;
var outputRules = new List();
var chunk;
var chunkNum = 1;
var chunkRules;
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.clone) {
ast = clone(ast);
}
if (ast.type === 'StyleSheet') {
inputRules = ast.rules;
ast.rules = outputRules;
} else {
inputRules = wrapBlock(ast);
}
if (options.usage) {

@@ -134,17 +142,17 @@ usageData = usageUtils.buildIndex(options.usage);

do {
block = readBlock(ast, Boolean(specialComments));
block.stylesheet.firstAtrulesAllowed = firstAtrulesAllowed;
block.stylesheet = compressBlock(block.stylesheet, usageData, blockNum++, logger);
chunk = readRulesChunk(inputRules, Boolean(specialComments));
compressChunk(chunk.stylesheet, firstAtrulesAllowed, usageData, chunkNum++, logger);
// structure optimisations
if (restructuring) {
restructureBlock(block.stylesheet, usageData, logger);
restructureBlock(chunk.stylesheet, usageData, logger);
}
blockRules = block.stylesheet.rules;
chunkRules = chunk.stylesheet.rules;
if (block.comment) {
// add \n before comment if there is another content in result
if (!result.isEmpty()) {
result.insert(List.createItem({
if (chunk.comment) {
// add \n before comment if there is another content in outputRules
if (!outputRules.isEmpty()) {
outputRules.insert(List.createItem({
type: 'Raw',

@@ -155,7 +163,7 @@ value: '\n'

result.insert(List.createItem(block.comment));
outputRules.insert(List.createItem(chunk.comment));
// add \n after comment if block is not empty
if (!blockRules.isEmpty()) {
result.insert(List.createItem({
// add \n after comment if chunk is not empty
if (!chunkRules.isEmpty()) {
outputRules.insert(List.createItem({
type: 'Raw',

@@ -167,4 +175,4 @@ value: '\n'

if (firstAtrulesAllowed && !blockRules.isEmpty()) {
var lastRule = blockRules.last();
if (firstAtrulesAllowed && !chunkRules.isEmpty()) {
var lastRule = chunkRules.last();

@@ -181,22 +189,8 @@ if (lastRule.type !== 'Atrule' ||

result.appendList(blockRules);
} while (!ast.rules.isEmpty());
outputRules.appendList(chunkRules);
} while (!inputRules.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
ast: ast
};
};

@@ -121,2 +121,6 @@ var List = require('../../utils/list.js');

case 'Function':
special = child.name;
break;
case 'Space':

@@ -123,0 +127,0 @@ return false; // ignore space

@@ -28,6 +28,2 @@ var List = require('../../utils/list.js');

function inList(selector) {
return selector.compareMarker in this;
}
function processRuleset(node, item, list) {

@@ -37,3 +33,5 @@ var avoidRulesMerge = this.stylesheet.avoidRulesMerge;

var block = node.block;
var skippedCompareMarkers = Object.create(null);
var disallowDownMarkers = Object.create(null);
var allowMergeUp = true;
var allowMergeDown = true;

@@ -53,4 +51,8 @@ list.prevUntil(item.prev, function(prev, prevItem) {

allowMergeDown = !prevSelectors.some(function(selector) {
return selector.compareMarker in disallowDownMarkers;
});
// try prev ruleset if simpleselectors has no equal specifity and element selector
if (prevSelectors.some(inList, skippedCompareMarkers)) {
if (!allowMergeDown && !allowMergeUp) {
return true;

@@ -60,3 +62,3 @@ }

// try to join by selectors
if (utils.isEqualLists(prevSelectors, selectors)) {
if (allowMergeUp && utils.isEqualLists(prevSelectors, selectors)) {
prevBlock.declarations.appendList(block.declarations);

@@ -75,4 +77,7 @@ list.remove(item);

// equal blocks
utils.addSelectors(selectors, prevSelectors);
list.remove(prevItem);
if (allowMergeDown) {
utils.addSelectors(selectors, prevSelectors);
list.remove(prevItem);
}
return true;

@@ -87,3 +92,3 @@ } else if (!avoidRulesMerge) { /* probably we don't need to prevent those merges for @keyframes

if (selectorLength < blockLength) {
if (allowMergeUp && selectorLength < blockLength) {
utils.addSelectors(prevSelectors, selectors);

@@ -97,3 +102,3 @@ block.declarations = new List(diff.ne1);

if (selectorLength < blockLength) {
if (allowMergeDown && selectorLength < blockLength) {
utils.addSelectors(selectors, prevSelectors);

@@ -115,3 +120,3 @@ prevBlock.declarations = new List(diff.ne2);

// ruleset description overhead
if (blockLength >= newBlockLength) {
if (allowMergeDown && blockLength >= newBlockLength) {
var newRuleset = {

@@ -138,4 +143,14 @@ type: 'Ruleset',

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) {
skippedCompareMarkers[data.compareMarker] = true;
disallowDownMarkers[data.compareMarker] = true;
});

@@ -142,0 +157,0 @@ });

@@ -71,2 +71,9 @@ var translate = require('../../../utils/translate.js');

case 'Attribute':
if (node.flags) {
pseudos['[' + node.flags + ']'] = true;
hasPseudo = true;
}
break;
case 'Combinator':

@@ -73,0 +80,0 @@ tagName = '*';

@@ -6,2 +6,3 @@ var parse = require('./parser');

var walkers = require('./utils/walk');
var clone = require('./utils/clone');
var List = require('./utils/list');

@@ -128,3 +129,6 @@

walkRules: walkers.rules,
walkRulesRight: walkers.rulesRight
walkRulesRight: walkers.rulesRight,
// utils
clone: clone
};

@@ -766,14 +766,17 @@ 'use strict';

if (scanner.token !== null && scanner.token.type !== TokenType.RightSquareBracket) {
node.operator = readAttrselector();
// avoid case `[name i]`
if (scanner.token.type !== TokenType.Identifier) {
node.operator = readAttrselector();
readSC();
readSC();
if (scanner.token !== null && scanner.token.type === TokenType.String) {
node.value = getString();
} else {
node.value = getIdentifier(false);
if (scanner.token !== null && scanner.token.type === TokenType.String) {
node.value = getString();
} else {
node.value = getIdentifier(false);
}
readSC();
}
readSC();
// attribute flags

@@ -780,0 +783,0 @@ if (scanner.token !== null && scanner.token.type === TokenType.Identifier) {

@@ -23,4 +23,3 @@ 'use strict';

var DIGIT = 3;
var STRING_SQ = 4;
var STRING_DQ = 5;
var STRING = 4;

@@ -86,4 +85,4 @@ var PUNCTUATION = {

SYMBOL_CATEGORY[QUOTE] = STRING_SQ;
SYMBOL_CATEGORY[DOUBLE_QUOTE] = STRING_DQ;
SYMBOL_CATEGORY[QUOTE] = STRING;
SYMBOL_CATEGORY[DOUBLE_QUOTE] = STRING;

@@ -129,13 +128,14 @@ //

next: function() {
this.prevToken = this.token;
var newToken = null;
if (this.buffer.length !== 0) {
this.token = this.buffer.shift();
newToken = this.buffer.shift();
} else if (!this.eof) {
this.token = this.getToken();
} else {
this.token = null;
newToken = this.getToken();
}
return this.token;
this.prevToken = this.token;
this.token = newToken;
return newToken;
},

@@ -168,4 +168,3 @@

case STRING_SQ:
case STRING_DQ:
case STRING:
type = TokenType.String;

@@ -182,3 +181,3 @@ value = this.readString(code);

if (code === SLASH) {
next = this.source.charCodeAt(this.pos + 1);
next = this.pos + 1 < this.source.length ? this.source.charCodeAt(this.pos + 1) : 0;

@@ -382,2 +381,6 @@ if (next === STAR) { // /*

// warm up tokenizer to elimitate code branches that never execute
// fix soft deoptimizations (insufficient type feedback)
new Scanner('\n\r\r\n\f//""\'\'/**/1a;.{url(a)}').lookup(1e3);
module.exports = Scanner;

@@ -79,2 +79,3 @@ function each(list) {

var result = translate(node.name);
var flagsPrefix = ' ';

@@ -87,4 +88,5 @@ if (node.operator !== null) {

if (node.flags !== null) {
result += (node.value.type !== 'String' ? ' ' : '') + node.flags;
// space between string and flags is not required
if (node.value.type === 'String') {
flagsPrefix = '';
}

@@ -94,2 +96,6 @@ }

if (node.flags !== null) {
result += flagsPrefix + node.flags;
}
return '[' + result + ']';

@@ -96,0 +102,0 @@

@@ -188,2 +188,3 @@ var SourceMapGenerator = require('source-map').SourceMapGenerator;

var result = translate(node.name);
var flagsPrefix = ' ';

@@ -196,4 +197,5 @@ if (node.operator !== null) {

if (node.flags !== null) {
result += (node.value.type !== 'String' ? ' ' : '') + node.flags;
// space between string and flags is not required
if (node.value.type === 'String') {
flagsPrefix = '';
}

@@ -203,2 +205,6 @@ }

if (node.flags !== null) {
result += flagsPrefix + node.flags;
}
return '[' + result + ']';

@@ -205,0 +211,0 @@

{
"name": "csso",
"version": "2.1.1",
"version": "2.2.0",
"description": "CSSO (CSS Optimizer) is a CSS minifier with structural optimisations",

@@ -5,0 +5,0 @@ "keywords": [

@@ -289,7 +289,10 @@ [![NPM version](https://img.shields.io/npm/v/csso.svg)](https://www.npmjs.com/package/csso)

Do the main task – compress AST.
Does the main task – compress AST.
> NOTE: `compress` performs AST compression by transforming input AST by default (since AST cloning is expensive and needed in rare cases). Use `clone` option with truthy value in case you want to keep input AST untouched.
Options:
- restructure `Boolean` – do the structure optimisations or not (`true` by default)
- clone `Boolean` - transform a copy of input AST if `true`, useful in case of AST reuse (`false` by default)
- comments `String` or `Boolean` – specify what comments to left

@@ -302,2 +305,22 @@ - `'exclamation'` or `true` (default) – left all exclamation comments (i.e. `/*! .. */`)

#### clone(ast)
Make an AST node deep copy.
```js
var orig = csso.parse('.test { color: red }');
var copy = csso.clone(orig);
csso.walk(copy, function(node) {
if (node.type === 'Class') {
node.name = 'replaced';
}
});
console.log(csso.translate(orig));
// .test{color:red}
console.log(csso.translate(copy));
// .replaced{color:red}
```
#### translate(ast)

@@ -304,0 +327,0 @@

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc