feat(language-service): provide diagnostics for invalid styleUrls (#32674)
Similar to diagnostics for invalid templateUrls, check that styleUrls actually point to a valid Url. Closes #32564. PR Close #32674
This commit is contained in:
parent
cd4021ba41
commit
4c168ed9ba
|
@ -116,7 +116,7 @@ export function getDeclarationDiagnostics(
|
|||
span: declarationSpan,
|
||||
});
|
||||
}
|
||||
const {template, templateUrl} = metadata.template !;
|
||||
const {template, templateUrl, styleUrls} = metadata.template !;
|
||||
if (template === null && !templateUrl) {
|
||||
results.push({
|
||||
kind: ng.DiagnosticKind.Error,
|
||||
|
@ -138,7 +138,7 @@ export function getDeclarationDiagnostics(
|
|||
// TODO: We should create an enum of the various properties a directive can have to use
|
||||
// instead of string literals. We can then perform a mass migration of all literal usages.
|
||||
const templateUrlNode = findPropertyValueOfType(
|
||||
directiveIdentifier.parent, 'templateUrl', ts.isStringLiteralLike);
|
||||
directiveIdentifier.parent, 'templateUrl', ts.isLiteralExpression);
|
||||
if (!templateUrlNode) {
|
||||
logImpossibleState(`templateUrl ${templateUrl} exists but its TypeScript node doesn't`);
|
||||
return [];
|
||||
|
@ -146,6 +146,19 @@ export function getDeclarationDiagnostics(
|
|||
|
||||
results.push(...validateUrls([templateUrlNode], host.tsLsHost));
|
||||
}
|
||||
|
||||
if (styleUrls.length > 0) {
|
||||
// Find styleUrls value from the directive call expression, which is the parent of the
|
||||
// directive identifier.
|
||||
const styleUrlsNode = findPropertyValueOfType(
|
||||
directiveIdentifier.parent, 'styleUrls', ts.isArrayLiteralExpression);
|
||||
if (!styleUrlsNode) {
|
||||
logImpossibleState(`styleUrls property exists but its TypeScript node doesn't'`);
|
||||
return [];
|
||||
}
|
||||
|
||||
results.push(...validateUrls(styleUrlsNode.elements, host.tsLsHost));
|
||||
}
|
||||
} else if (!directives.has(declaration.type)) {
|
||||
results.push({
|
||||
kind: ng.DiagnosticKind.Error,
|
||||
|
@ -168,7 +181,7 @@ export function getDeclarationDiagnostics(
|
|||
* @return diagnosed url errors, if any
|
||||
*/
|
||||
function validateUrls(
|
||||
urls: ts.StringLiteralLike[], tsLsHost: Readonly<ts.LanguageServiceHost>): ng.Diagnostic[] {
|
||||
urls: ArrayLike<ts.Expression>, tsLsHost: Readonly<ts.LanguageServiceHost>): ng.Diagnostic[] {
|
||||
if (!tsLsHost.fileExists) {
|
||||
return [];
|
||||
}
|
||||
|
@ -176,7 +189,13 @@ function validateUrls(
|
|||
const allErrors: ng.Diagnostic[] = [];
|
||||
// TODO(ayazhafiz): most of this logic can be unified with the logic in
|
||||
// definitions.ts#getUrlFromProperty. Create a utility function to be used by both.
|
||||
for (const urlNode of urls) {
|
||||
for (let i = 0; i < urls.length; ++i) {
|
||||
const urlNode = urls[i];
|
||||
if (!ts.isStringLiteralLike(urlNode)) {
|
||||
// If a non-string value is assigned to a URL node (like `templateUrl`), a type error will be
|
||||
// picked up by the TS Language Server.
|
||||
continue;
|
||||
}
|
||||
const curPath = urlNode.getSourceFile().fileName;
|
||||
const url = path.join(path.dirname(curPath), urlNode.text);
|
||||
if (tsLsHost.fileExists(url)) continue;
|
||||
|
|
|
@ -507,6 +507,37 @@ describe('diagnostics', () => {
|
|||
diagnostics.find(d => d.messageText === 'URL does not point to a valid file');
|
||||
expect(urlDiagnostic).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should report errors for invalid styleUrls', () => {
|
||||
const fileName = mockHost.addCode(`
|
||||
@Component({
|
||||
styleUrls: ['«notAFile»'],
|
||||
})
|
||||
export class MyComponent {}`);
|
||||
|
||||
const marker = mockHost.getReferenceMarkerFor(fileName, 'notAFile');
|
||||
|
||||
const diagnostics = ngLS.getDiagnostics(fileName) !;
|
||||
const urlDiagnostic =
|
||||
diagnostics.find(d => d.messageText === 'URL does not point to a valid file');
|
||||
expect(urlDiagnostic).toBeDefined();
|
||||
|
||||
const {start, length} = urlDiagnostic !;
|
||||
expect(start).toBe(marker.start);
|
||||
expect(length).toBe(marker.length);
|
||||
});
|
||||
|
||||
it('should not report errors for valid styleUrls', () => {
|
||||
const fileName = '/app/app.component.ts';
|
||||
mockHost.override(fileName, `
|
||||
@Component({
|
||||
styleUrls: ['./test.css', './test.css'],
|
||||
})
|
||||
export class MyComponent {}`);
|
||||
|
||||
const diagnostics = ngLS.getDiagnostics(fileName) !;
|
||||
expect(diagnostics.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
// https://github.com/angular/vscode-ng-language-service/issues/235
|
||||
|
|
Loading…
Reference in New Issue