clwoz-models
Version:
Models for ConversationLearner
135 lines • 6.49 kB
JavaScript
;
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
// TODO: Copied from ConversationLearner-UI. Need to improve Action design to find out how to consolidate knowledge to single layer
// Originally ConversationLearner-models was intended to know have to understand the tree structure which is why we added the
// pre-serialized 'text' field; however, now can't use the text field becuase it includes entity id's instead of human-readable names
// Instead of having to decide wether to perform substitutions from the serialized text or from the tree it's better to
// just have single method used everywhere
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __spreadArrays = (this && this.__spreadArrays) || function () {
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
for (var r = Array(s), k = 0, i = 0; i < il; i++)
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
r[k] = a[j];
return r;
};
Object.defineProperty(exports, "__esModule", { value: true });
// Can't import because it's from ConversationLearner-UI
//import { NodeTypes } from "./models";
var NodeTypes;
(function (NodeTypes) {
NodeTypes["Mention"] = "mention-inline-node";
NodeTypes["Optional"] = "optional-inline-node";
})(NodeTypes || (NodeTypes = {}));
var defaultOptions = {
fallbackToOriginal: false,
preserveOptionalNodeWrappingCharacters: false
};
function serialize(value, entityValuesMap, userOptions) {
if (userOptions === void 0) { userOptions = {}; }
var options = __assign(__assign({}, defaultOptions), userOptions);
var valueAsJson = typeof value.toJSON === 'function' ? value.toJSON() : value;
var processedDocument = removeOptionalNodesWithoutEntityValues(valueAsJson.document, Array.from(entityValuesMap.keys()));
return serializeNode(processedDocument, entityValuesMap, options);
}
/**
* Given node return filter out optional nodes without matching values provided
*
* E.g. You are welcome[, $name] -> You are welcome
* @param node Slate Node
* @param entityValues Key Value pair of entity id to entity display value
*/
function removeOptionalNodesWithoutEntityValues(node, entityIds) {
if (node.kind === 'inline' && node.type === NodeTypes.Optional) {
var entityIdsWithinOptionalNode = getEntityIds(node);
var hasValues = entityIdsWithinOptionalNode.every(function (x) { return entityIds.includes(x); });
return hasValues ? node : undefined;
}
if (Array.isArray(node.nodes)) {
node.nodes = node.nodes.map(function (n) { return removeOptionalNodesWithoutEntityValues(n, entityIds); }).filter(function (n) { return n; });
}
return node;
}
function getEntityIds(node) {
var entityIds = [];
// If current node is inline node which we know to have entityId then save it in the list
if (node.kind === 'inline' && node.type === NodeTypes.Mention) {
// This check is required because when input is Slate Value node is Immutable.Map object
// but it could also be a node from value.toJSON()
var data = typeof node.data.toJS === 'function' ? node.data.toJS() : node.data;
var option = data.option;
if (!option) {
throw new Error("Attempting to serialize inline node but it did not have option");
}
var entityId = option.id;
entityIds.push(entityId);
}
// Technically this would never get called because inline nodes shouldn't have other children which are inline nodes
// however, it's good to have working depth-first-traversal anyways
if (Array.isArray(node.nodes)) {
var childrenEntityIds = node.nodes
.map(function (n) { return getEntityIds(n); })
.reduce(function (totalIds, nodeIds) { return __spreadArrays(totalIds, nodeIds); }, []);
entityIds.push.apply(entityIds, childrenEntityIds);
}
return entityIds;
}
function serializeNode(node, entityValues, options) {
if (node.kind === 'text') {
return node.leaves.map(function (n) { return n.text; }).join('');
}
var serializedChildNodes = node.nodes.map(function (n) { return serializeNode(n, entityValues, options); });
if (node.kind === 'inline' && node.type === NodeTypes.Mention) {
// This check is required because when input is Slate Value node is Immutable.Map object
// but it could also be a node from value.toJSON()
var data = typeof node.data.toJS === 'function' ? node.data.toJS() : node.data;
if (!data.completed) {
return serializedChildNodes.join('');
}
var option = data.option;
if (!option) {
throw new Error("Attempting to serialize inline node but it did not have option");
}
var entityId = option.id;
var mapContainsEntity = entityValues.has(entityId);
if (!mapContainsEntity) {
if (options.fallbackToOriginal) {
return serializedChildNodes.join('');
}
var entityValuesString = Array.from(entityValues.entries())
.map(function (_a) {
var id = _a[0], value = _a[1];
return id + ": " + value;
})
.join(', ');
throw new Error("Inline node representing entity " + entityId + " was NOT provided a value in the given entityValue map: [" + entityValuesString + "]");
}
return entityValues.get(entityId);
}
if (node.kind === 'document') {
return serializedChildNodes.join('\n');
}
var serializedChildren = serializedChildNodes.join('');
return node.kind === 'inline' && node.type === NodeTypes.Optional
? options.preserveOptionalNodeWrappingCharacters
? serializedChildren
: serializedChildren.slice(1, -1)
: serializedChildren;
}
exports.default = {
serialize: serialize
};
//# sourceMappingURL=slateSerializer.js.map