From efbc2ffe6a1ee5ec38a4396305561d6515d0943e Mon Sep 17 00:00:00 2001 From: littleblack111 Date: Fri, 30 Aug 2024 17:21:18 +0800 Subject: node fixes, updates --- .../level-2/properties/every-values-pair.js | 28 ++ .../level-2/properties/find-component-in.js | 38 ++ .../optimizer/level-2/properties/has-inherit.js | 9 + .../level-2/properties/has-same-values.js | 14 + .../lib/optimizer/level-2/properties/has-unset.js | 9 + .../level-2/properties/is-component-of.js | 22 + .../level-2/properties/is-mergeable-shorthand.js | 11 + .../level-2/properties/merge-into-shorthands.js | 496 +++++++++++++++++++++ .../lib/optimizer/level-2/properties/optimize.js | 40 ++ .../level-2/properties/override-properties.js | 461 +++++++++++++++++++ .../overrides-non-component-shorthand.js | 9 + .../level-2/properties/populate-components.js | 61 +++ 12 files changed, 1198 insertions(+) create mode 100644 node_modules/clean-css/lib/optimizer/level-2/properties/every-values-pair.js create mode 100644 node_modules/clean-css/lib/optimizer/level-2/properties/find-component-in.js create mode 100644 node_modules/clean-css/lib/optimizer/level-2/properties/has-inherit.js create mode 100644 node_modules/clean-css/lib/optimizer/level-2/properties/has-same-values.js create mode 100644 node_modules/clean-css/lib/optimizer/level-2/properties/has-unset.js create mode 100644 node_modules/clean-css/lib/optimizer/level-2/properties/is-component-of.js create mode 100644 node_modules/clean-css/lib/optimizer/level-2/properties/is-mergeable-shorthand.js create mode 100644 node_modules/clean-css/lib/optimizer/level-2/properties/merge-into-shorthands.js create mode 100644 node_modules/clean-css/lib/optimizer/level-2/properties/optimize.js create mode 100644 node_modules/clean-css/lib/optimizer/level-2/properties/override-properties.js create mode 100644 node_modules/clean-css/lib/optimizer/level-2/properties/overrides-non-component-shorthand.js create mode 100644 node_modules/clean-css/lib/optimizer/level-2/properties/populate-components.js (limited to 'node_modules/clean-css/lib/optimizer/level-2/properties') diff --git a/node_modules/clean-css/lib/optimizer/level-2/properties/every-values-pair.js b/node_modules/clean-css/lib/optimizer/level-2/properties/every-values-pair.js new file mode 100644 index 00000000..44fcb7d5 --- /dev/null +++ b/node_modules/clean-css/lib/optimizer/level-2/properties/every-values-pair.js @@ -0,0 +1,28 @@ +var Marker = require('../../../tokenizer/marker'); + +function everyValuesPair(fn, left, right) { + var leftSize = left.value.length; + var rightSize = right.value.length; + var total = Math.max(leftSize, rightSize); + var lowerBound = Math.min(leftSize, rightSize) - 1; + var leftValue; + var rightValue; + var position; + + for (position = 0; position < total; position++) { + leftValue = left.value[position] && left.value[position][1] || leftValue; + rightValue = right.value[position] && right.value[position][1] || rightValue; + + if (leftValue == Marker.COMMA || rightValue == Marker.COMMA) { + continue; + } + + if (!fn(leftValue, rightValue, position, position <= lowerBound)) { + return false; + } + } + + return true; +} + +module.exports = everyValuesPair; diff --git a/node_modules/clean-css/lib/optimizer/level-2/properties/find-component-in.js b/node_modules/clean-css/lib/optimizer/level-2/properties/find-component-in.js new file mode 100644 index 00000000..745543b6 --- /dev/null +++ b/node_modules/clean-css/lib/optimizer/level-2/properties/find-component-in.js @@ -0,0 +1,38 @@ +var configuration = require('../../configuration'); + +function findComponentIn(shorthand, longhand) { + var comparator = nameComparator(longhand); + + return findInDirectComponents(shorthand, comparator) || findInSubComponents(shorthand, comparator); +} + +function nameComparator(to) { + return function(property) { + return to.name === property.name; + }; +} + +function findInDirectComponents(shorthand, comparator) { + return shorthand.components.filter(comparator)[0]; +} + +function findInSubComponents(shorthand, comparator) { + var shorthandComponent; + var longhandMatch; + var i, l; + + if (!configuration[shorthand.name].shorthandComponents) { + return; + } + + for (i = 0, l = shorthand.components.length; i < l; i++) { + shorthandComponent = shorthand.components[i]; + longhandMatch = findInDirectComponents(shorthandComponent, comparator); + + if (longhandMatch) { + return longhandMatch; + } + } +} + +module.exports = findComponentIn; diff --git a/node_modules/clean-css/lib/optimizer/level-2/properties/has-inherit.js b/node_modules/clean-css/lib/optimizer/level-2/properties/has-inherit.js new file mode 100644 index 00000000..8a029c59 --- /dev/null +++ b/node_modules/clean-css/lib/optimizer/level-2/properties/has-inherit.js @@ -0,0 +1,9 @@ +function hasInherit(property) { + for (var i = property.value.length - 1; i >= 0; i--) { + if (property.value[i][1] == 'inherit') { return true; } + } + + return false; +} + +module.exports = hasInherit; diff --git a/node_modules/clean-css/lib/optimizer/level-2/properties/has-same-values.js b/node_modules/clean-css/lib/optimizer/level-2/properties/has-same-values.js new file mode 100644 index 00000000..18815191 --- /dev/null +++ b/node_modules/clean-css/lib/optimizer/level-2/properties/has-same-values.js @@ -0,0 +1,14 @@ +function hasSameValues(property) { + var firstValue = property.value[0][1]; + var i, l; + + for (i = 1, l = property.value.length; i < l; i++) { + if (property.value[i][1] != firstValue) { + return false; + } + } + + return true; +} + +module.exports = hasSameValues; diff --git a/node_modules/clean-css/lib/optimizer/level-2/properties/has-unset.js b/node_modules/clean-css/lib/optimizer/level-2/properties/has-unset.js new file mode 100644 index 00000000..d31a4888 --- /dev/null +++ b/node_modules/clean-css/lib/optimizer/level-2/properties/has-unset.js @@ -0,0 +1,9 @@ +function hasUnset(property) { + for (var i = property.value.length - 1; i >= 0; i--) { + if (property.value[i][1] == 'unset') { return true; } + } + + return false; +} + +module.exports = hasUnset; diff --git a/node_modules/clean-css/lib/optimizer/level-2/properties/is-component-of.js b/node_modules/clean-css/lib/optimizer/level-2/properties/is-component-of.js new file mode 100644 index 00000000..571d05eb --- /dev/null +++ b/node_modules/clean-css/lib/optimizer/level-2/properties/is-component-of.js @@ -0,0 +1,22 @@ +var configuration = require('../../configuration'); + +function isComponentOf(property1, property2, shallow) { + return isDirectComponentOf(property1, property2) + || !shallow && !!configuration[property1.name].shorthandComponents && isSubComponentOf(property1, property2); +} + +function isDirectComponentOf(property1, property2) { + var descriptor = configuration[property1.name]; + + return 'components' in descriptor && descriptor.components.indexOf(property2.name) > -1; +} + +function isSubComponentOf(property1, property2) { + return property1 + .components + .some(function(component) { + return isDirectComponentOf(component, property2); + }); +} + +module.exports = isComponentOf; diff --git a/node_modules/clean-css/lib/optimizer/level-2/properties/is-mergeable-shorthand.js b/node_modules/clean-css/lib/optimizer/level-2/properties/is-mergeable-shorthand.js new file mode 100644 index 00000000..ee7191ef --- /dev/null +++ b/node_modules/clean-css/lib/optimizer/level-2/properties/is-mergeable-shorthand.js @@ -0,0 +1,11 @@ +var Marker = require('../../../tokenizer/marker'); + +function isMergeableShorthand(shorthand) { + if (shorthand.name != 'font') { + return true; + } + + return shorthand.value[0][1].indexOf(Marker.INTERNAL) == -1; +} + +module.exports = isMergeableShorthand; diff --git a/node_modules/clean-css/lib/optimizer/level-2/properties/merge-into-shorthands.js b/node_modules/clean-css/lib/optimizer/level-2/properties/merge-into-shorthands.js new file mode 100644 index 00000000..9ff9139f --- /dev/null +++ b/node_modules/clean-css/lib/optimizer/level-2/properties/merge-into-shorthands.js @@ -0,0 +1,496 @@ +var everyValuesPair = require('./every-values-pair'); +var hasInherit = require('./has-inherit'); +var hasSameValues = require('./has-same-values'); +var populateComponents = require('./populate-components'); + +var configuration = require('../../configuration'); +var deepClone = require('../../clone').deep; +var restoreWithComponents = require('../restore-with-components'); + +var restoreFromOptimizing = require('../../restore-from-optimizing'); +var wrapSingle = require('../../wrap-for-optimizing').single; + +var serializeBody = require('../../../writer/one-time').body; +var Token = require('../../../tokenizer/token'); + +function mergeIntoShorthands(properties, validator) { + var candidates = {}; + var descriptor; + var componentOf; + var property; + var i, l; + var j, m; + + // there is no shorthand property made up of less than 3 longhands + if (properties.length < 3) { + return; + } + + for (i = 0, l = properties.length; i < l; i++) { + property = properties[i]; + descriptor = configuration[property.name]; + + if (property.dynamic) { + continue; + } + + if (property.unused) { + continue; + } + + if (property.hack) { + continue; + } + + if (property.block) { + continue; + } + + if (descriptor && descriptor.singleTypeComponents && !hasSameValues(property)) { + continue; + } + + invalidateOrCompact(properties, i, candidates, validator); + + if (descriptor && descriptor.componentOf) { + for (j = 0, m = descriptor.componentOf.length; j < m; j++) { + componentOf = descriptor.componentOf[j]; + + candidates[componentOf] = candidates[componentOf] || {}; + candidates[componentOf][property.name] = property; + } + } + } + + invalidateOrCompact(properties, i, candidates, validator); +} + +function invalidateOrCompact(properties, position, candidates, validator) { + var invalidatedBy = properties[position]; + var shorthandName; + var shorthandDescriptor; + var candidateComponents; + var replacedCandidates = []; + var i; + + for (shorthandName in candidates) { + if (undefined !== invalidatedBy && shorthandName == invalidatedBy.name) { + continue; + } + + shorthandDescriptor = configuration[shorthandName]; + candidateComponents = candidates[shorthandName]; + if (invalidatedBy && invalidates(candidates, shorthandName, invalidatedBy)) { + delete candidates[shorthandName]; + continue; + } + + if (shorthandDescriptor.components.length > Object.keys(candidateComponents).length) { + continue; + } + + if (mixedImportance(candidateComponents)) { + continue; + } + + if (!overridable(candidateComponents, shorthandName, validator)) { + continue; + } + + if (!mergeable(candidateComponents)) { + continue; + } + + if (mixedInherit(candidateComponents)) { + replaceWithInheritBestFit(properties, candidateComponents, shorthandName, validator); + } else { + replaceWithShorthand(properties, candidateComponents, shorthandName, validator); + } + + replacedCandidates.push(shorthandName); + } + + for (i = replacedCandidates.length - 1; i >= 0; i--) { + delete candidates[replacedCandidates[i]]; + } +} + +function invalidates(candidates, shorthandName, invalidatedBy) { + var shorthandDescriptor = configuration[shorthandName]; + var invalidatedByDescriptor = configuration[invalidatedBy.name]; + var componentName; + + if ('overridesShorthands' in shorthandDescriptor && shorthandDescriptor.overridesShorthands.indexOf(invalidatedBy.name) > -1) { + return true; + } + + if (invalidatedByDescriptor && 'componentOf' in invalidatedByDescriptor) { + for (componentName in candidates[shorthandName]) { + if (invalidatedByDescriptor.componentOf.indexOf(componentName) > -1) { + return true; + } + } + } + + return false; +} + +function mixedImportance(components) { + var important; + var componentName; + + for (componentName in components) { + if (undefined !== important && components[componentName].important != important) { + return true; + } + + important = components[componentName].important; + } + + return false; +} + +function overridable(components, shorthandName, validator) { + var descriptor = configuration[shorthandName]; + var newValuePlaceholder = [ + Token.PROPERTY, + [Token.PROPERTY_NAME, shorthandName], + [Token.PROPERTY_VALUE, descriptor.defaultValue] + ]; + var newProperty = wrapSingle(newValuePlaceholder); + var component; + var mayOverride; + var i, l; + + populateComponents([newProperty], validator, []); + + for (i = 0, l = descriptor.components.length; i < l; i++) { + component = components[descriptor.components[i]]; + mayOverride = configuration[component.name].canOverride || sameValue; + + if (!everyValuesPair(mayOverride.bind(null, validator), newProperty.components[i], component)) { + return false; + } + } + + return true; +} + +function sameValue(_validator, value1, value2) { + return value1 === value2; +} + +function mergeable(components) { + var lastCount = null; + var currentCount; + var componentName; + var component; + var descriptor; + var values; + + for (componentName in components) { + component = components[componentName]; + descriptor = configuration[componentName]; + + if (!('restore' in descriptor)) { + continue; + } + + restoreFromOptimizing([component.all[component.position]], restoreWithComponents); + values = descriptor.restore(component, configuration); + + currentCount = values.length; + + if (lastCount !== null && currentCount !== lastCount) { + return false; + } + + lastCount = currentCount; + } + + return true; +} + +function mixedInherit(components) { + var componentName; + var lastValue = null; + var currentValue; + + for (componentName in components) { + currentValue = hasInherit(components[componentName]); + + if (lastValue !== null && lastValue !== currentValue) { + return true; + } + + lastValue = currentValue; + } + + return false; +} + +function replaceWithInheritBestFit(properties, candidateComponents, shorthandName, validator) { + var viaLonghands = buildSequenceWithInheritLonghands(candidateComponents, shorthandName, validator); + var viaShorthand = buildSequenceWithInheritShorthand(candidateComponents, shorthandName, validator); + var longhandTokensSequence = viaLonghands[0]; + var shorthandTokensSequence = viaShorthand[0]; + var isLonghandsShorter = serializeBody(longhandTokensSequence).length < serializeBody(shorthandTokensSequence).length; + var newTokensSequence = isLonghandsShorter ? longhandTokensSequence : shorthandTokensSequence; + var newProperty = isLonghandsShorter ? viaLonghands[1] : viaShorthand[1]; + var newComponents = isLonghandsShorter ? viaLonghands[2] : viaShorthand[2]; + var lastComponent = candidateComponents[Object.keys(candidateComponents).pop()]; + var all = lastComponent.all; + var insertAt = lastComponent.position; + var componentName; + var oldComponent; + var newComponent; + var newToken; + + newProperty.position = insertAt; + newProperty.shorthand = true; + newProperty.important = lastComponent.important; + newProperty.multiplex = false; + newProperty.dirty = true; + newProperty.all = all; + newProperty.all[insertAt] = newTokensSequence[0]; + + properties.splice(insertAt, 1, newProperty); + + for (componentName in candidateComponents) { + oldComponent = candidateComponents[componentName]; + oldComponent.unused = true; + + newProperty.multiplex = newProperty.multiplex || oldComponent.multiplex; + + if (oldComponent.name in newComponents) { + newComponent = newComponents[oldComponent.name]; + newToken = findTokenIn(newTokensSequence, componentName); + + newComponent.position = all.length; + newComponent.all = all; + newComponent.all.push(newToken); + + properties.push(newComponent); + } + } +} + +function buildSequenceWithInheritLonghands(components, shorthandName, validator) { + var tokensSequence = []; + var inheritComponents = {}; + var nonInheritComponents = {}; + var descriptor = configuration[shorthandName]; + var shorthandToken = [ + Token.PROPERTY, + [Token.PROPERTY_NAME, shorthandName], + [Token.PROPERTY_VALUE, descriptor.defaultValue] + ]; + var newProperty = wrapSingle(shorthandToken); + var component; + var longhandToken; + var newComponent; + var nameMetadata; + var i, l; + + populateComponents([newProperty], validator, []); + + for (i = 0, l = descriptor.components.length; i < l; i++) { + component = components[descriptor.components[i]]; + + if (hasInherit(component)) { + longhandToken = component.all[component.position].slice(0, 2); + Array.prototype.push.apply(longhandToken, component.value); + tokensSequence.push(longhandToken); + + newComponent = deepClone(component); + newComponent.value = inferComponentValue(components, newComponent.name); + + newProperty.components[i] = newComponent; + inheritComponents[component.name] = deepClone(component); + } else { + newComponent = deepClone(component); + newComponent.all = component.all; + newProperty.components[i] = newComponent; + + nonInheritComponents[component.name] = component; + } + } + + newProperty.important = components[Object.keys(components).pop()].important; + + nameMetadata = joinMetadata(nonInheritComponents, 1); + shorthandToken[1].push(nameMetadata); + + restoreFromOptimizing([newProperty], restoreWithComponents); + + shorthandToken = shorthandToken.slice(0, 2); + Array.prototype.push.apply(shorthandToken, newProperty.value); + + tokensSequence.unshift(shorthandToken); + + return [tokensSequence, newProperty, inheritComponents]; +} + +function inferComponentValue(components, propertyName) { + var descriptor = configuration[propertyName]; + + if ('oppositeTo' in descriptor) { + return components[descriptor.oppositeTo].value; + } + return [[Token.PROPERTY_VALUE, descriptor.defaultValue]]; +} + +function joinMetadata(components, at) { + var metadata = []; + var component; + var originalValue; + var componentMetadata; + var componentName; + + for (componentName in components) { + component = components[componentName]; + originalValue = component.all[component.position]; + componentMetadata = originalValue[at][originalValue[at].length - 1]; + + Array.prototype.push.apply(metadata, componentMetadata); + } + + return metadata.sort(metadataSorter); +} + +function metadataSorter(metadata1, metadata2) { + var line1 = metadata1[0]; + var line2 = metadata2[0]; + var column1 = metadata1[1]; + var column2 = metadata2[1]; + + if (line1 < line2) { + return -1; + } if (line1 === line2) { + return column1 < column2 ? -1 : 1; + } + return 1; +} + +function buildSequenceWithInheritShorthand(components, shorthandName, validator) { + var tokensSequence = []; + var inheritComponents = {}; + var nonInheritComponents = {}; + var descriptor = configuration[shorthandName]; + var shorthandToken = [ + Token.PROPERTY, + [Token.PROPERTY_NAME, shorthandName], + [Token.PROPERTY_VALUE, 'inherit'] + ]; + var newProperty = wrapSingle(shorthandToken); + var component; + var longhandToken; + var nameMetadata; + var valueMetadata; + var i, l; + + populateComponents([newProperty], validator, []); + + for (i = 0, l = descriptor.components.length; i < l; i++) { + component = components[descriptor.components[i]]; + + if (hasInherit(component)) { + inheritComponents[component.name] = component; + } else { + longhandToken = component.all[component.position].slice(0, 2); + Array.prototype.push.apply(longhandToken, component.value); + tokensSequence.push(longhandToken); + + nonInheritComponents[component.name] = deepClone(component); + } + } + + nameMetadata = joinMetadata(inheritComponents, 1); + shorthandToken[1].push(nameMetadata); + + valueMetadata = joinMetadata(inheritComponents, 2); + shorthandToken[2].push(valueMetadata); + + tokensSequence.unshift(shorthandToken); + + return [tokensSequence, newProperty, nonInheritComponents]; +} + +function findTokenIn(tokens, componentName) { + var i, l; + + for (i = 0, l = tokens.length; i < l; i++) { + if (tokens[i][1][1] == componentName) { + return tokens[i]; + } + } +} + +function replaceWithShorthand(properties, candidateComponents, shorthandName, validator) { + var descriptor = configuration[shorthandName]; + var nameMetadata; + var valueMetadata; + var newValuePlaceholder = [ + Token.PROPERTY, + [Token.PROPERTY_NAME, shorthandName], + [Token.PROPERTY_VALUE, descriptor.defaultValue] + ]; + var all; + var insertAt = inferInsertAtFrom(properties, candidateComponents, shorthandName); + + var newProperty = wrapSingle(newValuePlaceholder); + newProperty.shorthand = true; + newProperty.dirty = true; + newProperty.multiplex = false; + + populateComponents([newProperty], validator, []); + + for (var i = 0, l = descriptor.components.length; i < l; i++) { + var component = candidateComponents[descriptor.components[i]]; + + newProperty.components[i] = deepClone(component); + newProperty.important = component.important; + newProperty.multiplex = newProperty.multiplex || component.multiplex; + + all = component.all; + } + + for (var componentName in candidateComponents) { + candidateComponents[componentName].unused = true; + } + + nameMetadata = joinMetadata(candidateComponents, 1); + newValuePlaceholder[1].push(nameMetadata); + + valueMetadata = joinMetadata(candidateComponents, 2); + newValuePlaceholder[2].push(valueMetadata); + + newProperty.position = insertAt; + newProperty.all = all; + newProperty.all[insertAt] = newValuePlaceholder; + + properties.splice(insertAt, 1, newProperty); +} + +function inferInsertAtFrom(properties, candidateComponents, shorthandName) { + var candidateComponentNames = Object.keys(candidateComponents); + var firstCandidatePosition = candidateComponents[candidateComponentNames[0]].position; + var lastCandidatePosition = candidateComponents[candidateComponentNames[candidateComponentNames.length - 1]].position; + + if (shorthandName == 'border' && traversesVia(properties.slice(firstCandidatePosition, lastCandidatePosition), 'border-image')) { + return firstCandidatePosition; + } + return lastCandidatePosition; +} + +function traversesVia(properties, propertyName) { + for (var i = properties.length - 1; i >= 0; i--) { + if (properties[i].name == propertyName) { + return true; + } + } + + return false; +} + +module.exports = mergeIntoShorthands; diff --git a/node_modules/clean-css/lib/optimizer/level-2/properties/optimize.js b/node_modules/clean-css/lib/optimizer/level-2/properties/optimize.js new file mode 100644 index 00000000..536cd6d5 --- /dev/null +++ b/node_modules/clean-css/lib/optimizer/level-2/properties/optimize.js @@ -0,0 +1,40 @@ +var mergeIntoShorthands = require('./merge-into-shorthands'); +var overrideProperties = require('./override-properties'); +var populateComponents = require('./populate-components'); + +var restoreWithComponents = require('../restore-with-components'); + +var wrapForOptimizing = require('../../wrap-for-optimizing').all; +var removeUnused = require('../../remove-unused'); +var restoreFromOptimizing = require('../../restore-from-optimizing'); + +var OptimizationLevel = require('../../../options/optimization-level').OptimizationLevel; + +function optimizeProperties(properties, withOverriding, withMerging, context) { + var levelOptions = context.options.level[OptimizationLevel.Two]; + var _properties = wrapForOptimizing(properties, levelOptions.skipProperties); + var _property; + var i, l; + + populateComponents(_properties, context.validator, context.warnings); + + for (i = 0, l = _properties.length; i < l; i++) { + _property = _properties[i]; + if (_property.block) { + optimizeProperties(_property.value[0][1], withOverriding, withMerging, context); + } + } + + if (withMerging && levelOptions.mergeIntoShorthands) { + mergeIntoShorthands(_properties, context.validator); + } + + if (withOverriding && levelOptions.overrideProperties) { + overrideProperties(_properties, withMerging, context.options.compatibility, context.validator); + } + + restoreFromOptimizing(_properties, restoreWithComponents); + removeUnused(_properties); +} + +module.exports = optimizeProperties; diff --git a/node_modules/clean-css/lib/optimizer/level-2/properties/override-properties.js b/node_modules/clean-css/lib/optimizer/level-2/properties/override-properties.js new file mode 100644 index 00000000..5f7aa38e --- /dev/null +++ b/node_modules/clean-css/lib/optimizer/level-2/properties/override-properties.js @@ -0,0 +1,461 @@ +var hasInherit = require('./has-inherit'); +var hasUnset = require('./has-unset'); +var everyValuesPair = require('./every-values-pair'); +var findComponentIn = require('./find-component-in'); +var isComponentOf = require('./is-component-of'); +var isMergeableShorthand = require('./is-mergeable-shorthand'); +var overridesNonComponentShorthand = require('./overrides-non-component-shorthand'); +var sameVendorPrefixesIn = require('./../../vendor-prefixes').same; + +var configuration = require('../../configuration'); +var deepClone = require('../../clone').deep; +var restoreWithComponents = require('../restore-with-components'); +var shallowClone = require('../../clone').shallow; + +var restoreFromOptimizing = require('../../restore-from-optimizing'); + +var Token = require('../../../tokenizer/token'); +var Marker = require('../../../tokenizer/marker'); + +var serializeProperty = require('../../../writer/one-time').property; + +function sameValue(_validator, value1, value2) { + return value1 === value2; +} + +function wouldBreakCompatibility(property, validator) { + for (var i = 0; i < property.components.length; i++) { + var component = property.components[i]; + var descriptor = configuration[component.name]; + var canOverride = descriptor && descriptor.canOverride || sameValue; + + var _component = shallowClone(component); + _component.value = [[Token.PROPERTY_VALUE, descriptor.defaultValue]]; + + if (!everyValuesPair(canOverride.bind(null, validator), _component, component)) { + return true; + } + } + + return false; +} + +function overrideIntoMultiplex(property, by) { + by.unused = true; + + turnIntoMultiplex(by, multiplexSize(property)); + property.value = by.value; +} + +function overrideByMultiplex(property, by) { + by.unused = true; + property.multiplex = true; + property.value = by.value; +} + +function overrideSimple(property, by) { + by.unused = true; + property.value = by.value; +} + +function override(property, by) { + if (by.multiplex) { + overrideByMultiplex(property, by); + } else if (property.multiplex) { + overrideIntoMultiplex(property, by); + } else { + overrideSimple(property, by); + } +} + +function overrideShorthand(property, by) { + by.unused = true; + + for (var i = 0, l = property.components.length; i < l; i++) { + override(property.components[i], by.components[i]); + } +} + +function turnIntoMultiplex(property, size) { + property.multiplex = true; + + if (configuration[property.name].shorthand) { + turnShorthandValueIntoMultiplex(property, size); + } else { + turnLonghandValueIntoMultiplex(property, size); + } +} + +function turnShorthandValueIntoMultiplex(property, size) { + var component; + var i, l; + + for (i = 0, l = property.components.length; i < l; i++) { + component = property.components[i]; + + if (!component.multiplex) { + turnLonghandValueIntoMultiplex(component, size); + } + } +} + +function turnLonghandValueIntoMultiplex(property, size) { + var descriptor = configuration[property.name]; + var withRealValue = descriptor.intoMultiplexMode == 'real'; + var withValue = descriptor.intoMultiplexMode == 'real' + ? property.value.slice(0) + : (descriptor.intoMultiplexMode == 'placeholder' ? descriptor.placeholderValue : descriptor.defaultValue); + var i = multiplexSize(property); + var j; + var m = withValue.length; + + for (; i < size; i++) { + property.value.push([Token.PROPERTY_VALUE, Marker.COMMA]); + + if (Array.isArray(withValue)) { + for (j = 0; j < m; j++) { + property.value.push(withRealValue ? withValue[j] : [Token.PROPERTY_VALUE, withValue[j]]); + } + } else { + property.value.push(withRealValue ? withValue : [Token.PROPERTY_VALUE, withValue]); + } + } +} + +function multiplexSize(component) { + var size = 0; + + for (var i = 0, l = component.value.length; i < l; i++) { + if (component.value[i][1] == Marker.COMMA) { size++; } + } + + return size + 1; +} + +function lengthOf(property) { + var fakeAsArray = [ + Token.PROPERTY, + [Token.PROPERTY_NAME, property.name] + ].concat(property.value); + return serializeProperty([fakeAsArray], 0).length; +} + +function moreSameShorthands(properties, startAt, name) { + // Since we run the main loop in `compactOverrides` backwards, at this point some + // properties may not be marked as unused. + // We should consider reverting the order if possible + var count = 0; + + for (var i = startAt; i >= 0; i--) { + if (properties[i].name == name && !properties[i].unused) { count++; } + if (count > 1) { break; } + } + + return count > 1; +} + +function overridingFunction(shorthand, validator) { + for (var i = 0, l = shorthand.components.length; i < l; i++) { + if (!anyValue(validator.isUrl, shorthand.components[i]) + && anyValue(validator.isFunction, shorthand.components[i])) { return true; } + } + + return false; +} + +function anyValue(fn, property) { + for (var i = 0, l = property.value.length; i < l; i++) { + if (property.value[i][1] == Marker.COMMA) { continue; } + + if (fn(property.value[i][1])) { return true; } + } + + return false; +} + +function wouldResultInLongerValue(left, right) { + if (!left.multiplex && !right.multiplex || left.multiplex && right.multiplex) { return false; } + + var multiplex = left.multiplex ? left : right; + var simple = left.multiplex ? right : left; + var component; + + var multiplexClone = deepClone(multiplex); + restoreFromOptimizing([multiplexClone], restoreWithComponents); + + var simpleClone = deepClone(simple); + restoreFromOptimizing([simpleClone], restoreWithComponents); + + var lengthBefore = lengthOf(multiplexClone) + 1 + lengthOf(simpleClone); + + if (left.multiplex) { + component = findComponentIn(multiplexClone, simpleClone); + overrideIntoMultiplex(component, simpleClone); + } else { + component = findComponentIn(simpleClone, multiplexClone); + turnIntoMultiplex(simpleClone, multiplexSize(multiplexClone)); + overrideByMultiplex(component, multiplexClone); + } + + restoreFromOptimizing([simpleClone], restoreWithComponents); + + var lengthAfter = lengthOf(simpleClone); + + return lengthBefore <= lengthAfter; +} + +function isCompactable(property) { + return property.name in configuration; +} + +function noneOverrideHack(left, right) { + return !left.multiplex + && (left.name == 'background' || left.name == 'background-image') + && right.multiplex + && (right.name == 'background' || right.name == 'background-image') + && anyLayerIsNone(right.value); +} + +function anyLayerIsNone(values) { + var layers = intoLayers(values); + + for (var i = 0, l = layers.length; i < l; i++) { + if (layers[i].length == 1 && layers[i][0][1] == 'none') { return true; } + } + + return false; +} + +function intoLayers(values) { + var layers = []; + + for (var i = 0, layer = [], l = values.length; i < l; i++) { + var value = values[i]; + if (value[1] == Marker.COMMA) { + layers.push(layer); + layer = []; + } else { + layer.push(value); + } + } + + layers.push(layer); + return layers; +} + +function overrideProperties(properties, withMerging, compatibility, validator) { + var mayOverride, right, left, component; + var overriddenComponents; + var overriddenComponent; + var overridingComponent; + var overridable; + var i, j, k; + + propertyLoop: + for (i = properties.length - 1; i >= 0; i--) { + right = properties[i]; + + if (!isCompactable(right)) { continue; } + + if (right.block) { continue; } + + mayOverride = configuration[right.name].canOverride || sameValue; + + traverseLoop: + for (j = i - 1; j >= 0; j--) { + left = properties[j]; + + if (!isCompactable(left)) { continue; } + + if (left.block) { continue; } + + if (left.dynamic || right.dynamic) { continue; } + + if (left.unused || right.unused) { continue; } + + if (left.hack && !right.hack && !right.important || !left.hack && !left.important && right.hack) { continue; } + + if (left.important == right.important && left.hack[0] != right.hack[0]) { continue; } + + if (left.important == right.important + && (left.hack[0] != right.hack[0] || (left.hack[1] && left.hack[1] != right.hack[1]))) { continue; } + + if (hasInherit(right)) { continue; } + + if (noneOverrideHack(left, right)) { continue; } + + if (right.shorthand && isComponentOf(right, left)) { + // maybe `left` can be overridden by `right` which is a shorthand? + if (!right.important && left.important) { continue; } + + if (!sameVendorPrefixesIn([left], right.components)) { continue; } + + if (!anyValue(validator.isFunction, left) && overridingFunction(right, validator)) { continue; } + + if (!isMergeableShorthand(right)) { + left.unused = true; + continue; + } + + component = findComponentIn(right, left); + mayOverride = configuration[left.name].canOverride || sameValue; + if (everyValuesPair(mayOverride.bind(null, validator), left, component)) { + left.unused = true; + } + } else if (right.shorthand && overridesNonComponentShorthand(right, left)) { + // `right` is a shorthand while `left` can be overriden by it, think `border` and `border-top` + if (!right.important && left.important) { + continue; + } + + if (!sameVendorPrefixesIn([left], right.components)) { + continue; + } + + if (!anyValue(validator.isFunction, left) && overridingFunction(right, validator)) { + continue; + } + + overriddenComponents = left.shorthand + ? left.components + : [left]; + + for (k = overriddenComponents.length - 1; k >= 0; k--) { + overriddenComponent = overriddenComponents[k]; + overridingComponent = findComponentIn(right, overriddenComponent); + mayOverride = configuration[overriddenComponent.name].canOverride || sameValue; + + if (!everyValuesPair(mayOverride.bind(null, validator), left, overridingComponent)) { + continue traverseLoop; + } + } + + left.unused = true; + } else if (withMerging && left.shorthand && !right.shorthand && isComponentOf(left, right, true)) { + // maybe `right` can be pulled into `left` which is a shorthand? + if (right.important && !left.important) { continue; } + + if (!right.important && left.important) { + right.unused = true; + continue; + } + + // Pending more clever algorithm in #527 + if (moreSameShorthands(properties, i - 1, left.name)) { continue; } + + if (overridingFunction(left, validator)) { continue; } + + if (!isMergeableShorthand(left)) { continue; } + + if (hasUnset(left) || hasUnset(right)) { continue; } + + component = findComponentIn(left, right); + if (everyValuesPair(mayOverride.bind(null, validator), component, right)) { + var disabledBackgroundMerging = !compatibility.properties.backgroundClipMerging && component.name.indexOf('background-clip') > -1 + || !compatibility.properties.backgroundOriginMerging && component.name.indexOf('background-origin') > -1 + || !compatibility.properties.backgroundSizeMerging && component.name.indexOf('background-size') > -1; + var nonMergeableValue = configuration[right.name].nonMergeableValue === right.value[0][1]; + + if (disabledBackgroundMerging || nonMergeableValue) { continue; } + + if (!compatibility.properties.merging && wouldBreakCompatibility(left, validator)) { continue; } + + if (component.value[0][1] != right.value[0][1] && (hasInherit(left) || hasInherit(right))) { continue; } + + if (wouldResultInLongerValue(left, right)) { continue; } + + if (!left.multiplex && right.multiplex) { turnIntoMultiplex(left, multiplexSize(right)); } + + override(component, right); + left.dirty = true; + } + } else if (withMerging && left.shorthand && right.shorthand && left.name == right.name) { + // merge if all components can be merged + + if (!left.multiplex && right.multiplex) { continue; } + + if (!right.important && left.important) { + right.unused = true; + continue propertyLoop; + } + + if (right.important && !left.important) { + left.unused = true; + continue; + } + + if (!isMergeableShorthand(right)) { + left.unused = true; + continue; + } + + for (k = left.components.length - 1; k >= 0; k--) { + var leftComponent = left.components[k]; + var rightComponent = right.components[k]; + + mayOverride = configuration[leftComponent.name].canOverride || sameValue; + if (!everyValuesPair(mayOverride.bind(null, validator), leftComponent, rightComponent)) { + continue propertyLoop; + } + } + + overrideShorthand(left, right); + left.dirty = true; + } else if (withMerging && left.shorthand && right.shorthand && isComponentOf(left, right)) { + // border is a shorthand but any of its components is a shorthand too + + if (!left.important && right.important) { continue; } + + component = findComponentIn(left, right); + mayOverride = configuration[right.name].canOverride || sameValue; + if (!everyValuesPair(mayOverride.bind(null, validator), component, right)) { continue; } + + if (left.important && !right.important) { + right.unused = true; + continue; + } + + var rightRestored = configuration[right.name].restore(right, configuration); + if (rightRestored.length > 1) { continue; } + + component = findComponentIn(left, right); + override(component, right); + right.dirty = true; + } else if (left.name == right.name) { + // two non-shorthands should be merged based on understandability + overridable = true; + + if (right.shorthand) { + for (k = right.components.length - 1; k >= 0 && overridable; k--) { + overriddenComponent = left.components[k]; + overridingComponent = right.components[k]; + mayOverride = configuration[overridingComponent.name].canOverride || sameValue; + + overridable = everyValuesPair(mayOverride.bind(null, validator), overriddenComponent, overridingComponent); + } + } else { + mayOverride = configuration[right.name].canOverride || sameValue; + overridable = everyValuesPair(mayOverride.bind(null, validator), left, right); + } + + if (left.important && !right.important && overridable) { + right.unused = true; + continue; + } + + if (!left.important && right.important && overridable) { + left.unused = true; + continue; + } + + if (!overridable) { + continue; + } + + left.unused = true; + } + } + } +} + +module.exports = overrideProperties; diff --git a/node_modules/clean-css/lib/optimizer/level-2/properties/overrides-non-component-shorthand.js b/node_modules/clean-css/lib/optimizer/level-2/properties/overrides-non-component-shorthand.js new file mode 100644 index 00000000..2f5886f3 --- /dev/null +++ b/node_modules/clean-css/lib/optimizer/level-2/properties/overrides-non-component-shorthand.js @@ -0,0 +1,9 @@ +var configuration = require('../../configuration'); + +function overridesNonComponentShorthand(property1, property2) { + return property1.name in configuration + && 'overridesShorthands' in configuration[property1.name] + && configuration[property1.name].overridesShorthands.indexOf(property2.name) > -1; +} + +module.exports = overridesNonComponentShorthand; diff --git a/node_modules/clean-css/lib/optimizer/level-2/properties/populate-components.js b/node_modules/clean-css/lib/optimizer/level-2/properties/populate-components.js new file mode 100644 index 00000000..e5367465 --- /dev/null +++ b/node_modules/clean-css/lib/optimizer/level-2/properties/populate-components.js @@ -0,0 +1,61 @@ +var configuration = require('../../configuration'); +var InvalidPropertyError = require('../../invalid-property-error'); + +function populateComponents(properties, validator, warnings) { + var component; + var j, m; + + for (var i = properties.length - 1; i >= 0; i--) { + var property = properties[i]; + var descriptor = configuration[property.name]; + + if (!property.dynamic && descriptor && descriptor.shorthand) { + if (onlyValueIsVariable(property, validator) || moreThanOneValueIsVariable(property, validator)) { + property.optimizable = false; + continue; + } + + property.shorthand = true; + property.dirty = true; + + try { + property.components = descriptor.breakUp(property, configuration, validator); + + if (descriptor.shorthandComponents) { + for (j = 0, m = property.components.length; j < m; j++) { + component = property.components[j]; + component.components = configuration[component.name].breakUp(component, configuration, validator); + } + } + } catch (e) { + if (e instanceof InvalidPropertyError) { + property.components = []; // this will set property.unused to true below + warnings.push(e.message); + } else { + throw e; + } + } + + if (property.components.length > 0) { + property.multiplex = property.components[0].multiplex; + } else { + property.unused = true; + } + } + } +} + +function onlyValueIsVariable(property, validator) { + return property.value.length == 1 && validator.isVariable(property.value[0][1]); +} + +function moreThanOneValueIsVariable(property, validator) { + return property.value.length > 1 + && property.value.filter( + function(value) { + return validator.isVariable(value[1]); + } + ).length > 1; +} + +module.exports = populateComponents; -- cgit v1.2.3