diff options
Diffstat (limited to 'app/assets/javascripts/vue_shared/components/lib/utils/props_utils.js')
-rw-r--r-- | app/assets/javascripts/vue_shared/components/lib/utils/props_utils.js | 35 |
1 files changed, 35 insertions, 0 deletions
diff --git a/app/assets/javascripts/vue_shared/components/lib/utils/props_utils.js b/app/assets/javascripts/vue_shared/components/lib/utils/props_utils.js new file mode 100644 index 00000000000..b115b1fb34b --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/lib/utils/props_utils.js @@ -0,0 +1,35 @@ +/** + * Return the union of the given components' props options. Required props take + * precendence over non-required props of the same name. + * + * This makes two assumptions: + * - All given components define their props in verbose object format. + * - The components all agree on the `type` of a common prop. + * + * @param {object[]} components The components to derive the union from. + * @returns {object} The union of the props of the given components. + */ +export const propsUnion = (components) => + components.reduce((acc, component) => { + Object.entries(component.props ?? {}).forEach(([propName, propOptions]) => { + if (process.env.NODE_ENV !== 'production') { + if (typeof propOptions !== 'object' || !('type' in propOptions)) { + throw new Error( + `Cannot create props union: expected verbose prop options for prop "${propName}"`, + ); + } + + if (propName in acc && acc[propName]?.type !== propOptions?.type) { + throw new Error( + `Cannot create props union: incompatible prop types for prop "${propName}"`, + ); + } + } + + if (!(propName in acc) || propOptions.required) { + acc[propName] = propOptions; + } + }); + + return acc; + }, {}); |