function createNode(type, x, y, z) {
        const wasDirty = RED.nodes.dirty()
        var m = /^subflow:(.+)$/.exec(type);
        var activeSubflow = (z || RED.workspaces.active()) ? RED.nodes.subflow(z || RED.workspaces.active()) : null;

        if (activeSubflow && m) {
            var subflowId = m[1];
            let err
            if (subflowId === activeSubflow.id) {
                err = new Error(RED._("notification.errors.cannotAddSubflowToItself"))
            } else if (RED.nodes.subflowContains(m[1], activeSubflow.id)) {
                err = new Error(RED._("notification.errors.cannotAddCircularReference"))
            }
            if (err) {
                err.code = 'NODE_RED'
                throw err
            }
        }

        var nn = { id: RED.nodes.id(), z: z || RED.workspaces.active() };

        nn.type = type;
        nn._def = RED.nodes.getType(nn.type);

        if (!m) {
            nn.inputs = nn._def.inputs || 0;
            nn.outputs = nn._def.outputs;

            for (var d in nn._def.defaults) {
                if (nn._def.defaults.hasOwnProperty(d)) {
                    if (nn._def.defaults[d].value !== undefined) {
                        nn[d] = JSON.parse(JSON.stringify(nn._def.defaults[d].value));
                    }
                }
            }

            if (nn._def.onadd) {
                try {
                    nn._def.onadd.call(nn);
                } catch (err) {
                    console.log("Definition error: " + nn.type + ".onadd:", err);
                }
            }
        } else {
            var subflow = RED.nodes.subflow(m[1]);
            nn.name = "";
            nn.inputs = subflow.in.length;
            nn.outputs = subflow.out.length;
        }

        nn.changed = true;
        nn.moved = true;

        nn.w = RED.view.node_width;
        nn.h = Math.max(RED.view.node_height, (nn.outputs || 0) * 15);
        nn.resize = true;
        if (x != null && typeof x == "number" && x >= 0) {
            nn.x = x;
        }
        if (y != null && typeof y == "number" && y >= 0) {
            nn.y = y;
        }
        var historyEvent = {
            t: "add",
            nodes: [nn.id],
            dirty: wasDirty
        }
        if (activeSubflow) {
            var subflowRefresh = RED.subflow.refresh(true);
            if (subflowRefresh) {
                historyEvent.subflow = {
                    id: activeSubflow.id,
                    changed: activeSubflow.changed,
                    instances: subflowRefresh.instances
                }
            }
        }
        return {
            node: nn,
            historyEvent: historyEvent
        }
    }
Create a node from a type string.
**NOTE:** Can throw on error - use `try` `catch` block when calling
@param {string} type The node type to create
@param {number} [x] (optional) The horizontal position on the workspace
@param {number} [y] (optional)The vertical on the workspace
@param {string} [z] (optional) The flow tab this node will belong to. Defaults to active workspace.
@returns An object containing the `node` and a `historyEvent`
@private