@skirtle/vue-vnode-utils
Version:
Utilities for manipulating Vue 3 VNodes
373 lines (372 loc) • 11.8 kB
JavaScript
var VueVNodeUtils = function(exports, vue) {
"use strict";
const isComment = (vnode) => {
return getType(vnode) === "comment";
};
const isComponent = (vnode) => {
return getType(vnode) === "component";
};
const isElement = (vnode) => {
return getType(vnode) === "element";
};
const isFragment = (vnode) => {
return getType(vnode) === "fragment";
};
const isFunctionalComponent = (vnode) => {
return isComponent(vnode) && typeof vnode.type === "function";
};
const isStatefulComponent = (vnode) => {
return isComponent(vnode) && typeof vnode.type === "object";
};
const isStatic = (vnode) => {
return getType(vnode) === "static";
};
const isText = (vnode) => {
return getType(vnode) === "text";
};
const getText = (vnode) => {
if (typeof vnode === "string") {
return vnode;
}
if (typeof vnode === "number") {
return String(vnode);
}
if (vue.isVNode(vnode) && vnode.type === vue.Text) {
return String(vnode.children);
}
return void 0;
};
const getType = (vnode) => {
const typeofVNode = typeof vnode;
if (vnode == null || typeofVNode === "boolean") {
return "comment";
} else if (typeofVNode === "string" || typeofVNode === "number") {
return "text";
} else if (Array.isArray(vnode)) {
return "fragment";
}
if (vue.isVNode(vnode)) {
const { type } = vnode;
const typeofType = typeof type;
if (typeofType === "symbol") {
if (type === vue.Fragment) {
return "fragment";
} else if (type === vue.Text) {
return "text";
} else if (type === vue.Comment) {
return "comment";
} else if (type === vue.Static) {
return "static";
}
} else if (typeofType === "string") {
return "element";
} else if (typeofType === "object" || typeofType === "function") {
return "component";
}
}
return void 0;
};
const warn = (method, msg) => {
console.warn(`[${method}] ${msg}`);
};
const checkArguments = (method, passed, expected) => {
for (let index = 0; index < passed.length; ++index) {
const t = typeOf(passed[index]);
const expect = expected[index];
if (expect !== t) {
warn(method, `Argument ${index + 1} was ${t}, should be ${expect}`);
}
}
};
const isEmptyObject = (obj) => {
for (const prop in obj) {
return false;
}
return true;
};
const typeOf = (value) => {
let t = typeof value;
if (t === "object") {
if (value === null) {
t = "null";
} else if (Array.isArray(value)) {
t = "array";
} else if (vue.isVNode(value)) {
t = "vnode";
} else if (value instanceof Date) {
t = "date";
} else if (value instanceof RegExp) {
t = "regexp";
}
}
return t;
};
const getFragmentChildren = (fragmentVNode) => {
if (Array.isArray(fragmentVNode)) {
return fragmentVNode;
}
const { children } = fragmentVNode;
if (Array.isArray(children)) {
return children;
}
{
warn("getFragmentChildren", `Unknown children for fragment: ${typeOf(children)}`);
}
return [];
};
function freeze(obj) {
{
return Object.freeze(obj);
}
}
const COMPONENTS_AND_ELEMENTS = /* @__PURE__ */ freeze({
element: true,
component: true
});
const SKIP_COMMENTS = /* @__PURE__ */ freeze({
element: true,
component: true,
text: true,
static: true
});
const ALL_VNODES = /* @__PURE__ */ freeze({
element: true,
component: true,
text: true,
static: true,
comment: true
});
const promoteToVNode = (node, options) => {
const type = getType(node);
if (!type || type === "fragment" || !options[type]) {
return null;
}
if (vue.isVNode(node)) {
return node;
}
if (type === "text") {
return vue.createTextVNode(getText(node));
}
return vue.createCommentVNode();
};
const addProps = (children, callback, options = COMPONENTS_AND_ELEMENTS) => {
{
checkArguments("addProps", [children, callback, options], ["array", "function", "object"]);
}
return replaceChildrenInternal(children, (vnode) => {
const props = callback(vnode);
{
const typeofProps = typeOf(props);
if (!["object", "null", "undefined"].includes(typeofProps)) {
warn("addProps", `Callback returned unexpected ${typeofProps}: ${String(props)}`);
}
}
if (props && !isEmptyObject(props)) {
return vue.cloneVNode(vnode, props, true);
}
}, options);
};
const replaceChildren = (children, callback, options = SKIP_COMMENTS) => {
{
checkArguments("replaceChildren", [children, callback, options], ["array", "function", "object"]);
}
return replaceChildrenInternal(children, callback, options);
};
const replaceChildrenInternal = (children, callback, options) => {
var _a;
let nc = null;
for (let index = 0; index < children.length; ++index) {
const child = children[index];
if (isFragment(child)) {
const oldFragmentChildren = getFragmentChildren(child);
const newFragmentChildren = replaceChildrenInternal(oldFragmentChildren, callback, options);
let newChild = child;
if (oldFragmentChildren !== newFragmentChildren) {
nc != null ? nc : nc = children.slice(0, index);
if (Array.isArray(child)) {
newChild = newFragmentChildren;
} else {
newChild = vue.cloneVNode(child);
newChild.children = newFragmentChildren;
}
}
nc && nc.push(newChild);
} else {
const vnode = promoteToVNode(child, options);
if (vnode) {
const newNodes = (_a = callback(vnode)) != null ? _a : vnode;
{
const typeOfNewNodes = typeOf(newNodes);
if (!["array", "vnode", "string", "number", "undefined"].includes(typeOfNewNodes)) {
warn("replaceChildren", `Callback returned unexpected ${typeOfNewNodes} ${String(newNodes)}`);
}
}
if (newNodes !== child) {
nc != null ? nc : nc = children.slice(0, index);
}
if (Array.isArray(newNodes)) {
nc && nc.push(...newNodes);
} else {
nc && nc.push(newNodes);
}
} else {
nc && nc.push(child);
}
}
}
return nc != null ? nc : children;
};
const betweenChildren = (children, callback, options = SKIP_COMMENTS) => {
{
checkArguments("betweenChildren", [children, callback, options], ["array", "function", "object"]);
}
let previousVNode = null;
return replaceChildrenInternal(children, (vnode) => {
let insertedNodes = void 0;
if (previousVNode) {
insertedNodes = callback(previousVNode, vnode);
{
const typeOfInsertedNodes = typeOf(insertedNodes);
if (!["array", "vnode", "string", "number", "undefined"].includes(typeOfInsertedNodes)) {
warn("betweenChildren", `Callback returned unexpected ${typeOfInsertedNodes} ${String(insertedNodes)}`);
}
}
}
previousVNode = vnode;
if (insertedNodes == null || Array.isArray(insertedNodes) && insertedNodes.length === 0) {
return;
}
if (Array.isArray(insertedNodes)) {
return [...insertedNodes, vnode];
}
return [insertedNodes, vnode];
}, options);
};
const someChild = (children, callback, options = ALL_VNODES) => {
{
checkArguments("someChild", [children, callback, options], ["array", "function", "object"]);
}
return someChildInternal(children, callback, options);
};
const someChildInternal = (children, callback, options) => {
for (const child of children) {
if (isFragment(child)) {
if (someChild(getFragmentChildren(child), callback, options)) {
return true;
}
} else {
const vnode = promoteToVNode(child, options);
if (vnode && callback(vnode)) {
return true;
}
}
}
return false;
};
const everyChild = (children, callback, options = ALL_VNODES) => {
{
checkArguments("everyChild", [children, callback, options], ["array", "function", "object"]);
}
return !someChildInternal(children, (vnode) => !callback(vnode), options);
};
const eachChild = (children, callback, options = ALL_VNODES) => {
{
checkArguments("eachChild", [children, callback, options], ["array", "function", "object"]);
}
someChildInternal(children, (vnode) => {
callback(vnode);
}, options);
};
const findChild = (children, callback, options = ALL_VNODES) => {
{
checkArguments("findChild", [children, callback, options], ["array", "function", "object"]);
}
let node = void 0;
someChildInternal(children, (vnode) => {
if (callback(vnode)) {
node = vnode;
return true;
}
}, options);
return node;
};
const reduceChildren = (children, callback, initialValue, options = ALL_VNODES) => {
{
checkArguments("reduceChildren", [children, callback, null, options], ["array", "function", "null", "object"]);
}
someChildInternal(children, (vnode) => {
initialValue = callback(initialValue, vnode);
}, options);
return initialValue;
};
const COLLAPSIBLE_WHITESPACE_RE = /\S|\u00a0/;
const isEmpty = (children) => {
{
checkArguments("isEmpty", [children], ["array"]);
}
return !someChildInternal(children, (vnode) => {
if (isText(vnode)) {
const text = getText(vnode) || "";
return COLLAPSIBLE_WHITESPACE_RE.test(text);
}
return true;
}, SKIP_COMMENTS);
};
const extractSingleChild = (children) => {
{
checkArguments("extractSingleChild", [children], ["array"]);
}
const node = findChild(children, () => {
return true;
}, COMPONENTS_AND_ELEMENTS);
{
someChildInternal(children, (vnode) => {
let warning = "";
if (vnode === node) {
return false;
}
if (isElement(vnode) || isComponent(vnode)) {
warning = "Multiple root nodes found, only one expected";
} else if (isText(vnode)) {
const text = getText(vnode) || "";
if (COLLAPSIBLE_WHITESPACE_RE.test(text)) {
warning = `Non-empty text node:
'${text}'`;
}
} else {
warning = `Encountered unexpected ${getType(vnode)} VNode`;
}
if (warning) {
warn("extractSingleChild", warning);
return true;
}
}, SKIP_COMMENTS);
}
return node;
};
exports.ALL_VNODES = ALL_VNODES;
exports.COMPONENTS_AND_ELEMENTS = COMPONENTS_AND_ELEMENTS;
exports.SKIP_COMMENTS = SKIP_COMMENTS;
exports.addProps = addProps;
exports.betweenChildren = betweenChildren;
exports.eachChild = eachChild;
exports.everyChild = everyChild;
exports.extractSingleChild = extractSingleChild;
exports.findChild = findChild;
exports.getText = getText;
exports.getType = getType;
exports.isComment = isComment;
exports.isComponent = isComponent;
exports.isElement = isElement;
exports.isEmpty = isEmpty;
exports.isFragment = isFragment;
exports.isFunctionalComponent = isFunctionalComponent;
exports.isStatefulComponent = isStatefulComponent;
exports.isStatic = isStatic;
exports.isText = isText;
exports.reduceChildren = reduceChildren;
exports.replaceChildren = replaceChildren;
exports.someChild = someChild;
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
return exports;
}({}, Vue);