From 3859bcc70cdf4773cd4bae14b2c0218c273f1540 Mon Sep 17 00:00:00 2001 From: Ben Lesh Date: Fri, 31 May 2019 10:39:14 -0700 Subject: [PATCH] =?UTF-8?q?refactor(ivy):=20remove=20=C9=B5=C9=B5elementAt?= =?UTF-8?q?tribute=20instruction=20(#30640)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR Close #30640 --- .../compiler/src/render3/r3_identifiers.ts | 2 - .../core/src/core_render3_private_export.ts | 1 - packages/core/src/render3/i18n.ts | 12 +-- packages/core/src/render3/index.ts | 1 - .../src/render3/instructions/attribute.ts | 13 ++- .../instructions/attribute_interpolation.ts | 55 +++++++++---- .../core/src/render3/instructions/element.ts | 60 ++------------ .../core/src/render3/instructions/shared.ts | 31 ++++++- packages/core/src/render3/jit/environment.ts | 1 - .../core/test/render3/instructions_spec.ts | 81 +++++++++++++------ .../core/test/render3/integration_spec.ts | 7 +- tools/public_api_guard/core/core.d.ts | 2 - 12 files changed, 151 insertions(+), 115 deletions(-) diff --git a/packages/compiler/src/render3/r3_identifiers.ts b/packages/compiler/src/render3/r3_identifiers.ts index 22f1197d38..a17f4ffd12 100644 --- a/packages/compiler/src/render3/r3_identifiers.ts +++ b/packages/compiler/src/render3/r3_identifiers.ts @@ -37,8 +37,6 @@ export class Identifiers { static componentHostSyntheticListener: o.ExternalReference = {name: 'ɵɵcomponentHostSyntheticListener', moduleName: CORE}; - static elementAttribute: o.ExternalReference = {name: 'ɵɵelementAttribute', moduleName: CORE}; - static attribute: o.ExternalReference = {name: 'ɵɵattribute', moduleName: CORE}; static attributeInterpolate1: diff --git a/packages/core/src/core_render3_private_export.ts b/packages/core/src/core_render3_private_export.ts index aec2b0641e..e8016d3779 100644 --- a/packages/core/src/core_render3_private_export.ts +++ b/packages/core/src/core_render3_private_export.ts @@ -126,7 +126,6 @@ export { ɵɵenableBindings, ɵɵdisableBindings, ɵɵallocHostVars, - ɵɵelementAttribute, ɵɵelementContainerStart, ɵɵelementContainerEnd, ɵɵstyling, diff --git a/packages/core/src/render3/i18n.ts b/packages/core/src/render3/i18n.ts index 20729712a2..e04c076d80 100644 --- a/packages/core/src/render3/i18n.ts +++ b/packages/core/src/render3/i18n.ts @@ -7,16 +7,18 @@ */ import '../util/ng_i18n_closure_mode'; + import {getPluralCase} from '../i18n/localization'; import {SRCSET_ATTRS, URI_ATTRS, VALID_ATTRS, VALID_ELEMENTS, getTemplateContent} from '../sanitization/html_sanitizer'; import {InertBodyHelper} from '../sanitization/inert_body'; import {_sanitizeUrl, sanitizeSrcset} from '../sanitization/url_sanitizer'; import {addAllToArray} from '../util/array_utils'; import {assertDataInRange, assertDefined, assertEqual, assertGreaterThan} from '../util/assert'; + import {attachPatchData} from './context_discovery'; -import {elementAttributeInternal, setDelayProjection, ɵɵload, ɵɵtextBinding} from './instructions/all'; +import {setDelayProjection, ɵɵload, ɵɵtextBinding} from './instructions/all'; import {attachI18nOpCodesDebug} from './instructions/lview_debug'; -import {allocExpando, elementPropertyInternal, getOrCreateTNode, setInputsForProperty} from './instructions/shared'; +import {allocExpando, elementAttributeInternal, elementPropertyInternal, getOrCreateTNode, setInputsForProperty} from './instructions/shared'; import {LContainer, NATIVE} from './interfaces/container'; import {COMMENT_MARKER, ELEMENT_MARKER, I18nMutateOpCode, I18nMutateOpCodes, I18nUpdateOpCode, I18nUpdateOpCodes, IcuType, TI18n, TIcu} from './interfaces/i18n'; import {TElementNode, TIcuContainerNode, TNode, TNodeFlags, TNodeType, TProjectionNode} from './interfaces/node'; @@ -755,10 +757,9 @@ function readCreateOpCodes( const elementNodeIndex = opCode >>> I18nMutateOpCode.SHIFT_REF; const attrName = createOpCodes[++i] as string; const attrValue = createOpCodes[++i] as string; - const renderer = viewData[RENDERER]; // This code is used for ICU expressions only, since we don't support // directives/components in ICUs, we don't need to worry about inputs here - elementAttributeInternal(elementNodeIndex, attrName, attrValue, viewData, renderer); + elementAttributeInternal(elementNodeIndex, attrName, attrValue, viewData); break; default: throw new Error(`Unable to determine the type of mutate operation for "${opCode}"`); @@ -988,8 +989,7 @@ function i18nAttributesFirstPass(tView: TView, index: number, values: string[]) generateBindingUpdateOpCodes(value, previousElementIndex, attrName), updateOpCodes); } else { const lView = getLView(); - const renderer = lView[RENDERER]; - elementAttributeInternal(previousElementIndex, attrName, value, lView, renderer); + elementAttributeInternal(previousElementIndex, attrName, value, lView); // Check if that attribute is a directive input const tNode = getTNode(previousElementIndex, lView); const dataValue = tNode.inputs && tNode.inputs[attrName]; diff --git a/packages/core/src/render3/index.ts b/packages/core/src/render3/index.ts index d37795f76e..555b6d377a 100644 --- a/packages/core/src/render3/index.ts +++ b/packages/core/src/render3/index.ts @@ -47,7 +47,6 @@ export { ɵɵdirectiveInject, ɵɵelement, - ɵɵelementAttribute, ɵɵelementContainerEnd, ɵɵelementContainerStart, diff --git a/packages/core/src/render3/instructions/attribute.ts b/packages/core/src/render3/instructions/attribute.ts index f5fdc13f8a..8307c5d364 100644 --- a/packages/core/src/render3/instructions/attribute.ts +++ b/packages/core/src/render3/instructions/attribute.ts @@ -6,10 +6,13 @@ * found in the LICENSE file at https://angular.io/license */ import {SanitizerFn} from '../interfaces/sanitization'; -import {getSelectedIndex} from '../state'; +import {getLView, getSelectedIndex} from '../state'; +import {NO_CHANGE} from '../tokens'; -import {ɵɵelementAttribute} from './element'; import {ɵɵbind} from './property'; +import {elementAttributeInternal} from './shared'; + + /** * Updates the value of or removes a bound attribute on an Element. @@ -27,6 +30,10 @@ import {ɵɵbind} from './property'; export function ɵɵattribute( name: string, value: any, sanitizer?: SanitizerFn | null, namespace?: string) { const index = getSelectedIndex(); + const lView = getLView(); // TODO(FW-1340): Refactor to remove the use of other instructions here. - return ɵɵelementAttribute(index, name, ɵɵbind(value), sanitizer, namespace); + const bound = ɵɵbind(value); + if (bound !== NO_CHANGE) { + return elementAttributeInternal(index, name, bound, lView, sanitizer, namespace); + } } diff --git a/packages/core/src/render3/instructions/attribute_interpolation.ts b/packages/core/src/render3/instructions/attribute_interpolation.ts index c0505532e9..64dde617d2 100644 --- a/packages/core/src/render3/instructions/attribute_interpolation.ts +++ b/packages/core/src/render3/instructions/attribute_interpolation.ts @@ -6,10 +6,11 @@ * found in the LICENSE file at https://angular.io/license */ import {SanitizerFn} from '../interfaces/sanitization'; -import {getSelectedIndex} from '../state'; -import {ɵɵelementAttribute} from './element'; +import {getLView, getSelectedIndex} from '../state'; +import {NO_CHANGE} from '../tokens'; + import {ɵɵinterpolation1, ɵɵinterpolation2, ɵɵinterpolation3, ɵɵinterpolation4, ɵɵinterpolation5, ɵɵinterpolation6, ɵɵinterpolation7, ɵɵinterpolation8, ɵɵinterpolationV} from './interpolation'; -import {TsickleIssue1009} from './shared'; +import {TsickleIssue1009, elementAttributeInternal} from './shared'; @@ -41,12 +42,13 @@ export function ɵɵattributeInterpolate1( attrName: string, prefix: string, v0: any, suffix: string, sanitizer?: SanitizerFn, namespace?: string): TsickleIssue1009 { const index = getSelectedIndex(); + const lView = getLView(); // TODO(FW-1340): Refactor to remove the use of other instructions here. const interpolatedValue = ɵɵinterpolation1(prefix, v0, suffix); - - ɵɵelementAttribute(index, attrName, interpolatedValue, sanitizer, namespace); - + if (interpolatedValue !== NO_CHANGE) { + elementAttributeInternal(index, attrName, interpolatedValue, lView, sanitizer, namespace); + } return ɵɵattributeInterpolate1; } @@ -80,10 +82,13 @@ export function ɵɵattributeInterpolate2( attrName: string, prefix: string, v0: any, i0: string, v1: any, suffix: string, sanitizer?: SanitizerFn, namespace?: string): TsickleIssue1009 { const index = getSelectedIndex(); + const lView = getLView(); // TODO(FW-1340): Refactor to remove the use of other instructions here. const interpolatedValue = ɵɵinterpolation2(prefix, v0, i0, v1, suffix); - ɵɵelementAttribute(index, attrName, interpolatedValue, sanitizer, namespace); + if (interpolatedValue !== NO_CHANGE) { + elementAttributeInternal(index, attrName, interpolatedValue, lView, sanitizer, namespace); + } return ɵɵattributeInterpolate2; } @@ -120,10 +125,13 @@ export function ɵɵattributeInterpolate3( attrName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, suffix: string, sanitizer?: SanitizerFn, namespace?: string): TsickleIssue1009 { const index = getSelectedIndex(); + const lView = getLView(); // TODO(FW-1340): Refactor to remove the use of other instructions here. const interpolatedValue = ɵɵinterpolation3(prefix, v0, i0, v1, i1, v2, suffix); - ɵɵelementAttribute(index, attrName, interpolatedValue, sanitizer, namespace); + if (interpolatedValue !== NO_CHANGE) { + elementAttributeInternal(index, attrName, interpolatedValue, lView, sanitizer, namespace); + } return ɵɵattributeInterpolate3; } @@ -162,10 +170,13 @@ export function ɵɵattributeInterpolate4( attrName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any, suffix: string, sanitizer?: SanitizerFn, namespace?: string): TsickleIssue1009 { const index = getSelectedIndex(); + const lView = getLView(); // TODO(FW-1340): Refactor to remove the use of other instructions here. const interpolatedValue = ɵɵinterpolation4(prefix, v0, i0, v1, i1, v2, i2, v3, suffix); - ɵɵelementAttribute(index, attrName, interpolatedValue, sanitizer, namespace); + if (interpolatedValue !== NO_CHANGE) { + elementAttributeInternal(index, attrName, interpolatedValue, lView, sanitizer, namespace); + } return ɵɵattributeInterpolate4; } @@ -207,10 +218,13 @@ export function ɵɵattributeInterpolate5( v3: any, i3: string, v4: any, suffix: string, sanitizer?: SanitizerFn, namespace?: string): TsickleIssue1009 { const index = getSelectedIndex(); + const lView = getLView(); // TODO(FW-1340): Refactor to remove the use of other instructions here. const interpolatedValue = ɵɵinterpolation5(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix); - ɵɵelementAttribute(index, attrName, interpolatedValue, sanitizer, namespace); + if (interpolatedValue !== NO_CHANGE) { + elementAttributeInternal(index, attrName, interpolatedValue, lView, sanitizer, namespace); + } return ɵɵattributeInterpolate5; } @@ -254,10 +268,13 @@ export function ɵɵattributeInterpolate6( v3: any, i3: string, v4: any, i4: string, v5: any, suffix: string, sanitizer?: SanitizerFn, namespace?: string): TsickleIssue1009 { const index = getSelectedIndex(); + const lView = getLView(); // TODO(FW-1340): Refactor to remove the use of other instructions here. const interpolatedValue = ɵɵinterpolation6(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix); - ɵɵelementAttribute(index, attrName, interpolatedValue, sanitizer, namespace); + if (interpolatedValue !== NO_CHANGE) { + elementAttributeInternal(index, attrName, interpolatedValue, lView, sanitizer, namespace); + } return ɵɵattributeInterpolate6; } @@ -303,10 +320,13 @@ export function ɵɵattributeInterpolate7( v3: any, i3: string, v4: any, i4: string, v5: any, i5: string, v6: any, suffix: string, sanitizer?: SanitizerFn, namespace?: string): TsickleIssue1009 { const index = getSelectedIndex(); + const lView = getLView(); // TODO(FW-1340): Refactor to remove the use of other instructions here. const interpolatedValue = ɵɵinterpolation7(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix); - ɵɵelementAttribute(index, attrName, interpolatedValue, sanitizer, namespace); + if (interpolatedValue !== NO_CHANGE) { + elementAttributeInternal(index, attrName, interpolatedValue, lView, sanitizer, namespace); + } return ɵɵattributeInterpolate7; } @@ -354,10 +374,13 @@ export function ɵɵattributeInterpolate8( v3: any, i3: string, v4: any, i4: string, v5: any, i5: string, v6: any, i6: string, v7: any, suffix: string, sanitizer?: SanitizerFn, namespace?: string): TsickleIssue1009 { const index = getSelectedIndex(); + const lView = getLView(); // TODO(FW-1340): Refactor to remove the use of other instructions here. const interpolatedValue = ɵɵinterpolation8(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix); - ɵɵelementAttribute(index, attrName, interpolatedValue, sanitizer, namespace); + if (interpolatedValue !== NO_CHANGE) { + elementAttributeInternal(index, attrName, interpolatedValue, lView, sanitizer, namespace); + } return ɵɵattributeInterpolate8; } @@ -391,7 +414,11 @@ export function ɵɵattributeInterpolateV( attrName: string, values: any[], sanitizer?: SanitizerFn, namespace?: string): TsickleIssue1009 { const index = getSelectedIndex(); + const lView = getLView(); // TODO(FW-1340): Refactor to remove the use of other instructions here. - ɵɵelementAttribute(index, attrName, ɵɵinterpolationV(values), sanitizer, namespace); + const interpolated = ɵɵinterpolationV(values); + if (interpolated !== NO_CHANGE) { + elementAttributeInternal(index, attrName, interpolated, lView, sanitizer, namespace); + } return ɵɵattributeInterpolateV; } diff --git a/packages/core/src/render3/instructions/element.ts b/packages/core/src/render3/instructions/element.ts index 1cdc428251..219831e4df 100644 --- a/packages/core/src/render3/instructions/element.ts +++ b/packages/core/src/render3/instructions/element.ts @@ -5,16 +5,14 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {validateAgainstEventAttributes} from '../../sanitization/sanitization'; import {assertDataInRange, assertDefined, assertEqual} from '../../util/assert'; import {assertHasParent} from '../assert'; import {attachPatchData} from '../context_discovery'; import {registerPostOrderHooks} from '../hooks'; import {TAttributes, TNodeFlags, TNodeType} from '../interfaces/node'; -import {RElement, Renderer3, isProceduralRenderer} from '../interfaces/renderer'; -import {SanitizerFn} from '../interfaces/sanitization'; +import {RElement} from '../interfaces/renderer'; import {StylingContext} from '../interfaces/styling'; -import {BINDING_INDEX, HEADER_OFFSET, LView, QUERIES, RENDERER, TVIEW, T_HOST} from '../interfaces/view'; +import {BINDING_INDEX, HEADER_OFFSET, QUERIES, RENDERER, TVIEW, T_HOST} from '../interfaces/view'; import {assertNodeType} from '../node_assert'; import {appendChild} from '../node_manipulation'; import {applyOnCreateInstructions} from '../node_util'; @@ -23,14 +21,14 @@ import {getInitialClassNameValue, getInitialStyleStringValue, initializeStaticCo import {getStylingContextFromLView, hasClassInput, hasStyleInput} from '../styling/util'; import {registerInitialStylingIntoContext} from '../styling_next/instructions'; import {runtimeIsNewStylingInUse} from '../styling_next/state'; -import {NO_CHANGE} from '../tokens'; import {attrsStylingIndexOf, setUpAttributes} from '../util/attrs_utils'; -import {renderStringify} from '../util/misc_utils'; -import {getNativeByIndex, getNativeByTNode, getTNode} from '../util/view_utils'; +import {getNativeByTNode, getTNode} from '../util/view_utils'; + import {createDirectivesAndLocals, elementCreate, executeContentQueries, getOrCreateTNode, initializeTNodeInputs, setInputsForProperty, setNodeStylingTemplate} from './shared'; import {getActiveDirectiveStylingIndex} from './styling'; + /** * Create DOM element. The instruction must later be followed by `elementEnd()` call. * @@ -197,54 +195,6 @@ export function ɵɵelement( ɵɵelementEnd(); } - -/** - * Updates the value or removes an attribute on an Element. - * - * @param index The index of the element in the data array - * @param name name The name of the attribute. - * @param value value The attribute is removed when value is `null` or `undefined`. - * Otherwise the attribute value is set to the stringified value. - * @param sanitizer An optional function used to sanitize the value. - * @param namespace Optional namespace to use when setting the attribute. - * - * @codeGenApi - */ -export function ɵɵelementAttribute( - index: number, name: string, value: any, sanitizer?: SanitizerFn | null, - namespace?: string): void { - if (value !== NO_CHANGE) { - const lView = getLView(); - const renderer = lView[RENDERER]; - elementAttributeInternal(index, name, value, lView, renderer, sanitizer, namespace); - } -} - -export function elementAttributeInternal( - index: number, name: string, value: any, lView: LView, renderer: Renderer3, - sanitizer?: SanitizerFn | null, namespace?: string) { - ngDevMode && validateAgainstEventAttributes(name); - const element = getNativeByIndex(index, lView) as RElement; - if (value == null) { - ngDevMode && ngDevMode.rendererRemoveAttribute++; - isProceduralRenderer(renderer) ? renderer.removeAttribute(element, name, namespace) : - element.removeAttribute(name); - } else { - ngDevMode && ngDevMode.rendererSetAttribute++; - const tNode = getTNode(index, lView); - const strValue = - sanitizer == null ? renderStringify(value) : sanitizer(value, tNode.tagName || '', name); - - - if (isProceduralRenderer(renderer)) { - renderer.setAttribute(element, name, strValue, namespace); - } else { - namespace ? element.setAttributeNS(namespace, name, strValue) : - element.setAttribute(name, strValue); - } - } -} - /** * Assign static attribute values to a host element. * diff --git a/packages/core/src/render3/instructions/shared.ts b/packages/core/src/render3/instructions/shared.ts index 6607f8d93b..d787f19107 100644 --- a/packages/core/src/render3/instructions/shared.ts +++ b/packages/core/src/render3/instructions/shared.ts @@ -9,7 +9,7 @@ import {Injector} from '../../di'; import {ErrorHandler} from '../../error_handler'; import {Type} from '../../interface/type'; import {CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA, SchemaMetadata} from '../../metadata/schema'; -import {validateAgainstEventProperties} from '../../sanitization/sanitization'; +import {validateAgainstEventAttributes, validateAgainstEventProperties} from '../../sanitization/sanitization'; import {Sanitizer} from '../../sanitization/security'; import {assertDataInRange, assertDefined, assertDomNode, assertEqual, assertLessThan, assertNotEqual, assertNotSame} from '../../util/assert'; import {createNamedArrayType} from '../../util/named_array_type'; @@ -35,7 +35,7 @@ import {initializeStaticContext as initializeStaticStylingContext} from '../styl import {ANIMATION_PROP_PREFIX, isAnimationProp} from '../styling/util'; import {NO_CHANGE} from '../tokens'; import {attrsStylingIndexOf} from '../util/attrs_utils'; -import {INTERPOLATION_DELIMITER, stringifyForError} from '../util/misc_utils'; +import {INTERPOLATION_DELIMITER, renderStringify, stringifyForError} from '../util/misc_utils'; import {getLViewParent, getRootContext} from '../util/view_traversal_utils'; import {getComponentViewByIndex, getNativeByIndex, getNativeByTNode, getTNode, isComponent, isComponentDef, isContentQueryHost, isLContainer, isRootView, readPatchedLView, resetPreOrderHookFlags, unwrapRNode, viewAttachedToChangeDetector} from '../util/view_utils'; @@ -1303,6 +1303,33 @@ function addComponentLogic( } } +export function elementAttributeInternal( + index: number, name: string, value: any, lView: LView, sanitizer?: SanitizerFn | null, + namespace?: string) { + ngDevMode && assertNotSame(value, NO_CHANGE as any, 'Incoming value should never be NO_CHANGE.'); + ngDevMode && validateAgainstEventAttributes(name); + const element = getNativeByIndex(index, lView) as RElement; + const renderer = lView[RENDERER]; + if (value == null) { + ngDevMode && ngDevMode.rendererRemoveAttribute++; + isProceduralRenderer(renderer) ? renderer.removeAttribute(element, name, namespace) : + element.removeAttribute(name); + } else { + ngDevMode && ngDevMode.rendererSetAttribute++; + const tNode = getTNode(index, lView); + const strValue = + sanitizer == null ? renderStringify(value) : sanitizer(value, tNode.tagName || '', name); + + + if (isProceduralRenderer(renderer)) { + renderer.setAttribute(element, name, strValue, namespace); + } else { + namespace ? element.setAttributeNS(namespace, name, strValue) : + element.setAttribute(name, strValue); + } + } +} + /** * Sets initial input properties on directive instances from attribute data * diff --git a/packages/core/src/render3/jit/environment.ts b/packages/core/src/render3/jit/environment.ts index ec3cfad3e5..120ba7195d 100644 --- a/packages/core/src/render3/jit/environment.ts +++ b/packages/core/src/render3/jit/environment.ts @@ -46,7 +46,6 @@ export const angularCoreEnv: {[name: string]: Function} = 'ɵɵNgOnChangesFeature': r3.ɵɵNgOnChangesFeature, 'ɵɵProvidersFeature': r3.ɵɵProvidersFeature, 'ɵɵInheritDefinitionFeature': r3.ɵɵInheritDefinitionFeature, - 'ɵɵelementAttribute': r3.ɵɵelementAttribute, 'ɵɵbind': r3.ɵɵbind, 'ɵɵcontainer': r3.ɵɵcontainer, 'ɵɵnextContext': r3.ɵɵnextContext, diff --git a/packages/core/test/render3/instructions_spec.ts b/packages/core/test/render3/instructions_spec.ts index feb6940bbd..ee6e856108 100644 --- a/packages/core/test/render3/instructions_spec.ts +++ b/packages/core/test/render3/instructions_spec.ts @@ -9,7 +9,7 @@ import {NgForOfContext} from '@angular/common'; import {ɵɵdefineComponent} from '../../src/render3/definition'; -import {RenderFlags, ɵɵbind, ɵɵclassMap, ɵɵelement, ɵɵelementAttribute, ɵɵelementEnd, ɵɵelementStart, ɵɵinterpolation1, ɵɵproperty, ɵɵselect, ɵɵstyleMap, ɵɵstyleProp, ɵɵstyling, ɵɵstylingApply, ɵɵtemplate, ɵɵtext, ɵɵtextBinding} from '../../src/render3/index'; +import {RenderFlags, ɵɵattribute, ɵɵclassMap, ɵɵelement, ɵɵelementEnd, ɵɵelementStart, ɵɵinterpolation1, ɵɵproperty, ɵɵselect, ɵɵstyleMap, ɵɵstyleProp, ɵɵstyling, ɵɵstylingApply, ɵɵtemplate, ɵɵtext, ɵɵtextBinding} from '../../src/render3/index'; import {AttributeMarker} from '../../src/render3/interfaces/node'; import {bypassSanitizationTrustHtml, bypassSanitizationTrustResourceUrl, bypassSanitizationTrustScript, bypassSanitizationTrustStyle, bypassSanitizationTrustUrl} from '../../src/sanitization/bypass'; import {ɵɵdefaultStyleSanitizer, ɵɵsanitizeHtml, ɵɵsanitizeResourceUrl, ɵɵsanitizeScript, ɵɵsanitizeStyle, ɵɵsanitizeUrl} from '../../src/sanitization/sanitization'; @@ -119,16 +119,20 @@ describe('instructions', () => { }); }); - describe('elementAttribute', () => { + describe('attribute', () => { it('should use sanitizer function', () => { - const t = new TemplateFixture(createDiv, () => {}, 1); + const t = new TemplateFixture(createDiv, () => {}, 1, 1); - t.update(() => ɵɵelementAttribute(0, 'title', 'javascript:true', ɵɵsanitizeUrl)); + t.update(() => { + ɵɵselect(0); + ɵɵattribute('title', 'javascript:true', ɵɵsanitizeUrl); + }); expect(t.html).toEqual('
'); - t.update( - () => ɵɵelementAttribute( - 0, 'title', bypassSanitizationTrustUrl('javascript:true'), ɵɵsanitizeUrl)); + t.update(() => { + ɵɵselect(0); + ɵɵattribute('title', bypassSanitizationTrustUrl('javascript:true'), ɵɵsanitizeUrl); + }); expect(t.html).toEqual('
'); expect(ngDevMode).toHaveProperties({ firstTemplatePass: 1, @@ -360,99 +364,126 @@ describe('instructions', () => { describe('sanitization injection compatibility', () => { it('should work for url sanitization', () => { const s = new LocalMockSanitizer(value => `${value}-sanitized`); - const t = new TemplateFixture(createAnchor, undefined, 1, 0, null, null, s); + const t = new TemplateFixture(createAnchor, undefined, 1, 1, null, null, s); const inputValue = 'http://foo'; const outputValue = 'http://foo-sanitized'; - t.update(() => ɵɵelementAttribute(0, 'href', inputValue, ɵɵsanitizeUrl)); + t.update(() => { + ɵɵselect(0); + ɵɵattribute('href', inputValue, ɵɵsanitizeUrl); + }); expect(t.html).toEqual(``); expect(s.lastSanitizedValue).toEqual(outputValue); }); it('should bypass url sanitization if marked by the service', () => { const s = new LocalMockSanitizer(value => ''); - const t = new TemplateFixture(createAnchor, undefined, 1, 0, null, null, s); + const t = new TemplateFixture(createAnchor, undefined, 1, 1, null, null, s); const inputValue = s.bypassSecurityTrustUrl('http://foo'); const outputValue = 'http://foo'; - t.update(() => ɵɵelementAttribute(0, 'href', inputValue, ɵɵsanitizeUrl)); + t.update(() => { + ɵɵselect(0); + ɵɵattribute('href', inputValue, ɵɵsanitizeUrl); + }); expect(t.html).toEqual(``); expect(s.lastSanitizedValue).toBeFalsy(); }); it('should bypass ivy-level url sanitization if a custom sanitizer is used', () => { const s = new LocalMockSanitizer(value => ''); - const t = new TemplateFixture(createAnchor, undefined, 1, 0, null, null, s); + const t = new TemplateFixture(createAnchor, undefined, 1, 1, null, null, s); const inputValue = bypassSanitizationTrustUrl('http://foo'); const outputValue = 'http://foo-ivy'; - t.update(() => ɵɵelementAttribute(0, 'href', inputValue, ɵɵsanitizeUrl)); + t.update(() => { + ɵɵselect(0); + ɵɵattribute('href', inputValue, ɵɵsanitizeUrl); + }); expect(t.html).toEqual(``); expect(s.lastSanitizedValue).toBeFalsy(); }); it('should work for style sanitization', () => { const s = new LocalMockSanitizer(value => `color:blue`); - const t = new TemplateFixture(createDiv, undefined, 1, 0, null, null, s); + const t = new TemplateFixture(createDiv, undefined, 1, 1, null, null, s); const inputValue = 'color:red'; const outputValue = 'color:blue'; - t.update(() => ɵɵelementAttribute(0, 'style', inputValue, ɵɵsanitizeStyle)); + t.update(() => { + ɵɵselect(0); + ɵɵattribute('style', inputValue, ɵɵsanitizeStyle); + }); expect(stripStyleWsCharacters(t.html)).toEqual(`
`); expect(s.lastSanitizedValue).toEqual(outputValue); }); it('should bypass style sanitization if marked by the service', () => { const s = new LocalMockSanitizer(value => ''); - const t = new TemplateFixture(createDiv, undefined, 1, 0, null, null, s); + const t = new TemplateFixture(createDiv, undefined, 1, 1, null, null, s); const inputValue = s.bypassSecurityTrustStyle('color:maroon'); const outputValue = 'color:maroon'; - t.update(() => ɵɵelementAttribute(0, 'style', inputValue, ɵɵsanitizeStyle)); + t.update(() => { + ɵɵselect(0); + ɵɵattribute('style', inputValue, ɵɵsanitizeStyle); + }); expect(stripStyleWsCharacters(t.html)).toEqual(`
`); expect(s.lastSanitizedValue).toBeFalsy(); }); it('should bypass ivy-level style sanitization if a custom sanitizer is used', () => { const s = new LocalMockSanitizer(value => ''); - const t = new TemplateFixture(createDiv, undefined, 1, 0, null, null, s); + const t = new TemplateFixture(createDiv, undefined, 1, 1, null, null, s); const inputValue = bypassSanitizationTrustStyle('font-family:foo'); const outputValue = 'font-family:foo-ivy'; - t.update(() => ɵɵelementAttribute(0, 'style', inputValue, ɵɵsanitizeStyle)); + t.update(() => { + ɵɵselect(0); + ɵɵattribute('style', inputValue, ɵɵsanitizeStyle); + }); expect(stripStyleWsCharacters(t.html)).toEqual(`
`); expect(s.lastSanitizedValue).toBeFalsy(); }); it('should work for resourceUrl sanitization', () => { const s = new LocalMockSanitizer(value => `${value}-sanitized`); - const t = new TemplateFixture(createScript, undefined, 1, 0, null, null, s); + const t = new TemplateFixture(createScript, undefined, 1, 1, null, null, s); const inputValue = 'http://resource'; const outputValue = 'http://resource-sanitized'; - t.update(() => ɵɵelementAttribute(0, 'src', inputValue, ɵɵsanitizeResourceUrl)); + t.update(() => { + ɵɵselect(0); + ɵɵattribute('src', inputValue, ɵɵsanitizeResourceUrl); + }); expect(t.html).toEqual(``); expect(s.lastSanitizedValue).toEqual(outputValue); }); it('should bypass resourceUrl sanitization if marked by the service', () => { const s = new LocalMockSanitizer(value => ''); - const t = new TemplateFixture(createScript, undefined, 1, 0, null, null, s); + const t = new TemplateFixture(createScript, undefined, 1, 1, null, null, s); const inputValue = s.bypassSecurityTrustResourceUrl('file://all-my-secrets.pdf'); const outputValue = 'file://all-my-secrets.pdf'; - t.update(() => ɵɵelementAttribute(0, 'src', inputValue, ɵɵsanitizeResourceUrl)); + t.update(() => { + ɵɵselect(0); + ɵɵattribute('src', inputValue, ɵɵsanitizeResourceUrl); + }); expect(t.html).toEqual(``); expect(s.lastSanitizedValue).toBeFalsy(); }); it('should bypass ivy-level resourceUrl sanitization if a custom sanitizer is used', () => { const s = new LocalMockSanitizer(value => ''); - const t = new TemplateFixture(createScript, undefined, 1, 0, null, null, s); + const t = new TemplateFixture(createScript, undefined, 1, 1, null, null, s); const inputValue = bypassSanitizationTrustResourceUrl('file://all-my-secrets.pdf'); const outputValue = 'file://all-my-secrets.pdf-ivy'; - t.update(() => ɵɵelementAttribute(0, 'src', inputValue, ɵɵsanitizeResourceUrl)); + t.update(() => { + ɵɵselect(0); + ɵɵattribute('src', inputValue, ɵɵsanitizeResourceUrl); + }); expect(t.html).toEqual(``); expect(s.lastSanitizedValue).toBeFalsy(); }); diff --git a/packages/core/test/render3/integration_spec.ts b/packages/core/test/render3/integration_spec.ts index 14a53c0ddb..2bf250c4e7 100644 --- a/packages/core/test/render3/integration_spec.ts +++ b/packages/core/test/render3/integration_spec.ts @@ -8,8 +8,8 @@ import {RendererType2} from '../../src/render/api'; import {getLContext} from '../../src/render3/context_discovery'; -import {AttributeMarker, ɵɵdefineComponent, ɵɵdefineDirective, ɵɵproperty} from '../../src/render3/index'; -import {ɵɵallocHostVars, ɵɵbind, ɵɵcontainer, ɵɵcontainerRefreshEnd, ɵɵcontainerRefreshStart, ɵɵelement, ɵɵelementAttribute, ɵɵelementEnd, ɵɵelementStart, ɵɵembeddedViewEnd, ɵɵembeddedViewStart, ɵɵprojection, ɵɵprojectionDef, ɵɵselect, ɵɵstyling, ɵɵstylingApply, ɵɵtemplate, ɵɵtext, ɵɵtextBinding} from '../../src/render3/instructions/all'; +import {AttributeMarker, ɵɵattribute, ɵɵdefineComponent, ɵɵdefineDirective, ɵɵproperty} from '../../src/render3/index'; +import {ɵɵallocHostVars, ɵɵbind, ɵɵcontainer, ɵɵcontainerRefreshEnd, ɵɵcontainerRefreshStart, ɵɵelement, ɵɵelementEnd, ɵɵelementStart, ɵɵembeddedViewEnd, ɵɵembeddedViewStart, ɵɵprojection, ɵɵprojectionDef, ɵɵselect, ɵɵstyling, ɵɵstylingApply, ɵɵtemplate, ɵɵtext, ɵɵtextBinding} from '../../src/render3/instructions/all'; import {MONKEY_PATCH_KEY_NAME} from '../../src/render3/interfaces/context'; import {RenderFlags} from '../../src/render3/interfaces/definition'; import {RElement, Renderer3, RendererFactory3, domRendererFactory3} from '../../src/render3/interfaces/renderer'; @@ -286,7 +286,8 @@ describe('component animations', () => { ɵɵelement(0, 'div', [AttributeMarker.Bindings, '@fooAnimation']); } if (rf & RenderFlags.Update) { - ɵɵelementAttribute(0, '@fooAnimation', ɵɵbind(ctx.animationValue)); + ɵɵselect(0); + ɵɵattribute('@fooAnimation', ctx.animationValue); } } }); diff --git a/tools/public_api_guard/core/core.d.ts b/tools/public_api_guard/core/core.d.ts index 1b8f798d56..ef6757b785 100644 --- a/tools/public_api_guard/core/core.d.ts +++ b/tools/public_api_guard/core/core.d.ts @@ -818,8 +818,6 @@ export declare function ɵɵdisableBindings(): void; export declare function ɵɵelement(index: number, name: string, attrs?: TAttributes | null, localRefs?: string[] | null): void; -export declare function ɵɵelementAttribute(index: number, name: string, value: any, sanitizer?: SanitizerFn | null, namespace?: string): void; - export declare function ɵɵelementContainerEnd(): void; export declare function ɵɵelementContainerStart(index: number, attrs?: TAttributes | null, localRefs?: string[] | null): void;