refactor(ivy): ensure `StylingDebug` instances provide context debug info (#32753)
This patch enables a styling debug instance (which is apart of the `debugNode.styles` or `debugNode.classes` data structures) to expose its context value so that it can be easily debugged. PR Close #32753
This commit is contained in:
parent
52552b0520
commit
f8f7c1540a
|
@ -10,7 +10,7 @@ import {RElement} from '../interfaces/renderer';
|
||||||
import {ApplyStylingFn, LStylingData, TStylingConfig, TStylingContext, TStylingContextIndex} from '../interfaces/styling';
|
import {ApplyStylingFn, LStylingData, TStylingConfig, TStylingContext, TStylingContextIndex} from '../interfaces/styling';
|
||||||
import {getCurrentStyleSanitizer} from '../state';
|
import {getCurrentStyleSanitizer} from '../state';
|
||||||
import {attachDebugObject} from '../util/debug_utils';
|
import {attachDebugObject} from '../util/debug_utils';
|
||||||
import {allowDirectStyling as _allowDirectStyling, getDefaultValue, getGuardMask, getProp, getPropValuesStartPosition, getValuesCount, hasConfig, isContextLocked, isSanitizationRequired} from '../util/styling_utils';
|
import {allowDirectStyling as _allowDirectStyling, getDefaultValue, getGuardMask, getProp, getPropValuesStartPosition, getValuesCount, hasConfig, isContextLocked, isSanitizationRequired, isStylingContext} from '../util/styling_utils';
|
||||||
|
|
||||||
import {applyStylingViaContext} from './bindings';
|
import {applyStylingViaContext} from './bindings';
|
||||||
import {activateStylingMapFeature} from './map_based_bindings';
|
import {activateStylingMapFeature} from './map_based_bindings';
|
||||||
|
@ -27,33 +27,27 @@ import {activateStylingMapFeature} from './map_based_bindings';
|
||||||
* --------
|
* --------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A debug/testing-oriented summary of a styling entry.
|
* A debug-friendly version of `TStylingContext`.
|
||||||
*
|
*
|
||||||
* A value such as this is generated as an artifact of the `DebugStyling`
|
* An instance of this is attached to `tStylingContext.debug` when `ngDevMode` is active.
|
||||||
* summary.
|
|
||||||
*/
|
*/
|
||||||
export interface LStylingSummary {
|
export interface DebugStylingContext {
|
||||||
/** The style/class property that the summary is attached to */
|
/** The configuration settings of the associated `TStylingContext` */
|
||||||
prop: string;
|
config: DebugStylingConfig;
|
||||||
|
|
||||||
/** The last applied value for the style/class property */
|
|
||||||
value: string|boolean|null;
|
|
||||||
|
|
||||||
/** The binding index of the last applied style/class property */
|
|
||||||
bindingIndex: number|null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A debug/testing-oriented summary of all styling entries for a `DebugNode` instance.
|
|
||||||
*/
|
|
||||||
export interface DebugStyling {
|
|
||||||
/** The associated TStylingContext instance */
|
/** The associated TStylingContext instance */
|
||||||
context: TStylingContext;
|
context: TStylingContext;
|
||||||
|
|
||||||
/** Which configuration flags are active (see `TStylingContextConfig`) */
|
/** The associated TStylingContext instance */
|
||||||
config: {
|
entries: {[prop: string]: DebugStylingContextEntry};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A debug/testing-oriented summary of `TStylingConfig`.
|
||||||
|
*/
|
||||||
|
export interface DebugStylingConfig {
|
||||||
hasMapBindings: boolean; //
|
hasMapBindings: boolean; //
|
||||||
hasPropBindings: boolean; //
|
hasPropBindings: boolean; //
|
||||||
hasCollisions: boolean; //
|
hasCollisions: boolean; //
|
||||||
|
@ -62,30 +56,13 @@ export interface DebugStyling {
|
||||||
templateBindingsLocked: boolean; //
|
templateBindingsLocked: boolean; //
|
||||||
hostBindingsLocked: boolean; //
|
hostBindingsLocked: boolean; //
|
||||||
allowDirectStyling: boolean; //
|
allowDirectStyling: boolean; //
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A summarization of each style/class property
|
|
||||||
* present in the context
|
|
||||||
*/
|
|
||||||
summary: {[propertyName: string]: LStylingSummary};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A key/value map of all styling properties and their
|
|
||||||
* runtime values
|
|
||||||
*/
|
|
||||||
values: {[propertyName: string]: string | number | null | boolean};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Overrides the sanitizer used to process styles
|
|
||||||
*/
|
|
||||||
overrideSanitizer(sanitizer: StyleSanitizeFn|null): void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A debug/testing-oriented summary of all styling entries within a `TStylingContext`.
|
* A debug/testing-oriented summary of all styling entries within a `TStylingContext`.
|
||||||
*/
|
*/
|
||||||
export interface TStylingTupleSummary {
|
export interface DebugStylingContextEntry {
|
||||||
/** The property (style or class property) that this tuple represents */
|
/** The property (style or class property) that this tuple represents */
|
||||||
prop: string;
|
prop: string;
|
||||||
|
|
||||||
|
@ -120,6 +97,51 @@ export interface TStylingTupleSummary {
|
||||||
sources: (number|null|string)[];
|
sources: (number|null|string)[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A debug/testing-oriented summary of all styling entries for a `DebugNode` instance.
|
||||||
|
*/
|
||||||
|
export interface DebugNodeStyling {
|
||||||
|
/** The associated debug context of the TStylingContext instance */
|
||||||
|
context: DebugStylingContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A summarization of each style/class property
|
||||||
|
* present in the context
|
||||||
|
*/
|
||||||
|
summary: {[propertyName: string]: DebugNodeStylingEntry};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A key/value map of all styling properties and their
|
||||||
|
* runtime values
|
||||||
|
*/
|
||||||
|
values: {[propertyName: string]: string | number | null | boolean};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overrides the sanitizer used to process styles
|
||||||
|
*/
|
||||||
|
overrideSanitizer(sanitizer: StyleSanitizeFn|null): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A debug/testing-oriented summary of a styling entry.
|
||||||
|
*
|
||||||
|
* A value such as this is generated as an artifact of the `DebugStyling`
|
||||||
|
* summary.
|
||||||
|
*/
|
||||||
|
export interface DebugNodeStylingEntry {
|
||||||
|
/** The style/class property that the summary is attached to */
|
||||||
|
prop: string;
|
||||||
|
|
||||||
|
/** The last applied value for the style/class property */
|
||||||
|
value: string|boolean|null;
|
||||||
|
|
||||||
|
/** The binding index of the last applied style/class property */
|
||||||
|
bindingIndex: number|null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instantiates and attaches an instance of `TStylingContextDebug` to the provided context
|
* Instantiates and attaches an instance of `TStylingContextDebug` to the provided context
|
||||||
*/
|
*/
|
||||||
|
@ -135,21 +157,20 @@ export function attachStylingDebugObject(context: TStylingContext) {
|
||||||
* This class is designed to be used within testing code or when an
|
* This class is designed to be used within testing code or when an
|
||||||
* application has `ngDevMode` activated.
|
* application has `ngDevMode` activated.
|
||||||
*/
|
*/
|
||||||
class TStylingContextDebug {
|
class TStylingContextDebug implements DebugStylingContext {
|
||||||
constructor(public readonly context: TStylingContext) {}
|
constructor(public readonly context: TStylingContext) {}
|
||||||
|
|
||||||
get isTemplateLocked() { return isContextLocked(this.context, true); }
|
get config(): DebugStylingConfig { return buildConfig(this.context); }
|
||||||
get isHostBindingsLocked() { return isContextLocked(this.context, false); }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a detailed summary of each styling entry in the context.
|
* Returns a detailed summary of each styling entry in the context.
|
||||||
*
|
*
|
||||||
* See `TStylingTupleSummary`.
|
* See `TStylingTupleSummary`.
|
||||||
*/
|
*/
|
||||||
get entries(): {[prop: string]: TStylingTupleSummary} {
|
get entries(): {[prop: string]: DebugStylingContextEntry} {
|
||||||
const context = this.context;
|
const context = this.context;
|
||||||
const totalColumns = getValuesCount(context);
|
const totalColumns = getValuesCount(context);
|
||||||
const entries: {[prop: string]: TStylingTupleSummary} = {};
|
const entries: {[prop: string]: DebugStylingContextEntry} = {};
|
||||||
const start = getPropValuesStartPosition(context);
|
const start = getPropValuesStartPosition(context);
|
||||||
let i = start;
|
let i = start;
|
||||||
while (i < context.length) {
|
while (i < context.length) {
|
||||||
|
@ -189,12 +210,19 @@ class TStylingContextDebug {
|
||||||
* This class is designed to be used within testing code or when an
|
* This class is designed to be used within testing code or when an
|
||||||
* application has `ngDevMode` activated.
|
* application has `ngDevMode` activated.
|
||||||
*/
|
*/
|
||||||
export class NodeStylingDebug implements DebugStyling {
|
export class NodeStylingDebug implements DebugNodeStyling {
|
||||||
private _sanitizer: StyleSanitizeFn|null = null;
|
private _sanitizer: StyleSanitizeFn|null = null;
|
||||||
|
private _debugContext: DebugStylingContext;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public context: TStylingContext, private _data: LStylingData,
|
context: TStylingContext|DebugStylingContext, private _data: LStylingData,
|
||||||
private _isClassBased?: boolean) {}
|
private _isClassBased?: boolean) {
|
||||||
|
this._debugContext = isStylingContext(context) ?
|
||||||
|
new TStylingContextDebug(context as TStylingContext) :
|
||||||
|
(context as DebugStylingContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
get context() { return this._debugContext; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Overrides the sanitizer used to process styles.
|
* Overrides the sanitizer used to process styles.
|
||||||
|
@ -207,36 +235,15 @@ export class NodeStylingDebug implements DebugStyling {
|
||||||
*
|
*
|
||||||
* See `LStylingSummary`.
|
* See `LStylingSummary`.
|
||||||
*/
|
*/
|
||||||
get summary(): {[key: string]: LStylingSummary} {
|
get summary(): {[key: string]: DebugNodeStylingEntry} {
|
||||||
const entries: {[key: string]: LStylingSummary} = {};
|
const entries: {[key: string]: DebugNodeStylingEntry} = {};
|
||||||
this._mapValues((prop: string, value: any, bindingIndex: number | null) => {
|
this._mapValues((prop: string, value: any, bindingIndex: number | null) => {
|
||||||
entries[prop] = {prop, value, bindingIndex};
|
entries[prop] = {prop, value, bindingIndex};
|
||||||
});
|
});
|
||||||
return entries;
|
return entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
get config() {
|
get config() { return buildConfig(this.context.context); }
|
||||||
const hasMapBindings = hasConfig(this.context, TStylingConfig.HasMapBindings);
|
|
||||||
const hasPropBindings = hasConfig(this.context, TStylingConfig.HasPropBindings);
|
|
||||||
const hasCollisions = hasConfig(this.context, TStylingConfig.HasCollisions);
|
|
||||||
const hasTemplateBindings = hasConfig(this.context, TStylingConfig.HasTemplateBindings);
|
|
||||||
const hasHostBindings = hasConfig(this.context, TStylingConfig.HasHostBindings);
|
|
||||||
const templateBindingsLocked = hasConfig(this.context, TStylingConfig.TemplateBindingsLocked);
|
|
||||||
const hostBindingsLocked = hasConfig(this.context, TStylingConfig.HostBindingsLocked);
|
|
||||||
const allowDirectStyling =
|
|
||||||
_allowDirectStyling(this.context, false) || _allowDirectStyling(this.context, true);
|
|
||||||
|
|
||||||
return {
|
|
||||||
hasMapBindings, //
|
|
||||||
hasPropBindings, //
|
|
||||||
hasCollisions, //
|
|
||||||
hasTemplateBindings, //
|
|
||||||
hasHostBindings, //
|
|
||||||
templateBindingsLocked, //
|
|
||||||
hostBindingsLocked, //
|
|
||||||
allowDirectStyling, //
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a key/value map of all the styles/classes that were last applied to the element.
|
* Returns a key/value map of all the styles/classes that were last applied to the element.
|
||||||
|
@ -252,7 +259,7 @@ export class NodeStylingDebug implements DebugStyling {
|
||||||
// element is only used when the styling algorithm attempts to
|
// element is only used when the styling algorithm attempts to
|
||||||
// style the value (and we mock out the stylingApplyFn anyway).
|
// style the value (and we mock out the stylingApplyFn anyway).
|
||||||
const mockElement = {} as any;
|
const mockElement = {} as any;
|
||||||
const hasMaps = hasConfig(this.context, TStylingConfig.HasMapBindings);
|
const hasMaps = hasConfig(this.context.context, TStylingConfig.HasMapBindings);
|
||||||
if (hasMaps) {
|
if (hasMaps) {
|
||||||
activateStylingMapFeature();
|
activateStylingMapFeature();
|
||||||
}
|
}
|
||||||
|
@ -265,10 +272,33 @@ export class NodeStylingDebug implements DebugStyling {
|
||||||
|
|
||||||
// run the template bindings
|
// run the template bindings
|
||||||
applyStylingViaContext(
|
applyStylingViaContext(
|
||||||
this.context, null, mockElement, this._data, true, mapFn, sanitizer, false);
|
this.context.context, null, mockElement, this._data, true, mapFn, sanitizer, false);
|
||||||
|
|
||||||
// and also the host bindings
|
// and also the host bindings
|
||||||
applyStylingViaContext(
|
applyStylingViaContext(
|
||||||
this.context, null, mockElement, this._data, true, mapFn, sanitizer, true);
|
this.context.context, null, mockElement, this._data, true, mapFn, sanitizer, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function buildConfig(context: TStylingContext) {
|
||||||
|
const hasMapBindings = hasConfig(context, TStylingConfig.HasMapBindings);
|
||||||
|
const hasPropBindings = hasConfig(context, TStylingConfig.HasPropBindings);
|
||||||
|
const hasCollisions = hasConfig(context, TStylingConfig.HasCollisions);
|
||||||
|
const hasTemplateBindings = hasConfig(context, TStylingConfig.HasTemplateBindings);
|
||||||
|
const hasHostBindings = hasConfig(context, TStylingConfig.HasHostBindings);
|
||||||
|
const templateBindingsLocked = hasConfig(context, TStylingConfig.TemplateBindingsLocked);
|
||||||
|
const hostBindingsLocked = hasConfig(context, TStylingConfig.HostBindingsLocked);
|
||||||
|
const allowDirectStyling =
|
||||||
|
_allowDirectStyling(context, false) || _allowDirectStyling(context, true);
|
||||||
|
|
||||||
|
return {
|
||||||
|
hasMapBindings, //
|
||||||
|
hasPropBindings, //
|
||||||
|
hasCollisions, //
|
||||||
|
hasTemplateBindings, //
|
||||||
|
hasHostBindings, //
|
||||||
|
templateBindingsLocked, //
|
||||||
|
hostBindingsLocked, //
|
||||||
|
allowDirectStyling, //
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -212,7 +212,7 @@ export function getStylingMapArray(value: TStylingContext | StylingMapArray | nu
|
||||||
value as StylingMapArray;
|
value as StylingMapArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isStylingContext(value: TStylingContext | StylingMapArray | null): boolean {
|
export function isStylingContext(value: any): boolean {
|
||||||
// the StylingMapArray is in the format of [initial, prop, string, prop, string]
|
// the StylingMapArray is in the format of [initial, prop, string, prop, string]
|
||||||
// and this is the defining value to distinguish between arrays
|
// and this is the defining value to distinguish between arrays
|
||||||
return Array.isArray(value) && value.length >= TStylingContextIndex.ValuesStartPosition &&
|
return Array.isArray(value) && value.length >= TStylingContextIndex.ValuesStartPosition &&
|
||||||
|
|
|
@ -822,7 +822,7 @@ describe('styling', () => {
|
||||||
const node = getDebugNode(element) !;
|
const node = getDebugNode(element) !;
|
||||||
|
|
||||||
const styles = node.styles !;
|
const styles = node.styles !;
|
||||||
const config = styles.config;
|
const config = styles.context.config;
|
||||||
expect(config.hasCollisions).toBeFalsy();
|
expect(config.hasCollisions).toBeFalsy();
|
||||||
expect(config.hasMapBindings).toBeFalsy();
|
expect(config.hasMapBindings).toBeFalsy();
|
||||||
expect(config.hasPropBindings).toBeTruthy();
|
expect(config.hasPropBindings).toBeTruthy();
|
||||||
|
|
Loading…
Reference in New Issue