Skip to content

Commit 779e053

Browse files
committed
streamline primitive attribute value conversion
1 parent 8cc1c2a commit 779e053

File tree

1 file changed

+34
-35
lines changed

1 file changed

+34
-35
lines changed

packages/core/src/attributes.ts

Lines changed: 34 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import { DEBUG_BUILD } from './debug-build';
2+
import { debug } from './utils/debug-logger';
3+
14
export type RawAttributes<T> = T & ValidatedAttributes<T>;
25
// eslint-disable-next-line @typescript-eslint/no-explicit-any
36
export type RawAttribute<T> = T extends { value: any } | { unit: any } ? AttributeObject : T;
@@ -74,69 +77,65 @@ export function attributeValueToTypedAttributeValue(rawValue: unknown): TypedAtt
7477
return { ...getTypedAttributeValue(value), ...(unit && typeof unit === 'string' ? { unit } : {}) };
7578
}
7679

77-
// Disallow NaN, differentiate between integer and double
78-
const getNumberType: (num: number) => 'integer' | 'double' | null = item =>
79-
Number.isNaN(item) ? null : Number.isInteger(item) ? 'integer' : 'double';
80-
8180
// Only allow string, boolean, or number types
82-
const getPrimitiveType: (item: unknown) => 'string' | 'boolean' | 'integer' | 'double' | null = item =>
81+
const getPrimitiveType: (
82+
item: unknown,
83+
) => keyof Pick<AttributeTypeMap, 'string' | 'integer' | 'double' | 'boolean'> | null = item =>
8384
typeof item === 'string'
8485
? 'string'
8586
: typeof item === 'boolean'
8687
? 'boolean'
8788
: typeof item === 'number'
88-
? getNumberType(item)
89+
? Number.isNaN(item)
90+
? null
91+
: Number.isInteger(item)
92+
? 'integer'
93+
: 'double'
8994
: null;
9095

91-
function getTypedAttributeValue(val: unknown): TypedAttributeValue {
92-
switch (typeof val) {
93-
case 'number': {
94-
const numberType = getNumberType(val);
95-
if (!numberType) {
96-
break;
97-
}
98-
return {
99-
value: val,
100-
type: numberType,
101-
};
102-
}
103-
case 'boolean':
104-
return {
105-
value: val,
106-
type: 'boolean',
107-
};
108-
case 'string':
109-
return {
110-
value: val,
111-
type: 'string',
112-
};
96+
function getTypedAttributeValue(value: unknown): TypedAttributeValue {
97+
const primitiveType = getPrimitiveType(value);
98+
if (primitiveType) {
99+
// @ts-expect-error - TS complains because {@link TypedAttributeValue} is strictly typed to
100+
// avoid setting the wrong `type` on the attribute value.
101+
// In this case, getPrimitiveType already does the check but TS doesn't know that.
102+
// The "clean" alternative is to return an object per `typeof value` case
103+
// but that would require more bundle size
104+
// Therefore, we ignore it.
105+
return { value, type: primitiveType };
113106
}
114107

115-
if (Array.isArray(val)) {
116-
const coherentType = val.reduce((acc: 'string' | 'boolean' | 'integer' | 'double' | null, item) => {
108+
if (Array.isArray(value)) {
109+
const coherentArrayType = value.reduce((acc: 'string' | 'boolean' | 'integer' | 'double' | null, item) => {
117110
if (!acc || getPrimitiveType(item) !== acc) {
118111
return null;
119112
}
120113
return acc;
121-
}, getPrimitiveType(val[0]));
114+
}, getPrimitiveType(value[0]));
122115

123-
if (coherentType) {
124-
return { value: val, type: `${coherentType}[]` };
116+
if (coherentArrayType) {
117+
return { value, type: `${coherentArrayType}[]` };
125118
}
126119
}
127120

128121
// Fallback: stringify the passed value
129122
let fallbackValue = '';
130123
try {
131-
fallbackValue = JSON.stringify(val) ?? String(val);
124+
fallbackValue = JSON.stringify(value) ?? String(value);
132125
} catch {
133126
try {
134-
fallbackValue = String(val);
127+
fallbackValue = String(value);
135128
} catch {
129+
DEBUG_BUILD && debug.warn('Failed to stringify attribute value', value);
136130
// ignore
137131
}
138132
}
139133

134+
// This is quite a low-quality message but we cannot safely log the original `value`
135+
// here due to String() or JSON.stringify() potentially throwing.
136+
DEBUG_BUILD &&
137+
debug.log(`Stringified attribute value to ${fallbackValue} because it's not a supported attribute value type`);
138+
140139
return {
141140
value: fallbackValue,
142141
type: 'string',

0 commit comments

Comments
 (0)