diff --git a/src/locationCorrection.ts b/src/locationCorrection.ts index 7e013cd..90d6ad8 100644 --- a/src/locationCorrection.ts +++ b/src/locationCorrection.ts @@ -5,7 +5,8 @@ import {createPlaceholder} from './util.js'; const correctLocation = ( node: TaggedTemplateExpression, loc: Position, - baseIndentations: Map + baseIndentations: Map, + prefixOffsets?: {lines: number; offset: number} ): Position => { if (!node.quasi.loc || !node.quasi.range) { return loc; @@ -19,6 +20,11 @@ const correctLocation = ( let currentLine = 1; let columnOffset = nodeLoc.start.column + 1; + if (prefixOffsets) { + lineOffset += prefixOffsets.lines; + newOffset += prefixOffsets.offset; + } + for (let i = 0; i < node.quasi.expressions.length; i++) { const expr = node.quasi.expressions[i]; const previousQuasi = node.quasi.quasis[i]; @@ -72,9 +78,7 @@ const correctLocation = ( if (loc.line === currentLine) { loc.column += columnOffset; } - if (loc.line !== 1) { - loc.column += baseIndentation; - } + loc.column += baseIndentation; loc.offset = newOffset + indentationOffset; @@ -94,7 +98,7 @@ function computeBeforeAfter( ): void { if ( node.raws['before'] && - node.raws['before'].includes('\n') && + (node.raws['before'].includes('\n') || node.parent?.type === 'root') && node.source?.start ) { const raw = node.raws['before']; @@ -140,14 +144,16 @@ export function locationCorrectionWalker( node.source.start = correctLocation( expr, node.source.start, - baseIndentations + baseIndentations, + root.raws['litPrefixOffsets'] ); } if (node.source?.end) { node.source.end = correctLocation( expr, node.source.end, - baseIndentations + baseIndentations, + root.raws['litPrefixOffsets'] ); } }; diff --git a/src/parse.ts b/src/parse.ts index 1cb7d6a..0574a97 100644 --- a/src/parse.ts +++ b/src/parse.ts @@ -70,7 +70,15 @@ export const parse: Parser = ( const sourceLines = styleText.split('\n'); const baseIndentations = new Map(); const indentationPattern = new RegExp(`^[ \\t]{${baseIndentation}}`); + const emptyLinePattern = /^[ \\t\r]*$/; const deindentedLines: string[] = []; + const prefixOffsets = {lines: 0, offset: 0}; + + if (sourceLines[0] !== undefined && emptyLinePattern.test(sourceLines[0])) { + prefixOffsets.lines = 1; + prefixOffsets.offset = sourceLines[0].length + 1; + sourceLines.shift(); + } for (let i = 0; i < sourceLines.length; i++) { const sourceLine = sourceLines[i]; @@ -95,9 +103,19 @@ export const parse: Parser = ( map: false }) as Root; + root.raws['litPrefixOffsets'] = prefixOffsets; root.raws['litTemplateExpressions'] = expressionStrings; root.raws['litBaseIndentations'] = baseIndentations; - root.raws.codeBefore = sourceAsString.slice(currentOffset, startIndex); + // TODO (43081j): remove this if stylelint/stylelint#5767 ever gets fixed, + // or they drop the indentation rule. Their indentation rule depends on + // `beforeStart` existing as they unsafely try to call `endsWith` on it. + if (!root.raws['beforeStart']) { + root.raws['beforeStart'] = ''; + } + root.raws.codeBefore = sourceAsString.slice( + currentOffset, + startIndex + prefixOffsets.offset + ); root.parent = doc; // TODO (43081j): stylelint relies on this existing, really unsure why. // it could just access root.parent to get the document... diff --git a/src/test/parse_test.ts b/src/test/parse_test.ts index 6779b1c..abed0ba 100644 --- a/src/test/parse_test.ts +++ b/src/test/parse_test.ts @@ -16,7 +16,7 @@ describe('parse', () => { assert.equal(root.type, 'root'); assert.equal(rule.type, 'rule'); assert.equal(colour.type, 'decl'); - assert.equal(root.raws.codeBefore, '\n css`'); + assert.equal(root.raws.codeBefore, '\n css`\n'); assert.equal(root.parent, ast); assert.equal(root.raws.codeAfter, '`;\n '); assert.deepEqual(ast.source!.start, { @@ -73,7 +73,7 @@ describe('parse', () => { const root2 = ast.nodes[1] as Root; assert.equal(root1.type, 'root'); - assert.equal(root1.raws.codeBefore, '\n css`'); + assert.equal(root1.raws.codeBefore, '\n css`\n'); assert.equal(root1.raws.codeAfter, undefined); assert.equal(root1.parent, ast); assert.equal(root2.type, 'root'); diff --git a/src/test/postcss_test.ts b/src/test/postcss_test.ts index ccc30f9..685a63b 100644 --- a/src/test/postcss_test.ts +++ b/src/test/postcss_test.ts @@ -25,7 +25,7 @@ describe('postcss', () => { assert.equal(root.type, 'root'); assert.equal(rule.type, 'rule'); assert.equal(colour.type, 'decl'); - assert.equal(root.raws.codeBefore, '\n css`'); + assert.equal(root.raws.codeBefore, '\n css`\n'); assert.equal(root.parent, ast); assert.equal(root.raws.codeAfter, '`;\n '); assert.deepEqual(ast.source!.start, {