@esportsplus/template 0.16.1 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/attributes.js +29 -24
- package/build/constants.d.ts +13 -3
- package/build/constants.js +14 -4
- package/build/event.js +48 -46
- package/build/html/hydrate.d.ts +2 -8
- package/build/html/hydrate.js +28 -79
- package/build/html/index.d.ts +2106 -5
- package/build/html/index.js +12 -4
- package/build/html/{cache.d.ts → parser.d.ts} +1 -1
- package/build/html/{cache.js → parser.js} +6 -4
- package/build/render.d.ts +1 -2
- package/build/render.js +7 -10
- package/build/slot/cleanup.d.ts +4 -0
- package/build/slot/cleanup.js +52 -0
- package/build/slot/effect.d.ts +3 -0
- package/build/slot/effect.js +56 -0
- package/build/slot/index.d.ts +3 -0
- package/build/slot/index.js +8 -0
- package/build/slot/reactive.d.ts +3 -0
- package/build/slot/reactive.js +125 -0
- package/build/slot/render.d.ts +2 -0
- package/build/slot/render.js +81 -0
- package/build/svg.d.ts +1 -2
- package/build/types.d.ts +21 -17
- package/build/utilities/element.d.ts +11 -0
- package/build/utilities/element.js +9 -0
- package/build/utilities/fragment.d.ts +3 -0
- package/build/utilities/fragment.js +11 -0
- package/build/utilities/node.d.ts +8 -0
- package/build/utilities/node.js +9 -0
- package/build/utilities/queue.d.ts +3 -0
- package/build/utilities/queue.js +4 -0
- package/build/utilities/text.d.ts +3 -0
- package/build/utilities/text.js +9 -0
- package/package.json +2 -2
- package/src/attributes.ts +32 -29
- package/src/constants.ts +32 -5
- package/src/event.ts +55 -52
- package/src/html/hydrate.ts +36 -108
- package/src/html/index.ts +16 -8
- package/src/html/{cache.ts → parser.ts} +5 -3
- package/src/render.ts +8 -12
- package/src/slot/cleanup.ts +74 -0
- package/src/slot/effect.ts +74 -0
- package/src/slot/index.ts +12 -0
- package/src/slot/reactive.ts +177 -0
- package/src/slot/render.ts +117 -0
- package/src/svg.ts +1 -2
- package/src/types.ts +25 -18
- package/src/utilities/element.ts +28 -0
- package/src/utilities/fragment.ts +22 -0
- package/src/utilities/node.ts +26 -0
- package/src/utilities/queue.ts +9 -0
- package/src/utilities/text.ts +16 -0
- package/build/slot.d.ts +0 -21
- package/build/slot.js +0 -204
- package/build/utilities.d.ts +0 -28
- package/build/utilities.js +0 -37
- package/src/slot.ts +0 -277
- package/src/utilities.ts +0 -87
package/build/attributes.js
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import { effect } from '@esportsplus/reactivity';
|
|
2
|
-
import { isArray,
|
|
3
|
-
import { ondisconnect } from './slot.js';
|
|
4
|
-
import {
|
|
2
|
+
import { isArray, isObject, isString } from '@esportsplus/utilities';
|
|
3
|
+
import { ondisconnect } from './slot/cleanup.js';
|
|
4
|
+
import { STATE_HYDRATING, STATE_NONE, STATE_WAITING } from './constants.js';
|
|
5
|
+
import { className, removeAttribute, setAttribute } from './utilities/element.js';
|
|
6
|
+
import { raf } from './utilities/queue.js';
|
|
5
7
|
import q from '@esportsplus/queue';
|
|
6
8
|
import event from './event.js';
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const STATE_HYDRATING = 0;
|
|
11
|
-
const STATE_NONE = 1;
|
|
12
|
-
const STATE_WAITING = 2;
|
|
9
|
+
const EFFECT = Symbol();
|
|
10
|
+
const STORE = Symbol();
|
|
11
|
+
const UPDATES = Symbol();
|
|
13
12
|
let delimiters = {
|
|
14
13
|
class: ' ',
|
|
15
14
|
style: ';'
|
|
@@ -36,18 +35,17 @@ function schedule() {
|
|
|
36
35
|
raf.add(task);
|
|
37
36
|
}
|
|
38
37
|
function set(context, name, value, state) {
|
|
39
|
-
if (
|
|
40
|
-
|
|
41
|
-
set(context, name, value[i], state);
|
|
42
|
-
}
|
|
38
|
+
if (value === false || value == null) {
|
|
39
|
+
value = '';
|
|
43
40
|
}
|
|
44
|
-
|
|
41
|
+
let type = typeof value;
|
|
42
|
+
if (type === 'function') {
|
|
45
43
|
if (name.startsWith('on')) {
|
|
46
44
|
event(context.element, name, value);
|
|
47
45
|
}
|
|
48
46
|
else {
|
|
49
|
-
context.store[
|
|
50
|
-
let id = context.store[
|
|
47
|
+
context.store[EFFECT] ??= 0;
|
|
48
|
+
let id = context.store[EFFECT]++;
|
|
51
49
|
ondisconnect(context.element, effect(() => {
|
|
52
50
|
let v = value(context.element);
|
|
53
51
|
if (isArray(v)) {
|
|
@@ -65,6 +63,13 @@ function set(context, name, value, state) {
|
|
|
65
63
|
state = STATE_NONE;
|
|
66
64
|
}
|
|
67
65
|
}
|
|
66
|
+
else if (type === 'object') {
|
|
67
|
+
if (isArray(value)) {
|
|
68
|
+
for (let i = 0, n = value.length; i < n; i++) {
|
|
69
|
+
set(context, name, value[i], state);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
68
73
|
else {
|
|
69
74
|
update(context, null, name, value, state);
|
|
70
75
|
}
|
|
@@ -153,13 +158,18 @@ function update(context, id, name, value, state) {
|
|
|
153
158
|
}
|
|
154
159
|
}
|
|
155
160
|
const spread = function (element, value) {
|
|
156
|
-
let cache = (element[
|
|
161
|
+
let cache = (element[STORE] ??= { [UPDATES]: {} }), context = {
|
|
157
162
|
element,
|
|
158
163
|
store: cache,
|
|
159
|
-
updates: cache[
|
|
164
|
+
updates: cache[UPDATES],
|
|
160
165
|
updating: false
|
|
161
166
|
};
|
|
162
|
-
if (
|
|
167
|
+
if (isObject(value)) {
|
|
168
|
+
for (let name in value) {
|
|
169
|
+
set(context, name, value[name], STATE_HYDRATING);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
else if (isArray(value)) {
|
|
163
173
|
for (let i = 0, n = value.length; i < n; i++) {
|
|
164
174
|
let v = value[i];
|
|
165
175
|
for (let name in v) {
|
|
@@ -167,11 +177,6 @@ const spread = function (element, value) {
|
|
|
167
177
|
}
|
|
168
178
|
}
|
|
169
179
|
}
|
|
170
|
-
else if (isObject(value)) {
|
|
171
|
-
for (let name in value) {
|
|
172
|
-
set(context, name, value[name], STATE_HYDRATING);
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
180
|
};
|
|
176
181
|
export default { spread };
|
|
177
182
|
export { spread };
|
package/build/constants.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
declare const CLEANUP: unique symbol;
|
|
1
2
|
declare const EMPTY_FRAGMENT: DocumentFragment;
|
|
2
3
|
declare const NODE_CLOSING = 1;
|
|
3
4
|
declare const NODE_ELEMENT = 3;
|
|
@@ -7,9 +8,18 @@ declare const NODE_WHITELIST: Record<string, number>;
|
|
|
7
8
|
declare const REGEX_EMPTY_TEXT_NODES: RegExp;
|
|
8
9
|
declare const REGEX_SLOT_NODES: RegExp;
|
|
9
10
|
declare const RENDERABLE: unique symbol;
|
|
10
|
-
declare const
|
|
11
|
-
declare const
|
|
11
|
+
declare const RENDERABLE_ARRAY = 0;
|
|
12
|
+
declare const RENDERABLE_FRAGMENT = 1;
|
|
13
|
+
declare const RENDERABLE_HTML_FRAGMENT = 2;
|
|
14
|
+
declare const RENDERABLE_HTML_REACTIVE_ARRAY = 3;
|
|
15
|
+
declare const RENDERABLE_NODE = 4;
|
|
16
|
+
declare const RENDERABLE_NODE_LIST = 5;
|
|
17
|
+
declare const RENDERABLE_TEXT = 6;
|
|
18
|
+
declare const RENDERABLE_VOID = 7;
|
|
12
19
|
declare const SLOT_HTML = "<!--$-->";
|
|
13
20
|
declare const SLOT_MARKER = "{{$}}";
|
|
14
21
|
declare const SLOT_MARKER_LENGTH: number;
|
|
15
|
-
|
|
22
|
+
declare const STATE_HYDRATING = 0;
|
|
23
|
+
declare const STATE_NONE = 1;
|
|
24
|
+
declare const STATE_WAITING = 2;
|
|
25
|
+
export { CLEANUP, EMPTY_FRAGMENT, NODE_CLOSING, NODE_ELEMENT, NODE_SLOT, NODE_VOID, NODE_WHITELIST, REGEX_EMPTY_TEXT_NODES, REGEX_SLOT_NODES, RENDERABLE, RENDERABLE_ARRAY, RENDERABLE_FRAGMENT, RENDERABLE_HTML_FRAGMENT, RENDERABLE_HTML_REACTIVE_ARRAY, RENDERABLE_NODE, RENDERABLE_NODE_LIST, RENDERABLE_TEXT, RENDERABLE_VOID, SLOT_HTML, SLOT_MARKER, SLOT_MARKER_LENGTH, STATE_HYDRATING, STATE_NONE, STATE_WAITING };
|
package/build/constants.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { fragment } from './utilities.js';
|
|
1
|
+
import { fragment } from './utilities/fragment.js';
|
|
2
|
+
const CLEANUP = Symbol();
|
|
2
3
|
const EMPTY_FRAGMENT = fragment('');
|
|
3
4
|
const NODE_CLOSING = 1;
|
|
4
5
|
const NODE_COMMENT = 2;
|
|
@@ -28,9 +29,18 @@ const NODE_WHITELIST = {
|
|
|
28
29
|
const REGEX_EMPTY_TEXT_NODES = /(>|})\s+(<|{)/g;
|
|
29
30
|
const REGEX_SLOT_NODES = /<([\w-]+|[\/!])(?:([^><]*{{\$}}[^><]*)|(?:[^><]*))?>|{{\$}}/g;
|
|
30
31
|
const RENDERABLE = Symbol();
|
|
31
|
-
const
|
|
32
|
-
const
|
|
32
|
+
const RENDERABLE_ARRAY = 0;
|
|
33
|
+
const RENDERABLE_FRAGMENT = 1;
|
|
34
|
+
const RENDERABLE_HTML_FRAGMENT = 2;
|
|
35
|
+
const RENDERABLE_HTML_REACTIVE_ARRAY = 3;
|
|
36
|
+
const RENDERABLE_NODE = 4;
|
|
37
|
+
const RENDERABLE_NODE_LIST = 5;
|
|
38
|
+
const RENDERABLE_TEXT = 6;
|
|
39
|
+
const RENDERABLE_VOID = 7;
|
|
33
40
|
const SLOT_HTML = '<!--$-->';
|
|
34
41
|
const SLOT_MARKER = '{{$}}';
|
|
35
42
|
const SLOT_MARKER_LENGTH = SLOT_MARKER.length;
|
|
36
|
-
|
|
43
|
+
const STATE_HYDRATING = 0;
|
|
44
|
+
const STATE_NONE = 1;
|
|
45
|
+
const STATE_WAITING = 2;
|
|
46
|
+
export { CLEANUP, EMPTY_FRAGMENT, NODE_CLOSING, NODE_ELEMENT, NODE_SLOT, NODE_VOID, NODE_WHITELIST, REGEX_EMPTY_TEXT_NODES, REGEX_SLOT_NODES, RENDERABLE, RENDERABLE_ARRAY, RENDERABLE_FRAGMENT, RENDERABLE_HTML_FRAGMENT, RENDERABLE_HTML_REACTIVE_ARRAY, RENDERABLE_NODE, RENDERABLE_NODE_LIST, RENDERABLE_TEXT, RENDERABLE_VOID, SLOT_HTML, SLOT_MARKER, SLOT_MARKER_LENGTH, STATE_HYDRATING, STATE_NONE, STATE_WAITING };
|
package/build/event.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { root } from '@esportsplus/reactivity';
|
|
2
2
|
import { defineProperty } from '@esportsplus/utilities';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { addEventListener } from './utilities/element.js';
|
|
4
|
+
import { parentElement } from './utilities/node.js';
|
|
5
|
+
import { raf } from './utilities/queue.js';
|
|
6
|
+
import { ondisconnect } from './slot/cleanup.js';
|
|
5
7
|
let capture = new Set(['onblur', 'onfocus', 'onscroll']), controllers = new Map(), keys = {}, passive = new Set([
|
|
6
8
|
'onmousedown', 'onmouseenter', 'onmouseleave', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onmousewheel',
|
|
7
9
|
'onscroll',
|
|
@@ -11,6 +13,49 @@ let capture = new Set(['onblur', 'onfocus', 'onscroll']), controllers = new Map(
|
|
|
11
13
|
['onmousemove', 'onmousewheel', 'onscroll', 'ontouchend', 'ontouchmove', 'ontouchstart', 'onwheel'].map(event => {
|
|
12
14
|
controllers.set(event, null);
|
|
13
15
|
});
|
|
16
|
+
function register(element, event) {
|
|
17
|
+
let controller = controllers.get(event), signal;
|
|
18
|
+
if (controller === null) {
|
|
19
|
+
let { abort, signal } = new AbortController();
|
|
20
|
+
controllers.set(event, controller = {
|
|
21
|
+
abort,
|
|
22
|
+
signal,
|
|
23
|
+
listeners: 0,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
if (controller) {
|
|
27
|
+
controller.listeners++;
|
|
28
|
+
ondisconnect(element, () => {
|
|
29
|
+
if (--controller.listeners) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
controller.abort();
|
|
33
|
+
controllers.set(event, null);
|
|
34
|
+
});
|
|
35
|
+
signal = controller.signal;
|
|
36
|
+
}
|
|
37
|
+
let key = keys[event] = Symbol();
|
|
38
|
+
addEventListener.call(window.document, event.slice(2), (e) => {
|
|
39
|
+
let node = e.target;
|
|
40
|
+
while (node) {
|
|
41
|
+
if (key in node) {
|
|
42
|
+
defineProperty(e, 'currentTarget', {
|
|
43
|
+
configurable: true,
|
|
44
|
+
get() {
|
|
45
|
+
return node || window.document;
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
return node[key].call(node, e);
|
|
49
|
+
}
|
|
50
|
+
node = parentElement.call(node);
|
|
51
|
+
}
|
|
52
|
+
}, {
|
|
53
|
+
capture: capture.has(event),
|
|
54
|
+
passive: passive.has(event),
|
|
55
|
+
signal
|
|
56
|
+
});
|
|
57
|
+
return key;
|
|
58
|
+
}
|
|
14
59
|
export default (element, event, listener) => {
|
|
15
60
|
if (event === 'onconnect') {
|
|
16
61
|
let retry = 60, task = () => {
|
|
@@ -34,48 +79,5 @@ export default (element, event, listener) => {
|
|
|
34
79
|
root(() => listener(element));
|
|
35
80
|
return;
|
|
36
81
|
}
|
|
37
|
-
|
|
38
|
-
if (controller === null) {
|
|
39
|
-
let { abort, signal } = new AbortController();
|
|
40
|
-
controllers.set(event, controller = {
|
|
41
|
-
abort,
|
|
42
|
-
signal,
|
|
43
|
-
listeners: 0,
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
if (controller) {
|
|
47
|
-
controller.listeners++;
|
|
48
|
-
ondisconnect(element, () => {
|
|
49
|
-
if (--controller.listeners) {
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
controller.abort();
|
|
53
|
-
controllers.set(event, null);
|
|
54
|
-
});
|
|
55
|
-
signal = controller.signal;
|
|
56
|
-
}
|
|
57
|
-
let key = keys[event];
|
|
58
|
-
if (!key) {
|
|
59
|
-
key = keys[event] = Symbol();
|
|
60
|
-
addEventListener.call(window.document, event.slice(2), (e) => {
|
|
61
|
-
let node = e.target;
|
|
62
|
-
defineProperty(e, 'currentTarget', {
|
|
63
|
-
configurable: true,
|
|
64
|
-
get() {
|
|
65
|
-
return node || window.document;
|
|
66
|
-
}
|
|
67
|
-
});
|
|
68
|
-
while (node) {
|
|
69
|
-
if (key in node) {
|
|
70
|
-
return node[key].call(node, e);
|
|
71
|
-
}
|
|
72
|
-
node = parentElement.call(node);
|
|
73
|
-
}
|
|
74
|
-
}, {
|
|
75
|
-
capture: capture.has(event),
|
|
76
|
-
passive: passive.has(event),
|
|
77
|
-
signal
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
element[key] = listener;
|
|
82
|
+
element[keys[event] || register(element, event)] = listener;
|
|
81
83
|
};
|
package/build/html/hydrate.d.ts
CHANGED
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
declare function reactive<T>(elements: Elements[], fragment: Fragment, renderable: RenderableReactive<T>, slot: Slot): void;
|
|
4
|
-
declare function hydrate<T>(elements: Elements[] | null, fragment: Fragment, renderable: RenderableTemplate<T>): void;
|
|
5
|
-
declare const _default: {
|
|
6
|
-
reactive: typeof reactive;
|
|
7
|
-
static: typeof hydrate;
|
|
8
|
-
};
|
|
1
|
+
import { Fragment, RenderableValues, Template } from '../types.js';
|
|
2
|
+
declare const _default: ({ fragment, slots }: Template, values: RenderableValues[]) => Fragment;
|
|
9
3
|
export default _default;
|
package/build/html/hydrate.js
CHANGED
|
@@ -1,85 +1,34 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
slot.
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}, template = function (data, i) {
|
|
16
|
-
hydrate(elements, fragment, factory.call(this, data, i));
|
|
17
|
-
};
|
|
18
|
-
array.on('clear', () => slot.clear());
|
|
19
|
-
array.on('pop', () => slot.pop());
|
|
20
|
-
array.on('reverse', refresh);
|
|
21
|
-
array.on('shift', () => slot.shift());
|
|
22
|
-
array.on('sort', refresh);
|
|
23
|
-
array.on('push', ({ items }) => {
|
|
24
|
-
let anchor = slot.anchor();
|
|
25
|
-
elements = slot.nodes;
|
|
26
|
-
root(() => array.map(template, array.length - items.length));
|
|
27
|
-
anchor.after(fragment);
|
|
28
|
-
reset();
|
|
29
|
-
});
|
|
30
|
-
array.on('splice', ({ deleteCount: d, items: i, start: s }) => {
|
|
31
|
-
if (array.length === 0) {
|
|
32
|
-
slot.clear();
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
root(() => array.map(template, s, i.length));
|
|
36
|
-
slot.splice(s, d, fragment, ...elements);
|
|
37
|
-
reset();
|
|
38
|
-
});
|
|
39
|
-
array.on('unshift', ({ items }) => {
|
|
40
|
-
root(() => array.map(template, 0, items.length));
|
|
41
|
-
slot.unshift(fragment, ...elements);
|
|
42
|
-
reset();
|
|
43
|
-
});
|
|
44
|
-
root(() => array.map(template));
|
|
45
|
-
reset();
|
|
46
|
-
}
|
|
47
|
-
function hydrate(elements, fragment, renderable) {
|
|
48
|
-
let { fragment: frag, slots } = cache.get(renderable.literals), clone = cloneNode.call(frag, true);
|
|
49
|
-
if (slots !== null) {
|
|
50
|
-
let node, nodePath, parent, parentPath, values = renderable.values;
|
|
51
|
-
for (let i = 0, n = slots.length; i < n; i++) {
|
|
52
|
-
let { fn, path, slot } = slots[i], pp = path.parent, pr = path.relative;
|
|
53
|
-
if (pp !== parentPath) {
|
|
54
|
-
if (pp === nodePath) {
|
|
55
|
-
parent = node;
|
|
56
|
-
parentPath = nodePath;
|
|
57
|
-
nodePath = undefined;
|
|
58
|
-
}
|
|
59
|
-
else {
|
|
60
|
-
parent = clone;
|
|
61
|
-
parentPath = pp;
|
|
62
|
-
for (let o = 0, j = pp.length; o < j; o++) {
|
|
63
|
-
parent = pp[o].call(parent);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
1
|
+
import { cloneNode } from '../utilities/node.js';
|
|
2
|
+
export default ({ fragment, slots }, values) => {
|
|
3
|
+
let clone = cloneNode.call(fragment, true);
|
|
4
|
+
if (slots === null) {
|
|
5
|
+
return clone;
|
|
6
|
+
}
|
|
7
|
+
let node, nodePath, parent, parentPath;
|
|
8
|
+
for (let i = 0, n = slots.length; i < n; i++) {
|
|
9
|
+
let { fn, path, slot } = slots[i], pp = path.parent, pr = path.relative;
|
|
10
|
+
if (pp !== parentPath) {
|
|
11
|
+
if (pp === nodePath) {
|
|
12
|
+
parent = node;
|
|
13
|
+
parentPath = nodePath;
|
|
14
|
+
nodePath = undefined;
|
|
66
15
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
for (let
|
|
71
|
-
|
|
16
|
+
else {
|
|
17
|
+
parent = clone;
|
|
18
|
+
parentPath = pp;
|
|
19
|
+
for (let i = 0, n = pp.length; i < n; i++) {
|
|
20
|
+
parent = pp[i].call(parent);
|
|
72
21
|
}
|
|
73
22
|
}
|
|
74
|
-
fn(node, values[slot]);
|
|
75
23
|
}
|
|
24
|
+
if (pr !== nodePath) {
|
|
25
|
+
node = parent;
|
|
26
|
+
nodePath = path.absolute;
|
|
27
|
+
for (let i = 0, n = pr.length; i < n; i++) {
|
|
28
|
+
node = pr[i].call(node);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
fn(node, values[slot]);
|
|
76
32
|
}
|
|
77
|
-
|
|
78
|
-
elements.push([...clone.childNodes]);
|
|
79
|
-
}
|
|
80
|
-
fragment.appendChild(clone);
|
|
81
|
-
}
|
|
82
|
-
export default {
|
|
83
|
-
reactive,
|
|
84
|
-
static: hydrate
|
|
33
|
+
return clone;
|
|
85
34
|
};
|