feat(ivy): support inline <style> and <link> tags in components (#28997)
Angular supports using <style> and <link> tags inline in component templates, but previously such tags were not implemented within the ngtsc compiler. This commit introduces that support. FW-1069 #resolve PR Close #28997
This commit is contained in:

committed by
Ben Lesh

parent
40833ba54b
commit
827e89cfc4
@ -47,9 +47,12 @@ const IDENT_EVENT_IDX = 10;
|
||||
const TEMPLATE_ATTR_PREFIX = '*';
|
||||
|
||||
// Result of the html AST to Ivy AST transformation
|
||||
export type Render3ParseResult = {
|
||||
nodes: t.Node[]; errors: ParseError[];
|
||||
};
|
||||
export interface Render3ParseResult {
|
||||
nodes: t.Node[];
|
||||
errors: ParseError[];
|
||||
styles: string[];
|
||||
styleUrls: string[];
|
||||
}
|
||||
|
||||
export function htmlAstToRender3Ast(
|
||||
htmlNodes: html.Node[], bindingParser: BindingParser): Render3ParseResult {
|
||||
@ -68,28 +71,33 @@ export function htmlAstToRender3Ast(
|
||||
return {
|
||||
nodes: ivyNodes,
|
||||
errors: allErrors,
|
||||
styleUrls: transformer.styleUrls,
|
||||
styles: transformer.styles,
|
||||
};
|
||||
}
|
||||
|
||||
class HtmlAstToIvyAst implements html.Visitor {
|
||||
errors: ParseError[] = [];
|
||||
styles: string[] = [];
|
||||
styleUrls: string[] = [];
|
||||
|
||||
constructor(private bindingParser: BindingParser) {}
|
||||
|
||||
// HTML visitor
|
||||
visitElement(element: html.Element): t.Node|null {
|
||||
const preparsedElement = preparseElement(element);
|
||||
if (preparsedElement.type === PreparsedElementType.SCRIPT ||
|
||||
preparsedElement.type === PreparsedElementType.STYLE) {
|
||||
// Skipping <script> for security reasons
|
||||
// Skipping <style> as we already processed them
|
||||
// in the StyleCompiler
|
||||
if (preparsedElement.type === PreparsedElementType.SCRIPT) {
|
||||
return null;
|
||||
}
|
||||
if (preparsedElement.type === PreparsedElementType.STYLESHEET &&
|
||||
} else if (preparsedElement.type === PreparsedElementType.STYLE) {
|
||||
const contents = textContents(element);
|
||||
if (contents !== null) {
|
||||
this.styles.push(contents);
|
||||
}
|
||||
return null;
|
||||
} else if (
|
||||
preparsedElement.type === PreparsedElementType.STYLESHEET &&
|
||||
isStyleUrlResolvable(preparsedElement.hrefAttr)) {
|
||||
// Skipping stylesheets with either relative urls or package scheme as we already processed
|
||||
// them in the StyleCompiler
|
||||
this.styleUrls.push(preparsedElement.hrefAttr);
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -419,3 +427,11 @@ function isEmptyTextNode(node: html.Node): boolean {
|
||||
function isCommentNode(node: html.Node): boolean {
|
||||
return node instanceof html.Comment;
|
||||
}
|
||||
|
||||
function textContents(node: html.Element): string|null {
|
||||
if (node.children.length !== 1 || !(node.children[0] instanceof html.Text)) {
|
||||
return null;
|
||||
} else {
|
||||
return (node.children[0] as html.Text).value;
|
||||
}
|
||||
}
|
@ -1618,8 +1618,8 @@ export interface ParseTemplateOptions {
|
||||
* @param options options to modify how the template is parsed
|
||||
*/
|
||||
export function parseTemplate(
|
||||
template: string, templateUrl: string,
|
||||
options: ParseTemplateOptions = {}): {errors?: ParseError[], nodes: t.Node[]} {
|
||||
template: string, templateUrl: string, options: ParseTemplateOptions = {}):
|
||||
{errors?: ParseError[], nodes: t.Node[], styleUrls: string[], styles: string[]} {
|
||||
const {interpolationConfig, preserveWhitespaces} = options;
|
||||
const bindingParser = makeBindingParser(interpolationConfig);
|
||||
const htmlParser = new HtmlParser();
|
||||
@ -1627,7 +1627,7 @@ export function parseTemplate(
|
||||
htmlParser.parse(template, templateUrl, {...options, tokenizeExpansionForms: true});
|
||||
|
||||
if (parseResult.errors && parseResult.errors.length > 0) {
|
||||
return {errors: parseResult.errors, nodes: []};
|
||||
return {errors: parseResult.errors, nodes: [], styleUrls: [], styles: []};
|
||||
}
|
||||
|
||||
let rootNodes: html.Node[] = parseResult.rootNodes;
|
||||
@ -1650,12 +1650,12 @@ export function parseTemplate(
|
||||
new I18nMetaVisitor(interpolationConfig, /* keepI18nAttrs */ false), rootNodes);
|
||||
}
|
||||
|
||||
const {nodes, errors} = htmlAstToRender3Ast(rootNodes, bindingParser);
|
||||
const {nodes, errors, styleUrls, styles} = htmlAstToRender3Ast(rootNodes, bindingParser);
|
||||
if (errors && errors.length > 0) {
|
||||
return {errors, nodes: []};
|
||||
return {errors, nodes: [], styleUrls: [], styles: []};
|
||||
}
|
||||
|
||||
return {nodes};
|
||||
return {nodes, styleUrls, styles};
|
||||
}
|
||||
|
||||
/**
|
||||
|
Reference in New Issue
Block a user