@ray-core/runtime
Version:
Ray 是一个全新的基于 React 的小程序开发框架
439 lines (438 loc) • 16.3 kB
JavaScript
var __values = (this && this.__values) || function(o) {
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
if (m) return m.call(o);
if (o && typeof o.length === "number") return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
};
var __read = (this && this.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
};
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
import { RuntimeOptions } from '@ray-core/framework-shared';
import propsAlias, { propAlias } from './propsAlias';
import { RAY_METHOD, TYPE_TEXT, RAY_METHOD_REGEXP } from './constants';
import { generate } from './instanceId';
import { typeOf } from './utils/typeOf';
import { parseHTML /* , svgVNodeToImage */ } from './utils/parseHTML';
import { gStore } from './gStore';
var isWrappedMethodByRay = function (k) { return RAY_METHOD_REGEXP.test(k); };
export function processProps(newProps, node) {
node.unregisteredCallbacks();
function h(newProps, node, parentKey) {
var e_1, _a;
if (parentKey === void 0) { parentKey = ''; }
var props = typeOf(newProps) === 'array' ? [] : {};
var _loop_1 = function (propKey) {
var value = newProps[propKey];
if (isWrappedMethodByRay(value)) {
value = gStore.getCallback(value);
}
var k = parentKey ? "".concat(parentKey, ".").concat(propKey) : propKey;
var t = typeOf(value);
if (propKey === 'children') {
// pass
}
else if (t === 'function') {
var id = node.registerCallback(k, value);
props[propKey] = id;
}
else if (t === 'object') {
props[propKey] = h(value, node, k);
}
else if (t === 'array') {
props[propKey] = value.map(function (item, index) {
var t1 = typeOf(item);
var k1 = parentKey ? "".concat(parentKey, ".").concat(propKey, ".").concat(index) : "".concat(propKey, ".").concat(index);
if (t1 === 'object' || t1 === 'array') {
return h(item, node, k1);
}
if (t1 === 'function') {
return node.registerCallback(k1, value);
}
return item;
});
}
else if (propKey === 'style') {
props[propKey] = value || '';
}
else {
props[propKey] = value;
}
};
try {
for (var _b = __values(Object.keys(newProps)), _c = _b.next(); !_c.done; _c = _b.next()) {
var propKey = _c.value;
_loop_1(propKey);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_1) throw e_1.error; }
}
return props;
}
return h(newProps, node);
}
function toRawNode(node, skip2html) {
var data;
if (node.type === TYPE_TEXT) {
data = {
id: node.id,
type: node.type,
text: node.text,
};
}
else {
data = {
id: node.id,
type: node.type,
props: node.props,
children: [],
text: node.text,
};
}
if (data.type === 'page-slot') {
return data;
}
var d = skip2html ? data : RuntimeOptions.get('pluginDriver').onVirtualNodeSerialize(data, false);
data = d || data;
data.props = propsAlias(data.props, data.type);
return data;
}
var VNode = /** @class */ (function () {
function VNode(_a) {
var type = _a.type, props = _a.props, container = _a.container;
this.mounted = false;
this.deleted = false;
this.parent = null;
this.callbackIds = new Set();
this.children = [];
this.id = generate();
this.container = container;
this.type = type;
if (props) {
props = processProps(props, this);
props.__instid__ = this.id;
}
this.props = props;
if (props && props.dangerouslySetInnerHTML) {
this.setInnerHTML(props.dangerouslySetInnerHTML.__html);
}
}
VNode.prototype.appendChild = function (node) {
var _this_1 = this;
node.parent = this;
node.deleted = false; // 交换节点时删除的节点会被复用
if (node.type === 'page-slot') {
this.container._pageSlot = node;
}
this.children = this.children.filter(function (c) { return c !== node; }); // 解决节点交换位置后,节点重复的问题
var slots = this.container.replaceSlot(this, node);
!slots && this.children.push(node);
if (this.isMounted()) {
if (slots) {
slots.forEach(function (slot) {
_this_1.container.requestUpdate({
type: 'splice',
path: _this_1.path,
id: slot.id,
children: _this_1.children,
raw: slot.toJSON(),
node: _this_1,
});
});
}
else {
this.container.requestUpdate({
type: 'splice',
path: this.path,
id: node.id,
children: this.children,
raw: node.toJSON(),
node: this,
});
}
}
};
VNode.prototype.removeChild = function (node) {
var _a;
if (node.type === 'page-slot') {
var c = this.container;
if (node.id === ((_a = c._pageSlot) === null || _a === void 0 ? void 0 : _a.id)) {
c._pageSlot = null;
}
}
if (node.parent !== this) {
return;
}
this.container.removeSlot(this, node);
node.deleted = true;
node.unregisteredCallbacks();
for (var n = 0; n < this.children.length; n++) {
var child = this.children[n];
if (child.id === node.id) {
this.children.splice(n, 1);
break;
}
}
if (this.isMounted()) {
this.container.requestUpdate({
type: 'splice',
path: this.path,
id: node.id,
children: this.children,
raw: null,
node: this,
});
}
};
VNode.prototype.insertBefore = function (node, referenceNode) {
var _this_1 = this;
if (node.type === 'page-slot') {
this.container._pageSlot = node;
}
node.parent = this;
node.deleted = false; // 交换节点时删除的节点会被复用
this.children = this.children.filter(function (c) { return c !== node; });
var children = [].concat(this.children);
var slots;
for (var n = 0; n < children.length; n++) {
var child = children[n];
if (child.id === referenceNode.id) {
slots = this.container.replaceSlot(this, node, n);
!slots && this.children.splice(n, 0, node);
break;
}
}
if (this.isMounted()) {
if (slots) {
slots.forEach(function (slot) {
_this_1.container.requestUpdate({
type: 'splice',
path: _this_1.path,
id: slot.id,
children: _this_1.children,
raw: slot.toJSON(),
node: _this_1,
});
});
}
else {
this.container.requestUpdate({
type: 'splice',
path: this.path,
id: node.id,
children: this.children,
raw: node.toJSON(),
node: this,
});
}
}
};
// todo 需要注意安全
VNode.prototype.setInnerHTML = function (html) {
var _this_1 = this;
var container = this.container;
var data = html ? parseHTML(html) : [];
var fn = function (item, parent) {
item = RuntimeOptions.get('pluginDriver').onSetInnerHTML(item);
if (item === null || item === undefined) {
return;
}
var type;
var props;
if (typeof item === 'string') {
type = TYPE_TEXT;
props = null;
}
else {
type = item.type;
props = item.props;
}
var node = new VNode({ type: type, props: props, container: container });
if (typeof item === 'string') {
node.text = item;
}
else {
var children = (item.children || []).map(function (x) { return fn(x, node); });
node.children = children.filter(function (x) { return x; });
}
node.parent = parent;
return node;
};
this.children = data.map(function (x) { return fn(x, _this_1); }).filter(function (x) { return x; });
};
VNode.prototype.update = function (payload) {
var _a;
var _this_1 = this;
if (this.type === 'text' || !payload) {
var slots = this.container.replaceSlot(this.parent, this);
if (slots) {
var _this_2 = this.parent;
slots.forEach(function (slot) {
_this_1.container.requestUpdate({
type: 'splice',
path: _this_2.path,
id: slot.id,
children: _this_2.children,
raw: slot.toJSON(),
node: _this_2,
});
});
}
else {
this.container.requestUpdate({
type: 'splice',
// root 不会更新,所以肯定有 parent
path: this.parent.path,
id: this.id,
raw: this.toJSON(),
node: this,
});
}
return;
}
var parentPath = this.parent.path;
for (var i = 0; i < payload.length; i = i + 2) {
var data = {
id: this.id,
type: this.type,
props: (_a = {}, _a[payload[i]] = payload[i + 1], _a),
};
data = RuntimeOptions.get('pluginDriver').onVirtualNodeSerialize(data, true) || data;
var keyAndValue = Object.entries(data.props)[0];
var _b = __read(propAlias(keyAndValue[0], keyAndValue[1], data.type), 2), propName = _b[0], propValue = _b[1];
var path = __spreadArray(__spreadArray([], __read(parentPath), false), ['nodes', this.id.toString(), 'props'], false);
if (RuntimeOptions.get('platform') === 'ali') {
var index = this.parent.children.indexOf(this);
path = __spreadArray(__spreadArray([], __read(parentPath), false), ["children[".concat(index, "].props")], false);
}
if (propName === 'dangerouslySetInnerHTML') {
this.setInnerHTML(propValue.__html);
}
this.container.requestUpdate({
type: 'set',
path: path,
name: propName,
value: propValue,
node: this,
});
}
};
Object.defineProperty(VNode.prototype, "path", {
get: function () {
var dataPath = [];
var parents = [];
var parent = this.parent;
while (parent) {
parents.unshift(parent);
parent = parent.parent;
}
for (var i = 0; i < parents.length; i++) {
var child = parents[i + 1] || this;
if (RuntimeOptions.get('platform') === 'ali') {
dataPath.push('children');
var index = child.parent.children.indexOf(child);
dataPath.push(index.toString());
}
else {
dataPath.push('nodes');
dataPath.push(child.id.toString());
}
}
return dataPath;
},
enumerable: false,
configurable: true
});
VNode.prototype.isMounted = function () {
return this.parent ? this.parent.isMounted() : this.mounted;
};
VNode.prototype.isDeleted = function () {
var _a, _b;
return this.deleted === true ? this.deleted : (_b = (_a = this.parent) === null || _a === void 0 ? void 0 : _a.isDeleted()) !== null && _b !== void 0 ? _b : false;
};
VNode.prototype.registerCallback = function (propKey, propValue) {
var _a;
// 传递的函数包含在数组中
var index = (_a = propKey.match(/\.(\d+)$/)) === null || _a === void 0 ? void 0 : _a[1];
if (index) {
index = Number(index);
}
var id = "".concat(RAY_METHOD, "_").concat(this.id, "_").concat(propKey);
this.callbackIds.add(id);
this.container.createCallback(id, propKey, this, index ? propValue[index] : propValue);
return id;
};
VNode.prototype.unregisteredCallbacks = function () {
var _this_1 = this;
this.callbackIds.forEach(function (id) {
_this_1.container.removeCallback(id);
});
};
VNode.prototype.toJSON = function (skip2html) {
var stack = [];
var rawNode = toRawNode(this, skip2html);
stack.push({
current: rawNode,
children: this.children,
});
while (stack.length > 0) {
// while 循环已经保证了不会有空值
var stackItem = stack.pop();
var _a = stackItem.children, children = _a === void 0 ? [] : _a, current = stackItem.current;
for (var i = children.length - 1; i >= 0; i--) {
var item = children[i];
var currentRawNode = toRawNode(item, skip2html);
if (RuntimeOptions.get('platform') !== 'ali') {
current.children.unshift(currentRawNode.id);
}
else {
current.children.unshift(currentRawNode);
}
if (RuntimeOptions.get('platform') !== 'ali') {
if (!current.nodes) {
current.nodes = {};
}
current.nodes[currentRawNode.id] = currentRawNode;
}
stack.push({
current: currentRawNode,
children: item.children,
});
}
}
return rawNode;
};
return VNode;
}());
export default VNode;