ngx-route-manager
Version:
A route management library for Angular
301 lines (287 loc) • 9.34 kB
JavaScript
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