Skip to content

Commit

Permalink
add routeUtils
Browse files Browse the repository at this point in the history
  • Loading branch information
antoniopresto committed Dec 1, 2023
1 parent aca96a6 commit 3e0d272
Show file tree
Hide file tree
Showing 24 changed files with 440 additions and 22 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "powership",
"version": "3.1.7",
"version": "3.1.9",
"private": true,
"scripts": {
"pack": "run-s pack:*",
Expand Down
2 changes: 1 addition & 1 deletion packages/accounts/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@powership/accounts",
"version": "3.1.7",
"version": "3.1.9",
"description": "Powership accounts",
"#type": "module",
"main": "./out/index.cjs",
Expand Down
2 changes: 1 addition & 1 deletion packages/babel-plugins/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@powership/babel-plugins",
"version": "3.1.7",
"version": "3.1.9",
"main": "out",
"sideEffects": false,
"typings": "out",
Expand Down
2 changes: 1 addition & 1 deletion packages/boilerplate/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@powership/boilerplate",
"version": "3.1.7",
"version": "3.1.9",
"author": "antoniopresto <[email protected]>",
"sideEffects": false,
"#type": "module",
Expand Down
2 changes: 1 addition & 1 deletion packages/deepstate/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@powership/deepstate",
"version": "3.1.7",
"version": "3.1.9",
"main": "out/index.js",
"module": "out/module/index.mjs",
"sideEffects": false,
Expand Down
2 changes: 1 addition & 1 deletion packages/entity/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@powership/entity",
"version": "3.1.7",
"version": "3.1.9",
"#type": "module",
"main": "./out/index.cjs",
"module": "./out/module/index.mjs",
Expand Down
2 changes: 1 addition & 1 deletion packages/helpers/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@powership/helpers",
"version": "3.1.7",
"version": "3.1.9",
"#type": "module",
"main": "./out/index.cjs",
"module": "./out/module/index.mjs",
Expand Down
2 changes: 1 addition & 1 deletion packages/logstorm/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "logstorm",
"version": "3.1.7",
"version": "3.1.9",
"typings": "out",
"author": "antoniopresto <[email protected]>",
"#type": "module",
Expand Down
2 changes: 1 addition & 1 deletion packages/mongo/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@powership/mongo",
"version": "3.1.7",
"version": "3.1.9",
"#type": "module",
"main": "./out/index.cjs",
"module": "./out/module/index.mjs",
Expand Down
2 changes: 1 addition & 1 deletion packages/plugin-engine/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "plugin-engine",
"version": "3.1.7",
"version": "3.1.9",
"#type": "module",
"main": "./out/index.cjs",
"module": "./out/module/index.mjs",
Expand Down
2 changes: 1 addition & 1 deletion packages/powership/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "powership",
"version": "3.1.7",
"version": "3.1.9",
"author": "antoniopresto <[email protected]>",
"#type": "module",
"main": "./out/index.cjs",
Expand Down
2 changes: 1 addition & 1 deletion packages/runmate/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "runmate",
"version": "3.1.7",
"version": "3.1.9",
"typings": "out",
"author": "antoniopresto <[email protected]>",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion packages/schema/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@powership/schema",
"version": "3.1.7",
"version": "3.1.9",
"#type": "module",
"main": "./out/index.cjs",
"module": "./out/module/index.mjs",
Expand Down
23 changes: 23 additions & 0 deletions packages/schema/src/__tests__/createSimpleRouter.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { createSimpleRouter } from '../createRoutes';

describe('createSimpleRouter', () => {
const routes = createSimpleRouter({
home: { path: '/home' },
about: { path: '/about', query: { foo: 'int' } },
});

test('should create route handlers for each route', () => {
expect(typeof routes.home.match).toBe('function');
expect(typeof routes.home.mount).toBe('function');
expect(typeof routes.about.match).toBe('function');
expect(typeof routes.about.mount).toBe('function');
});

test('mount should return correct URL without query', () => {
expect(routes.home.mount()).toBe('/home');
});

test('mount should return correct URL with query', () => {
expect(routes.about.mount({ query: { foo: 1 } })).toBe('/about?foo=1');
});
});
53 changes: 53 additions & 0 deletions packages/schema/src/createSimpleRouter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { AnyRecord, RouteMatcher, RouteUtils } from '@powership/utils';

import type { InferObjectDefinition } from './fields/Infer';
import type { ObjectDefinitionInput } from './fields/_parseFields';

export type RouteConfig = {
path: string;
query?: ObjectDefinitionInput;
};

export type SimpleRoute = RouteConfig & {
match(route: string): AnyRecord | null;
mount(config?: { query: AnyRecord }): string;
};

export type SimpleRouter<
Routes extends Readonly<{ [K: string]: RouteConfig }>
> = {
[K in Extract<keyof Routes, string>]: { [K in keyof Routes]: Routes[K] } & {
match: RouteMatcher<K>['match'];
mount: [InferObjectDefinition<Routes[K]['query']>] extends [never]
? () => string
: (config: {
query: InferObjectDefinition<Routes[K]['query']>;
}) => string;
};
};

export function createSimpleRouter<
Routes extends Readonly<{ [K: string]: RouteConfig }>
>(config: Routes): SimpleRouter<Routes> {
const router = Object.create(null);

Object.entries(config).forEach(([key, definition]) => {
const { match } = RouteUtils.createRouteMatcher(definition.path);

const route: SimpleRoute = {
...definition,
match,
mount(conf?: any) {
let url = '/' + RouteUtils.normalizePath(definition.path);
if (conf?.query) {
url += '?' + RouteUtils.stringifyQueryString(conf.query);
}
return url;
},
};

router[key] = route;
});

return router;
}
1 change: 1 addition & 0 deletions packages/schema/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export * from './fields/FieldTypeErrors';
export * from './extendObjectDefinition';
export * from './extendType';
export * from './isHiddenFieldName';
export * from './createSimpleRouter';

// @only-server
export * from './Resolver';
Expand Down
2 changes: 1 addition & 1 deletion packages/server/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@powership/server",
"version": "3.1.7",
"version": "3.1.9",
"#type": "module",
"main": "./out/index.cjs",
"module": "./out/module/index.mjs",
Expand Down
4 changes: 2 additions & 2 deletions packages/server/src/routeMatch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,15 @@ export type GetRouteParams<Path extends string> = IsKnown<Path> extends 0
} extends infer Parsed
? {
// removing ending "?" simbol
[K in ExcludeOptionalSimbol<keyof Parsed>]: Parsed extends {
[K in ExcludeOptionalSymbol<keyof Parsed>]: Parsed extends {
[KK in `${K}?`]: any;
}
? AlphaNumeric | undefined
: AlphaNumeric;
}
: never;

type ExcludeOptionalSimbol<T> = Extract<
type ExcludeOptionalSymbol<T> = Extract<
T extends `${infer Value}?` ? Value : T,
string
>;
2 changes: 1 addition & 1 deletion packages/transporter/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@powership/transporter",
"version": "3.1.7",
"version": "3.1.9",
"#type": "module",
"main": "./out/index.cjs",
"module": "./out/module/index.mjs",
Expand Down
7 changes: 5 additions & 2 deletions packages/utils/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@powership/utils",
"version": "3.1.7",
"version": "3.1.9",
"typings": "out",
"author": "antoniopresto <[email protected]>",
"license": "MIT",
Expand Down Expand Up @@ -62,7 +62,9 @@
"prettier": "2.8.8",
"slugify": "1.6.5",
"ts-toolbelt": "9.6.0",
"ulid": "2.3.0"
"ulid": "2.3.0",
"qs": "6.11.2",
"url-pattern": "1.0.3"
},
"devDependencies": {
"@powership/boilerplate": "workspace:*",
Expand All @@ -72,6 +74,7 @@
"@babel/preset-typescript": "7.18.6",
"@powership/babel-plugins": "workspace:*",
"@types/big.js": "6.1.6",
"@types/qs": "6.9.10",
"@types/deep-diff": "^1.0.2",
"@types/ejson": "2.2.0",
"@types/fs-extra": "9.0.13",
Expand Down
86 changes: 86 additions & 0 deletions packages/utils/src/__tests__/routeUtils.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { RouteUtils } from '../routeUtils'; // Adjust the import path as necessary

describe('RouteUtils', () => {
describe('normalizePath', () => {
it('should remove starting and trailing slashes', () => {
expect(RouteUtils.normalizePath('/a/b/c/')).toBe('a/b/c');
});

it('should remove double slashes', () => {
expect(RouteUtils.normalizePath('a//b//c')).toBe('a/b/c');
});
});

describe('joinPaths', () => {
it('should join multiple path segments', () => {
expect(
RouteUtils.joinPaths('/a/', 'b', null, undefined, '', '/c', 'd/')
).toBe('a/b/c/d');
});
});

describe('parseQueryString', () => {
it('should parse query string into an object', () => {
expect(RouteUtils.parseQueryString('?key1=value1&key2=value2')).toEqual({
key1: 'value1',
key2: 'value2',
});
});
});

describe('stringifyQueryString', () => {
it('should stringify an object into a query string', () => {
expect(
RouteUtils.stringifyQueryString({ key1: 'value1', key2: 'value2' })
).toBe('key1=value1&key2=value2');
});
});

describe('resortQueryString', () => {
it('should resort query string', () => {
expect(RouteUtils.resortQueryString('?b=2&a=1')).toBe('a=1&b=2');
});
});

describe('parseURL', () => {
it('should parse URL into its components', () => {
const parsed = RouteUtils.parseURL('/test?query=string#hash');

expect(parsed).toEqual({
pathname: '/test',
search: '?query=string',
hash: '#hash',
route: '/test?query=string#hash',
id: 'test^query=string^hash',
href: 'http://localhost/test?query=string#hash',
domain: 'http://localhost',
isAbsolutePath: false,
protocol: 'http:',
host: 'localhost',
hostname: 'localhost',
port: '',
});
});
});

describe('isSamePathname', () => {
it('should return true for URLs with the same pathname', () => {
expect(
RouteUtils.isSamePathname('http://localhost/a', 'http://example.com/a')
).toBe(true);
});

it('should return false for URLs with different pathnames', () => {
expect(
RouteUtils.isSamePathname('http://localhost/a', 'http://example.com/b')
).toBe(false);
});
});

describe('createRouteMatcher', () => {
it('should create a route matcher and match a given route', () => {
const matcher = RouteUtils.createRouteMatcher('/test/:id');
expect(matcher.match('/test/123')).toEqual({ id: '123' });
});
});
});
1 change: 1 addition & 0 deletions packages/utils/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ export * from './objectEntries';
export * from './immer';
export * from './MicroState';
export * from './skipper';
export * from './routeUtils';

// @only-server
export * from './logLevels';
Expand Down
Loading

0 comments on commit 3e0d272

Please sign in to comment.