elliptical
Version:
Interactive natural-language interfaces
138 lines (114 loc) • 4.36 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
var _lodash = require('lodash');
var _lodash2 = _interopRequireDefault(_lodash);
var _utils = require('../utils');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function* visit(option, _ref, traverse) {
var _ref$props$unique = _ref.props.unique;
let unique = _ref$props$unique === undefined ? false : _ref$props$unique;
let children = _ref.children;
const mods = { result: {}, score: 1 };
const trueOption = _lodash2.default.assign({}, option, mods);
if (children.length) {
const iterator = parseChildControl(0, trueOption, unique, children, traverse);
yield* iterator;
}
}
function shouldDoEllipsis(index, option, children) {
// Don't do ellipsis for the first element,
// or if this element is both optional and ellipsis, and the text is ''
// because that results in duplicate options output
const child = children[index];
return index > 0 && children[index - 1].props.ellipsis && !(child.props.ellipsis && child.props.optional && option.text === '');
}
function* optionalTraversals(index, option, unique, children, traverse) {
const child = children[index];
const withChildParse = parseChild(index, option, unique, children, traverse);
const withoutChildParse = parseChildControl(index + 1, option, unique, children, traverse);
// yield * limitIterator(optionals, child.props.limited ? 1 : undefined)
if (child.props.preferred) {
yield withChildParse;
yield withoutChildParse;
} else {
yield withoutChildParse;
yield withChildParse;
}
}
function* parseChildControl(index, option, unique, children, traverse) {
if (index >= children.length) {
// we've reached the end
yield option;
return;
}
const child = children[index];
if (shouldDoEllipsis(index, option, children)) {
if (option.text === '') {
yield option;
} else {
let success = false;
yield _lodash2.default.assign({}, option, {
callbacks: option.callbacks.concat(() => {
success = true;
})
});
if (success) return;
}
}
if (child.props.optional) {
yield* (0, _utils.limitIterator)(optionalTraversals(index, option, unique, children, traverse), child.props.limited ? 1 : undefined);
} else {
yield* parseChild(index, option, unique, children, traverse);
}
}
function hasSomeSameKeys(option, output) {
const sameKeys = _lodash2.default.intersection(_lodash2.default.keys(option.result), _lodash2.default.keys(output.result));
return !_lodash2.default.isEmpty(sameKeys);
}
function* parseChild(index, option, unique, children, traverse) {
const child = children[index];
const childOption = _lodash2.default.assign({}, option, {
qualifiers: [],
annotations: [],
categories: [],
arguments: []
});
for (let output of traverse(child, childOption)) {
if (unique && output.result != null) {
if (child.props.id && option.result[child.props.id] != null) {
continue;
} else if (child.props.merge && hasSomeSameKeys(option, output)) {
continue;
}
}
const modifications = {
result: getAccumulatedResult(option.result, child, output.result),
score: option.score * output.score,
qualifiers: option.qualifiers.concat(output.qualifiers),
annotations: option.annotations.concat(output.annotations),
categories: option.categories.concat(output.categories),
arguments: option.arguments.concat(output.arguments)
};
let nextOutput = _lodash2.default.assign({}, output, modifications);
yield* parseChildControl(index + 1, nextOutput, unique, children, traverse);
}
}
function getAccumulatedResult(inputResult, child, childResult) {
if (!_lodash2.default.isUndefined(childResult)) {
const childId = child.props.id;
const childMerge = child.props.merge;
if (childId) {
return _lodash2.default.assign({}, inputResult, { [childId]: childResult });
} else if (childMerge) {
if (!_lodash2.default.isEmpty(inputResult) && _lodash2.default.isPlainObject(childResult)) {
return _lodash2.default.merge({}, inputResult, childResult);
} else {
return childResult;
}
}
}
return inputResult;
}
exports.default = { visit: visit };