Skip to content

Reports incorrect node locations for files with comments containing single quote #163

@nwalters512

Description

@nwalters512

I originally reported this problem in stylelint (stylelint/stylelint#5438), but eventually determined it was caused by postcss-less.

  • Node Version: 14.17.0
  • NPM Version: 6.14.13
  • postcss Version: 8.3.5
  • postcss-less Version: master

LESS

This example may look kind of contrived, but it's based on many real-world examples in our code (long, rambling explanations that happen to single quotes). This is as simplified as I could get it.

a {
  // '
  color: pink;
}

/** ' */

JavaScript

Here is the test I added to test/parser/comments.test.js to reproduce the problem:

test('handles single quotes in comments', (t) => {
  const less = `a {\n  // '\n  color: pink;\n}\n\n/** ' */`;

  const root = parse(less);

  const [ruleNode, commentNode] = root.nodes;

  t.is(ruleNode.type, 'rule');
  t.is(commentNode.type, 'comment');

  const [innerCommentNode, declarationNode] = ruleNode.nodes;

  t.is(innerCommentNode.type, 'comment');
  t.is(declarationNode.type, 'decl');

  t.is(declarationNode.source.start.line, 3);
  t.is(declarationNode.source.start.column, 3);
  t.is(declarationNode.source.end.line, 3);
  t.is(declarationNode.source.end.column, 14);

  t.is(nodeToString(root), less);
});

All assertions about declarationNode.source.*.line fail.

Expected Behavior

I would expect that the declaration node for color: pink to be marked as starting and ending on line 3.

Actual Behavior

The declaration node for color: pink is marked as starting and ending on line 2. As you can see from the original LESS document, this is incorrect; line 2 is a comment.

How can we reproduce the behavior?

If you add the above test to test/parser/comments.test.js and run npm run test -- test/parser/comments.test.js, you can observe the test failing:

> ava "test/parser/comments.test.js"


  handles single quotes in comments

  test/parser/comments.test.js:198

   197:                                                
   198:   t.is(declarationNode.source.start.line, 3);  
   199:   t.is(declarationNode.source.start.column, 3);

  Difference:

  - 2
  + 3

  › test/parser/comments.test.js:198:5

  ─

  1 test failed

Potential fix

I spent a good deal of time trying to develop a fix for this, but I haven't yet figured out a way to work around the fact that the inline-comment node creates a new tokenizer in the middle of parsing (source). My current thinking is to try to do some kind of post-processing on the tree in the parse function - does that seem like a reasonable approach to you?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions