element-vir
Version:
Heroic. Reactive. Declarative. Type safe. Web components without compromise.
119 lines (118 loc) • 4.03 kB
JavaScript
import { check } from '@augment-vir/assert';
import { filterMap } from '@augment-vir/common';
import { hasTagName, isMinimalDefinitionWithInputs } from './minimal-element-definition.js';
function extractElementKeys(values) {
return filterMap(values, (value) => {
if (isMinimalDefinitionWithInputs(value)) {
return value.definition;
}
else if (hasTagName(value)) {
return value.tagInterpolationKey || value;
}
return undefined;
}, check.isTruthy);
}
/**
* The transformed templates are written to a map so that we can preserve reference equality between
* calls. Without maintaining reference equality between html`` calls, lit-element reconstructs all
* of its children on every render.
*
* This is a WeakMap because we only care about the transformed array value as long as the original
* template array key exists.
*/
const transformedTemplateStrings = new WeakMap();
export function getAlreadyMappedTemplate(templateStringsKey, values) {
const elementKeys = extractElementKeys(values);
const nestedValue = getNestedValues(transformedTemplateStrings, [
templateStringsKey,
...elementKeys,
]);
return nestedValue.value?.template;
}
export function setMappedTemplate(templateStringsKey, values, valueToSet) {
const elementKeys = extractElementKeys(values);
return setNestedValues(transformedTemplateStrings, [
templateStringsKey,
...elementKeys,
], valueToSet);
}
function getNestedValues(map, keys, index = 0) {
const { currentTemplateAndNested, reason } = getCurrentKeyAndValue(map, keys, index);
if (!currentTemplateAndNested) {
return {
value: currentTemplateAndNested,
reason,
};
}
else if (index === keys.length - 1) {
return {
value: currentTemplateAndNested,
reason: 'reached end of keys array',
};
}
else if (!currentTemplateAndNested.nested) {
return {
value: undefined,
reason: `map at key index ${index} did not have nested maps`,
};
}
return getNestedValues(currentTemplateAndNested.nested, keys, index + 1);
}
function getCurrentKeyAndValue(map, keys, index) {
const currentKey = keys[index];
if (currentKey == undefined) {
return {
currentKey: undefined,
currentTemplateAndNested: undefined,
reason: `key at index ${index} not found`,
};
}
else if (!map.has(currentKey)) {
return {
currentKey,
currentTemplateAndNested: undefined,
reason: `key at index ${index} was not in the map`,
};
}
const currentTemplateAndNested = map.get(currentKey);
if (currentTemplateAndNested == undefined) {
return {
currentKey,
currentTemplateAndNested: undefined,
reason: `value at key at index ${index} was undefined`,
};
}
return {
currentKey,
currentTemplateAndNested,
reason: 'key and value exists',
};
}
function setNestedValues(map, keys, valueToSet, index = 0) {
const { currentTemplateAndNested, currentKey, reason } = getCurrentKeyAndValue(map, keys, index);
if (!currentKey) {
return {
result: false,
reason,
};
}
const nestedAndTemplate = currentTemplateAndNested ?? {
nested: undefined,
template: undefined,
};
if (!currentTemplateAndNested) {
map.set(currentKey, nestedAndTemplate);
}
if (index === keys.length - 1) {
nestedAndTemplate.template = valueToSet;
return {
result: true,
reason: 'set value at end of keys array',
};
}
const nestedWeakMap = nestedAndTemplate.nested ?? new WeakMap();
if (!nestedAndTemplate.nested) {
nestedAndTemplate.nested = nestedWeakMap;
}
return setNestedValues(nestedWeakMap, keys, valueToSet, index + 1);
}