element-vir
Version:
Heroic. Reactive. Declarative. Type safe. Web components without compromise.
70 lines (69 loc) • 2.33 kB
JavaScript
import { AssertionError, check } from '@augment-vir/assert';
import { getObjectTypedKeys, wrapInTry } from '@augment-vir/common';
const expectedStaticProperties = getObjectTypedKeys({
assign: '',
assignedInputs: '',
cssVars: '',
elementOptions: '',
events: '',
hostClasses: '',
init: '',
InputsType: '',
render: '',
slotNames: '',
testIds: '',
StateType: '',
styles: '',
tagName: '',
UpdateStateType: '',
});
/** `assignedInputs` is only populated by the template transforms, so it is legitimately unset. */
const staticPropertiesAllowedToBeUndefined = ['assignedInputs'];
/**
* The type-only statics (such as `InputsType`) are getters that throw, so their descriptors must be
* inspected instead of their values.
*/
function findStaticDescriptor(input, key) {
const ownDescriptor = Object.getOwnPropertyDescriptor(input, key);
if (ownDescriptor) {
return ownDescriptor;
}
const parent = Object.getPrototypeOf(input);
return parent == undefined ? undefined : findStaticDescriptor(parent, key);
}
/**
* Asserts that the given input is a declarative element definition.
*
* @category Util
* @see {@link isDeclarativeElementDefinition}
*/
export function assertDeclarativeElementDefinition(input, failMessage) {
if (!check.isFunction(input)) {
throw new AssertionError('Input is not a declarative element constructor', failMessage);
}
expectedStaticProperties.forEach((expectedProperty) => {
const descriptor = findStaticDescriptor(input, expectedProperty);
if (!descriptor) {
throw new AssertionError(`missing prop '${expectedProperty}'`, failMessage);
}
else if (!descriptor.get &&
descriptor.value === undefined &&
!staticPropertiesAllowedToBeUndefined.includes(expectedProperty)) {
throw new AssertionError(`undefined prop '${expectedProperty}'`, failMessage);
}
});
}
/**
* Checks that the given input is a declarative element definition.
*
* @category Util
* @see {@link assertDeclarativeElementDefinition}
*/
export function isDeclarativeElementDefinition(input) {
return wrapInTry(() => {
assertDeclarativeElementDefinition(input);
return true;
}, {
fallbackValue: false,
});
}