feat(ivy): in `ngDevMode` use named object literals and arrays for easier debugging/profiling (#30542)
PR Close #30542
This commit is contained in:
parent
c7850fff3b
commit
55a14e4866
|
@ -6,31 +6,31 @@
|
|||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import { getPluralCase } from '../i18n/localization';
|
||||
import { getTemplateContent, SRCSET_ATTRS, URI_ATTRS, VALID_ATTRS, VALID_ELEMENTS } from '../sanitization/html_sanitizer';
|
||||
import { InertBodyHelper } from '../sanitization/inert_body';
|
||||
import { sanitizeSrcset, _sanitizeUrl } from '../sanitization/url_sanitizer';
|
||||
import { addAllToArray } from '../util/array_utils';
|
||||
import { assertDataInRange, assertDefined, assertEqual, assertGreaterThan } from '../util/assert';
|
||||
import '../util/ng_i18n_closure_mode';
|
||||
import { attachPatchData } from './context_discovery';
|
||||
import { attachI18nOpCodesDebug } from './debug';
|
||||
import { elementAttributeInternal, ɵɵload, ɵɵtextBinding } from './instructions/all';
|
||||
import { allocExpando, 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, TNodeType } from './interfaces/node';
|
||||
import { RComment, RElement, RText } from './interfaces/renderer';
|
||||
import { SanitizerFn } from './interfaces/sanitization';
|
||||
import { StylingContext } from './interfaces/styling';
|
||||
import { BINDING_INDEX, HEADER_OFFSET, LView, RENDERER, TVIEW, TView, T_HOST } from './interfaces/view';
|
||||
import { appendChild, createTextNode, nativeRemoveNode } from './node_manipulation';
|
||||
import { getIsParent, getLView, getPreviousOrParentTNode, setIsNotParent, setPreviousOrParentTNode } from './state';
|
||||
import { NO_CHANGE } from './tokens';
|
||||
import { renderStringify } from './util/misc_utils';
|
||||
import { getNativeByIndex, getNativeByTNode, getTNode, isLContainer } from './util/view_utils';
|
||||
|
||||
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, ɵɵload, ɵɵtextBinding} from './instructions/all';
|
||||
import {attachI18nOpCodesDebug} from './instructions/lview_debug';
|
||||
import {allocExpando, 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, TNodeType} from './interfaces/node';
|
||||
import {RComment, RElement, RText} from './interfaces/renderer';
|
||||
import {SanitizerFn} from './interfaces/sanitization';
|
||||
import {StylingContext} from './interfaces/styling';
|
||||
import {BINDING_INDEX, HEADER_OFFSET, LView, RENDERER, TVIEW, TView, T_HOST} from './interfaces/view';
|
||||
import {appendChild, createTextNode, nativeRemoveNode} from './node_manipulation';
|
||||
import {getIsParent, getLView, getPreviousOrParentTNode, setIsNotParent, setPreviousOrParentTNode} from './state';
|
||||
import {NO_CHANGE} from './tokens';
|
||||
import {renderStringify} from './util/misc_utils';
|
||||
import {getNativeByIndex, getNativeByTNode, getTNode, isLContainer} from './util/view_utils';
|
||||
|
||||
|
||||
const MARKER = `<EFBFBD>`;
|
||||
|
|
|
@ -6,20 +6,24 @@
|
|||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ComponentTemplate} from '..';
|
||||
import {SchemaMetadata} from '../../core';
|
||||
import {assertDefined} from '../../util/assert';
|
||||
|
||||
import {createNamedArrayType} from '../../util/named_array_type';
|
||||
import {ACTIVE_INDEX, CONTAINER_HEADER_OFFSET, LContainer, NATIVE} from '../interfaces/container';
|
||||
import {DirectiveDefList, PipeDefList, ViewQueriesFunction} from '../interfaces/definition';
|
||||
import {COMMENT_MARKER, ELEMENT_MARKER, I18nMutateOpCode, I18nMutateOpCodes, I18nUpdateOpCode, I18nUpdateOpCodes, TIcu} from '../interfaces/i18n';
|
||||
import {TNode} from '../interfaces/node';
|
||||
import {TElementNode, TNode, TViewNode} from '../interfaces/node';
|
||||
import {LQueries} from '../interfaces/query';
|
||||
import {RComment, RElement} from '../interfaces/renderer';
|
||||
import {StylingContext} from '../interfaces/styling';
|
||||
import {BINDING_INDEX, CHILD_HEAD, CHILD_TAIL, CLEANUP, CONTENT_QUERIES, CONTEXT, DECLARATION_VIEW, FLAGS, HEADER_OFFSET, HOST, INJECTOR, LView, LViewFlags, NEXT, PARENT, QUERIES, RENDERER, RENDERER_FACTORY, SANITIZER, TVIEW, T_HOST} from '../interfaces/view';
|
||||
import {BINDING_INDEX, CHILD_HEAD, CHILD_TAIL, CLEANUP, CONTENT_QUERIES, CONTEXT, DECLARATION_VIEW, ExpandoInstructions, FLAGS, HEADER_OFFSET, HOST, HookData, INJECTOR, LView, LViewFlags, NEXT, PARENT, QUERIES, RENDERER, RENDERER_FACTORY, SANITIZER, TData, TVIEW, TView as ITView, T_HOST} from '../interfaces/view';
|
||||
import {runtimeIsNewStylingInUse} from '../styling_next/state';
|
||||
import {DebugStyling as DebugNewStyling, NodeStylingDebug} from '../styling_next/styling_debug';
|
||||
import {attachDebugObject} from '../util/debug_utils';
|
||||
import {getTNode, isStylingContext, unwrapRNode} from '../util/view_utils';
|
||||
|
||||
|
||||
/*
|
||||
* This file contains conditionally attached classes which provide human readable (debug) level
|
||||
* information for `LView`, `LContainer` and other internal data structures. These data structures
|
||||
|
@ -50,6 +54,80 @@ import {getTNode, isStylingContext, unwrapRNode} from '../util/view_utils';
|
|||
*/
|
||||
|
||||
|
||||
export const LViewArray = ngDevMode && createNamedArrayType('LView');
|
||||
let LVIEW_EMPTY: unknown[]; // can't initialize here or it will not be tree shaken, because `LView`
|
||||
// constructor could have side-effects.
|
||||
/**
|
||||
* This function clones a blueprint and creates LView.
|
||||
*
|
||||
* Simple slice will keep the same type, and we need it to be LView
|
||||
*/
|
||||
export function cloneToLView(list: any[]): LView {
|
||||
if (LVIEW_EMPTY === undefined) LVIEW_EMPTY = new LViewArray !();
|
||||
return LVIEW_EMPTY.concat(list) as any;
|
||||
}
|
||||
|
||||
/**
|
||||
* This class is a debug version of Object literal so that we can have constructor name show up in
|
||||
* debug tools in ngDevMode.
|
||||
*/
|
||||
export const TViewConstructor = class TView implements ITView {
|
||||
constructor(
|
||||
public id: number, //
|
||||
public blueprint: LView, //
|
||||
public template: ComponentTemplate<{}>|null, //
|
||||
public viewQuery: ViewQueriesFunction<{}>|null, //
|
||||
public node: TViewNode|TElementNode|null, //
|
||||
public data: TData, //
|
||||
public bindingStartIndex: number, //
|
||||
public viewQueryStartIndex: number, //
|
||||
public expandoStartIndex: number, //
|
||||
public expandoInstructions: ExpandoInstructions|null, //
|
||||
public firstTemplatePass: boolean, //
|
||||
public staticViewQueries: boolean, //
|
||||
public staticContentQueries: boolean, //
|
||||
public preOrderHooks: HookData|null, //
|
||||
public preOrderCheckHooks: HookData|null, //
|
||||
public contentHooks: HookData|null, //
|
||||
public contentCheckHooks: HookData|null, //
|
||||
public viewHooks: HookData|null, //
|
||||
public viewCheckHooks: HookData|null, //
|
||||
public destroyHooks: HookData|null, //
|
||||
public cleanup: any[]|null, //
|
||||
public contentQueries: number[]|null, //
|
||||
public components: number[]|null, //
|
||||
public directiveRegistry: DirectiveDefList|null, //
|
||||
public pipeRegistry: PipeDefList|null, //
|
||||
public firstChild: TNode|null, //
|
||||
public schemas: SchemaMetadata[]|null, //
|
||||
) {}
|
||||
};
|
||||
|
||||
const TViewData = ngDevMode && createNamedArrayType('TViewData');
|
||||
let TVIEWDATA_EMPTY:
|
||||
unknown[]; // can't initialize here or it will not be tree shaken, because `LView`
|
||||
// constructor could have side-effects.
|
||||
/**
|
||||
* This function clones a blueprint and creates TData.
|
||||
*
|
||||
* Simple slice will keep the same type, and we need it to be TData
|
||||
*/
|
||||
export function cloneToTViewData(list: any[]): TData {
|
||||
if (TVIEWDATA_EMPTY === undefined) TVIEWDATA_EMPTY = new TViewData !();
|
||||
return TVIEWDATA_EMPTY.concat(list) as any;
|
||||
}
|
||||
|
||||
export const LViewBlueprint = ngDevMode && createNamedArrayType('LViewBlueprint');
|
||||
export const MatchesArray = ngDevMode && createNamedArrayType('MatchesArray');
|
||||
export const TViewComponents = ngDevMode && createNamedArrayType('TViewComponents');
|
||||
export const TNodeLocalNames = ngDevMode && createNamedArrayType('TNodeLocalNames');
|
||||
export const TNodeInitialInputs = ngDevMode && createNamedArrayType('TNodeInitialInputs');
|
||||
export const TNodeInitialData = ngDevMode && createNamedArrayType('TNodeInitialData');
|
||||
export const LCleanup = ngDevMode && createNamedArrayType('LCleanup');
|
||||
export const TCleanup = ngDevMode && createNamedArrayType('TCleanup');
|
||||
|
||||
|
||||
|
||||
export function attachLViewDebug(lView: LView) {
|
||||
attachDebugObject(lView, new LViewDebug(lView));
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import {CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA, SchemaMetadata} from '../../me
|
|||
import {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';
|
||||
import {normalizeDebugBindingName, normalizeDebugBindingValue} from '../../util/ng_reflect';
|
||||
import {assertLView, assertPreviousIsParent} from '../assert';
|
||||
import {attachPatchData, getComponentViewByInstance} from '../context_discovery';
|
||||
|
@ -37,7 +38,8 @@ import {attrsStylingIndexOf} from '../util/attrs_utils';
|
|||
import {INTERPOLATION_DELIMITER, 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';
|
||||
import {attachLContainerDebug, attachLViewDebug} from './lview_debug';
|
||||
|
||||
import {LCleanup, LViewBlueprint, MatchesArray, TCleanup, TNodeInitialData, TNodeInitialInputs, TNodeLocalNames, TViewComponents, TViewConstructor, attachLContainerDebug, attachLViewDebug, cloneToLView, cloneToTViewData} from './lview_debug';
|
||||
|
||||
|
||||
|
||||
|
@ -199,13 +201,12 @@ export function elementCreate(name: string, overriddenRenderer?: Renderer3): REl
|
|||
}
|
||||
return native;
|
||||
}
|
||||
|
||||
export function createLView<T>(
|
||||
parentLView: LView | null, tView: TView, context: T | null, flags: LViewFlags,
|
||||
host: RElement | null, tHostNode: TViewNode | TElementNode | null,
|
||||
rendererFactory?: RendererFactory3 | null, renderer?: Renderer3 | null,
|
||||
sanitizer?: Sanitizer | null, injector?: Injector | null): LView {
|
||||
const lView = tView.blueprint.slice() as LView;
|
||||
const lView = ngDevMode ? cloneToLView(tView.blueprint) : tView.blueprint.slice() as LView;
|
||||
lView[HOST] = host;
|
||||
lView[FLAGS] = flags | LViewFlags.CreationMode | LViewFlags.Attached | LViewFlags.FirstLViewPass;
|
||||
resetPreOrderHookFlags(lView);
|
||||
|
@ -553,6 +554,7 @@ export function getOrCreateTView(def: ComponentDef<any>): TView {
|
|||
def.viewQuery, def.schemas));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a TView instance
|
||||
*
|
||||
|
@ -575,7 +577,39 @@ export function createTView(
|
|||
// that has a host binding, we will update the blueprint with that def's hostVars count.
|
||||
const initialViewLength = bindingStartIndex + vars;
|
||||
const blueprint = createViewBlueprint(bindingStartIndex, initialViewLength);
|
||||
return blueprint[TVIEW as any] = {
|
||||
return blueprint[TVIEW as any] = ngDevMode ?
|
||||
new TViewConstructor(
|
||||
viewIndex, // id: number,
|
||||
blueprint, // blueprint: LView,
|
||||
templateFn, // template: ComponentTemplate<{}>|null,
|
||||
viewQuery, // viewQuery: ViewQueriesFunction<{}>|null,
|
||||
null !, // node: TViewNode|TElementNode|null,
|
||||
cloneToTViewData(blueprint).fill(null, bindingStartIndex), // data: TData,
|
||||
bindingStartIndex, // bindingStartIndex: number,
|
||||
initialViewLength, // viewQueryStartIndex: number,
|
||||
initialViewLength, // expandoStartIndex: number,
|
||||
null, // expandoInstructions: ExpandoInstructions|null,
|
||||
true, // firstTemplatePass: boolean,
|
||||
false, // staticViewQueries: boolean,
|
||||
false, // staticContentQueries: boolean,
|
||||
null, // preOrderHooks: HookData|null,
|
||||
null, // preOrderCheckHooks: HookData|null,
|
||||
null, // contentHooks: HookData|null,
|
||||
null, // contentCheckHooks: HookData|null,
|
||||
null, // viewHooks: HookData|null,
|
||||
null, // viewCheckHooks: HookData|null,
|
||||
null, // destroyHooks: HookData|null,
|
||||
null, // cleanup: any[]|null,
|
||||
null, // contentQueries: number[]|null,
|
||||
null, // components: number[]|null,
|
||||
typeof directives === 'function' ?
|
||||
directives() :
|
||||
directives, // directiveRegistry: DirectiveDefList|null,
|
||||
typeof pipes === 'function' ? pipes() : pipes, // pipeRegistry: PipeDefList|null,
|
||||
null, // firstChild: TNode|null,
|
||||
schemas, // schemas: SchemaMetadata[]|null,
|
||||
) :
|
||||
{
|
||||
id: viewIndex,
|
||||
blueprint: blueprint,
|
||||
template: templateFn,
|
||||
|
@ -605,8 +639,9 @@ export function createTView(
|
|||
schemas: schemas,
|
||||
};
|
||||
}
|
||||
|
||||
function createViewBlueprint(bindingStartIndex: number, initialViewLength: number): LView {
|
||||
const blueprint = new Array(initialViewLength)
|
||||
const blueprint = new (ngDevMode ? LViewBlueprint ! : Array)(initialViewLength)
|
||||
.fill(null, 0, bindingStartIndex)
|
||||
.fill(NO_CHANGE, bindingStartIndex) as LView;
|
||||
blueprint[BINDING_INDEX] = bindingStartIndex;
|
||||
|
@ -1132,7 +1167,6 @@ function postProcessBaseDirective<T>(
|
|||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Matches the current node against all available selectors.
|
||||
* If a component is matched (at most one), it is returned in first position in the array.
|
||||
|
@ -1146,7 +1180,7 @@ function findDirectiveMatches(tView: TView, viewData: LView, tNode: TNode): Dire
|
|||
for (let i = 0; i < registry.length; i++) {
|
||||
const def = registry[i] as ComponentDef<any>| DirectiveDef<any>;
|
||||
if (isNodeMatchingSelectorList(tNode, def.selectors !, /* isProjectionMode */ false)) {
|
||||
matches || (matches = []);
|
||||
matches || (matches = ngDevMode ? new MatchesArray !() : []);
|
||||
diPublicInInjector(
|
||||
getOrCreateNodeInjectorForNode(
|
||||
getPreviousOrParentTNode() as TElementNode | TContainerNode | TElementContainerNode,
|
||||
|
@ -1173,7 +1207,8 @@ export function queueComponentIndexForCheck(previousOrParentTNode: TNode): void
|
|||
const tView = getLView()[TVIEW];
|
||||
ngDevMode &&
|
||||
assertEqual(tView.firstTemplatePass, true, 'Should only be called in first template pass.');
|
||||
(tView.components || (tView.components = [])).push(previousOrParentTNode.index);
|
||||
(tView.components || (tView.components = ngDevMode ? new TViewComponents !() : [
|
||||
])).push(previousOrParentTNode.index);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1181,7 +1216,8 @@ export function queueComponentIndexForCheck(previousOrParentTNode: TNode): void
|
|||
function cacheMatchingLocalNames(
|
||||
tNode: TNode, localRefs: string[] | null, exportsMap: {[key: string]: number}): void {
|
||||
if (localRefs) {
|
||||
const localNames: (string | number)[] = tNode.localNames = [];
|
||||
const localNames: (string | number)[] = tNode.localNames =
|
||||
ngDevMode ? new TNodeLocalNames !() : [];
|
||||
|
||||
// Local names must be stored in tNode in the same order that localRefs are defined
|
||||
// in the template to ensure the data is loaded in the same slots as their refs
|
||||
|
@ -1320,7 +1356,8 @@ function setInputsFromAttrs<T>(
|
|||
*/
|
||||
function generateInitialInputs(
|
||||
directiveIndex: number, inputs: {[key: string]: string}, tNode: TNode): InitialInputData {
|
||||
const initialInputData: InitialInputData = tNode.initialInputs || (tNode.initialInputs = []);
|
||||
const initialInputData: InitialInputData =
|
||||
tNode.initialInputs || (tNode.initialInputs = ngDevMode ? new TNodeInitialInputs !() : []);
|
||||
// Ensure that we don't create sparse arrays
|
||||
for (let i = initialInputData.length; i <= directiveIndex; i++) {
|
||||
initialInputData.push(null);
|
||||
|
@ -1347,8 +1384,8 @@ function generateInitialInputs(
|
|||
const attrValue = attrs[i + 1];
|
||||
|
||||
if (minifiedInputName !== undefined) {
|
||||
const inputsToStore: InitialInputs =
|
||||
initialInputData[directiveIndex] || (initialInputData[directiveIndex] = []);
|
||||
const inputsToStore: InitialInputs = initialInputData[directiveIndex] ||
|
||||
(initialInputData[directiveIndex] = ngDevMode ? new TNodeInitialData !() : []);
|
||||
inputsToStore.push(attrName as string, minifiedInputName, attrValue as string);
|
||||
}
|
||||
|
||||
|
@ -1361,6 +1398,9 @@ function generateInitialInputs(
|
|||
//// ViewContainer & View
|
||||
//////////////////////////
|
||||
|
||||
// Not sure why I need to do `any` here but TS complains later.
|
||||
const LContainerArray: any = ngDevMode && createNamedArrayType('LContainer');
|
||||
|
||||
/**
|
||||
* Creates a LContainer, either from a container instruction, or for a ViewContainerRef.
|
||||
*
|
||||
|
@ -1376,7 +1416,8 @@ export function createLContainer(
|
|||
tNode: TNode, isForViewContainerRef?: boolean): LContainer {
|
||||
ngDevMode && assertDomNode(native);
|
||||
ngDevMode && assertLView(currentView);
|
||||
const lContainer: LContainer = [
|
||||
// https://jsperf.com/array-literal-vs-new-array-really
|
||||
const lContainer: LContainer = new (ngDevMode ? LContainerArray : Array)(
|
||||
hostNative, // host native
|
||||
true, // Boolean `true` in this position signifies that this is an `LContainer`
|
||||
isForViewContainerRef ? -1 : 0, // active index
|
||||
|
@ -1385,7 +1426,7 @@ export function createLContainer(
|
|||
null, // queries
|
||||
tNode, // t_host
|
||||
native, // native
|
||||
];
|
||||
);
|
||||
ngDevMode && attachLContainerDebug(lContainer);
|
||||
return lContainer;
|
||||
}
|
||||
|
@ -1711,14 +1752,13 @@ export function initializeTNodeInputs(tNode: TNode): PropertyAliases|null {
|
|||
return tNode.inputs;
|
||||
}
|
||||
|
||||
|
||||
export function getCleanup(view: LView): any[] {
|
||||
// top level variables should not be exported for performance reasons (PERF_NOTES.md)
|
||||
return view[CLEANUP] || (view[CLEANUP] = []);
|
||||
return view[CLEANUP] || (view[CLEANUP] = ngDevMode ? new LCleanup !() : []);
|
||||
}
|
||||
|
||||
function getTViewCleanup(view: LView): any[] {
|
||||
return view[TVIEW].cleanup || (view[TVIEW].cleanup = []);
|
||||
return view[TVIEW].cleanup || (view[TVIEW].cleanup = ngDevMode ? new TCleanup !() : []);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* 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 './ng_dev_mode';
|
||||
import {global} from './global';
|
||||
|
||||
/**
|
||||
* THIS FILE CONTAINS CODE WHICH SHOULD BE TREE SHAKEN AND NEVER CALLED FROM PRODUCTION CODE!!!
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Creates an `Array` construction with a given name. This is useful when
|
||||
* looking for memory consumption to see what time of array it is.
|
||||
*
|
||||
*
|
||||
* @param name Name to give to the constructor
|
||||
* @returns A subclass of `Array` if possible. This can only be done in
|
||||
* environments which support `class` construct.
|
||||
*/
|
||||
export function createNamedArrayType(name: string): typeof Array {
|
||||
// This should never be called in prod mode, so let's verify that is the case.
|
||||
if (ngDevMode) {
|
||||
try {
|
||||
// We need to do it this way so that TypeScript does not down-level the below code.
|
||||
const FunctionConstructor: any = createNamedArrayType.constructor;
|
||||
return (new FunctionConstructor('Array', `return class ABC extends Array{}`))(Array);
|
||||
} catch (e) {
|
||||
// If it does not work just give up and fall back to regular Array.
|
||||
return Array;
|
||||
}
|
||||
} else {
|
||||
throw new Error(
|
||||
'Looks like we are in \'prod mode\', but we are creating a named Array type, which is wrong! Check your code');
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@ import {global} from './global';
|
|||
declare global {
|
||||
const ngDevMode: null|NgDevModePerfCounters;
|
||||
interface NgDevModePerfCounters {
|
||||
namedConstructors: boolean;
|
||||
firstTemplatePass: number;
|
||||
tNode: number;
|
||||
tView: number;
|
||||
|
@ -45,7 +46,9 @@ declare global {
|
|||
}
|
||||
|
||||
export function ngDevModeResetPerfCounters(): NgDevModePerfCounters {
|
||||
const locationString = typeof location !== 'undefined' ? location.toString() : '';
|
||||
const newCounters: NgDevModePerfCounters = {
|
||||
namedConstructors: locationString.indexOf('ngDevMode=namedConstructors') != -1,
|
||||
firstTemplatePass: 0,
|
||||
tNode: 0,
|
||||
tView: 0,
|
||||
|
@ -79,7 +82,8 @@ export function ngDevModeResetPerfCounters(): NgDevModePerfCounters {
|
|||
};
|
||||
|
||||
// Make sure to refer to ngDevMode as ['ngDevMode'] for closure.
|
||||
global['ngDevMode'] = newCounters;
|
||||
const allowNgDevModeTrue = locationString.indexOf('ngDevMode=false') === -1;
|
||||
global['ngDevMode'] = allowNgDevModeTrue && newCounters;
|
||||
return newCounters;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import {CompilerStylingMode, compilerSetStylingMode} from '@angular/compiler/src
|
|||
import {Component, Directive, HostBinding, Input, ViewChild} from '@angular/core';
|
||||
import {SecurityContext} from '@angular/core/src/core';
|
||||
import {getLContext} from '@angular/core/src/render3/context_discovery';
|
||||
import {DebugNode, LViewDebug, toDebug} from '@angular/core/src/render3/debug';
|
||||
import {DebugNode, LViewDebug, toDebug} from '@angular/core/src/render3/instructions/lview_debug';
|
||||
import {SANITIZER} from '@angular/core/src/render3/interfaces/view';
|
||||
import {RuntimeStylingMode, runtimeSetStylingMode, setCurrentStyleSanitizer} from '@angular/core/src/render3/styling_next/state';
|
||||
import {loadLContextFromNode} from '@angular/core/src/render3/util/discovery_utils';
|
||||
|
|
Loading…
Reference in New Issue