diff --git a/.changeset/cuddly-boats-slide.md b/.changeset/cuddly-boats-slide.md
new file mode 100644
index 0000000000..6ef7582a1c
--- /dev/null
+++ b/.changeset/cuddly-boats-slide.md
@@ -0,0 +1,5 @@
+---
+'@lit-labs/analyzer': patch
+---
+
+Adjust attribute source locations in template parser
diff --git a/packages/labs/analyzer/src/lib/lit/template.ts b/packages/labs/analyzer/src/lib/lit/template.ts
index 996f0ed8c1..d33bf14bfb 100644
--- a/packages/labs/analyzer/src/lib/lit/template.ts
+++ b/packages/labs/analyzer/src/lib/lit/template.ts
@@ -419,7 +419,14 @@ export const parseLitTemplate = (
if (node.attrs.length > 0) {
for (const attr of node.attrs) {
- // TODO (justinfagnani): adjust attribute locations
+ const attrSourceLocation =
+ node.sourceCodeLocation?.attrs?.[attr.name];
+
+ if (attrSourceLocation !== undefined) {
+ attrSourceLocation.startLine += lineAdjust;
+ attrSourceLocation.startCol += colAdjust;
+ attrSourceLocation.startOffset += offsetAdjust;
+ }
if (attr.name.startsWith(marker)) {
// An element binding, like
@@ -515,6 +522,12 @@ export const parseLitTemplate = (
);
spanIndex += strings.length - 1;
}
+
+ if (attrSourceLocation !== undefined) {
+ attrSourceLocation.endLine += lineAdjust;
+ attrSourceLocation.endCol += colAdjust;
+ attrSourceLocation.endOffset += offsetAdjust;
+ }
}
}
diff --git a/packages/labs/analyzer/src/test/server/lit/template_test.ts b/packages/labs/analyzer/src/test/server/lit/template_test.ts
index 478574c741..080d8d656f 100644
--- a/packages/labs/analyzer/src/test/server/lit/template_test.ts
+++ b/packages/labs/analyzer/src/test/server/lit/template_test.ts
@@ -193,6 +193,27 @@ const assertTemplateNodeText = (
assert.equal(elementTextFromLinesAndCols, expected);
};
+const assertAttributeText = (
+ node: Element,
+ attrName: string,
+ templateExpression: ts.TaggedTemplateExpression,
+ expected: string
+) => {
+ // Trim off the leading and trailing backticks
+ const templateText = templateExpression.template.getFullText().slice(1, -1);
+ assert.ok(node.sourceCodeLocation?.attrs);
+ const sourceLocation = node.sourceCodeLocation?.attrs?.[attrName];
+ assert.ok(
+ sourceLocation,
+ `source location for attribute not found: ${attrName}`
+ );
+ const {startOffset, endOffset} = sourceLocation;
+
+ // Check that the offsets are correct:
+ const textFromOffsets = templateText.substring(startOffset, endOffset);
+ assert.equal(textFromOffsets, expected);
+};
+
suite('parseLitTemplate', () => {
const testFilePath = path.resolve(testFilesDir, 'hello.ts');
const {sourceFile, checker} = getTestSourceFile(testFilePath);
@@ -325,6 +346,13 @@ suite('parseLitTemplate', () => {
`
Hello, world!
`
);
+ assertAttributeText(
+ div as Element,
+ 'class$lit$',
+ templateExpression,
+ `class="\${'a'}"`
+ );
+
const span = (div as Element).childNodes[0];
assert.equal(span.nodeName, 'span');
assertTemplateNodeText(