Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

css-coverage

Package Overview
Dependencies
Maintainers
1
Versions
29
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

css-coverage - npm Package Compare versions

Comparing version 1.3.1 to 2.0.0

4

package.json
{
"name": "css-coverage",
"version": "1.3.1",
"version": "2.0.0",
"scripts": {
"pretest": "sass --source-map ./test/test.scss ./test/test.css",
"test": "./bin/css-coverage.js --cover-declarations --html ./test/test.html --css ./test/test.css --lcov ./test/test.lcov",
"test": "./bin/css-coverage.js --html ./test/test.html --css ./test/test.css --lcov ./test/test.lcov --ignore-declarations 'move-to,move-foobar'",
"test-debug": "node --inspect-brk ./bin/css-coverage.js --cover-declarations --html ./test/test.html --css ./test/test.css --lcov ./test/test.lcov",

@@ -8,0 +8,0 @@ "posttest": "standard --fix"

@@ -22,2 +22,6 @@ const fs = require('fs')

function parseTokenList (tokenString) {
return tokenString.split(',').map(token => token.trim().toLowerCase())
}
const STATUS_CODE = {

@@ -36,3 +40,3 @@ ERROR: 111,

.option('--ignore-source-map', 'disable loading the sourcemap if one is found')
.option('--cover-declarations', 'try to cover CSS declarations as well as selectors (best-effort, difficult with sourcemaps)')
.option('--ignore-declarations [move-to,content]', 'A comma-separated list of declarations to ignore', parseTokenList)
.parse(process.argv)

@@ -74,2 +78,4 @@

const cssRules = []
const cssDeclarations = {} // so it is serializable to the browser
cssTree.walkRules(ast, (rule) => {

@@ -80,2 +86,13 @@ if (rule.type === 'Atrule') {

const converted = rule.prelude.children.map((selector) => {
rule.block.children.each(declaration => {
if (commander.ignoreDeclarations.indexOf(declaration.property.toLowerCase()) >= 0) {
return // skip because it is ignored
}
// Append to a list of locations
const key = cssTree.translate(declaration)
let locs = cssDeclarations[key]
locs = locs || []
locs.push(declaration.loc)
cssDeclarations[key] = locs
})
return cssTree.translate(selector)

@@ -159,3 +176,3 @@ })

log.debug(`Calculating coverage`)
const coverageOutput = await page.evaluate(cssRules => {
const { matchedSelectors: coverageOutput, supportedDeclarations } = await page.evaluate((cssRules, cssDeclarations) => {
// This is the meat of the code. It runs inside the browser

@@ -173,3 +190,3 @@ console.log(`Starting evaluation`)

const ret = []
const matchedSelectors = []
rules.forEach(function (selectors) {

@@ -203,9 +220,19 @@ console.log(`Checking selector: "${JSON.stringify(selectors)}"`)

ret.push([count, selectors])
matchedSelectors.push([count, selectors])
})
console.log(`Finished checking selectors`)
return ret
}, cssRules)
console.log(`Checking if declarations are understandable by the browser`)
const supportedDeclarations = []
for (const decl of cssDeclarations) {
if (window.CSS.supports(decl)) {
supportedDeclarations.push(decl)
} else {
console.warn(`Unsupported declaration ${decl}`)
}
}
return { matchedSelectors, supportedDeclarations }
}, cssRules, Object.keys(cssDeclarations))
log.debug('Closing browser')

@@ -217,3 +244,3 @@ await browser.close()

const lcovStr = await generateLcovStr(coverageOutput)
const lcovStr = await generateLcovStr(coverageOutput, supportedDeclarations)
if (commander.lcov) {

@@ -234,3 +261,3 @@ fs.writeFileSync(commander.lcov, lcovStr)

async function generateLcovStr (coverageOutput) {
async function generateLcovStr (coverageOutput, supportedDeclarations) {
// coverageOutput is of the form:

@@ -259,7 +286,24 @@ // [[1, ['body']], [400, ['div.foo']]]

function getStartInfo (origStart, origEnd) {
const startInfo = sourceMapConsumer.originalPositionFor({ line: origStart.line, column: origStart.column - 1 })
// const endInfo = sourceMapConsumer.originalPositionFor({line: origEnd.line, column: origEnd.column - 2})
// When there is no match, startInfo.source is null
if (!startInfo.source /* || startInfo.source !== endInfo.source */) {
console.error('cssStart', JSON.stringify(origStart))
origEnd && console.error('cssEnd', JSON.stringify(origEnd))
// console.error('sourceStart', JSON.stringify(startInfo));
// console.error('sourceEnd', JSON.stringify(endInfo));
throw new Error('BUG: sourcemap might be invalid. Maybe try regenerating it?')
} else {
if (commander.verbose) {
console.error('DEBUG: MATCHED this one', JSON.stringify(startInfo))
}
}
return startInfo
}
const files = {} // key is filename, value is [{startLine, endLine, count}]
const ret = [] // each line in the lcov file. Joined at the end of the function
const cssLines = CSS_STR.split('\n')
function addCoverage (fileName, count, startLine, endLine) {

@@ -292,51 +336,4 @@ // add it to the files

if (commander.coverDeclarations) {
// Loop over every character between origStart and origEnd to make sure they are covered
// TODO: Do not duplicate-count lines just because this code runs character-by-character
let parseColumn = origStart.column
for (let parseLine = origStart.line; parseLine <= origEnd.line; parseLine++) {
const curLineText = cssLines[parseLine - 1]
for (let curColumn = parseColumn - 1; curColumn < curLineText.length; curColumn++) {
const info = sourceMapConsumer.originalPositionFor({ line: parseLine, column: curColumn })
// stop processing when we hit origEnd
if (parseLine === origEnd.line && curColumn >= origEnd.column) {
break
}
if (/\s/.test(curLineText[curColumn])) {
continue
}
// console.error('PHIL ', curLineText[curColumn], {line: parseLine, column: curColumn}, info);
if (info.source) {
addCoverage(info.source, count, info.line, info.line)
} else {
if (commander.verbose) {
console.error('BUG: Could not look up source for this range:')
console.error('origStart', origStart)
console.error('origEnd', origEnd)
console.error('currIndexes', { line: parseLine, column: curColumn })
}
}
}
parseColumn = 1
}
} else {
// Just cover the selectors
const startInfo = sourceMapConsumer.originalPositionFor({ line: origStart.line, column: origStart.column - 1 })
// const endInfo = sourceMapConsumer.originalPositionFor({line: origEnd.line, column: origEnd.column - 2})
// When there is no match, startInfo.source is null
if (!startInfo.source /* || startInfo.source !== endInfo.source */) {
console.error('cssStart', JSON.stringify(origStart))
console.error('cssEnd', JSON.stringify(origEnd))
// console.error('sourceStart', JSON.stringify(startInfo));
// console.error('sourceEnd', JSON.stringify(endInfo));
throw new Error('BUG: sourcemap might be invalid. Maybe try regenerating it?')
} else {
if (commander.verbose) {
console.error('DEBUG: MATCHED this one', JSON.stringify(startInfo))
}
}
addCoverage(startInfo.source, count, startInfo.line, startInfo.line)
}
const startInfo = getStartInfo(origStart, origEnd)
addCoverage(startInfo.source, count, startInfo.line, startInfo.line)
} else {

@@ -355,2 +352,11 @@ // No sourceMap available

// Mark all the unsupported declarations
const unsupportedDeclarations = Object.keys(cssDeclarations).filter(decl => supportedDeclarations.indexOf(decl) < 0)
for (const decl of unsupportedDeclarations) {
for (const loc of cssDeclarations[decl]) {
const startInfo = getStartInfo(loc.start)
addCoverage(startInfo.source, 0, startInfo.line, startInfo.line)
}
}
for (const fileName in files) {

@@ -357,0 +363,0 @@ let nonZero = 0 // For summary info

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

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