UNPKG

ember-source

Version:

A JavaScript framework for creating ambitious web applications

246 lines (229 loc) 7.59 kB
import '../../-internals/meta/lib/meta.js'; import '../../../shared-chunks/mandatory-setter-BiXq-dpN.js'; import { isDevelopingApp } from '@embroider/macros'; import '../../debug/index.js'; import '../../../@glimmer/destroyable/index.js'; import '../../../@glimmer/validator/index.js'; import '../../../@glimmer/manager/index.js'; import { g as get } from '../../../shared-chunks/cache-Djf2I3Za.js'; import '../../../shared-chunks/env-CwR5CFCu.js'; import { getOwner } from '../../-internals/owner/index.js'; import EngineInstance from '../../engine/instance.js'; import '../../../route-recognizer/index.js'; import '../../../shared-chunks/rsvp-DaQAFb0W.js'; import { S as STATE_SYMBOL } from '../../../shared-chunks/unrecognized-url-error-zpz-JEoG.js'; import { assert } from '../../debug/lib/assert.js'; const ALL_PERIODS_REGEX = /\./g; function extractRouteArgs(args) { // SAFETY: This should just be the same thing args = args.slice(); let possibleOptions = args[args.length - 1]; let queryParams; if (isRouteOptions(possibleOptions)) { args.pop(); // Remove options queryParams = possibleOptions.queryParams; } else { queryParams = {}; } let routeName; if (typeof args[0] === 'string') { routeName = args.shift(); // We just checked this! (isDevelopingApp() && !(typeof routeName === 'string') && assert('routeName is a string', typeof routeName === 'string')); } // SAFTEY: We removed the name and options if they existed, only models left. let models = args; return { routeName, models, queryParams }; } function getActiveTargetName(router) { let routeInfos = router.activeTransition ? router.activeTransition[STATE_SYMBOL].routeInfos : router.state.routeInfos; let lastRouteInfo = routeInfos[routeInfos.length - 1]; (isDevelopingApp() && !(lastRouteInfo) && assert('has last route info', lastRouteInfo)); return lastRouteInfo.name; } function stashParamNames(router, routeInfos) { if (routeInfos['_namesStashed']) { return; } // This helper exists because router.js/route-recognizer.js awkwardly // keeps separate a routeInfo's list of parameter names depending // on whether a URL transition or named transition is happening. // Hopefully we can remove this in the future. let routeInfo = routeInfos[routeInfos.length - 1]; (isDevelopingApp() && !(routeInfo) && assert('has route info', routeInfo)); let targetRouteName = routeInfo.name; let recogHandlers = router._routerMicrolib.recognizer.handlersFor(targetRouteName); let dynamicParent; for (let i = 0; i < routeInfos.length; ++i) { let routeInfo = routeInfos[i]; (isDevelopingApp() && !(routeInfo) && assert('has route info', routeInfo)); let names = recogHandlers[i].names; if (names.length) { dynamicParent = routeInfo; } routeInfo['_names'] = names; let route = routeInfo.route; route._stashNames(routeInfo, dynamicParent); } routeInfos['_namesStashed'] = true; } function _calculateCacheValuePrefix(prefix, part) { // calculates the dot separated sections from prefix that are also // at the start of part - which gives us the route name // given : prefix = site.article.comments, part = site.article.id // - returns: site.article (use get(values[site.article], 'id') to get the dynamic part - used below) // given : prefix = site.article, part = site.article.id // - returns: site.article. (use get(values[site.article], 'id') to get the dynamic part - used below) let prefixParts = prefix.split('.'); let currPrefix = ''; for (let i = 0; i < prefixParts.length; i++) { let currPart = prefixParts.slice(0, i + 1).join('.'); if (part.indexOf(currPart) !== 0) { break; } currPrefix = currPart; } return currPrefix; } /* Stolen from Controller */ function calculateCacheKey(prefix, parts = [], values) { let suffixes = ''; for (let part of parts) { let cacheValuePrefix = _calculateCacheValuePrefix(prefix, part); let value; if (values) { if (cacheValuePrefix && cacheValuePrefix in values) { let partRemovedPrefix = part.indexOf(cacheValuePrefix) === 0 ? part.substring(cacheValuePrefix.length + 1) : part; value = get(values[cacheValuePrefix], partRemovedPrefix); } else { value = get(values, part); } } suffixes += `::${part}:${value}`; } return prefix + suffixes.replace(ALL_PERIODS_REGEX, '-'); } /* Controller-defined query parameters can come in three shapes: Array queryParams: ['foo', 'bar'] Array of simple objects where value is an alias queryParams: [ { 'foo': 'rename_foo_to_this' }, { 'bar': 'call_bar_this_instead' } ] Array of fully defined objects queryParams: [ { 'foo': { as: 'rename_foo_to_this' }, } { 'bar': { as: 'call_bar_this_instead', scope: 'controller' } } ] This helper normalizes all three possible styles into the 'Array of fully defined objects' style. */ function normalizeControllerQueryParams(queryParams) { let qpMap = {}; for (let queryParam of queryParams) { accumulateQueryParamDescriptors(queryParam, qpMap); } return qpMap; } function accumulateQueryParamDescriptors(_desc, accum) { let desc = typeof _desc === 'string' ? { [_desc]: { as: null } } : _desc; for (let key in desc) { if (!Object.prototype.hasOwnProperty.call(desc, key)) { return; } let _singleDesc = desc[key]; let singleDesc = typeof _singleDesc === 'string' ? { as: _singleDesc } : _singleDesc; let partialVal = accum[key] || { as: null, scope: 'model' }; let val = { ...partialVal, ...singleDesc }; accum[key] = val; } } /* Check if a routeName resembles a url instead @private */ function resemblesURL(str) { return typeof str === 'string' && (str === '' || str[0] === '/'); } /* Returns an arguments array where the route name arg is prefixed based on the mount point @private */ function prefixRouteNameArg(route, args) { let routeName; let owner = getOwner(route); (isDevelopingApp() && !(owner instanceof EngineInstance) && assert('Expected route to have EngineInstance as owner', owner instanceof EngineInstance)); let prefix = owner.mountPoint; // only alter the routeName if it's actually referencing a route. if (owner.routable && typeof args[0] === 'string') { routeName = args[0]; if (resemblesURL(routeName)) { throw new Error('Programmatic transitions by URL cannot be used within an Engine. Please use the route name instead.'); } else { routeName = `${prefix}.${routeName}`; args[0] = routeName; } } return args; } function shallowEqual(a, b) { let aCount = 0; let bCount = 0; for (let kA in a) { if (Object.prototype.hasOwnProperty.call(a, kA)) { if (a[kA] !== b[kA]) { return false; } aCount++; } } for (let kB in b) { if (Object.prototype.hasOwnProperty.call(b, kB)) { bCount++; } } return aCount === bCount; } function isRouteOptions(value) { if (value && typeof value === 'object') { let qps = value.queryParams; if (qps && typeof qps === 'object') { return Object.keys(qps).every(k => typeof k === 'string'); } } return false; } export { calculateCacheKey, extractRouteArgs, getActiveTargetName, normalizeControllerQueryParams, prefixRouteNameArg, resemblesURL, shallowEqual, stashParamNames };