Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(core): size regression with closure compiler #25531

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
117 changes: 63 additions & 54 deletions packages/compiler/src/ml_parser/html_tags.ts
Expand Up @@ -69,63 +69,72 @@ export class HtmlTagDefinition implements TagDefinition {
}
}

let _DEFAULT_TAG_DEFINITION !: HtmlTagDefinition;

// see http://www.w3.org/TR/html51/syntax.html#optional-tags
// This implementation does not fully conform to the HTML5 spec.
const TAG_DEFINITIONS: {[key: string]: HtmlTagDefinition} = {
'base': new HtmlTagDefinition({isVoid: true}),
'meta': new HtmlTagDefinition({isVoid: true}),
'area': new HtmlTagDefinition({isVoid: true}),
'embed': new HtmlTagDefinition({isVoid: true}),
'link': new HtmlTagDefinition({isVoid: true}),
'img': new HtmlTagDefinition({isVoid: true}),
'input': new HtmlTagDefinition({isVoid: true}),
'param': new HtmlTagDefinition({isVoid: true}),
'hr': new HtmlTagDefinition({isVoid: true}),
'br': new HtmlTagDefinition({isVoid: true}),
'source': new HtmlTagDefinition({isVoid: true}),
'track': new HtmlTagDefinition({isVoid: true}),
'wbr': new HtmlTagDefinition({isVoid: true}),
'p': new HtmlTagDefinition({
closedByChildren: [
'address', 'article', 'aside', 'blockquote', 'div', 'dl', 'fieldset', 'footer', 'form',
'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'hgroup', 'hr',
'main', 'nav', 'ol', 'p', 'pre', 'section', 'table', 'ul'
],
closedByParent: true
}),
'thead': new HtmlTagDefinition({closedByChildren: ['tbody', 'tfoot']}),
'tbody': new HtmlTagDefinition({closedByChildren: ['tbody', 'tfoot'], closedByParent: true}),
'tfoot': new HtmlTagDefinition({closedByChildren: ['tbody'], closedByParent: true}),
'tr': new HtmlTagDefinition({
closedByChildren: ['tr'],
requiredParents: ['tbody', 'tfoot', 'thead'],
closedByParent: true
}),
'td': new HtmlTagDefinition({closedByChildren: ['td', 'th'], closedByParent: true}),
'th': new HtmlTagDefinition({closedByChildren: ['td', 'th'], closedByParent: true}),
'col': new HtmlTagDefinition({requiredParents: ['colgroup'], isVoid: true}),
'svg': new HtmlTagDefinition({implicitNamespacePrefix: 'svg'}),
'math': new HtmlTagDefinition({implicitNamespacePrefix: 'math'}),
'li': new HtmlTagDefinition({closedByChildren: ['li'], closedByParent: true}),
'dt': new HtmlTagDefinition({closedByChildren: ['dt', 'dd']}),
'dd': new HtmlTagDefinition({closedByChildren: ['dt', 'dd'], closedByParent: true}),
'rb': new HtmlTagDefinition({closedByChildren: ['rb', 'rt', 'rtc', 'rp'], closedByParent: true}),
'rt': new HtmlTagDefinition({closedByChildren: ['rb', 'rt', 'rtc', 'rp'], closedByParent: true}),
'rtc': new HtmlTagDefinition({closedByChildren: ['rb', 'rtc', 'rp'], closedByParent: true}),
'rp': new HtmlTagDefinition({closedByChildren: ['rb', 'rt', 'rtc', 'rp'], closedByParent: true}),
'optgroup': new HtmlTagDefinition({closedByChildren: ['optgroup'], closedByParent: true}),
'option': new HtmlTagDefinition({closedByChildren: ['option', 'optgroup'], closedByParent: true}),
'pre': new HtmlTagDefinition({ignoreFirstLf: true}),
'listing': new HtmlTagDefinition({ignoreFirstLf: true}),
'style': new HtmlTagDefinition({contentType: TagContentType.RAW_TEXT}),
'script': new HtmlTagDefinition({contentType: TagContentType.RAW_TEXT}),
'title': new HtmlTagDefinition({contentType: TagContentType.ESCAPABLE_RAW_TEXT}),
'textarea':
new HtmlTagDefinition({contentType: TagContentType.ESCAPABLE_RAW_TEXT, ignoreFirstLf: true}),
};

const _DEFAULT_TAG_DEFINITION = new HtmlTagDefinition();
let TAG_DEFINITIONS !: {[key: string]: HtmlTagDefinition};

export function getHtmlTagDefinition(tagName: string): HtmlTagDefinition {
if (!TAG_DEFINITIONS) {
_DEFAULT_TAG_DEFINITION = new HtmlTagDefinition();
TAG_DEFINITIONS = {
'base': new HtmlTagDefinition({isVoid: true}),
'meta': new HtmlTagDefinition({isVoid: true}),
'area': new HtmlTagDefinition({isVoid: true}),
'embed': new HtmlTagDefinition({isVoid: true}),
'link': new HtmlTagDefinition({isVoid: true}),
'img': new HtmlTagDefinition({isVoid: true}),
'input': new HtmlTagDefinition({isVoid: true}),
'param': new HtmlTagDefinition({isVoid: true}),
'hr': new HtmlTagDefinition({isVoid: true}),
'br': new HtmlTagDefinition({isVoid: true}),
'source': new HtmlTagDefinition({isVoid: true}),
'track': new HtmlTagDefinition({isVoid: true}),
'wbr': new HtmlTagDefinition({isVoid: true}),
'p': new HtmlTagDefinition({
closedByChildren: [
'address', 'article', 'aside', 'blockquote', 'div', 'dl', 'fieldset',
'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5',
'h6', 'header', 'hgroup', 'hr', 'main', 'nav', 'ol',
'p', 'pre', 'section', 'table', 'ul'
],
closedByParent: true
}),
'thead': new HtmlTagDefinition({closedByChildren: ['tbody', 'tfoot']}),
'tbody': new HtmlTagDefinition({closedByChildren: ['tbody', 'tfoot'], closedByParent: true}),
'tfoot': new HtmlTagDefinition({closedByChildren: ['tbody'], closedByParent: true}),
'tr': new HtmlTagDefinition({
closedByChildren: ['tr'],
requiredParents: ['tbody', 'tfoot', 'thead'],
closedByParent: true
}),
'td': new HtmlTagDefinition({closedByChildren: ['td', 'th'], closedByParent: true}),
'th': new HtmlTagDefinition({closedByChildren: ['td', 'th'], closedByParent: true}),
'col': new HtmlTagDefinition({requiredParents: ['colgroup'], isVoid: true}),
'svg': new HtmlTagDefinition({implicitNamespacePrefix: 'svg'}),
'math': new HtmlTagDefinition({implicitNamespacePrefix: 'math'}),
'li': new HtmlTagDefinition({closedByChildren: ['li'], closedByParent: true}),
'dt': new HtmlTagDefinition({closedByChildren: ['dt', 'dd']}),
'dd': new HtmlTagDefinition({closedByChildren: ['dt', 'dd'], closedByParent: true}),
'rb': new HtmlTagDefinition(
{closedByChildren: ['rb', 'rt', 'rtc', 'rp'], closedByParent: true}),
'rt': new HtmlTagDefinition(
{closedByChildren: ['rb', 'rt', 'rtc', 'rp'], closedByParent: true}),
'rtc': new HtmlTagDefinition({closedByChildren: ['rb', 'rtc', 'rp'], closedByParent: true}),
'rp': new HtmlTagDefinition(
{closedByChildren: ['rb', 'rt', 'rtc', 'rp'], closedByParent: true}),
'optgroup': new HtmlTagDefinition({closedByChildren: ['optgroup'], closedByParent: true}),
'option':
new HtmlTagDefinition({closedByChildren: ['option', 'optgroup'], closedByParent: true}),
'pre': new HtmlTagDefinition({ignoreFirstLf: true}),
'listing': new HtmlTagDefinition({ignoreFirstLf: true}),
'style': new HtmlTagDefinition({contentType: TagContentType.RAW_TEXT}),
'script': new HtmlTagDefinition({contentType: TagContentType.RAW_TEXT}),
'title': new HtmlTagDefinition({contentType: TagContentType.ESCAPABLE_RAW_TEXT}),
'textarea': new HtmlTagDefinition(
{contentType: TagContentType.ESCAPABLE_RAW_TEXT, ignoreFirstLf: true}),
};
}
return TAG_DEFINITIONS[tagName.toLowerCase()] || _DEFAULT_TAG_DEFINITION;
}
8 changes: 7 additions & 1 deletion packages/compiler/src/render3/view/template.ts
Expand Up @@ -1018,8 +1018,14 @@ export class BindingScope implements LocalResolver {
private map = new Map<string, BindingData>();
private referenceNameIndex = 0;
private restoreViewVariable: o.ReadVarExpr|null = null;
private static _ROOT_SCOPE: BindingScope;

static ROOT_SCOPE = new BindingScope().set(0, '$event', o.variable('$event'));
static get ROOT_SCOPE(): BindingScope {
if (!BindingScope._ROOT_SCOPE) {
BindingScope._ROOT_SCOPE = new BindingScope().set(0, '$event', o.variable('$event'));
}
return BindingScope._ROOT_SCOPE;
}

private constructor(public bindingLevel: number = 0, private parent: BindingScope|null = null) {}

Expand Down
4 changes: 2 additions & 2 deletions packages/compiler/src/schema/dom_element_schema_registry.ts
Expand Up @@ -342,11 +342,11 @@ export class DomElementSchemaRegistry extends ElementSchemaRegistry {
// property names do not have a security impact.
tagName = tagName.toLowerCase();
propName = propName.toLowerCase();
let ctx = SECURITY_SCHEMA[tagName + '|' + propName];
let ctx = SECURITY_SCHEMA()[tagName + '|' + propName];
if (ctx) {
return ctx;
}
ctx = SECURITY_SCHEMA['*|' + propName];
ctx = SECURITY_SCHEMA()['*|' + propName];
return ctx ? ctx : SecurityContext.NONE;
}

Expand Down
72 changes: 39 additions & 33 deletions packages/compiler/src/schema/dom_security_schema.ts
Expand Up @@ -20,39 +20,45 @@ import {SecurityContext} from '../core';
// =================================================================================================

/** Map from tagName|propertyName SecurityContext. Properties applying to all tags use '*'. */
export const SECURITY_SCHEMA: {[k: string]: SecurityContext} = {};
let _SECURITY_SCHEMA !: {[k: string]: SecurityContext};

function registerContext(ctx: SecurityContext, specs: string[]) {
for (const spec of specs) SECURITY_SCHEMA[spec.toLowerCase()] = ctx;
}
export function SECURITY_SCHEMA(): {[k: string]: SecurityContext} {
if (!_SECURITY_SCHEMA) {
_SECURITY_SCHEMA = {};
// Case is insignificant below, all element and attribute names are lower-cased for lookup.

// Case is insignificant below, all element and attribute names are lower-cased for lookup.
registerContext(SecurityContext.HTML, [
'iframe|srcdoc',
'*|innerHTML',
'*|outerHTML',
]);
registerContext(SecurityContext.STYLE, ['*|style']);
// NB: no SCRIPT contexts here, they are never allowed due to the parser stripping them.
registerContext(SecurityContext.URL, [
'*|formAction', 'area|href', 'area|ping', 'audio|src', 'a|href',
'a|ping', 'blockquote|cite', 'body|background', 'del|cite', 'form|action',
'img|src', 'img|srcset', 'input|src', 'ins|cite', 'q|cite',
'source|src', 'source|srcset', 'track|src', 'video|poster', 'video|src',
]);
registerContext(SecurityContext.RESOURCE_URL, [
'applet|code',
'applet|codebase',
'base|href',
'embed|src',
'frame|src',
'head|profile',
'html|manifest',
'iframe|src',
'link|href',
'media|src',
'object|codebase',
'object|data',
'script|src',
]);
}
return _SECURITY_SCHEMA;
}

registerContext(SecurityContext.HTML, [
'iframe|srcdoc',
'*|innerHTML',
'*|outerHTML',
]);
registerContext(SecurityContext.STYLE, ['*|style']);
// NB: no SCRIPT contexts here, they are never allowed due to the parser stripping them.
registerContext(SecurityContext.URL, [
'*|formAction', 'area|href', 'area|ping', 'audio|src', 'a|href',
'a|ping', 'blockquote|cite', 'body|background', 'del|cite', 'form|action',
'img|src', 'img|srcset', 'input|src', 'ins|cite', 'q|cite',
'source|src', 'source|srcset', 'track|src', 'video|poster', 'video|src',
]);
registerContext(SecurityContext.RESOURCE_URL, [
'applet|code',
'applet|codebase',
'base|href',
'embed|src',
'frame|src',
'head|profile',
'html|manifest',
'iframe|src',
'link|href',
'media|src',
'object|codebase',
'object|data',
'script|src',
]);
function registerContext(ctx: SecurityContext, specs: string[]) {
for (const spec of specs) _SECURITY_SCHEMA[spec.toLowerCase()] = ctx;
}
12 changes: 9 additions & 3 deletions packages/compiler/src/template_parser/template_parser.ts
Expand Up @@ -57,7 +57,13 @@ const IDENT_EVENT_IDX = 10;
const TEMPLATE_ATTR_PREFIX = '*';
const CLASS_ATTR = 'class';

const TEXT_CSS_SELECTOR = CssSelector.parse('*')[0];
let _TEXT_CSS_SELECTOR !: CssSelector;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is there no corresponding change on the usage site to call TEXT_CSS_SELCTOR as a function?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

function TEXT_CSS_SELECTOR(): CssSelector {
if (!_TEXT_CSS_SELECTOR) {
_TEXT_CSS_SELECTOR = CssSelector.parse('*')[0];
}
return _TEXT_CSS_SELECTOR;
}

export class TemplateParseError extends ParseError {
constructor(message: string, span: ParseSourceSpan, level: ParseErrorLevel) {
Expand Down Expand Up @@ -227,7 +233,7 @@ class TemplateParseVisitor implements html.Visitor {
visitExpansionCase(expansionCase: html.ExpansionCase, context: any): any { return null; }

visitText(text: html.Text, parent: ElementContext): any {
const ngContentIndex = parent.findNgContentIndex(TEXT_CSS_SELECTOR) !;
const ngContentIndex = parent.findNgContentIndex(TEXT_CSS_SELECTOR()) !;
const valueNoNgsp = replaceNgsp(text.value);
const expr = this._bindingParser.parseInterpolation(valueNoNgsp, text.sourceSpan !);
return expr ? new t.BoundTextAst(expr, ngContentIndex, text.sourceSpan !) :
Expand Down Expand Up @@ -775,7 +781,7 @@ class NonBindableVisitor implements html.Visitor {
}

visitText(text: html.Text, parent: ElementContext): t.TextAst {
const ngContentIndex = parent.findNgContentIndex(TEXT_CSS_SELECTOR) !;
const ngContentIndex = parent.findNgContentIndex(TEXT_CSS_SELECTOR()) !;
return new t.TextAst(text.value, ngContentIndex, text.sourceSpan !);
}

Expand Down
Expand Up @@ -1436,9 +1436,6 @@
{
"name": "SyncAsync"
},
{
"name": "TAG_DEFINITIONS"
},
{
"name": "TAG_TO_PLACEHOLDER_NAMES"
},
Expand Down Expand Up @@ -1727,9 +1724,6 @@
{
"name": "_DEFAULT_SOURCE_LANG$1"
},
{
"name": "_DEFAULT_TAG_DEFINITION"
},
{
"name": "_DOCTYPE"
},
Expand Down Expand Up @@ -3497,6 +3491,9 @@
{
"name": "refCount"
},
{
"name": "registerContext"
},
{
"name": "registerModuleFactory"
},
Expand Down