@@ -36,7 +36,6 @@ commander
3636 . option ( '--lcov [path/to/output.lcov]' , 'the LCOV output file' , parseFileName )
3737 . option ( '--verbose' , 'verbose/debugging output' )
3838 . option ( '--ignore-source-map' , 'disable loading the sourcemap if one is found' )
39- . option ( '--cover-declarations' , 'try to cover CSS declarations as well as selectors (best-effort, difficult with sourcemaps)' )
4039 . option ( '--ignore-declarations [move-to,content]' , 'A comma-separated list of declarations to ignore' , parseTokenList )
4140 . parse ( process . argv )
4241
@@ -251,7 +250,7 @@ runCoverage()
251250 process . exit ( STATUS_CODE . ERROR )
252251 } )
253252
254- async function generateLcovStr ( coverageOutput ) {
253+ async function generateLcovStr ( coverageOutput , supportedDeclarations ) {
255254 // coverageOutput is of the form:
256255 // [[1, ['body']], [400, ['div.foo']]]
257256 // where each entry is a pair of count, selectors
@@ -275,11 +274,28 @@ async function generateLcovStr (coverageOutput) {
275274 sourceMapPath = realConsumer . sourceMapPath
276275 }
277276
277+ function getStartInfo ( origStart , origEnd ) {
278+ const startInfo = sourceMapConsumer . originalPositionFor ( { line : origStart . line , column : origStart . column - 1 } )
279+ // const endInfo = sourceMapConsumer.originalPositionFor({line: origEnd.line, column: origEnd.column - 2})
280+
281+ // When there is no match, startInfo.source is null
282+ if ( ! startInfo . source /* || startInfo.source !== endInfo.source */ ) {
283+ console . error ( 'cssStart' , JSON . stringify ( origStart ) )
284+ origEnd && console . error ( 'cssEnd' , JSON . stringify ( origEnd ) )
285+ // console.error('sourceStart', JSON.stringify(startInfo));
286+ // console.error('sourceEnd', JSON.stringify(endInfo));
287+ throw new Error ( 'BUG: sourcemap might be invalid. Maybe try regenerating it?' )
288+ } else {
289+ if ( commander . verbose ) {
290+ console . error ( 'DEBUG: MATCHED this one' , JSON . stringify ( startInfo ) )
291+ }
292+ }
293+ return startInfo
294+ }
295+
278296 const files = { } // key is filename, value is [{startLine, endLine, count}]
279297 const ret = [ ] // each line in the lcov file. Joined at the end of the function
280298
281- const cssLines = CSS_STR . split ( '\n' )
282-
283299 function addCoverage ( fileName , count , startLine , endLine ) {
284300 // add it to the files
285301 if ( ! files [ fileName ] ) {
@@ -307,55 +323,8 @@ async function generateLcovStr (coverageOutput) {
307323 const origStart = rule . loc . start
308324 const origEnd = rule . loc . end
309325
310- if ( commander . coverDeclarations ) {
311- // Loop over every character between origStart and origEnd to make sure they are covered
312- // TODO: Do not duplicate-count lines just because this code runs character-by-character
313- let parseColumn = origStart . column
314- for ( let parseLine = origStart . line ; parseLine <= origEnd . line ; parseLine ++ ) {
315- const curLineText = cssLines [ parseLine - 1 ]
316- for ( let curColumn = parseColumn - 1 ; curColumn < curLineText . length ; curColumn ++ ) {
317- const info = sourceMapConsumer . originalPositionFor ( { line : parseLine , column : curColumn } )
318- // stop processing when we hit origEnd
319- if ( parseLine === origEnd . line && curColumn >= origEnd . column ) {
320- break
321- }
322- if ( / \s / . test ( curLineText [ curColumn ] ) ) {
323- continue
324- }
325- // console.error('PHIL ', curLineText[curColumn], {line: parseLine, column: curColumn}, info);
326- if ( info . source ) {
327- addCoverage ( info . source , count , info . line , info . line )
328- } else {
329- if ( commander . verbose ) {
330- console . error ( 'BUG: Could not look up source for this range:' )
331- console . error ( 'origStart' , origStart )
332- console . error ( 'origEnd' , origEnd )
333- console . error ( 'currIndexes' , { line : parseLine , column : curColumn } )
334- }
335- }
336- }
337- parseColumn = 1
338- }
339- } else {
340- // Just cover the selectors
341- const startInfo = sourceMapConsumer . originalPositionFor ( { line : origStart . line , column : origStart . column - 1 } )
342- // const endInfo = sourceMapConsumer.originalPositionFor({line: origEnd.line, column: origEnd.column - 2})
343-
344- // When there is no match, startInfo.source is null
345- if ( ! startInfo . source /* || startInfo.source !== endInfo.source */ ) {
346- console . error ( 'cssStart' , JSON . stringify ( origStart ) )
347- console . error ( 'cssEnd' , JSON . stringify ( origEnd ) )
348- // console.error('sourceStart', JSON.stringify(startInfo));
349- // console.error('sourceEnd', JSON.stringify(endInfo));
350- throw new Error ( 'BUG: sourcemap might be invalid. Maybe try regenerating it?' )
351- } else {
352- if ( commander . verbose ) {
353- console . error ( 'DEBUG: MATCHED this one' , JSON . stringify ( startInfo ) )
354- }
355- }
356-
357- addCoverage ( startInfo . source , count , startInfo . line , startInfo . line )
358- }
326+ const startInfo = getStartInfo ( origStart , origEnd )
327+ addCoverage ( startInfo . source , count , startInfo . line , startInfo . line )
359328 } else {
360329 // No sourceMap available
361330 fileName = commander . css
@@ -369,6 +338,15 @@ async function generateLcovStr (coverageOutput) {
369338 }
370339 } )
371340
341+ // Mark all the unsupported declarations
342+ const unsupportedDeclarations = Object . keys ( cssDeclarations ) . filter ( decl => supportedDeclarations . indexOf ( decl ) < 0 )
343+ for ( const decl of unsupportedDeclarations ) {
344+ for ( const loc of cssDeclarations [ decl ] ) {
345+ const startInfo = getStartInfo ( loc . start )
346+ addCoverage ( startInfo . source , 0 , startInfo . line , startInfo . line )
347+ }
348+ }
349+
372350 for ( const fileName in files ) {
373351 let nonZero = 0 // For summary info
374352 let allCounter = 0
0 commit comments