scancss
Version:
A robust CSS stylesheet statistics collector and analyzer
257 lines (197 loc) • 8 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.handleTransitionsAndAnimations = handleTransitionsAndAnimations;
var _postcss = require('postcss');
var _postcss2 = _interopRequireDefault(_postcss);
var _postcssValuesParser = require('postcss-values-parser');
var _postcssValuesParser2 = _interopRequireDefault(_postcssValuesParser);
var _cssPropertyParser = require('css-property-parser');
var _cssNamedTimingFunctions = require('../../../constants/cssNamedTimingFunctions');
var _cssExplicitDefaultingKeywords = require('../../../constants/cssExplicitDefaultingKeywords');
var _reExistingVendorPrefix = require('../../../constants/reExistingVendorPrefix');
var _reTime = require('../../../constants/reTime');
var _countUsage = require('../../../calculators/countUsage');
var _isNumber = require('../../../predicates/isNumber');
var _isShorthandProperty = require('../../../predicates/isShorthandProperty');
var _isSafeAst = require('../../../predicates/isSafeAst');
var _handleVendorPrefix = require('../../handleVendorPrefix');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const reCubicBezier = /cubic-bezier\(.+?\)/g;
const reInfiniteKeyword = /\binfinite\b/g;
function countInfiniteAnimations(propValue, report) {
if (reInfiniteKeyword.test(propValue)) {
report.animations.infinite += propValue.match(reInfiniteKeyword).length;
}
}
function countNamedTimingFunctions(decl, report) {
const ast = (0, _postcssValuesParser2.default)(decl.value).parse();
/* istanbul ignore else */
if ((0, _isSafeAst.isSafeAst)(ast)) {
const reportSection = decl.prop.includes('animation') ? report.animations : report.transitions;
ast.nodes[0].nodes.forEach(node => {
if (node.type === 'word') {
const keyword = node.value;
if (_cssNamedTimingFunctions.cssNamedTimingFunctions.includes(keyword) || _cssExplicitDefaultingKeywords.cssExplicitDefaultingKeywords.includes(keyword)) {
(0, _countUsage.countUsage)(keyword, reportSection.timingFunctions);
} else {
(0, _countUsage.countUsage)(keyword, reportSection.invalidTimingFunctions);
}
}
});
}
}
function countDurations(decl, report) {
const reportSection = decl.prop.includes('animation') ? report.animations : report.transitions;
_postcss2.default.list.comma(decl.value).forEach(duration => {
/* istanbul ignore else */
if (duration.match(_reTime.reTime) !== null) {
const parsedDurationInSeconds = duration.endsWith('ms') ? parseFloat(duration) / 1000 : parseFloat(duration);
if ((0, _isNumber.isNumber)(parsedDurationInSeconds) && reportSection.longestDuration < parsedDurationInSeconds) {
reportSection.longestDuration = parsedDurationInSeconds;
}
if ((0, _isNumber.isNumber)(parsedDurationInSeconds) && reportSection.shortestDuration > parsedDurationInSeconds) {
reportSection.shortestDuration = parsedDurationInSeconds;
}
}
});
}
function countDelays(decl, report) {
const reportSection = decl.prop.includes('animation') ? report.animations : report.transitions;
_postcss2.default.list.comma(decl.value).forEach(delay => {
/* istanbul ignore else */
if (delay.match(_reTime.reTime) !== null) {
const parsedDelayInSeconds = delay.endsWith('ms') ? parseFloat(delay) / 1000 : parseFloat(delay);
if ((0, _isNumber.isNumber)(parsedDelayInSeconds) && reportSection.longestDelay < parsedDelayInSeconds) {
reportSection.longestDelay = parsedDelayInSeconds;
}
if ((0, _isNumber.isNumber)(parsedDelayInSeconds) && reportSection.shortestDelay > parsedDelayInSeconds) {
reportSection.shortestDelay = parsedDelayInSeconds;
}
}
});
}
function countTransitionablePropeties(propValue, report) {
_postcss2.default.list.comma(propValue).forEach(prop => (0, _countUsage.countUsage)(prop, report.transitions.properties));
}
function countAnimationNames(propValue, report) {
_postcss2.default.list.comma(propValue).forEach(name => {
report.animations.total++;
(0, _countUsage.countUsage)(name, report.animations.usage);
});
}
function handleAnimationLonghand(longhand, report) {
/* istanbul ignore else */
if (typeof longhand['animation-iteration-count'] === 'string') {
countInfiniteAnimations(longhand['animation-iteration-count'], report);
}
/* istanbul ignore else */
if (typeof longhand['animation-name'] === 'string') {
countAnimationNames(longhand['animation-name'], report);
}
/* istanbul ignore else */
if (typeof longhand['animation-timing-function'] === 'string') {
const decl = {
prop: 'animation-timing-function',
value: longhand['animation-timing-function']
};
countNamedTimingFunctions(decl, report);
}
/* istanbul ignore else */
if (typeof longhand['animation-duration'] === 'string') {
const decl = {
prop: 'animation-duration',
value: longhand['animation-duration']
};
countDurations(decl, report);
}
/* istanbul ignore else */
if (typeof longhand['animation-delay'] === 'string') {
const decl = {
prop: 'animation-delay',
value: longhand['animation-delay']
};
countDelays(decl, report);
}
}
function handleTransitionLonghand(longhand, report) {
/* istanbul ignore else */
if (typeof longhand['transition-timing-function'] === 'string') {
const decl = {
prop: 'transition-timing-function',
value: longhand['transition-timing-function']
};
countNamedTimingFunctions(decl, report);
}
/* istanbul ignore else */
if (typeof longhand['transition-duration'] === 'string') {
const decl = {
prop: 'transition-duration',
value: longhand['transition-duration']
};
countDurations(decl, report);
}
/* istanbul ignore else */
if (typeof longhand['transition-delay'] === 'string') {
const decl = {
prop: 'transition-delay',
value: longhand['transition-delay']
};
countDelays(decl, report);
}
/* istanbul ignore else */
if (typeof longhand['transition-property'] === 'string') {
countTransitionablePropeties(longhand['transition-property'], report);
}
}
function handleTransitionsAndAnimations(decl, report) {
const prop = decl.prop;
const propValue = decl.value;
if ((0, _isShorthandProperty.isShorthandProperty)(prop)) {
const safePropValue = _postcss2.default.list.comma(propValue).map(value => {
// https://github.com/mahirshah/css-property-parser/issues/26
const cleanedValue = reCubicBezier.test(value) ? value.replace(reCubicBezier, '') : value;
return _postcss2.default.list.space(cleanedValue).map(valuePart => {
// https://github.com/mahirshah/css-property-parser/issues/27
/* istanbul ignore else */
if (_reExistingVendorPrefix.reExistingVendorPrefix.test(valuePart)) {
(0, _handleVendorPrefix.handleVendorPrefix)(valuePart, report);
return valuePart.replace(_reExistingVendorPrefix.reExistingVendorPrefix, '');
}
return valuePart;
}).join(' ');
}).join(', ');
try {
const longhand = (0, _cssPropertyParser.expandShorthandProperty)(_postcss2.default.vendor.unprefixed(prop), safePropValue);
if (prop.includes('animation')) {
handleAnimationLonghand(longhand, report);
}
if (prop.includes('transition')) {
handleTransitionLonghand(longhand, report);
}
} catch (err) {
/* istanbul ignore next */
/* eslint-disable-next-line no-console */
console.log(`'css-property-parser' module error\n${err}`);
}
}
if (prop === 'animation-iteration-count') {
countInfiniteAnimations(propValue, report);
}
if (prop === 'animation-name') {
countAnimationNames(propValue, report);
}
if (prop === 'animation-timing-function' || prop === 'transition-timing-function') {
countNamedTimingFunctions(decl, report);
}
if (prop === 'animation-duration' || prop === 'transition-duration') {
countDurations(decl, report);
}
if (prop === 'animation-delay' || prop === 'transition-delay') {
countDelays(decl, report);
}
if (prop === 'transition-property') {
countTransitionablePropeties(propValue, report);
}
}