UNPKG

@sanity/desk-tool

Version:

Tool for managing all sorts of content in a structured manner

184 lines (180 loc) • 9.83 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.resolveIntent = resolveIntent; var _omit2 = _interopRequireDefault(require("lodash/omit")); var _operators = require("rxjs/operators"); var _assignId = require("./assignId"); var _createPaneResolver = require("./createPaneResolver"); var _loadStructure = require("./loadStructure"); var _memoBind = require("./memoBind"); var _excluded = ["id", "type"]; function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; } function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); } function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } /* eslint-disable complexity */ /** * Resolves an intent request using breadth first search. If a match is not * found, the intent will resolve to the fallback editor. * * A match is found if: * 1. the `PaneNode` is of type `document` and the its ID matches the intent ID * 2. the `PaneNode` is of type `documentList` and the `schemaTypeName` matches * 3. the `PaneNode`'s `canHandleIntent` method returns true * * If a `PaneNode` of type `list` is found, it will be searched for a match. * * @see PaneNode */ function resolveIntent(_x) { return _resolveIntent.apply(this, arguments); } function _resolveIntent() { _resolveIntent = _asyncToGenerator(function* (options) { var resolvedPaneCache = new Map(); // this is a simple version of the memoizer in `createResolvedPaneNodeStream` var memoize = nextFn => (unresolvedPane, context, flatIndex) => { var key = unresolvedPane && "".concat((0, _assignId.assignId)(unresolvedPane), "-").concat(context.path.join('__')); var cachedResolvedPane = key && resolvedPaneCache.get(key); if (cachedResolvedPane) return cachedResolvedPane; var result = nextFn(unresolvedPane, context, flatIndex); if (key) resolvedPaneCache.set(key, result); return result; }; var resolvePane = (0, _createPaneResolver.createPaneResolver)(memoize); var fallbackEditorPanes = [[{ id: "__edit__".concat(options.params.id), params: _objectSpread(_objectSpread({}, (0, _omit2.default)(options.params, ['id'])), {}, { type: options.params.type }), payload: options.payload }]]; function traverse(_x2) { return _traverse.apply(this, arguments); } function _traverse() { _traverse = _asyncToGenerator(function* (_ref) { var _resolvedPane$canHand; var currentId = _ref.currentId, flatIndex = _ref.flatIndex, intent = _ref.intent, params = _ref.params, parent = _ref.parent, path = _ref.path, payload = _ref.payload, unresolvedPane = _ref.unresolvedPane, levelIndex = _ref.levelIndex; if (!unresolvedPane) return []; var targetId = params.id, schemaTypeName = params.type, otherParams = _objectWithoutProperties(params, _excluded); var context = { id: currentId, splitIndex: 0, parent, path, index: flatIndex, params: {}, payload: undefined }; var resolvedPane = yield resolvePane(unresolvedPane, context, flatIndex).pipe((0, _operators.first)()).toPromise(); // if the resolved pane is a document pane and the pane's ID matches then // resolve the intent to the current path if (resolvedPane.type === 'document' && resolvedPane.id === targetId) { return [{ panes: [...path.slice(0, path.length - 1).map(i => [{ id: i }]), [{ id: targetId, params: otherParams, payload }]], depthIndex: path.length, levelIndex }]; } // NOTE: if you update this logic, please also update the similar handler in // `getIntentState.ts` if ( // if the resolve pane's `canHandleIntent` returns true, then resolve (_resolvedPane$canHand = resolvedPane.canHandleIntent) !== null && _resolvedPane$canHand !== void 0 && _resolvedPane$canHand.call(resolvedPane, intent, params, { pane: resolvedPane, index: flatIndex }) || // if the pane's `canHandleIntent` did not return true, then match against // this default case. we will resolve the intent if: resolvedPane.type === 'documentList' && // 1. the schema type matches (this required for the document to render) resolvedPane.schemaTypeName === schemaTypeName && // 2. the filter is the default filter. // // NOTE: this case is to prevent false positive matches where the user // has configured a more specific filter for a particular type. In that // case, the user can implement their own `canHandleIntent` function resolvedPane.options.filter === '_type == $type') { return [{ panes: [ // map the current path to router panes ...path.map(id => [{ id }]), // then augment with the intents IDs and params [{ id: params.id, params: otherParams, payload }]], depthIndex: path.length, levelIndex }]; } if (resolvedPane.type === 'list' && resolvedPane.child && resolvedPane.items) { return (yield Promise.all(resolvedPane.items.map((item, nextLevelIndex) => { if (item.type === 'divider') return Promise.resolve([]); return traverse({ currentId: item._id || item.id, flatIndex: flatIndex + 1, intent, params, parent: resolvedPane, path: [...path, item.id], payload, unresolvedPane: typeof resolvedPane.child === 'function' ? (0, _memoBind.memoBind)(resolvedPane, 'child') : resolvedPane.child, levelIndex: nextLevelIndex }); }))).flat(); } return []; }); return _traverse.apply(this, arguments); } var matchingPanes = yield traverse({ currentId: 'root', flatIndex: 0, levelIndex: 0, intent: options.intent, params: options.params, parent: null, path: [], payload: options.payload, unresolvedPane: options.rootPaneNode || (0, _loadStructure.loadStructure)() }); var closestPaneToRoot = matchingPanes.sort((a, b) => { // break ties with the level index if (a.depthIndex === b.depthIndex) return a.levelIndex - b.levelIndex; return a.depthIndex - b.depthIndex; })[0]; if (closestPaneToRoot) { return closestPaneToRoot.panes; } return fallbackEditorPanes; }); return _resolveIntent.apply(this, arguments); }