Skip to content

Commit b5642c7

Browse files
committed
1 parent 9cc94dc commit b5642c7

6 files changed

+58
-32
lines changed

e2e/tests/_helpers.js

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
const assert = require('chai').assert;
2+
13
exports.openMockFile = (server, mockFileName, fileContent) => {
24
server.send({
35
command: 'open',

e2e/tests/errors.js

+15-10
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ describe('Errors', () => {
1212
server.send({ command: 'semanticDiagnosticsSync', arguments: { file: mockFileName } });
1313

1414
return server.close().then(() => {
15-
const errorResponse = getFirstResponseOfType('semanticDiagnosticsSync', server.responses);
15+
const errorResponse = getFirstResponseOfType('semanticDiagnosticsSync', server);
1616
assert.isTrue(errorResponse.success);
1717
assert.strictEqual(errorResponse.body.length, 1);
1818
const error = errorResponse.body[0];
@@ -30,7 +30,7 @@ describe('Errors', () => {
3030
server.send({ command: 'semanticDiagnosticsSync', arguments: { file: mockFileName } });
3131

3232
return server.close().then(() => {
33-
const errorResponse = getFirstResponseOfType('semanticDiagnosticsSync', server.responses);
33+
const errorResponse = getFirstResponseOfType('semanticDiagnosticsSync', server);
3434
assert.isTrue(errorResponse.success);
3535
assert.strictEqual(errorResponse.body.length, 0);
3636
});
@@ -42,7 +42,7 @@ describe('Errors', () => {
4242
server.send({ command: 'semanticDiagnosticsSync', arguments: { file: mockFileName } });
4343

4444
return server.close().then(() => {
45-
const errorResponse = getFirstResponseOfType('semanticDiagnosticsSync', server.responses);
45+
const errorResponse = getFirstResponseOfType('semanticDiagnosticsSync', server);
4646
assert.isTrue(errorResponse.success);
4747
assert.strictEqual(errorResponse.body.length, 0);
4848
});
@@ -54,7 +54,7 @@ describe('Errors', () => {
5454
server.send({ command: 'semanticDiagnosticsSync', arguments: { file: mockFileName } });
5555

5656
return server.close().then(() => {
57-
const errorResponse = getFirstResponseOfType('semanticDiagnosticsSync', server.responses);
57+
const errorResponse = getFirstResponseOfType('semanticDiagnosticsSync', server);
5858
assert.isTrue(errorResponse.success);
5959
assert.strictEqual(errorResponse.body.length, 0);
6060
});
@@ -69,22 +69,27 @@ describe('Errors', () => {
6969
server.send({ command: 'semanticDiagnosticsSync', arguments: { file: mockFileName } });
7070

7171
return server.close().then(() => {
72-
const errorResponse = getFirstResponseOfType('semanticDiagnosticsSync', server.responses);
72+
const errorResponse = getFirstResponseOfType('semanticDiagnosticsSync', server);
7373
assert.isTrue(errorResponse.success);
7474
assert.strictEqual(errorResponse.body.length, 0);
7575
});
7676
});
7777

78-
it('should return errors for invalid text', () => {
78+
it('should return errors when error occures in last position', () => {
7979
const server = createServer();
80-
openMockFile(server, mockFileName, 'function css(strings, ...) { return ""; }; const q = css`@@ ; @erer ;`')
80+
openMockFile(server, mockFileName, 'function css(strings, ...) { return ""; }; const q = css`;`')
8181
server.send({ command: 'semanticDiagnosticsSync', arguments: { file: mockFileName } });
8282

8383
return server.close().then(() => {
84-
const errorResponse = getFirstResponseOfType('semanticDiagnosticsSync', server.responses);
85-
console.log(errorResponse)
84+
const errorResponse = getFirstResponseOfType('semanticDiagnosticsSync', server);
8685
assert.isTrue(errorResponse.success);
87-
assert.strictEqual(errorResponse.body.length, 0);
86+
assert.strictEqual(errorResponse.body.length, 1);
87+
const error = errorResponse.body[0];
88+
assert.strictEqual(error.text, '} expected');
89+
assert.strictEqual(error.start.line, 1);
90+
assert.strictEqual(error.start.offset, 58);
91+
assert.strictEqual(error.end.line, 1);
92+
assert.strictEqual(error.end.offset, 59);
8893
});
8994
});
9095
})

package-lock.json

+10-8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"url": "https://github.com/Microsoft/typescript-styled-plugin/issues"
2121
},
2222
"dependencies": {
23-
"vscode-css-languageservice": "^2.1.4"
23+
"vscode-css-languageservice": "^2.1.10"
2424
},
2525
"files": [
2626
"lib"

src/styled-string-language-service.ts

+20-8
Original file line numberDiff line numberDiff line change
@@ -71,14 +71,15 @@ export default class VscodeLanguageServiceAdapter implements TemplateStringLangu
7171
return this.translateDiagnostics(
7272
this.scssLanguageService.doValidation(doc, stylesheet),
7373
doc,
74-
context);
74+
context,
75+
contents).filter(x => !!x) as ts.Diagnostic[];
7576
}
7677

7778
private createVirtualDocument(
7879
contents: string,
7980
context: TemplateContext
8081
): vscode.TextDocument {
81-
contents = `${wrapperPre}${contents}}`;
82+
contents = `${wrapperPre}${contents}\n}`;
8283
return {
8384
uri: 'untitled://embedded.scss',
8485
languageId: 'scss',
@@ -121,20 +122,31 @@ export default class VscodeLanguageServiceAdapter implements TemplateStringLangu
121122
private translateDiagnostics(
122123
diagnostics: vscode.Diagnostic[],
123124
doc: vscode.TextDocument,
124-
context: TemplateContext
125+
context: TemplateContext,
126+
content: string
125127
) {
126128
const sourceFile = context.node.getSourceFile();
127129
return diagnostics.map(diag =>
128-
this.translateDiagnostic(diag, sourceFile, doc));
130+
this.translateDiagnostic(diag, sourceFile, doc, context, content));
129131
}
130132

131133
private translateDiagnostic(
132134
diagnostic: vscode.Diagnostic,
133135
file: ts.SourceFile,
134-
doc: vscode.TextDocument
135-
): ts.Diagnostic {
136-
const start = this.fromVirtualDocOffset(doc.offsetAt(diagnostic.range.start));
137-
const length = this.fromVirtualDocOffset(doc.offsetAt(diagnostic.range.end)) - start;
136+
doc: vscode.TextDocument,
137+
context: TemplateContext,
138+
content: string
139+
): ts.Diagnostic | undefined {
140+
// Make sure returned error is within the real document
141+
if (diagnostic.range.start.line === 0
142+
|| diagnostic.range.start.line >= doc.lineCount
143+
|| diagnostic.range.start.character >= content.length
144+
) {
145+
return undefined;
146+
}
147+
148+
const start = context.toOffset(this.fromVirtualDocPosition(diagnostic.range.start));
149+
const length = context.toOffset(this.fromVirtualDocPosition(diagnostic.range.end)) - start;
138150
const code = typeof diagnostic.code === 'number' ? diagnostic.code : 9999;
139151
return {
140152
code,

src/template-string-language-service-proxy.ts

+10-5
Original file line numberDiff line numberDiff line change
@@ -216,10 +216,15 @@ class TemplateLanguageServiceProxyBuilder {
216216
return node;
217217
}
218218

219-
private getAllTemplateNodes(fileName: string): ts.TemplateExpression[] {
220-
return this.helper
221-
.getAllNodes(fileName, node => this.getValidTemplateNode(node) !== undefined)
222-
.map(node => this.getValidTemplateNode(node) as ts.TemplateExpression);
219+
private getAllValidTemplateNodes(fileName: string): ts.TemplateLiteral[] {
220+
const out: ts.TemplateLiteral[] = [];
221+
for (const node of this.helper.getAllNodes(fileName, n => this.getValidTemplateNode(n) !== undefined)) {
222+
const validNode = this.getValidTemplateNode(node);
223+
if (validNode) {
224+
out.push(validNode);
225+
}
226+
}
227+
return out;
223228
}
224229

225230
private getValidTemplateNode(node: ts.Node | undefined): ts.TemplateLiteral | undefined {
@@ -281,7 +286,7 @@ class TemplateLanguageServiceProxyBuilder {
281286
) {
282287
const baseDiagnostics = delegate(fileName);
283288
const templateDiagnostics: ts.Diagnostic[] = [];
284-
for (const templateNode of this.getAllTemplateNodes(fileName)) {
289+
for (const templateNode of this.getAllValidTemplateNodes(fileName)) {
285290
const contents = this.getContents(templateNode);
286291
const diagnostics: ts.Diagnostic[] = implementation(
287292
contents,

0 commit comments

Comments
 (0)