@varlet/schema-renderer
Version:
Lightweight Schema renderer based on Vue3
362 lines (356 loc) • 12.1 kB
JavaScript
var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
// src/renderer.ts
import {
defineComponent,
h,
renderList,
ref,
isRef,
unref,
toRefs,
isProxy,
isReactive,
isReadonly,
reactive,
computed,
readonly,
watch,
watchEffect,
watchSyncEffect,
watchPostEffect,
onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,
onUnmounted,
Fragment,
getCurrentInstance
} from "vue";
import { isArray as isArray2 } from "@varlet/shared";
import { createAxle } from "@varlet/axle";
// src/shared.ts
import { isPlainObject, isArray, isString } from "@varlet/shared";
// src/types.ts
var BuiltInSchemaNodeNames = /* @__PURE__ */ ((BuiltInSchemaNodeNames2) => {
BuiltInSchemaNodeNames2["PAGE"] = "Page";
BuiltInSchemaNodeNames2["TEXT"] = "Text";
return BuiltInSchemaNodeNames2;
})(BuiltInSchemaNodeNames || {});
var BuiltInSchemaNodeBindingTypes = /* @__PURE__ */ ((BuiltInSchemaNodeBindingTypes2) => {
BuiltInSchemaNodeBindingTypes2["EXPRESSION_BINDING"] = "Expression";
BuiltInSchemaNodeBindingTypes2["RENDER_BINDING"] = "Render";
BuiltInSchemaNodeBindingTypes2["V_NODE_BINDING"] = "VNode";
return BuiltInSchemaNodeBindingTypes2;
})(BuiltInSchemaNodeBindingTypes || {});
// src/shared.ts
function isSchemaPageNode(schemaNode) {
return schemaNode.name === "Page" /* PAGE */;
}
function isSchemaTextNode(schemaNode) {
return schemaNode.name === "Text" /* TEXT */;
}
function isExpressionBinding(value) {
return isPlainObject(value) && value.type === "Expression" /* EXPRESSION_BINDING */;
}
function isObjectBinding(value) {
return isPlainObject(value) && !isExpressionBinding(value) && !isRenderBinding(value) && !isVNodeBinding(value);
}
function isRenderBinding(value) {
return isPlainObject(value) && value.type === "Render" /* RENDER_BINDING */ && value.id;
}
function isVNodeBinding(value) {
return isPlainObject(value) && value.type === "VNode" /* V_NODE_BINDING */;
}
function cloneSchemaNode(schemaNode) {
return JSON.parse(JSON.stringify(schemaNode));
}
function normalizeClasses(value) {
return isArray(value) ? value : isString(value) ? value.split(" ") : [];
}
// src/renderer.ts
var STYLE_ID_PREFIX = "schema-renderer-style";
var SCOPE_VARIABLES = ["$item", "$index", "$slotProps", "$renderArgs"];
var axle = createAxle({});
var props = {
schema: {
type: Object,
required: true,
default: () => ({})
},
components: {
type: Object,
default: () => ({})
},
injects: {
type: Object,
default: () => ({})
}
};
var Renderer = defineComponent({
props,
setup(props2) {
const internals = {
h,
ref,
reactive,
computed,
readonly,
watch,
watchEffect,
watchSyncEffect,
watchPostEffect,
isRef,
unref,
toRefs,
isProxy,
isReactive,
isReadonly,
onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,
onUnmounted,
axle
};
let ctx = __spreadValues(__spreadValues({}, internals), props2.injects);
const { uid } = getCurrentInstance();
runSetup();
onMounted(mountCss);
onUnmounted(unmountCss);
watch(() => props2.schema.css, updateCss);
watch(
() => props2.injects,
() => {
ctx = __spreadValues(__spreadValues({}, internals), props2.injects);
}
);
function runSetup() {
var _a, _b;
const code = (_b = (_a = props2.schema.compatibleCode) != null ? _a : props2.schema.code) != null ? _b : "function setup() { return {} }";
const setup = exec(code);
const setupCtx = setup();
Object.assign(ctx, setupCtx);
}
function exec(expression, context) {
return window.evalWith(expression, context != null ? context : ctx);
}
function mountCss() {
if (!props2.schema.css) {
return;
}
const style = document.createElement("style");
style.innerHTML = props2.schema.css;
style.id = `${STYLE_ID_PREFIX}-${uid}`;
document.head.appendChild(style);
}
function unmountCss() {
const style = document.querySelector(`#${STYLE_ID_PREFIX}-${uid}`);
if (style) {
document.head.removeChild(style);
}
}
function updateCss() {
unmountCss();
mountCss();
}
function createNewScopeVariables(oldScopeVariables, partialScopeVariables) {
return __spreadValues(__spreadValues({}, oldScopeVariables), partialScopeVariables);
}
function includesScopeVariable(expression) {
return SCOPE_VARIABLES.some((scopedVariable) => expression.includes(scopedVariable));
}
function resolveScopedExpression(expression, scopeVariables) {
return exec(expression, __spreadValues(__spreadValues({}, ctx), scopeVariables));
}
function getExpressionBindingValue(expression, scopeVariables) {
if (!includesScopeVariable(expression)) {
return exec(expression);
}
return resolveScopedExpression(expression, scopeVariables);
}
function getObjectBindingValue(value, scopeVariables) {
return Object.keys(value).reduce((newValue, key) => {
newValue[key] = getBindingValue(value[key], scopeVariables);
return newValue;
}, {});
}
function getBindingValue(value, scopeVariables) {
var _a, _b;
if (isRenderBinding(value)) {
return (...args) => {
const newScopeVariables = createNewScopeVariables(scopeVariables, {
$renderArgs: __spreadProps(__spreadValues({}, scopeVariables.$renderArgs), {
[value.id]: args
})
});
const conditionedSchemaNodes = withCondition(value.value, newScopeVariables);
return h(
Fragment,
conditionedSchemaNodes.map((schemaNode) => renderSchemaNode(schemaNode, newScopeVariables))
);
};
}
if (isVNodeBinding(value)) {
const condition = (_a = getBindingValue(value.value.if, scopeVariables)) != null ? _a : true;
return condition ? renderSchemaNode(value.value, scopeVariables) : void 0;
}
if (isExpressionBinding(value)) {
return getExpressionBindingValue((_b = value.compatibleValue) != null ? _b : value.value, scopeVariables);
}
if (isObjectBinding(value)) {
return getObjectBindingValue(value, scopeVariables);
}
if (isArray2(value)) {
return value.map((value2) => getBindingValue(value2, scopeVariables));
}
return value;
}
function renderVNode(schemaNode, scopeVariables) {
const propsBinding = getPropsBinding(schemaNode, scopeVariables);
const classes = normalizeClasses(propsBinding.class);
const props3 = __spreadProps(__spreadValues({}, propsBinding), { class: classes });
if (isSchemaTextNode(schemaNode)) {
const { value } = schemaNode;
return h("span", props3, getBindingValue(value, scopeVariables));
}
return h(getComponent(schemaNode.name), props3, renderSchemaNodeSlots(schemaNode, scopeVariables));
}
function getComponent(schemaNodeName) {
return props2.components[schemaNodeName];
}
function parsePropsVModel(schemaNodeProps = {}) {
const newSchemaNodeProps = Object.entries(schemaNodeProps).reduce((newSchemaNodeProps2, [key, value]) => {
if (!key.startsWith("v-model")) {
newSchemaNodeProps2[key] = value;
return newSchemaNodeProps2;
}
const stateKey = key.startsWith("v-model:") ? key.replace("v-model:", "") : "modelValue";
const updateKey = `onUpdate:${stateKey}`;
newSchemaNodeProps2[stateKey] = value;
newSchemaNodeProps2[updateKey] = {
type: "Expression" /* EXPRESSION_BINDING */,
value: `(value) => { ${value.value} = value }`
};
return newSchemaNodeProps2;
}, {});
return newSchemaNodeProps;
}
function getPropsBinding(schemaNode, scopeVariables) {
var _a;
const rawProps = Object.entries(parsePropsVModel((_a = schemaNode.props) != null ? _a : {})).reduce((rawProps2, [key, value]) => {
rawProps2[key] = getBindingValue(value, scopeVariables);
return rawProps2;
}, {});
return rawProps;
}
function withCondition(schemaNodes, scopeVariables) {
return schemaNodes.filter((schemaNode) => {
var _a;
return !!getBindingValue((_a = schemaNode.if) != null ? _a : true, scopeVariables);
});
}
function renderSchemaNode(schemaNode, scopeVariables) {
if (!schemaNode.hasOwnProperty("for")) {
return renderVNode(schemaNode, scopeVariables);
}
const bindingValue = getBindingValue(schemaNode.for, scopeVariables);
return h(
Fragment,
null,
renderList(bindingValue, (item, index) => {
const clonedSchemaNode = cloneSchemaNode(schemaNode);
return renderVNode(
clonedSchemaNode,
createNewScopeVariables(scopeVariables, {
$item: __spreadProps(__spreadValues({}, scopeVariables.$item), {
[schemaNode.id]: item
}),
$index: __spreadProps(__spreadValues({}, scopeVariables.$index), {
[schemaNode.id]: index
})
})
);
})
);
}
function renderSchemaNodeSlots(schemaNode, scopeVariables) {
var _a;
try {
const slots = __spreadValues({}, (_a = schemaNode.slots) != null ? _a : {});
if (!slots.default && schemaNode.children) {
slots.default = {
children: [...schemaNode.children]
};
}
return Object.entries(slots).reduce((rawSlots, [slotName, slot]) => {
rawSlots[slotName] = (slotProps) => {
var _a2;
const newScopeVariables = createNewScopeVariables(scopeVariables, {
$slotProps: __spreadProps(__spreadValues({}, scopeVariables.$slotProps), {
[schemaNode.id]: slotProps
})
});
return withCondition((_a2 = slot.children) != null ? _a2 : [], newScopeVariables).map(
(schemaNode2) => renderSchemaNode(schemaNode2, newScopeVariables)
);
};
return rawSlots;
}, {});
} catch (e) {
console.error("Renderer error, please check console");
throw e;
}
}
return () => h("div", { class: "var-schema-renderer" }, renderSchemaNodeSlots(props2.schema, {}));
}
});
var SchemaRenderer = defineComponent({
props,
setup(props2) {
let oldCode = "";
let rendererKey = ref(0);
watch(() => props2.schema, (value) => {
var _a;
if (value.code !== oldCode) {
rendererKey.value++;
}
oldCode = (_a = value.code) != null ? _a : "";
}, { immediate: true });
return () => {
return h(Renderer, __spreadProps(__spreadValues({}, props2), { key: rendererKey.value }));
};
}
});
export {
BuiltInSchemaNodeBindingTypes,
BuiltInSchemaNodeNames,
SchemaRenderer,
cloneSchemaNode,
isExpressionBinding,
isObjectBinding,
isRenderBinding,
isSchemaPageNode,
isSchemaTextNode,
isVNodeBinding,
normalizeClasses
};