forked from stenciljs/core
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathparse-property-value.ts
More file actions
85 lines (78 loc) · 3.35 KB
/
Copy pathparse-property-value.ts
File metadata and controls
85 lines (78 loc) · 3.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
import { BUILD } from '@app-data';
import { MEMBER_FLAGS, SERIALIZED_PREFIX } from '../utils/constants';
import { isComplexType } from '../utils/helpers';
import { deserializeProperty } from '../utils/serialize';
/**
* Parse a new property value for a given property type.
*
* While the prop value can reasonably be expected to be of `any` type as far as TypeScript's type checker is concerned,
* it is not safe to assume that the string returned by evaluating `typeof propValue` matches:
* 1. `any`, the type given to `propValue` in the function signature
* 2. the type stored from `propType`.
*
* This function provides the capability to parse/coerce a property's value to potentially any other JavaScript type.
*
* Property values represented in TSX preserve their type information. In the example below, the number 0 is passed to
* a component. This `propValue` will preserve its type information (`typeof propValue === 'number'`). Note that is
* based on the type of the value being passed in, not the type declared of the class member decorated with `@Prop`.
* ```tsx
* <my-cmp prop-val={0}></my-cmp>
* ```
*
* HTML prop values on the other hand, will always a string
*
* @param propValue the new value to coerce to some type
* @param propType the type of the prop, expressed as a binary number
* @param isFormAssociated whether the component is form-associated (optional)
* @returns the parsed/coerced value
*/
export const parsePropertyValue = (propValue: unknown, propType: number, isFormAssociated?: boolean): any => {
/**
* Allow hydrate parameters that contain a complex non-serialized values.
* This is SSR-specific and should only run during hydration.
*/
if (
(BUILD.hydrateClientSide || BUILD.hydrateServerSide) &&
typeof propValue === 'string' &&
propValue.startsWith(SERIALIZED_PREFIX)
) {
propValue = deserializeProperty(propValue);
return propValue;
}
if (propValue != null && !isComplexType(propValue)) {
/**
* ensure this value is of the correct prop type
*/
if (BUILD.propBoolean && propType & MEMBER_FLAGS.Boolean) {
/**
* For form-associated components, according to HTML spec, the presence of any boolean attribute
* (regardless of its value, even "false") should make the property true.
* For non-form-associated components, we maintain the legacy behavior where "false" becomes false.
*/
if (BUILD.formAssociated && isFormAssociated && typeof propValue === 'string') {
// For form-associated components, any string attribute value (including "false") means true
return propValue === '' || !!propValue;
} else {
// Legacy behavior: string "false" becomes boolean false
return propValue === 'false' ? false : propValue === '' || !!propValue;
}
}
/**
* force it to be a number
*/
if (BUILD.propNumber && propType & MEMBER_FLAGS.Number) {
return typeof propValue === 'string' ? parseFloat(propValue) : typeof propValue === 'number' ? propValue : NaN;
}
/**
* could have been passed as a number or boolean but we still want it as a string
*/
if (BUILD.propString && propType & MEMBER_FLAGS.String) {
return String(propValue);
}
return propValue;
}
/**
* not sure exactly what type we want so no need to change to a different type
*/
return propValue;
};