UNPKG

scancss

Version:

A robust CSS stylesheet statistics collector and analyzer

257 lines (197 loc) 8 kB
'use strict'; 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); } }