From 90d62e42d5c89c140818d248ec8ae2b3cd4dc6d3 Mon Sep 17 00:00:00 2001 From: Yosuke Ota Date: Fri, 17 Jun 2022 17:54:31 +0900 Subject: [PATCH] Fix incorrect AST for nesting block with trailing comment (#6) * Fix incorrect AST for nesting block with trailing comment * fix --- lib/parser/index.js | 47 +++++- lib/parser/parse-raw-after.js | 23 +-- .../input.styl | 4 + .../parsed-win.json | 136 ++++++++++++++++++ .../parsed.json | 136 ++++++++++++++++++ .../stringify.css | 4 + .../transform-remraws.styl | 6 + 7 files changed, 332 insertions(+), 24 deletions(-) create mode 100644 tests/fixtures/inline-comment08-at-end-of-rule copy/input.styl create mode 100644 tests/fixtures/inline-comment08-at-end-of-rule copy/parsed-win.json create mode 100644 tests/fixtures/inline-comment08-at-end-of-rule copy/parsed.json create mode 100644 tests/fixtures/inline-comment08-at-end-of-rule copy/stringify.css create mode 100644 tests/fixtures/inline-comment08-at-end-of-rule copy/transform-remraws.styl diff --git a/lib/parser/index.js b/lib/parser/index.js index a311efa..20ef422 100644 --- a/lib/parser/index.js +++ b/lib/parser/index.js @@ -14,7 +14,7 @@ const parseMediaParams = require("./parse-media-params") const getSelectorEndIndex = require("./get-selector-end-index") const getCssLiteralIndices = require("./get-css-literal-indices") const { getName } = require("./stylus-nodes") -const { findLast } = require("./util") +const { findLast, findIndex } = require("./util") const debug = require("debug")("postcss-styl:parser") @@ -366,6 +366,34 @@ function atrulePostProc(atRule, { postfix, parsedNameAndCondition } = {}) { } } +/** + *Get block contents indent + */ +function getBlockContentIndent(sourceCode, bodyStartIndex) { + let hasLineBreak = false + const indentedTokenIndex = findIndex( + sourceCode.text, + (c) => { + if (!hasLineBreak) { + if (c === "\n") { + hasLineBreak = true + } + return false + } + return c.trim() + }, + bodyStartIndex, + ) + if (indentedTokenIndex >= 0) { + // Has before token + // | .a + // | color red + // | // comment + return sourceCode.getIndentFromIndex(indentedTokenIndex) + } + return null +} + class StylusParser { constructor(input) { this.input = input @@ -1928,7 +1956,9 @@ class StylusParser { const rawAfter = parseRawAfter(this.sourceCode, bodyEndIndex, { blockCommentAsRaw: false, - bodyStartIndex: hasBrace ? null : bodyStartIndex, + maxIndent: hasBrace + ? null + : getBlockContentIndent(this.sourceCode, bodyStartIndex), }) return { @@ -1976,12 +2006,19 @@ class StylusParser { * @returns {number} */ function calcBlockEnd(initEndIndex) { + let blockContentIndent = null + if (!hasBrace) { + blockContentIndent = getBlockContentIndent( + sourceCode, + bodyStartIndex, + ) + } const { startIndex, inlineComments } = parseRawAfter( sourceCode, initEndIndex, { blockCommentAsRaw: false, - bodyStartIndex: hasBrace ? null : bodyStartIndex, + maxIndent: blockContentIndent, }, ) if (!hasBrace && inlineComments.length) { @@ -1991,12 +2028,12 @@ class StylusParser { // Step 1. calc indent let minIndent = 0 - if (bodyStartIndex < startIndex) { + if (blockContentIndent != null) { // Has before token // | .a // | color red // | // comment - minIndent = sourceCode.getIndentFromIndex(startIndex - 1) + minIndent = blockContentIndent } else { minIndent = sourceCode.getIndentFromIndex(startIndex - 1) + 1 diff --git a/lib/parser/parse-raw-after.js b/lib/parser/parse-raw-after.js index 0f3a961..a75e15c 100644 --- a/lib/parser/parse-raw-after.js +++ b/lib/parser/parse-raw-after.js @@ -1,7 +1,7 @@ "use strict" const { tokensToRaws, isSkipToken } = require("./token-utils") -const { findLastIndex, findIndex } = require("./util") +const { findLastIndex } = require("./util") module.exports = (sourceCode, end, opt = {}) => { const options = Object.assign({ blockCommentAsRaw: true }, opt) @@ -23,28 +23,13 @@ module.exports = (sourceCode, end, opt = {}) => { token.value !== "{" ? stripStartLineComments(after) : after - if (options.bodyStartIndex != null || options.maxIndent != null) { + if (options.maxIndent != null) { // Process for // | .a // | // comment // | // comment - - let maxIndent = options.maxIndent - if (maxIndent == null) { - const firstTokenIndex = findIndex( - sourceCode.text, - (c) => c.trim(), - options.bodyStartIndex, - ) - if (firstTokenIndex >= 0) { - // Comments beyond the indentation of the first token are child node comments. - maxIndent = sourceCode.getIndentFromIndex(firstTokenIndex) - } - } - - if (maxIndent != null) { - afterTokens = processComment(sourceCode, afterTokens, maxIndent) - } + const maxIndent = options.maxIndent + afterTokens = processComment(sourceCode, afterTokens, maxIndent) } startIndex = afterTokens.length ? afterTokens[0].range[0] : startIndex diff --git a/tests/fixtures/inline-comment08-at-end-of-rule copy/input.styl b/tests/fixtures/inline-comment08-at-end-of-rule copy/input.styl new file mode 100644 index 0000000..f942c7b --- /dev/null +++ b/tests/fixtures/inline-comment08-at-end-of-rule copy/input.styl @@ -0,0 +1,4 @@ +.foo + .bar + //bar + //foo diff --git a/tests/fixtures/inline-comment08-at-end-of-rule copy/parsed-win.json b/tests/fixtures/inline-comment08-at-end-of-rule copy/parsed-win.json new file mode 100644 index 0000000..010a65b --- /dev/null +++ b/tests/fixtures/inline-comment08-at-end-of-rule copy/parsed-win.json @@ -0,0 +1,136 @@ +{ + "raws": { + "semicolon": false, + "after": "\r\n" + }, + "type": "root", + "nodes": [ + { + "raws": { + "before": "", + "between": "", + "semicolon": false, + "after": "" + }, + "type": "rule", + "nodes": [ + { + "raws": { + "before": "\r\n ", + "between": "", + "after": "" + }, + "type": "rule", + "nodes": [ + { + "raws": { + "before": "\r\n ", + "left": "", + "right": "", + "inline": true + }, + "type": "comment", + "source": { + "start": { + "offset": 18, + "line": 3, + "column": 5 + }, + "input": { + "file": "input.styl" + }, + "end": { + "offset": 22, + "line": 3, + "column": 9 + } + }, + "text": "bar" + } + ], + "source": { + "start": { + "offset": 8, + "line": 2, + "column": 3 + }, + "startChildren": { + "offset": 12, + "line": 2, + "column": 7 + }, + "input": { + "file": "input.styl" + }, + "end": { + "offset": 22, + "line": 3, + "column": 9 + } + }, + "selector": ".bar", + "pythonic": true + }, + { + "raws": { + "before": "\r\n ", + "left": "", + "right": "", + "inline": true + }, + "type": "comment", + "source": { + "start": { + "offset": 27, + "line": 4, + "column": 3 + }, + "input": { + "file": "input.styl" + }, + "end": { + "offset": 31, + "line": 4, + "column": 7 + } + }, + "text": "foo" + } + ], + "source": { + "start": { + "offset": 0, + "line": 1, + "column": 1 + }, + "startChildren": { + "offset": 4, + "line": 1, + "column": 5 + }, + "input": { + "file": "input.styl" + }, + "end": { + "offset": 31, + "line": 4, + "column": 7 + } + }, + "selector": ".foo", + "pythonic": true + } + ], + "source": { + "input": { + "file": "input.styl" + }, + "start": { + "offset": 0, + "line": 1, + "column": 1 + }, + "lang": "stylus", + "syntax": "ok" + } +} \ No newline at end of file diff --git a/tests/fixtures/inline-comment08-at-end-of-rule copy/parsed.json b/tests/fixtures/inline-comment08-at-end-of-rule copy/parsed.json new file mode 100644 index 0000000..2732658 --- /dev/null +++ b/tests/fixtures/inline-comment08-at-end-of-rule copy/parsed.json @@ -0,0 +1,136 @@ +{ + "raws": { + "semicolon": false, + "after": "\n" + }, + "type": "root", + "nodes": [ + { + "raws": { + "before": "", + "between": "", + "semicolon": false, + "after": "" + }, + "type": "rule", + "nodes": [ + { + "raws": { + "before": "\n ", + "between": "", + "after": "" + }, + "type": "rule", + "nodes": [ + { + "raws": { + "before": "\n ", + "left": "", + "right": "", + "inline": true + }, + "type": "comment", + "source": { + "start": { + "offset": 16, + "line": 3, + "column": 5 + }, + "input": { + "file": "input.styl" + }, + "end": { + "offset": 20, + "line": 3, + "column": 9 + } + }, + "text": "bar" + } + ], + "source": { + "start": { + "offset": 7, + "line": 2, + "column": 3 + }, + "startChildren": { + "offset": 11, + "line": 2, + "column": 7 + }, + "input": { + "file": "input.styl" + }, + "end": { + "offset": 20, + "line": 3, + "column": 9 + } + }, + "selector": ".bar", + "pythonic": true + }, + { + "raws": { + "before": "\n ", + "left": "", + "right": "", + "inline": true + }, + "type": "comment", + "source": { + "start": { + "offset": 24, + "line": 4, + "column": 3 + }, + "input": { + "file": "input.styl" + }, + "end": { + "offset": 28, + "line": 4, + "column": 7 + } + }, + "text": "foo" + } + ], + "source": { + "start": { + "offset": 0, + "line": 1, + "column": 1 + }, + "startChildren": { + "offset": 4, + "line": 1, + "column": 5 + }, + "input": { + "file": "input.styl" + }, + "end": { + "offset": 28, + "line": 4, + "column": 7 + } + }, + "selector": ".foo", + "pythonic": true + } + ], + "source": { + "input": { + "file": "input.styl" + }, + "start": { + "offset": 0, + "line": 1, + "column": 1 + }, + "lang": "stylus", + "syntax": "ok" + } +} \ No newline at end of file diff --git a/tests/fixtures/inline-comment08-at-end-of-rule copy/stringify.css b/tests/fixtures/inline-comment08-at-end-of-rule copy/stringify.css new file mode 100644 index 0000000..46ae704 --- /dev/null +++ b/tests/fixtures/inline-comment08-at-end-of-rule copy/stringify.css @@ -0,0 +1,4 @@ +.foo{ + .bar{ + /*bar*/} + /*foo*/} diff --git a/tests/fixtures/inline-comment08-at-end-of-rule copy/transform-remraws.styl b/tests/fixtures/inline-comment08-at-end-of-rule copy/transform-remraws.styl new file mode 100644 index 0000000..ba66805 --- /dev/null +++ b/tests/fixtures/inline-comment08-at-end-of-rule copy/transform-remraws.styl @@ -0,0 +1,6 @@ +.foo + .bar + /* bar */ + + /* foo */ +