Skip to content

Commit

Permalink
fixup! fix(compiler-cli): Allow analysis to continue with invalid sty…
Browse files Browse the repository at this point in the history
…le url
  • Loading branch information
atscott committed Apr 5, 2021
1 parent 6fe6bda commit 64aa114
Showing 1 changed file with 77 additions and 102 deletions.
179 changes: 77 additions & 102 deletions packages/compiler-cli/src/ngtsc/annotations/src/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -262,19 +262,16 @@ export class ComponentDecoratorHandler implements
const component = reflectObjectLiteral(meta);
const containingFile = node.getSourceFile().fileName;

const resolveStyleUrl =
(styleUrl: string, nodeForError: ts.Node,
resourceType: ResourceTypeForDiagnostics): Promise<void>|undefined => {
try {
const resourceUrl =
this._resolveResourceOrThrow(styleUrl, containingFile, nodeForError, resourceType);
return this.resourceLoader.preload(resourceUrl, {type: 'style', containingFile});
} catch {
// Don't worry about failures to preload. We can handle this problem during analysis by
// producing a diagnostic.
return undefined;
}
};
const resolveStyleUrl = (styleUrl: string): Promise<void>|undefined => {
try {
const resourceUrl = this.resourceLoader.resolve(styleUrl, containingFile);
return this.resourceLoader.preload(resourceUrl, {type: 'style', containingFile});
} catch {
// Don't worry about failures to preload. We can handle this problem during analysis by
// producing a diagnostic.
return undefined;
}
};

// A Promise that waits for the template and all <link>ed styles within it to be preloaded.
const templateAndTemplateStyleResources =
Expand All @@ -284,12 +281,7 @@ export class ComponentDecoratorHandler implements
return undefined;
}

const nodeForError = getTemplateDeclarationNodeForError(template.declaration);
return Promise
.all(template.styleUrls.map(
styleUrl => resolveStyleUrl(
styleUrl, nodeForError,
ResourceTypeForDiagnostics.StylesheetFromTemplate)))
return Promise.all(template.styleUrls.map(styleUrl => resolveStyleUrl(styleUrl)))
.then(() => undefined);
});

Expand Down Expand Up @@ -317,10 +309,7 @@ export class ComponentDecoratorHandler implements
return Promise
.all([
templateAndTemplateStyleResources, inlineStyles,
...componentStyleUrls.map(
styleUrl => resolveStyleUrl(
styleUrl.url, styleUrl.nodeForError,
ResourceTypeForDiagnostics.StylesheetFromDecorator))
...componentStyleUrls.map(styleUrl => resolveStyleUrl(styleUrl.url))
])
.then(() => undefined);
}
Expand Down Expand Up @@ -416,29 +405,23 @@ export class ComponentDecoratorHandler implements
];

for (const styleUrl of styleUrls) {
const resourceType = styleUrl.source === ResourceTypeForDiagnostics.StylesheetFromDecorator ?
ResourceTypeForDiagnostics.StylesheetFromDecorator :
ResourceTypeForDiagnostics.StylesheetFromTemplate;
try {
const resourceUrl = this._resolveResourceOrThrow(
styleUrl.url, containingFile, styleUrl.nodeForError, resourceType);
const resourceUrl = this.resourceLoader.resolve(styleUrl.url, containingFile);
const resourceStr = this.resourceLoader.load(resourceUrl);

styles.push(resourceStr);

if (this.depTracker !== null) {
this.depTracker.addResourceDependency(node.getSourceFile(), absoluteFrom(resourceUrl));
}
} catch (e) {
if (e instanceof FatalDiagnosticError) {
if (diagnostics === undefined) {
diagnostics = [];
}
diagnostics.push(makeDiagnostic(e.code, e.node, e.message, e.relatedInformation));
isPoisoned = true;
} else {
throw e;
} catch {
if (diagnostics === undefined) {
diagnostics = [];
}
const resourceType =
styleUrl.source === ResourceTypeForDiagnostics.StylesheetFromDecorator ?
ResourceTypeForDiagnostics.StylesheetFromDecorator :
ResourceTypeForDiagnostics.StylesheetFromTemplate;
const e = this.makeResourceNotFoundError(styleUrl.url, styleUrl.nodeForError, resourceType)
diagnostics.push(makeDiagnostic(e.code, e.node, e.message));
}
}

Expand Down Expand Up @@ -855,13 +838,8 @@ export class ComponentDecoratorHandler implements
let styles: string[] = [];
if (analysis.styleUrls !== null) {
for (const styleUrl of analysis.styleUrls) {
const resourceType =
styleUrl.source === ResourceTypeForDiagnostics.StylesheetFromDecorator ?
ResourceTypeForDiagnostics.StylesheetFromDecorator :
ResourceTypeForDiagnostics.StylesheetFromTemplate;
try {
const resolvedStyleUrl = this._resolveResourceOrThrow(
styleUrl.url, containingFile, styleUrl.nodeForError, resourceType);
const resolvedStyleUrl = this.resourceLoader.resolve(styleUrl.url, containingFile);
const styleText = this.resourceLoader.load(resolvedStyleUrl);
styles.push(styleText);
} catch (e) {
Expand Down Expand Up @@ -1006,9 +984,7 @@ export class ComponentDecoratorHandler implements
if (styleUrlsExpr !== undefined && ts.isArrayLiteralExpression(styleUrlsExpr)) {
for (const expression of stringLiteralElements(styleUrlsExpr)) {
try {
const resourceUrl = this._resolveResourceOrThrow(
expression.text, containingFile, expression,
ResourceTypeForDiagnostics.StylesheetFromDecorator);
const resourceUrl = this.resourceLoader.resolve(expression.text, containingFile);
styles.add({path: absoluteFrom(resourceUrl), expression});
} catch {
// Errors in style resource extraction do not need to be handled here. We will produce
Expand Down Expand Up @@ -1039,22 +1015,27 @@ export class ComponentDecoratorHandler implements
throw createValueHasWrongTypeError(
templateUrlExpr, templateUrl, 'templateUrl must be a string');
}
const resourceUrl = this._resolveResourceOrThrow(
templateUrl, containingFile, templateUrlExpr, ResourceTypeForDiagnostics.Template);
const templatePromise =
this.resourceLoader.preload(resourceUrl, {type: 'template', containingFile});

// If the preload worked, then actually load and parse the template, and wait for any style
// URLs to resolve.
if (templatePromise !== undefined) {
return templatePromise.then(() => {
const templateDecl = this.parseTemplateDeclaration(decorator, component, containingFile);
const template = this.extractTemplate(node, templateDecl);
this.preanalyzeTemplateCache.set(node, template);
return template;
});
} else {
return Promise.resolve(null);
try {
const resourceUrl = this.resourceLoader.resolve(templateUrl, containingFile);
const templatePromise =
this.resourceLoader.preload(resourceUrl, {type: 'template', containingFile});

// If the preload worked, then actually load and parse the template, and wait for any style
// URLs to resolve.
if (templatePromise !== undefined) {
return templatePromise.then(() => {
const templateDecl =
this.parseTemplateDeclaration(decorator, component, containingFile);
const template = this.extractTemplate(node, templateDecl);
this.preanalyzeTemplateCache.set(node, template);
return template;
});
} else {
return Promise.resolve(null);
}
} catch (e) {
throw this.makeResourceNotFoundError(
templateUrl, templateUrlExpr, ResourceTypeForDiagnostics.Template)
}
} else {
const templateDecl = this.parseTemplateDeclaration(decorator, component, containingFile);
Expand Down Expand Up @@ -1219,18 +1200,21 @@ export class ComponentDecoratorHandler implements
throw createValueHasWrongTypeError(
templateUrlExpr, templateUrl, 'templateUrl must be a string');
}
const resourceUrl = this._resolveResourceOrThrow(
templateUrl, containingFile, templateUrlExpr, ResourceTypeForDiagnostics.Template);

return {
isInline: false,
interpolationConfig,
preserveWhitespaces,
templateUrl,
templateUrlExpression: templateUrlExpr,
resolvedTemplateUrl: resourceUrl,
sourceMapUrl: sourceMapUrl(resourceUrl),
};
try {
const resourceUrl = this.resourceLoader.resolve(templateUrl, containingFile);
return {
isInline: false,
interpolationConfig,
preserveWhitespaces,
templateUrl,
templateUrlExpression: templateUrlExpr,
resolvedTemplateUrl: resourceUrl,
sourceMapUrl: sourceMapUrl(resourceUrl),
};
} catch (e) {
throw this.makeResourceNotFoundError(
templateUrl, templateUrlExpr, ResourceTypeForDiagnostics.Template)
}
} else if (component.has('template')) {
return {
isInline: true,
Expand Down Expand Up @@ -1293,33 +1277,24 @@ export class ComponentDecoratorHandler implements
this.cycleAnalyzer.recordSyntheticImport(origin, imported);
}

/**
* Resolve the url of a resource relative to the file that contains the reference to it.
*
* Throws a FatalDiagnosticError when unable to resolve the file.
*/
private _resolveResourceOrThrow(
file: string, basePath: string, nodeForError: ts.Node,
resourceType: ResourceTypeForDiagnostics): string {
try {
return this.resourceLoader.resolve(file, basePath);
} catch (e) {
let errorText: string;
switch (resourceType) {
case ResourceTypeForDiagnostics.Template:
errorText = `Could not find template file '${file}'.`;
break;
case ResourceTypeForDiagnostics.StylesheetFromTemplate:
errorText = `Could not find stylesheet file '${file}' linked from the template.`;
break;
case ResourceTypeForDiagnostics.StylesheetFromDecorator:
errorText = `Could not find stylesheet file '${file}'.`;
break;
}

throw new FatalDiagnosticError(
ErrorCode.COMPONENT_RESOURCE_NOT_FOUND, nodeForError, errorText);
private makeResourceNotFoundError(
file: string, nodeForError: ts.Node,
resourceType: ResourceTypeForDiagnostics): FatalDiagnosticError {
let errorText: string;
switch (resourceType) {
case ResourceTypeForDiagnostics.Template:
errorText = `Could not find template file '${file}'.`;
break;
case ResourceTypeForDiagnostics.StylesheetFromTemplate:
errorText = `Could not find stylesheet file '${file}' linked from the template.`;
break;
case ResourceTypeForDiagnostics.StylesheetFromDecorator:
errorText = `Could not find stylesheet file '${file}'.`;
break;
}

return new FatalDiagnosticError(
ErrorCode.COMPONENT_RESOURCE_NOT_FOUND, nodeForError, errorText);
}

private _extractTemplateStyleUrls(template: ParsedTemplateWithSource): StyleUrlMeta[] {
Expand Down

0 comments on commit 64aa114

Please sign in to comment.