UNPKG

gl-react

Version:

Universal React library, write and compose WebGL shaders, implement complex effects using a descriptive paradigm

781 lines (772 loc) 26.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _invariant = _interopRequireDefault(require("invariant")); var _react = _interopRequireWildcard(require("react")); var _propTypes = _interopRequireDefault(require("prop-types")); var _typedarrayPool = _interopRequireDefault(require("typedarray-pool")); var _ndarray = _interopRequireDefault(require("ndarray")); var _Uniform = _interopRequireDefault(require("./Uniform")); var _Bus = _interopRequireDefault(require("./Bus")); var _Shaders = _interopRequireWildcard(require("./Shaders")); var _invariantNoDependentsLoop = _interopRequireDefault(require("./helpers/invariantNoDependentsLoop")); var _genId = _interopRequireDefault(require("./genId")); var _GLContext = _interopRequireDefault(require("./GLContext")); function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); } function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } const blendFuncAliases = { zero: "ZERO", one: "ONE", "src color": "SRC_COLOR", "one minus src color": "ONE_MINUS_SRC_COLOR", "src alpha": "SRC_ALPHA", "one minus src alpha": "ONE_MINUS_SRC_ALPHA", "dst color": "DST_COLOR", "one minus dst color": "ONE_MINUS_DST_COLOR", "dst alpha": "DST_ALPHA", "one minus dst alpha": "ONE_MINUS_DST_ALPHA", "constant color": "CONSTANT_COLOR", "one minus constant color": "ONE_MINUS_CONSTANT_COLOR", "constant alpha": "CONSTANT_ALPHA", "one minus constant alpha": "ONE_MINUS_CONSTANT_ALPHA", "src alpha saturate": "SRC_ALPHA_SATURATE" }; const isBackbuffer = obj => { if (obj === "Backbuffer") { console.warn('Backbuffer is deprecated, use Uniform.Backbuffer instead: `import {Uniform} from "gl-react"`'); return true; } return obj === _Uniform.default.Backbuffer; }; const isBackbufferFrom = obj => obj && typeof obj === "object" && obj.type === "BackbufferFrom"; const isTextureSizeGetter = obj => obj && typeof obj === "object" && obj.type === "TextureSize"; const nodeWidthHeight = ({ width, height }, { glSizable }) => { if (width && height) return [width, height]; const [cw, ch] = glSizable.getGLSize(); return [width || cw, height || ch]; }; const mapBlendFunc = (gl, name) => { if (name in gl) return gl[name]; if (name in blendFuncAliases) { const id = blendFuncAliases[name]; if (id in gl) return gl[id]; } console.warn("Invalid blendFunc. Got:", name); }; const parseWrap = (gl, w) => { switch (w) { case "clamp to edge": return gl.CLAMP_TO_EDGE; case "repeat": return gl.REPEAT; case "mirrored repeat": return gl.MIRRORED_REPEAT; default: console.warn("Invalid wrap. Got:", w); return gl.CLAMP_TO_EDGE; } }; const mergeArrays = (a, b) => { const t = []; const length = Math.max(a.length, b.length); for (let i = 0; i < length; i++) { t[i] = b[i] || a[i]; } return t; }; const parseInterpolation = (gl, i) => { switch (i) { case "linear": return gl.LINEAR; case "nearest": return gl.NEAREST; default: console.warn("Invalid interpolation. Got:", i); return gl.LINEAR; } }; // minimal version of gl-fbo const createFBO = (gl, width, height) => { var handle = gl.createFramebuffer(); gl.bindFramebuffer(gl.FRAMEBUFFER, handle); var color = gl.createTexture(); if (!color) throw new Error("createTexture returned null"); gl.bindTexture(gl.TEXTURE_2D, color); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, color, 0); return { handle, color, bind: () => { gl.bindFramebuffer(gl.FRAMEBUFFER, handle); gl.viewport(0, 0, width, height); }, syncSize: (w, h) => { if (w !== width || h !== height) { width = w; height = h; gl.bindTexture(gl.TEXTURE_2D, color); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, w, h, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); } }, dispose: () => { gl.deleteFramebuffer(handle); gl.deleteTexture(color); } }; }; const defaultTextureOptions = { interpolation: "linear", wrap: ["clamp to edge", "clamp to edge"] }; const applyTextureOptions = (gl, partialOpts) => { const opts = { ...defaultTextureOptions, ...partialOpts }; let filter = parseInterpolation(gl, opts.interpolation); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, filter); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, filter); let wrapS, wrapT; if (Array.isArray(opts.wrap)) { if (opts.wrap.length !== 2) { console.warn("textureOptions wrap: should be an array of 2 values. Got:", opts.wrap); wrapS = wrapT = gl.CLAMP_TO_EDGE; } else { wrapS = parseWrap(gl, opts.wrap[0]); wrapT = parseWrap(gl, opts.wrap[1]); } } else { wrapS = wrapT = parseWrap(gl, opts.wrap); } gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, wrapS); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, wrapT); }; const NodePropTypes = { shader: _propTypes.default.object.isRequired, uniformsOptions: _propTypes.default.object, uniforms: _propTypes.default.object, ignoreUnusedUniforms: _propTypes.default.any, sync: _propTypes.default.bool, width: _propTypes.default.number, height: _propTypes.default.number, children: _propTypes.default.any, backbuffering: _propTypes.default.bool, blendFunc: _propTypes.default.object, clear: _propTypes.default.object, onDraw: _propTypes.default.func }; /** * `<Node>` is the primitive that renders a shader program into a Framebuffer. * It can be composed with other `Node` via using a sampler2D uniforms. */ class Node extends _react.Component { drawProps = this.props; framebuffer; backbuffer; _needsRedraw = false; capturePixelsArray; id = (0, _genId.default)(); uniformsBus = {}; dependencies = []; // Node this instance depends on dependents = []; // Node/Surface that depends on this instance static propTypes = NodePropTypes; static defaultProps = { uniformsOptions: {}, uniforms: {}, blendFunc: { src: "src alpha", dst: "one minus src alpha" }, clear: { color: [0, 0, 0, 0] } }; static contextType = _GLContext.default; componentDidMount() { const { glSurface: { gl } } = this.context; if (gl) this._prepareGLObjects(gl); this.context.glParent._addGLNodeChild(this); this.redraw(); if (this.props.sync) this.flush(); } componentWillUnmount() { const { capturePixelsArray } = this; this._destroyGLObjects(); if (capturePixelsArray) { _typedarrayPool.default.freeUint8(capturePixelsArray); } this._needsRedraw = false; this.context.glParent._removeGLNodeChild(this); this.dependencies.forEach(d => d._removeDependent(this)); } _syncNextDrawProps(nextProps, nextContext) { const nextWidthHeight = nodeWidthHeight(nextProps, nextContext); if (this.framebuffer) { this.framebuffer.syncSize(...nextWidthHeight); } if (this.backbuffer) { this.backbuffer.syncSize(...nextWidthHeight); } (0, _invariant.default)(nextProps.backbuffering === this.drawProps.backbuffering, "Node backbuffering prop must not changed. (not yet supported)"); this.drawProps = nextProps; } _resolveElement = (uniform, value, index) => { if (! /*#__PURE__*/_react.default.isValidElement(value)) { if (typeof value === "function") { value = value(this.redraw); if (! /*#__PURE__*/_react.default.isValidElement(value)) { return; // the function don't return an Element, skip } } else { return; // the value isn't an Element, skip } } return /*#__PURE__*/_react.default.createElement(_Bus.default, { key: uniform + (index ? "." + index : ""), uniform: uniform, index: index }, value); }; _renderUniformElement = key => { const { uniforms } = this.props; let value = uniforms[key]; return Array.isArray(value) ? value.map((v, i) => this._resolveElement(key, v, i)) : this._resolveElement(key, value, 0); }; render() { const { children, uniforms } = this.props; const { glSurface: { RenderLessElement } } = this.context; return /*#__PURE__*/_react.default.createElement(_GLContext.default.Provider, { value: { glParent: this, glSurface: this.context.glSurface, glSizable: this } }, /*#__PURE__*/_react.default.createElement(RenderLessElement, null, children, Object.keys(uniforms).map(this._renderUniformElement))); } componentDidUpdate() { this._syncNextDrawProps(this.props, this.context); this.redraw(); if (this.props.sync) this.flush(); } getGLShortName() { const { shader } = this.drawProps; const shaderName = (0, _Shaders.isShaderIdentifier)(shader) ? _Shaders.default.getShortName(shader) : "<inline>"; return `Node(${shaderName})`; } getGLName() { const { shader } = this.drawProps; const shaderName = (0, _Shaders.isShaderIdentifier)(shader) ? _Shaders.default.getName(shader) : "<inline>"; return `Node#${this.id}(${shaderName})`; } getGLSize() { return nodeWidthHeight(this.drawProps, this.context); } getGLOutput() { const { framebuffer } = this; (0, _invariant.default)(framebuffer, "Node#getGLOutput: framebuffer is not defined. It cannot be called on a root Node"); return framebuffer.color; } getGLBackbufferOutput() { const { backbuffer } = this; (0, _invariant.default)(backbuffer, "Node#getGLBackbufferOutput: backbuffer is not defined. Make sure `backbuffering` prop is defined"); return backbuffer.color; } /** * Imperatively set the props with a partial subset of props to apply. */ setDrawProps(patch) { const nextProps = { ...this.drawProps, ...patch }; this._syncNextDrawProps(nextProps, this.context); this.redraw(); if (nextProps.sync) this.flush(); } /** * Capture the node pixels. */ capture(x, y, w, h) { const [width, height] = this.getGLSize(); const { gl } = this.context.glSurface; (0, _invariant.default)(gl, "gl is no longer available"); if (x === undefined) x = 0; if (y === undefined) y = 0; if (w === undefined) w = width - x; if (h === undefined) h = height - y; (0, _invariant.default)(x >= 0 && x + w <= width && y >= 0 && y + h <= height, "capture(%s,%s,%s,%s): requested rectangle is out of bounds (%s,%s)", x, y, w, h, width, height); const size = w * h * 4; const pixels = this._captureAlloc(size); this._bind(); gl.readPixels(x, y, w, h, gl.RGBA, gl.UNSIGNED_BYTE, pixels); return (0, _ndarray.default)(pixels, [h, w, 4]).step(-1, 1, 1).transpose(1, 0, 2); } /** * Schedule a redraw of this node and all dependent nodes. */ redraw = () => { if (!this._needsRedraw) { this._needsRedraw = true; this.dependents.forEach(d => d.redraw()); } }; /** * Force the redraw (if any) to happen now, synchronously. */ flush = () => { this.context.glSurface._draw(); }; _destroyGLObjects() { const { glSurface } = this.context; if (glSurface.glIsAvailable()) { const { framebuffer, backbuffer, _shader } = this; if (_shader) { _shader.dispose(); } if (framebuffer) { framebuffer.dispose(); } if (backbuffer) { backbuffer.dispose(); } } this._shader = undefined; this.framebuffer = undefined; this.backbuffer = undefined; } _prepareGLObjects(gl) { const [width, height] = this.getGLSize(); const { glParent, glSurface } = this.context; if (glParent === glSurface) { (0, _invariant.default)(!this.drawProps.backbuffering, "`backbuffering` is currently not supported for a Root Node. " + "Try to wrap %s in a <LinearCopy> or <NearestCopy>.", this.getGLName()); } else { const fbo = createFBO(gl, width, height); this.framebuffer = fbo; if (this.drawProps.backbuffering) { const fbo = createFBO(gl, width, height); this.backbuffer = fbo; } } } _onContextLost() { this.dependencies.forEach(d => d._onContextLost()); this._destroyGLObjects(); } _onContextRestored(gl) { this._prepareGLObjects(gl); this.dependencies.forEach(d => d._onContextRestored(gl)); this._needsRedraw = true; } _addGLNodeChild(node) {} _removeGLNodeChild(node) {} _addUniformBus(uniformBus, uniformName, index) { const array = this.uniformsBus[uniformName] || (this.uniformsBus[uniformName] = []); array[index] = uniformBus; } _removeUniformBus(uniformBus, uniformName, index) { const array = this.uniformsBus[uniformName] || (this.uniformsBus[uniformName] = []); if (array[index] === uniformBus) { array[index] = null; } } _addDependent(node) { const i = this.dependents.indexOf(node); if (i === -1) { (0, _invariantNoDependentsLoop.default)(this, node); this.dependents.push(node); } } _removeDependent(node) { const i = this.dependents.indexOf(node); if (i !== -1) { this.dependents.splice(i, 1); } } _syncDependencies(newdeps) { const olddeps = this.dependencies; const additions = newdeps.filter(node => olddeps.indexOf(node) === -1); const deletions = olddeps.filter(node => newdeps.indexOf(node) === -1); olddeps.forEach(d => d._removeDependent(this)); newdeps.forEach(d => d._addDependent(this)); this.dependencies = newdeps; return [additions, deletions]; } _bind() { if (this.framebuffer) { this.framebuffer.bind(); } else { this.context.glSurface._bindRootNode(); } } _captureAlloc(size) { let { capturePixelsArray } = this; if (capturePixelsArray && size !== capturePixelsArray.length) { _typedarrayPool.default.freeUint8(capturePixelsArray); capturePixelsArray = undefined; } const pixels = capturePixelsArray || _typedarrayPool.default.mallocUint8(size); this.capturePixelsArray = pixels; return pixels; } _latestShaderInfo; _shader; _getShader(shaderProp) { const { glSurface } = this.context; const nodeName = this.getGLName(); (0, _invariant.default)(shaderProp, nodeName + ": shader prop must be provided"); if ((0, _Shaders.isShaderIdentifier)(shaderProp)) { return glSurface._getShader(shaderProp); } const shaderInfo = (0, _Shaders.shaderDefinitionToShaderInfo)((0, _Shaders.ensureShaderDefinition)(shaderProp, " in " + nodeName), nodeName); const latestShaderInfo = this._latestShaderInfo; let shader = this._shader; if (!shader || !latestShaderInfo || !(0, _Shaders.shaderInfoEquals)(latestShaderInfo, shaderInfo)) { if (shader) { shader.dispose(); this._shader = undefined; } shader = glSurface._makeShader(shaderInfo); this._latestShaderInfo = shaderInfo; this._shader = shader; } return shader; } _draw() { const { glSurface } = this.context; const { gl } = glSurface; const visitors = glSurface.getVisitors(); const nodeName = this.getGLName(); if (!gl || !this._needsRedraw) { visitors.forEach(v => v.onNodeDrawSkipped(this)); return; } const { backbuffering, uniforms, uniformsOptions, shader: shaderProp, blendFunc, clear, onDraw, ignoreUnusedUniforms } = this.drawProps; //~ PREPARE phase if (!this.framebuffer) { const { glSizable } = this.context; const [width, height] = glSizable.getGLSize(); const [nw, nh] = this.getGLSize(); (0, _invariant.default)(nw === width && nh === height, nodeName + " is root but have overrided {width=%s,height=%s} which doesn't match Surface size {width=%s,height=%s}. " + "Try to wrap your Node in a <NearestCopy> or <LinearCopy>", nw, nh, width, height); } const shader = this._getShader(shaderProp); this._needsRedraw = false; const { types } = shader; const glRedrawableDependencies = []; const pendingTextures = []; let units = 0; const usedUniforms = Object.keys(types.uniforms); const providedUniforms = Object.keys(uniforms); const { uniformsBus } = this; for (let k in uniformsBus) { if (!(k in uniforms)) { providedUniforms.push(k); } } const textureUnits = new Map(); const prepareTexture = (initialObj, uniformOptions, uniformKeyName) => { let obj = initialObj, dependency = null, result = null; if (typeof obj === "function") { obj = obj(this.redraw); } if (!obj) { if (obj === undefined) { console.warn(`${nodeName}, uniform '${uniformKeyName}' is undefined.` + "If you explicitely want to clear a texture, set it to null."); } } else if (isBackbuffer(obj)) { if (!this.drawProps.backbuffering) { console.warn(`${nodeName}, uniform ${uniformKeyName}: you must set \`backbuffering\` on Node when using Backbuffer`); } result = { glNode: this, glNodePickBackbuffer: true }; } else if (isBackbufferFrom(obj)) { (0, _invariant.default)(typeof obj === "object", "invalid backbufferFromNode. Got: %s", obj); let node = obj.node; if (node instanceof _Bus.default) { node = node.getGLRenderableNode(); (0, _invariant.default)(node, "backbufferFromNode(bus) but bus.getGLRenderableNode() is %s", node); } (0, _invariant.default)(node instanceof Node, "invalid backbufferFromNode(obj): obj must be an instanceof Node or Bus. Got: %s", obj); if (!node.drawProps.backbuffering) { console.warn(`${nodeName}, uniform ${uniformKeyName}: you must set \`backbuffering\` on the Node referenced in backbufferFrom(${node.getGLName()})`); } result = { glNode: node, glNodePickBackbuffer: true }; } else if (obj instanceof Node) { dependency = obj; result = { glNode: obj }; } else if (obj instanceof _Bus.default) { const node = obj.getGLRenderableNode(); if (node) { dependency = node; result = { glNode: node }; } else { dependency = obj; const renderable = obj.getGLRenderableContent(); if (!renderable) { console.warn(`${nodeName}, uniform ${uniformKeyName}: child is not renderable. Got:`, renderable); result = { directTexture: null }; } else { obj = renderable; } } } if (!result && obj) { const { loader, input } = glSurface._resolveTextureLoader(obj); if (!loader) { console.warn(`${nodeName}, uniform ${uniformKeyName}: no loader found for value`, input, obj); } else { const t = loader.get(input); if (t) { loader.update(input); result = { directTexture: t.texture, directTextureSize: [t.width, t.height] }; } else { const p = loader.load(input); pendingTextures.push(p); } } } if (dependency) glRedrawableDependencies.push(dependency); const textureOptions = result ? uniformOptions : null; const getMetaInfo = () => ({ initialObj, obj, dependency, textureOptions }); const getSize = () => { const fallback = [2, 2]; return result ? "directTextureSize" in result ? result.directTextureSize || fallback : result.glNode ? result.glNode.getGLSize() : fallback : fallback; }; const prepare = () => { const texture = result && (result.directTexture || result.glNode && (result.glNodePickBackbuffer ? result.glNode.getGLBackbufferOutput() : result.glNode.getGLOutput())) || glSurface.getEmptyTexture(); if (textureUnits.has(texture)) { return textureUnits.get(texture); } const value = units++; gl.activeTexture(gl.TEXTURE0 + value); gl.bindTexture(gl.TEXTURE_2D, texture); applyTextureOptions(gl, textureOptions); textureUnits.set(texture, value); return value; }; return { getMetaInfo, getSize, prepare }; }; const prepareUniform = key => { const uniformType = types.uniforms[key]; if (!uniformType) { const ignoredWarn = ignoreUnusedUniforms === true || ignoreUnusedUniforms instanceof Array && ignoreUnusedUniforms.includes(key); if (!ignoredWarn) { console.warn(`${nodeName} uniform '${key}' is not declared, nor used, in your shader code`); } return { key, value: undefined }; } const uniformValue = uniforms[key]; usedUniforms.splice(usedUniforms.indexOf(key), 1); if (uniformType === "sampler2D") { const uniformBus = uniformsBus[key]; const { getMetaInfo, prepare } = prepareTexture(uniformBus && uniformBus[0] || uniformValue, uniformsOptions[key], key); return { key, type: uniformType, getMetaInfo, prepare }; } else if (uniformValue === _Uniform.default.Resolution) { return { key, type: uniformType, value: this.getGLSize() }; } else if (isTextureSizeGetter(uniformValue)) { (0, _invariant.default)(uniformValue && typeof uniformValue === "object", "unexpected textureSize object. Got: %s", uniformValue); const { getSize } = prepareTexture(uniformValue.obj, null, key); const size = getSize(); if (!size) { console.warn(`${nodeName}, uniform ${key}: texture size is undetermined`); } const value = uniformValue.ratio ? size ? size[0] / size[1] : 1 : size || [0, 0]; return { key, type: uniformType, value }; } else if (Array.isArray(uniformType) && uniformType[0] === "sampler2D") { let values; const uniformBus = uniformsBus[key]; const v = mergeArrays(Array.isArray(uniformValue) ? uniformValue : [], Array.isArray(uniformBus) ? uniformBus : []); if (!v.length) { console.warn(`${nodeName}, uniform '${key}' should be an array of textures.`); values = uniformType.map(() => null); } else if (v.length !== uniformType.length) { console.warn(`${nodeName}, uniform '${key}' should be an array of exactly ${uniformType.length} textures (not ${v.length}).`); values = uniformType.map(() => null); } else { values = v; } const uniformOptions = uniformsOptions[key]; const all = values.map((value, i) => prepareTexture(value, uniformOptions, key + "[" + i + "]")); return { key, type: uniformType, getMetaInfo: () => all.reduce((acc, o) => acc.concat(o.getMetaInfo()), []), prepare: () => all.map(o => o.prepare()) }; } else { if (uniformValue === undefined) { console.warn(`${nodeName}, uniform '${key}' is undefined.`); } return { key, type: uniformType, value: uniformValue }; } }; const preparedUniforms = providedUniforms.map(prepareUniform); if (usedUniforms.length !== 0) { console.warn(nodeName + ": Missing uniforms: " + usedUniforms.map(u => `'${u}'`).join(", ") + "\n" + "all uniforms must be provided " + "because implementations might share and reuse a Shader Program"); } if (pendingTextures.length > 0) { Promise.all(pendingTextures).then(this.redraw); visitors.forEach(v => v.onNodeDrawSkipped(this)); return; } visitors.forEach(v => v.onNodeDrawStart(this)); const [additions, deletions] = this._syncDependencies(glRedrawableDependencies); visitors.forEach(v => v.onNodeSyncDeps(this, additions, deletions)); if (backbuffering) { const { backbuffer, framebuffer } = this; this.backbuffer = framebuffer; if (backbuffer) { this.framebuffer = backbuffer; } } const drawDep = d => d._draw(); this.dependencies.forEach(drawDep); visitors.forEach(v => v.onNodeDraw(this, preparedUniforms)); shader.bind(); this._bind(); preparedUniforms.forEach(obj => { const value = obj.prepare ? obj.prepare() : obj.value; if (value !== undefined) { shader.uniforms[obj.key] = value; } }); if (blendFunc) { const src = mapBlendFunc(gl, blendFunc.src); const dst = mapBlendFunc(gl, blendFunc.dst); if (src && dst) gl.blendFunc(src, dst); } if (clear) { gl.clearColor(...clear.color); gl.clear(gl.COLOR_BUFFER_BIT); } gl.drawArrays(gl.TRIANGLES, 0, 3); if (onDraw) onDraw(); visitors.forEach(v => v.onNodeDrawEnd(this)); } } exports.default = Node; //# sourceMappingURL=Node.js.map