Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
@skava/router / dist / OneRouterToRuleThemAll.js
Size: Mime:
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const mobx_1 = require("xmobx/mobx");
const query_string_1 = __importDefault(require("query-string"));
const react_router_dom_1 = require("react-router-dom");
const exotic_1 = require("exotic");
const chain_able_lego_1 = require("chain-able-lego");
const dopemerge_1 = __importDefault(require("chain-able-deps/dist/dopemerge"));
// local
const makeHistory_1 = __importDefault(require("./makeHistory"));
const deps_1 = require("./deps");
const config_1 = require("./config");
/**
 * @todo why is this not done in another file?
 */
exports.history = makeHistory_1.default();
/**
 * @todo @@perf dedupe from exotic
 */
const isNonEmptyString = (x) => exotic_1.isString(x) && x !== '';
/**
 * @todo @@perf freeze if it is safe
 */
exports.EMPTY_ROUTER = {
    history: exports.history,
    route: undefined,
    location: undefined,
};
/**
 * @todo subscribe, observe, unsubscribe
 *
 * @note modules/ does not hot reload
 * extends Container
 */
class OneRouterToRuleThemAll {
    constructor() {
        /**
         * @todo @@prod
         */
        this.version = '6.0.3';
        // this.observersList = new WeakMap()
        // observersList: Array<Function> = []
        this.oneUrl = undefined;
        // @todo @type OneRouterStoreType
        // @todo can use this to avoid
        // making all history and router observable
        this.store = mobx_1.observable.map();
        this.shallowStore = mobx_1.observable.map(undefined, { deep: false });
        // @todo put this in shallow store...
        this._router = exports.EMPTY_ROUTER;
        /**
         * @deprecated remove this
         * .shallow
         */
        this.observable = {
            urlList: [],
            url: '',
        };
        this.handleRouteChange = (location, actionName) => {
            console.debug('[oneRouter] updated');
            this.setAsDirty(true);
        };
    }
    setAsDirty(isDirty = true) {
        console.debug('marking as dirty: ' + isDirty);
        // @todo could use `location` instead?
        this.store.set('hasChangedSinceLastEntries', isDirty);
        this.shallowStore.delete('entries');
        return this;
    }
    get url() {
        // used ||, but @deprecated
        return this.store.get('url') || this.observable.url || '';
    }
    get router() {
        return this._router;
    }
    set router(router) {
        /**
         * @todo did this change in react-router????
         */
        const historyToListenTo = exotic_1.isObj(router.history) ? router.history : exports.history;
        if (this.shallowStore.has('listener')) {
            const unsubscribe = this.shallowStore.get('listener');
            unsubscribe();
        }
        if (exotic_1.isFunction(historyToListenTo.listen) === false) {
            console.warn('oneRouter.router = {} < router is missing history.listen');
        }
        else {
            const listener = historyToListenTo.listen(this.handleRouteChange);
            this.shallowStore.set('listener', listener);
        }
        this.setAsDirty(true);
        this._router = router;
    }
    /**
     * @todo could ensure no duplication?
     */
    setUrl(value) {
        this.store.set('url', value);
        if (this.store.has('urlList') === false) {
            this.store.set('urlList', mobx_1.observable.array());
        }
        const urlList = this.store.get('urlList');
        urlList.push(value);
        // @@remove - @@compatability
        this.observable.url = value;
        this.observable.urlList = urlList;
        this.setAsDirty(true);
        return this;
    }
    get prevUrl() {
        // @@perf could optimize by checking length
        const length = this.observable.urlList.length;
        const lastIndex = length - 1;
        const last = this.observable.urlList[lastIndex];
        return last || '';
    }
    setTapEntries(tapEntries) {
        if (tapEntries === undefined) {
            this.store.delete('tapEntries');
        }
        else {
            this.store.set('tapEntries', tapEntries);
        }
        this.setAsDirty(true);
        return this;
    }
    get location() {
        if (process.env.NODE_ENV === 'development') {
            if (this.router.location) {
                throw new Error('invalid router - has location');
            }
        }
        return this.history.location;
    }
    /**
     * @todo @@typings
     */
    get(key) {
        const entries = this.entries();
        return entries[key] === undefined ? this.store.get(key) : entries[key];
    }
    set(key, value) {
        this.store.set(key, value);
        return this;
    }
    /**
     * @todo @@typings
     */
    from(obj) {
        const keys = Object.keys(obj);
        let didChange = false;
        // const original = stringify(this.entries())
        // const changed = stringify(obj)
        // if (original === changed) {
        //   return
        // }
        // // go through keys
        keys.forEach(key => {
            const value = obj[key];
            // update if it changed
            if (this.store.get(key) !== value) {
                this.store.set(key, value);
                didChange = true;
            }
        });
        // // could also  set the .diff
        // if (didChange === true) {
        //   this.observersList.forEach(subscriber => subscriber(this))
        // }
        return this;
    }
    get urlFromExpress() {
        // @note this is because of the next line with the `set`
        return this.location.full || '';
    }
    /**
     * @todo action @@strict
     */
    set urlFromExpress(oneUrl) {
        this.oneUrl = oneUrl;
        this.history.location = oneUrl;
    }
    /**
     * @todo optimize with computed
     */
    toString() {
        const entries = this.entries();
        return chain_able_lego_1.stringify(entries);
    }
    /**
     * @todo can use this for debug
     *       replacing using `pretty: true` in toString
     * @todo can serialize ALL like the `store` etc
     */
    toJSON() {
        // oneUrl, store,
        // router, router.history, router.route,
        // props, observable
        // toString()
        return {
            entries: this.entries(),
        };
    }
    /**
     * @note the type was `AnyObj | string`
     *       but not sure how that makes much sense
     *       don't see the use case, YAGNI
     */
    has(data) {
        return this.toString().includes(data);
    }
    /**
     * @see history/goBack
     * @description common naming
     * @alias goBack
     * @alias gotoBack
     */
    gotoPrev() {
        /**
         * @todo - should unify this history usage stuff & simplify v3
         */
        this.history.goBack();
    }
    gotoNext() {
        this.history.goForward();
    }
    /**
     * @example https://uxui.com/route?search=eh#hash
     * @alias fullyQualifiedWebAddress
     * @alias absolute
     * @alias absoluteWebAddress
     */
    get full() {
        const IS_BROWSER = typeof window === 'object';
        return IS_BROWSER
            ? window.location.href
            : this.history.location.href ||
                this.history.location.origin +
                    '/' +
                    this.history.location.pathname;
    }
    /**
     * @note also available in entries
     *       and the history.location can be from express
     */
    get origin() {
        const IS_BROWSER = typeof window === 'object';
        return IS_BROWSER
            ? window.location.origin
            : this.history.location.origin ||
                this.history.location.origin;
    }
    /**
     * @description (pathname.match(/\w+/gim) || []).join('')
     */
    // @computed
    get pathname() {
        const IS_BROWSER = typeof window === 'object';
        if (IS_BROWSER) {
            console.debug('[1router] window.location.pathname');
            return window.location.pathname;
        }
        if (this.oneUrl !== undefined) {
            console.debug('[1router] oneUrl');
            return this.oneUrl.pathname;
        }
        if (typeof global === 'object' && global.oneUrl !== undefined) {
            console.debug('[1router] global.oneUrl.pathname');
            return global.oneUrl.pathname;
        }
        if (isNonEmptyString(this.urlFromExpress)) {
            console.debug('[1router] urlFromExpress');
            return String(this.urlFromExpress);
        }
        if (exotic_1.isObj(this.router) &&
            exotic_1.isObj(this.history) &&
            exotic_1.isObj(this.history.location) &&
            exotic_1.isString(this.history.location.pathname) &&
            this.history.location.pathname !== '/') {
            console.debug('[1router] router.history.location.pathname 1');
            return this.history.location.pathname;
        }
        if (process.env.NODE_ENV !== 'production') {
            if (this.history.pathname) {
                throw new Error('history has pathname');
            }
        }
        if (this.history.location.pathname) {
            console.debug('[1router] history.location.pathname 2');
            return this.history.location.pathname;
        }
        const unknown = new Error('could not find pathname');
        console.error(unknown);
        console.log(this);
        return '@@unknown';
    }
    /**
     * @example
     *    localhost/eh/10/
     *    /eh/:categoryId
     *    match.params.categoryId
     *    => 10
     */
    get matched() {
        const matched = {};
        const pathname = this.pathname;
        const routePathsList = config_1.config.get('routePathsList');
        // @todo forEach for readability?
        //
        // go through our routes
        // use the sealed object for perf
        // match params (which has a cache)
        // merge with matched object
        // return matched
        for (let index = 0; index < routePathsList.length; index++) {
            const matchablePath = routePathsList[index];
            deps_1.routePathCurrent.path = matchablePath;
            const matchedFromPath = react_router_dom_1.matchPath(pathname, deps_1.routePathCurrent);
            // !!!!!!!!! IMPORTANT
            // console.log(
            //   '[1router] ____MATCHED___',
            //   index,
            //   pathname,
            //   matchedFromPath,
            //   matchablePath
            // )
            if (exotic_1.isObj(matchedFromPath)) {
                // @note this was
                // const params = { ...matchedFromPath.params }
                Object.assign(matched, matchedFromPath.params);
            }
        }
        return matched;
    }
    /**
     * @todo not sure if it's used
     */
    get searchParams() {
        return this.getSearchParams();
    }
    /**
     * @note - removed `@computed` from it
     *         since we had issues with that updating before
     *         because `router` is a ref, not an observable
     * @description this.router this.history history
     */
    // @computed
    get history() {
        return exotic_1.isObj(this.router) && exotic_1.isObj(this.router.history)
            ? this.router.history
            : exports.history;
    }
    /**
     * @see http://unixpapa.com/js/querystring.html
     * @api https://github.com/sindresorhus/query-string#nesting
     * @todo these entries could be observable...
     */
    getSearchParams(fallback = exotic_1.EMPTY_OBJ) {
        const IS_BROWSER = typeof window === 'object';
        /**
         * @todo use URLSearchParams not qs...
         */
        const parsed = this.history.location.search
            ? query_string_1.default.parse(this.history.location.search)
            : fallback;
        if (!parsed) {
            return parsed;
        }
        // could optimize this
        const searchParams = {};
        Object.assign(searchParams, parsed);
        /**
         * it does not support doing things like
         * @example &eh=1&eh=10
         */
        if (IS_BROWSER) {
            const params = new URLSearchParams(window.location.search);
            const entries = Array.from(params);
            const obj = exotic_1.fromPairsToObj(entries);
            Object.assign(searchParams, obj);
        }
        const final = this.parse(searchParams);
        return final;
    }
    /**
     * @todo should add parsing options
     * @param parsed object with values that can be parsed
     * @return destringified/parsed
     */
    parse(parsed) {
        if (exotic_1.isObj(parsed)) {
            deps_1.parseObjWithSerializedValues(parsed);
        }
        return parsed;
    }
    /**
     * @todo !!! optimize with a hash for sure
     *
     * @todo computed
     * @todo this needs to get the routing from routing
     * ^ need to put in config
     *
     * @alias toObj
     */
    entries() {
        if (this.store.get('hasChangedSinceLastEntries')) {
            this.setAsDirty(false);
        }
        else if (this.shallowStore.has('entries')) {
            console.debug('[1router] using optimized .entries');
            return this.shallowStore.get('entries');
        }
        else {
            console.warn('[1router] should never get here...');
        }
        const IS_BROWSER = typeof window === 'object';
        const pathname = this.pathname;
        const browserLocation = IS_BROWSER ? window.location : exotic_1.EMPTY_OBJ;
        const params = this.getSearchParams();
        const matched = this.matched;
        /**
         * @todo should make things not enumerable here
         */
        const flattenedActions = Object.assign({}, browserLocation, this.history, this.history.location, this.router);
        // autofixSafe
        const entries = Object.assign({ pathname }, params, matched);
        const mergedEntries = Object.assign({}, flattenedActions, entries);
        console.debug('[1router] calling .entries');
        if (this.store.has('tapEntries') === true) {
            const tapEntries = this.store.get('tapEntries');
            const finalEntries = tapEntries(mergedEntries);
            this.shallowStore.set('entries', finalEntries);
        }
        else {
            this.shallowStore.set('entries', mergedEntries);
        }
        return this.shallowStore.get('entries');
    }
    /**
     * @tutorial https://github.com/ReactTraining/history/blob/master/modules/LocationUtils.js
     * @alias push
     * @alias merge
     * @alias updateQueryParams
     *
     * @fires observable update
     * @description any kind of url update can be done here
     *
     * @param to
     *
     * @example
     *   [state, pathname, hash]
     *   toUrlOrPathNameOrParams, optionalParamAsDataOrPath
     *   let to = toUrlOrPathNameOrParams
     *   let state = optionalParamAsDataOrPath
     *   let hash
     *   if (arguments.length === 2)
     */
    update(to, options = {
        shouldStringify: true,
        shouldMerge: true,
        shouldUseNative: false,
    }) {
        console.info('oneRouter.update(to =' + JSON.stringify(to) + ')');
        this.setAsDirty(true);
        if (exotic_1.isObj(to)) {
            console.info('oneRouter.update isObj(to)');
            // if (to.search) {
            //   to = to.search
            // }
            // if (to.hash) {
            //   return this.update('#' + to.hash)
            // }
            if (process.env.NODE_ENV !== 'production') {
                if (to.pathname) {
                    console.warn(`avoid stringifying history-like properties: ` + to);
                }
            }
            // Commented the below line for filter to work in plp
            const searchParams = {};
            // const searchParams = this.getSearchParams(false)
            console.info('.update(to = ', to, ')');
            if (options.shouldMerge !== false) {
                to = dopemerge_1.default(searchParams, to);
                console.info('oneRouter.update(to =' + JSON.stringify(to) + ')');
            }
            // const params = options.shouldStringify ? qs.stringify(to) : to
            const params = deps_1.goodLookingStringify(to);
            if (options.shouldUseNative === true) {
                // to, document.title, url
                window.history.pushState(to, '', this.pathname + '?' + params);
                return this;
            }
            else {
                this.history.push({ pathname: this.pathname, search: params });
            }
        }
        // @todo types below should work
        // not a string
        if (!exotic_1.isString(to)) {
            if (process.env.NODE_ENV !== 'production') {
                console.warn('oneRouter.update(to, opts) must have an object or a string as `to`');
            }
        }
        // @note this works but we don't want to use this
        // the way it was being used in our domain/reference-store
        // else if (isHash(to)) {
        //   this.history.push({ pathname: this.pathname, hash: to })
        //   return this
        // }
        else if (deps_1.isStringifiedParams(to)) {
            console.info('isStringifiedParams');
            const parsed = query_string_1.default.parse(to);
            return this.update(parsed);
        }
        //
        // @todo for the below two cases, check our local routes
        //
        // @example https://eh.com
        else if (deps_1.isFullyQualifiedWebAddress(to)) {
            console.info('isFullyQualifiedWebAddress');
            this.history.push({
                pathname: to,
            });
        }
        // @example /eh
        else if (deps_1.isRelativeWebAddress(to)) {
            console.info('isRelativeWebAddress');
            this.history.replace(to);
        }
        // uglifyable
        else {
            return this;
        }
    }
    /**
     * @todo !!! should be used as last resort, need to debug usage
     */
    forceUpdate(path) {
        console.warn('[1router] should not be using .forceUpdate, this is a last resort!');
        this.setAsDirty(true);
        const finalPath = deps_1.isRelativeWebAddress(path) ? this.origin + path : path;
        const IS_BROWSER = typeof window === 'object';
        if (IS_BROWSER) {
            window.location.href = path;
            console.warn('todo - for tests');
            // window.location.pathname = path
        }
        this.history.location.href = finalPath;
        this.store.clear();
        return this;
    }
    /**
     * @param param query param to delete
     */
    delete(param) {
        this.store.delete(param);
        this.setAsDirty(true);
        if (exotic_1.isString(param)) {
            const searchParamsRaw = this.getSearchParams();
            if (searchParamsRaw === undefined) {
                return this;
            }
            /**
             * @todo there be a better way to do this...
             */
            const searchParams = this.parse(searchParamsRaw);
            delete searchParams[param];
            return this.update(searchParams);
        }
        else {
            return this;
        }
    }
    /**
     * @alias goto
     * @description same as update, but goto this url instead of merging
     */
    replace(path) {
        this.setAsDirty(true);
        this.history.replace(path);
        return this;
    }
    /**
     * @description reset url, goto root
     */
    clearHistory() {
        this.setAsDirty(true);
        this.history.replace({
            pathname: this.location.pathname,
            search: ``,
        });
        return this;
    }
    clear() {
        this.setAsDirty(true);
        this.history.location.pathname = '';
        this.history.location.href = '';
        this.history.location.origin = '';
        this.clearHistory();
        this.store.clear();
        return this;
    }
    /**
     * @alias observe
     * @alias subscribe
     * @param subscriber called when observable changes
     */
    onChange(subscriber) {
        const subscribeToRouteChange = this.history.listen;
        if (exotic_1.isFunction(subscribeToRouteChange)) {
            subscribeToRouteChange(subscriber);
        }
        if (process.env.NODE_ENV !== 'production') {
            console.assert(typeof subscribeToRouteChange === 'function', 'ON_CHANGE_ONE_ROUTER_NOT_FUNCTION');
        }
        return this;
    }
    /**
     * @description window.location.reload()
     */
    reload() {
        window.location.reload();
    }
    /**
     * @todo use chain-able/matcher
     *    ^ regexp, function, or string, or string wildcard/route-params
     *    @example isMatch(restrictedRoutes, this.pathname)
     */
    get isRestricted() {
        const restrictedRoutes = this.get('restrictedRoutes') || exotic_1.EMPTY_ARRAY;
        const isRestricted = restrictedRoutes.includes(this.pathname);
        return isRestricted;
    }
}
__decorate([
    mobx_1.observable.ref
], OneRouterToRuleThemAll.prototype, "oneUrl", void 0);
__decorate([
    mobx_1.observable.ref
], OneRouterToRuleThemAll.prototype, "_router", void 0);
__decorate([
    mobx_1.observable
], OneRouterToRuleThemAll.prototype, "observable", void 0);
__decorate([
    mobx_1.action
], OneRouterToRuleThemAll.prototype, "setAsDirty", null);
__decorate([
    mobx_1.computed
], OneRouterToRuleThemAll.prototype, "url", null);
__decorate([
    mobx_1.action
], OneRouterToRuleThemAll.prototype, "setUrl", null);
__decorate([
    mobx_1.computed
], OneRouterToRuleThemAll.prototype, "prevUrl", null);
__decorate([
    mobx_1.action
], OneRouterToRuleThemAll.prototype, "setTapEntries", null);
__decorate([
    mobx_1.computed
], OneRouterToRuleThemAll.prototype, "location", null);
__decorate([
    mobx_1.action
], OneRouterToRuleThemAll.prototype, "set", null);
__decorate([
    mobx_1.action
], OneRouterToRuleThemAll.prototype, "from", null);
__decorate([
    mobx_1.computed
], OneRouterToRuleThemAll.prototype, "matched", null);
__decorate([
    mobx_1.action
], OneRouterToRuleThemAll.prototype, "update", null);
__decorate([
    mobx_1.action
], OneRouterToRuleThemAll.prototype, "delete", null);
__decorate([
    mobx_1.action
], OneRouterToRuleThemAll.prototype, "replace", null);
__decorate([
    mobx_1.action
], OneRouterToRuleThemAll.prototype, "clearHistory", null);
__decorate([
    mobx_1.computed
], OneRouterToRuleThemAll.prototype, "isRestricted", null);
exports.OneRouterToRuleThemAll = OneRouterToRuleThemAll;
exports.default = OneRouterToRuleThemAll;
//# sourceMappingURL=OneRouterToRuleThemAll.js.map