UNPKG

ngx-route-manager

Version:
301 lines (287 loc) 9.34 kB
import * as i0 from '@angular/core'; import { signal, InjectionToken, APP_INITIALIZER, NgModule, computed } from '@angular/core'; import { NavigationEnd, Router, ActivatedRoute } from '@angular/router'; import { filter, of, map } from 'rxjs'; const internalSignalRoute = signal(undefined); // Factory function to initialize the service function listenForRouteChange(router, route) { return () => { internalSignalRoute.set(route); const subscription = router.events.pipe(filter(event => event instanceof NavigationEnd)).subscribe(() => { // Traverse to the most deeply activated route let route = router.routerState.root; while (route.firstChild) { route = route.firstChild; } internalSignalRoute.set(route); }); return () => subscription.unsubscribe(); }; } const NGX_ROUTE_MANAGER_CONFIG = new InjectionToken('NGX_ROUTE_MANAGER_CONFIG'); class NgxRouteManagerModule { static forRoot(config) { return { ngModule: NgxRouteManagerModule, providers: [ { provide: NGX_ROUTE_MANAGER_CONFIG, useValue: config }, { provide: APP_INITIALIZER, useFactory: listenForRouteChange, deps: [Router, ActivatedRoute], multi: true } ] }; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: NgxRouteManagerModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.0.5", ngImport: i0, type: NgxRouteManagerModule }); static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: NgxRouteManagerModule }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: NgxRouteManagerModule, decorators: [{ type: NgModule, args: [{}] }] }); function createUrlFunction(template, queryParamsKeys) { return ((args, queryParams) => { if (!args && template.includes(':')) { throw new Error('Arguments are required for this template'); } if (args && !template.includes(':')) { throw new Error('This template does not accept any arguments'); } let path = template.replace(/:([a-zA-Z]+)/g, (_, key) => { const value = args?.[key]; if (value === undefined) throw new Error(`Missing value for parameter: ${key}`); return value; }); if (queryParams && Object.keys(queryParams).length > 0) { const searchParams = new URLSearchParams(queryParams).toString(); path += `?${searchParams}`; } return path; }); } function createUrlFunctionV2(template, queryParamsKeys) { return ((args, queryParams) => { if (!args && template.includes(':')) { throw new Error('Arguments are required for this template'); } if (args && !template.includes(':')) { throw new Error('This template does not accept any arguments'); } let path = template.replace(/:([a-zA-Z]+)/g, (_, key) => { const value = args?.[key]; if (value === undefined) throw new Error(`Missing value for parameter: ${key}`); return value; }); if (queryParams && Object.keys(queryParams).length > 0) { const searchParams = new URLSearchParams(queryParams).toString(); path += `?${searchParams}`; } return parseUrl(path); }); } function parseUrl(url) { const [path, queryString] = url.split('?'); const params = new URLSearchParams(queryString || ''); const queryParams = {}; params.forEach((value, key) => { queryParams[key] = value; }); return { route: [path], extras: { queryParams }, }; } class NgxParam { /** * Name of the param */ _name = ''; get name() { return this._name; } /** * Returns the current snapshoot of the value in the url route */ snapshotValue = computed(() => { if (!internalSignalRoute()) { return ''; } else { return internalSignalRoute()?.snapshot.paramMap.get(this.name) || ''; } }); /** * Listens for change on param in the route */ listenForValue = computed(() => { if (!internalSignalRoute()) { console.log(internalSignalRoute()); return of(''); } else { return internalSignalRoute()?.paramMap .pipe(filter(paramMap => paramMap.has(this.name)), map(paramMap => paramMap.get(this.name) || '')); } }); constructor(name) { this._name = name; } } function urlToNgxParam(route) { const segments = route.split('/'); const params = {}; segments.forEach((segment) => { if (segment.startsWith(':')) { const param = segment.slice(1); if (!/^[A-Za-z]+$/.test(param)) { throw new Error(`${param} must contain only alphabets in ${route}`); } params[param] = new NgxParam(param); } }); return params; } class NgxRoute { /** * The url path */ path = ''; /** * Function to generate the url, requiring the right params */ fn = {}; /** * Function to generate the url, requiring the right params */ url = {}; /** * Stores all the params as */ _params = {}; /** * Stores all the params as */ _queryParams = {}; /** * Stores all the segments as */ _segments = {}; constructor(path, fn, url, params, segments, queryParams) { this.path = path; this.fn = fn; this.url = url; this._params = params; this._segments = segments; this._queryParams = queryParams; } /** * All params store as an object */ get params() { return this._params; } /** * All query params store as an object */ get queryParams() { return this._queryParams; } /** * All segments store as an object */ get segments() { return this._segments; } } /** * Extracts static segments from a URL pattern and returns them as a typed object * Types are automatically inferred from the URL pattern * @param url - The URL pattern to parse * @returns Object with extracted segments with automatic type inference */ function urlToSegments(url) { // Remove leading and trailing slashes const cleanUrl = url.replace(/^\/+|\/+$/g, ''); // Split the URL into segments const segments = cleanUrl.split('/'); // Initialize result object const result = {}; // Process each segment segments.forEach(segment => { // Skip dynamic segments (those starting with ':') if (segment.startsWith(':') || segment.trim().length == 0) { return; } if (!/^[a-zA-Z][a-zA-Z0-9-_]*$/.test(segment)) { throw new Error(`Segment '${segment}' must start with a letter and contain only letters, numbers, hyphens, or underscores in ${url}`); } // Add valid segments to result object result[segment] = segment; }); return result; } class NgxQueryParam { /** * Name of the param */ _name = ''; get name() { return this._name; } /** * Returns the current snapshot of the value in the query url route */ snapshotValue = computed(() => { if (!internalSignalRoute()) { return ''; } else { return internalSignalRoute()?.snapshot.queryParamMap.get(this.name) || ''; } }); /** * Listens for change on param in the query route */ listenForValue = computed(() => { if (!internalSignalRoute()) { return of(''); } else { const route = internalSignalRoute() || {}; return route.queryParamMap.pipe(filter((queryParamMap) => queryParamMap.has(this.name)), map((queryParamMap) => queryParamMap.get(this.name) || '')); } }); constructor(name) { this._name = name; } } function urlToNgxQueryParam(route) { return route.reduce((a, b) => { if (!/^[A-Za-z_]+$/.test(b)) { throw new Error(`${b} must contain only alphabets and underscore`); } a[b] = new NgxQueryParam(b); return a; }, {}); } function generateNgxRoute(urlPattern, queryParamsKeys = []) { const pattern = urlPattern ? urlPattern : ''; const ngxRoute = new NgxRoute(pattern, createUrlFunction(pattern), createUrlFunctionV2(pattern), urlToNgxParam(pattern), urlToSegments(pattern), urlToNgxQueryParam(queryParamsKeys)); return ngxRoute; } /* * Public API Surface of ngx-route-manager */ /** * Generated bundle index. Do not edit. */ export { NgxRouteManagerModule, generateNgxRoute }; //# sourceMappingURL=ngx-route-manager.mjs.map