element-vir
Version:
Heroic. Reactive. Declarative. Type safe. Web components without compromise.
43 lines (42 loc) • 2.85 kB
TypeScript
import { type AnyFunction, type Overwrite } from '@augment-vir/common';
import { type CSSResult, type TemplateResult, type nothing } from 'lit';
import { type EmptyObject, type HasRequiredKeys, type IsNever } from 'type-fest';
import { type DeclarativeElementDefinition } from '../../declarative-element/declarative-element.js';
import { type Decrement, type Increment } from '../../util/increment.js';
import { type MinimalDefinitionWithInputs, type MinimalElementDefinition } from '../minimal-element-definition.js';
/**
* Unfortunately the type for `DirectiveResult` means it's just an empty object. So in order to
* block actual objects, we have to narrow `DirectiveResult` further to this empty object type.
*
* @category Internal
*/
export type DirectiveOutput = EmptyObject;
/**
* This is used in order to block accidental object interpolations into HTML, which get stringified
* into `'[object Object]'`, which nobody ever wants that.
*
* @category Internal
*/
export type HtmlInterpolation = null | undefined | string | number | boolean | bigint | CSSResult | Readonly<CSSResult> | Element | Readonly<Element> | TemplateResult | Readonly<TemplateResult> | MinimalElementDefinition | Readonly<MinimalElementDefinition> | MinimalDefinitionWithInputs | Readonly<MinimalDefinitionWithInputs> | DeclarativeElementDefinition | Readonly<DeclarativeElementDefinition> | DirectiveOutput | Readonly<DirectiveOutput> | AnyFunction | typeof nothing | HtmlInterpolation[] | ReadonlyArray<HtmlInterpolation>;
/**
* This type ensures that interpolated element definitions are not missing their inputs, when inputs
* are required.
*
* @category Internal
*/
export type VerifyHtmlValues<Values extends HtmlInterpolation[], WaitingForEndTags extends Record<string, number> = {}> = Values extends [
infer CurrentDefinition extends DeclarativeElementDefinition,
...infer Rest extends HtmlInterpolation[]
] ? CurrentDefinition extends DeclarativeElementDefinition<infer TagName, infer Inputs> ? HasRequiredKeys<Inputs> extends true ? IsNever<Decrement<WaitingForEndTags[TagName]>> extends true ? [
`ERROR: This element is missing its inputs.`,
...VerifyHtmlValues<Rest, WaitingForEndTags>
] : [
CurrentDefinition,
...VerifyHtmlValues<Rest, Overwrite<WaitingForEndTags, Record<TagName, Decrement<WaitingForEndTags[TagName]>>>>
] : [CurrentDefinition, ...VerifyHtmlValues<Rest, WaitingForEndTags>] : [CurrentDefinition, ...VerifyHtmlValues<Rest, WaitingForEndTags>] : Values extends [
infer CurrentDefinition extends MinimalDefinitionWithInputs,
...infer Rest extends HtmlInterpolation[]
] ? [
CurrentDefinition,
...VerifyHtmlValues<Rest, Overwrite<WaitingForEndTags, Record<CurrentDefinition['definition']['tagName'], Increment<WaitingForEndTags[CurrentDefinition['definition']['tagName']]>>>>
] : Values;