Skip to content

packages/core/src/lib/style/diagnostics.ts

Read as Markdown

This is the source snapshot used to build these API details. View this revision on GitHub.

Back to reference

1 import type { normalizeEdges } from './normalize.js';
2 import type { resolveLength } from './resolve-length.js';
3 import type { Constraints } from '../layout/types.js';
4 
5 /**
6  * Component and source context attached to a layout diagnostic.
7  *
8  * @see {@link Constraints}
9  * @see {@link LayoutDiagnosticInput}
10  * @see {@link normalizeEdges}
11  * @see {@link resolveLength}
12  */
13 export interface LayoutDiagnosticContext {
14   /**
15    * Component identity or diagnostic name associated with this value. See
16    * {@link LayoutDiagnosticContext}.
17    */
18   component?: string;
19   /**
20    * Name of the layout algorithm producing this diagnostic or resolution. See
21    * {@link LayoutDiagnosticContext}.
22    */
23   algorithm?: string;
24   /** Sizing limits and available dimensions for this operation. See {@link Constraints}. */
25   constraints?: Readonly<Constraints>;
26 }
27 
28 /**
29  * Validation-failure details used to construct a layout diagnostic.
30  *
31  * @see {@link LayoutDiagnosticContext}
32  * @see {@link layoutDiagnostic}
33  */
34 export interface LayoutDiagnosticInput extends LayoutDiagnosticContext {
35   /** Name of the affected input property. See {@link LayoutDiagnosticInput}. */
36   property: string;
37   /** Value associated with this sample, input, or result. See {@link LayoutDiagnosticInput}. */
38   value: unknown;
39   /**
40    * Reason the operation could not produce its ordinary result. See {@link LayoutDiagnosticInput}
41    * .
42    */
43   reason: string;
44 }
45 
46 /**
47  * A layout validation error carrying the affected property and component context.
48  *
49  * @see {@link layoutDiagnostic}
50  */
51 export class LayoutDiagnostic extends Error {
52   /**
53    * Component identity or diagnostic name associated with this value. See {@link LayoutDiagnostic}
54    * .
55    */
56   readonly component: string;
57   /** Name of the affected input property. See {@link LayoutDiagnostic}. */
58   readonly property: string;
59   /** The original value that failed validation. See {@link LayoutDiagnostic}. */
60   readonly suppliedValue: unknown;
61   /**
62    * Name of the layout algorithm producing this diagnostic or resolution. See
63    * {@link LayoutDiagnostic}.
64    */
65   readonly algorithm: string;
66   /** Sizing limits and available dimensions for this operation. See {@link Constraints}. */
67   readonly constraints: Readonly<Constraints> | undefined;
68 
69   /**
70    * Creates a layout error containing the property, supplied value, and diagnostic context. See
71    * {@link LayoutDiagnostic}.
72    * @param input - Diagnostic code, message, property, and layout context. See
73    * {@link LayoutDiagnosticInput} .
74    */
75   constructor(input: LayoutDiagnosticInput) {
76     const component = input.component ?? 'layout';
77     const algorithm = input.algorithm ?? 'value-resolution';
78     const constraints = input.constraints;
79     super(
80       `${component}: property ${input.property} received ${formatValue(input.value)} ` +
81         `during ${algorithm}; constraints ${formatConstraints(constraints)}; ${input.reason}`,
82     );
83     this.name = 'LayoutDiagnostic';
84     this.component = component;
85     this.property = input.property;
86     this.suppliedValue = input.value;
87     this.algorithm = algorithm;
88     this.constraints = constraints;
89   }
90 }
91 
92 /**
93  * Creates a structured layout error from a validation failure and its component context.
94  *
95  * @param input - Diagnostic code, message, property, and layout context. See
96  * {@link LayoutDiagnosticInput} .
97  * @returns A structured layout diagnostic. See {@link LayoutDiagnostic}.
98  *
99  * @see {@link LayoutDiagnosticInput}
100  * @see {@link LayoutDiagnostic}
101  */
102 export function layoutDiagnostic(
103   input: LayoutDiagnosticInput,
104 ): LayoutDiagnostic {
105   return new LayoutDiagnostic(input);
106 }
107 
108 function formatValue(value: unknown): string {
109   if (typeof value === 'string') return JSON.stringify(value);
110   if (typeof value === 'number') {
111     if (Number.isNaN(value)) return 'NaN';
112     if (value === Number.POSITIVE_INFINITY) return 'Infinity';
113     if (value === Number.NEGATIVE_INFINITY) return '-Infinity';
114   }
115   try {
116     return JSON.stringify(value) ?? String(value);
117   } catch {
118     return String(value);
119   }
120 }
121 
122 function formatConstraints(
123   constraints: Readonly<Constraints> | undefined,
124 ): string {
125   if (!constraints) return 'unspecified';
126   return (
127     `{ minWidth: ${formatValue(constraints.minWidth)}, maxWidth: ${formatValue(constraints.maxWidth)}, ` +
128     `minHeight: ${formatValue(constraints.minHeight)}, maxHeight: ${formatValue(constraints.maxHeight)} }`
129   );
130 }
131 

Documentation built with @pibbl/core 0.0.2, revision 272a94a. ALPHA — NOT FOR PRODUCTION USE.