5htp-core 0.1.1-2 → 0.1.1-4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "5htp-core",
|
|
3
3
|
"description": "5-HTP, scientifically called 5-Hydroxytryptophan, is the precursor of happiness neurotransmitter.",
|
|
4
|
-
"version": "0.1.1-
|
|
4
|
+
"version": "0.1.1-4",
|
|
5
5
|
"author": "Gaetan Le Gac (https://github.com/gaetanlegac)",
|
|
6
6
|
"repository": "git://github.com/gaetanlegac/5htp-core.git",
|
|
7
7
|
"license": "MIT",
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/*----------------------------------
|
|
2
|
+
- DEPENDANCES
|
|
3
|
+
----------------------------------*/
|
|
4
|
+
|
|
5
|
+
// Npm
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import type { ComponentChild } from 'preact';
|
|
8
|
+
import { history } from './request/history';
|
|
9
|
+
|
|
10
|
+
/*----------------------------------
|
|
11
|
+
- COMPONENT
|
|
12
|
+
----------------------------------*/
|
|
13
|
+
// Simple link
|
|
14
|
+
export const Link = ({ to, ...props }: {
|
|
15
|
+
to: string,
|
|
16
|
+
children?: ComponentChild,
|
|
17
|
+
class?: string,
|
|
18
|
+
className?: string
|
|
19
|
+
} & React.HTMLProps<HTMLAnchorElement>) => {
|
|
20
|
+
|
|
21
|
+
// External = open in new tab by default
|
|
22
|
+
if (to[0] !== '/' || to.startsWith('//'))
|
|
23
|
+
props.target = '_blank';
|
|
24
|
+
// Otherwise, propagate to the router
|
|
25
|
+
else
|
|
26
|
+
props.onClick = (e) => {
|
|
27
|
+
history?.push(to);
|
|
28
|
+
e.preventDefault();
|
|
29
|
+
return false
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<a {...props} href={to} />
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
}
|
|
@@ -4,119 +4,97 @@
|
|
|
4
4
|
|
|
5
5
|
// Npm
|
|
6
6
|
import React from 'react';
|
|
7
|
-
import type { ComponentChild } from 'preact';
|
|
8
|
-
import type { Location } from 'history';
|
|
9
7
|
|
|
10
8
|
// Core: libs
|
|
11
9
|
import ClientRequest from './request';
|
|
12
10
|
import ClientResponse from './response';
|
|
13
|
-
import { history } from './request/history';
|
|
14
11
|
|
|
15
12
|
// Core: types
|
|
16
|
-
import BaseRouter, {
|
|
13
|
+
import BaseRouter, { defaultOptions, } from '@common/router'
|
|
17
14
|
import { PageResponse } from '@common/router/response';
|
|
18
|
-
import {
|
|
19
|
-
import type { TSsrData, default as ServerResponse } from '@server/services/router/response';
|
|
15
|
+
import type { TSsrData } from '@server/services/router/response';
|
|
20
16
|
import type { ClientContext } from '@client/context';
|
|
21
17
|
|
|
22
18
|
// Type xports
|
|
23
19
|
export type { default as ClientResponse } from "./response";
|
|
20
|
+
export { Link } from './Link';
|
|
21
|
+
import type {
|
|
22
|
+
TClientRoute,
|
|
23
|
+
TUnresolvedRoute,
|
|
24
|
+
TSsrUnresolvedRoute,
|
|
25
|
+
TRoutesLoaders,
|
|
26
|
+
TRouteCallback,
|
|
27
|
+
TFetchedRoute,
|
|
28
|
+
TRegisterPageArgs
|
|
29
|
+
} from './route';
|
|
30
|
+
|
|
31
|
+
// Temporary
|
|
32
|
+
// TODO: Import these types directly from router/routes
|
|
33
|
+
export type {
|
|
34
|
+
TClientRoute,
|
|
35
|
+
TUnresolvedRoute,
|
|
36
|
+
TSsrUnresolvedRoute,
|
|
37
|
+
TRoutesLoaders,
|
|
38
|
+
TRouteCallback,
|
|
39
|
+
TFetchedRoute,
|
|
40
|
+
TRegisterPageArgs
|
|
41
|
+
} from './route';
|
|
24
42
|
|
|
25
43
|
/*----------------------------------
|
|
26
|
-
-
|
|
44
|
+
- CONFIG
|
|
27
45
|
----------------------------------*/
|
|
28
46
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
chunk: string,
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export type TUnresolvedRoute = Pick<TClientRoute, 'type' | 'keys'> & {
|
|
35
|
-
regex: RegExp,
|
|
36
|
-
chunk: string,
|
|
37
|
-
load: TRouteLoader,
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
type TFetchedRoute = Pick<TClientRoute, 'path' | 'options' | 'controller' | 'renderer' | 'method'>
|
|
47
|
+
const debug = true;
|
|
48
|
+
const LogPrefix = '[router]'
|
|
41
49
|
|
|
42
50
|
/*----------------------------------
|
|
43
|
-
- TYPES
|
|
51
|
+
- TYPES
|
|
44
52
|
----------------------------------*/
|
|
45
53
|
|
|
46
|
-
type
|
|
47
|
-
|
|
48
|
-
export type TRoutesLoaders = {
|
|
49
|
-
[chunkId: string]: /* Preloaded via require() */TFetchedRoute | /* Loader via import() */TRouteLoader/* | undefined*/
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
type TRouteCallback = (route?: TClientRoute) => void;
|
|
54
|
+
export type THookCallback = (request: ClientRequest) => void;
|
|
53
55
|
|
|
54
|
-
|
|
55
|
-
path: string,
|
|
56
|
-
options: Partial<TRouteOptions>,
|
|
57
|
-
controller: TFrontController<TControllerData> | null,
|
|
58
|
-
renderer: TFrontRenderer<TControllerData>
|
|
59
|
-
];
|
|
56
|
+
type THookName = 'locationChange'
|
|
60
57
|
|
|
61
58
|
/*----------------------------------
|
|
62
|
-
-
|
|
59
|
+
- ROUTER
|
|
63
60
|
----------------------------------*/
|
|
61
|
+
class Router extends BaseRouter {
|
|
64
62
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
63
|
+
/*----------------------------------
|
|
64
|
+
- HOOKS
|
|
65
|
+
----------------------------------*/
|
|
66
|
+
private hooks: {[hookname in THookName]?: THookCallback[]} = {}
|
|
67
|
+
public on( hookName: THookName, callback: THookCallback ) {
|
|
71
68
|
|
|
72
|
-
|
|
73
|
-
type TypeWithGeneric<T> = TFetcher<T>
|
|
74
|
-
type extractGeneric<Type> = Type extends TypeWithGeneric<infer X> ? X : never
|
|
75
|
-
|
|
76
|
-
export type TFrontController<TControllerData extends TFetcherList = {}> =
|
|
77
|
-
(urlParams: TObjetDonnees, context: ClientContext) => TControllerData
|
|
78
|
-
|
|
79
|
-
export type TFrontRenderer<TControllerData extends TFetcherList = {}> = (
|
|
80
|
-
data: {
|
|
81
|
-
[Property in keyof TControllerData]: undefined | (extractGeneric<TControllerData[Property]> extends ((...args: any[]) => any)
|
|
82
|
-
? ThenArg<ReturnType< extractGeneric<TControllerData[Property]> >>
|
|
83
|
-
: extractGeneric<TControllerData[Property]>
|
|
84
|
-
)
|
|
85
|
-
},
|
|
86
|
-
context: ClientContext
|
|
87
|
-
) => ComponentChild
|
|
88
|
-
|
|
89
|
-
// Simple link
|
|
90
|
-
export const Link = ({ to, ...props }: {
|
|
91
|
-
to: string,
|
|
92
|
-
children?: ComponentChild,
|
|
93
|
-
class?: string,
|
|
94
|
-
className?: string
|
|
95
|
-
}) => {
|
|
96
|
-
|
|
97
|
-
// External = open in new tab by default
|
|
98
|
-
if (to[0] !== '/' || to.startsWith('//'))
|
|
99
|
-
props.target = '_blank';
|
|
100
|
-
// Otherwise, propagate to the router
|
|
101
|
-
else
|
|
102
|
-
props.onClick = (e) => {
|
|
103
|
-
history?.push(to);
|
|
104
|
-
e.preventDefault();
|
|
105
|
-
return false
|
|
106
|
-
}
|
|
69
|
+
debug && console.info(LogPrefix, `Register hook ${hookName}`);
|
|
107
70
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
71
|
+
let cbIndex: number;
|
|
72
|
+
let callbacks = this.hooks[ hookName ];
|
|
73
|
+
if (!callbacks) {
|
|
74
|
+
cbIndex = 0;
|
|
75
|
+
callbacks = this.hooks[ hookName ] = [callback]
|
|
76
|
+
} else {
|
|
77
|
+
cbIndex = callbacks.length;
|
|
78
|
+
callbacks.push(callback);
|
|
79
|
+
}
|
|
111
80
|
|
|
112
|
-
|
|
81
|
+
// Listener remover
|
|
82
|
+
return () => {
|
|
83
|
+
debug && console.info(LogPrefix, `De-register hook ${hookName} (index ${cbIndex})`);
|
|
84
|
+
delete (callbacks as THookCallback[])[ cbIndex ];
|
|
85
|
+
}
|
|
113
86
|
|
|
114
|
-
|
|
87
|
+
}
|
|
88
|
+
private runHook( hookName: THookName, request: ClientRequest ) {
|
|
89
|
+
const callbacks = this.hooks[hookName];
|
|
90
|
+
if (callbacks)
|
|
91
|
+
for (const callback of callbacks)
|
|
92
|
+
callback(request);
|
|
93
|
+
}
|
|
115
94
|
|
|
116
|
-
/*----------------------------------
|
|
117
|
-
-
|
|
118
|
-
----------------------------------*/
|
|
119
|
-
class Router extends BaseRouter {
|
|
95
|
+
/*----------------------------------
|
|
96
|
+
- ROUTES MANAGEMENT
|
|
97
|
+
----------------------------------*/
|
|
120
98
|
|
|
121
99
|
public disableResolver = false;
|
|
122
100
|
|
|
@@ -171,6 +149,8 @@ class Router extends BaseRouter {
|
|
|
171
149
|
public async resolve( request: ClientRequest, context: ClientContext ): Promise<PageResponse | undefined | null> {
|
|
172
150
|
debug && console.log('Resolving request', request.path, Object.keys(request.data));
|
|
173
151
|
|
|
152
|
+
this.runHook('locationChange', request);
|
|
153
|
+
|
|
174
154
|
for (let iRoute = 0; iRoute < this.routes.length; iRoute++) {
|
|
175
155
|
|
|
176
156
|
let route = this.routes[iRoute];
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/*----------------------------------
|
|
2
|
+
- DEPENDANCES
|
|
3
|
+
----------------------------------*/
|
|
4
|
+
|
|
5
|
+
// Npm
|
|
6
|
+
import type { ComponentChild } from 'preact';
|
|
7
|
+
|
|
8
|
+
// Core
|
|
9
|
+
import type { ClientContext } from '@client/context';
|
|
10
|
+
import type { TBaseRoute, TRouteOptions, } from '@common/router'
|
|
11
|
+
import type { TFetcher, TFetcherList } from '@common/router/request';
|
|
12
|
+
|
|
13
|
+
/*----------------------------------
|
|
14
|
+
- TYPES: PARTIAL ROUTES
|
|
15
|
+
----------------------------------*/
|
|
16
|
+
|
|
17
|
+
export type TSsrUnresolvedRoute = Pick<TClientRoute, 'type' | 'keys'> & {
|
|
18
|
+
regex: string,
|
|
19
|
+
chunk: string,
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type TUnresolvedRoute = Pick<TClientRoute, 'type' | 'keys'> & {
|
|
23
|
+
regex: RegExp | null,
|
|
24
|
+
chunk: string,
|
|
25
|
+
load: TRouteLoader,
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export type TFetchedRoute = Pick<TClientRoute, 'path' | 'options' | 'controller' | 'renderer' | 'method'>
|
|
29
|
+
|
|
30
|
+
/*----------------------------------
|
|
31
|
+
- TYPES: REGISTER
|
|
32
|
+
----------------------------------*/
|
|
33
|
+
|
|
34
|
+
type TRouteLoader = () => Promise<{ default: TFetchedRoute }>;
|
|
35
|
+
|
|
36
|
+
export type TRoutesLoaders = {
|
|
37
|
+
[chunkId: string]: /* Preloaded via require() */TFetchedRoute | /* Loader via import() */TRouteLoader/* | undefined*/
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export type TRouteCallback = (route?: TClientRoute) => void;
|
|
41
|
+
|
|
42
|
+
export type TRegisterPageArgs<TControllerData extends TFetcherList = {}> = [
|
|
43
|
+
path: string,
|
|
44
|
+
options: Partial<TRouteOptions>,
|
|
45
|
+
controller: TFrontController<TControllerData> | null,
|
|
46
|
+
renderer: TFrontRenderer<TControllerData>
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
/*----------------------------------
|
|
50
|
+
- TYPES: COMPLETE ROUTES
|
|
51
|
+
----------------------------------*/
|
|
52
|
+
|
|
53
|
+
export type TClientRoute = TBaseRoute & {
|
|
54
|
+
type: 'PAGE',
|
|
55
|
+
method: 'GET',
|
|
56
|
+
controller: TFrontController | null,
|
|
57
|
+
renderer: TFrontRenderer
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// https://stackoverflow.com/questions/44851268/typescript-how-to-extract-the-generic-parameter-from-a-type
|
|
61
|
+
type TypeWithGeneric<T> = TFetcher<T>
|
|
62
|
+
type extractGeneric<Type> = Type extends TypeWithGeneric<infer X> ? X : never
|
|
63
|
+
|
|
64
|
+
export type TFrontController<TControllerData extends TFetcherList = {}> =
|
|
65
|
+
(urlParams: TObjetDonnees, context: ClientContext) => TControllerData
|
|
66
|
+
|
|
67
|
+
export type TFrontRenderer<TControllerData extends TFetcherList = {}> = (
|
|
68
|
+
data: {
|
|
69
|
+
[Property in keyof TControllerData]: undefined | (extractGeneric<TControllerData[Property]> extends ((...args: any[]) => any)
|
|
70
|
+
? ThenArg<ReturnType< extractGeneric<TControllerData[Property]> >>
|
|
71
|
+
: extractGeneric<TControllerData[Property]>
|
|
72
|
+
)
|
|
73
|
+
},
|
|
74
|
+
context: ClientContext
|
|
75
|
+
) => ComponentChild
|