galbe 0.4.1 → 0.5.0

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/docs/plugins.md CHANGED
@@ -17,7 +17,7 @@ type GalbePlugin = {
17
17
 
18
18
  **name**
19
19
 
20
- The name should be a Unique Plugin Identifier. It should be chosen to be unique to avoid conflicts with other potential plugins. For example, Galbe's official plugins names will always start with `dev.galbe.*`.
20
+ The name should be a Unique Plugin Identifier. It should be chosen to be unique to avoid conflicts with other potential plugins. Ideally, it will have the form of `com.example.myplugin`.
21
21
 
22
22
  **init**
23
23
 
@@ -62,44 +62,44 @@ Here is an example of a plugin implementation that handles routes tagged with `@
62
62
 
63
63
  ```ts
64
64
  // myPlugin.ts
65
-
66
- import { Galbe, type Context, type Route } from 'galbe'
67
-
68
- class MyPlugin {
69
- name = 'dev.galbe.example'
70
- deprecated: Record<string, string[]> = {}
71
- // Retrieve and store all route with a @deprecated flag metadata
72
- init(config: any, galbe: Galbe) {
73
- if (config?.enabled && galbe.meta) {
74
- for (const f of galbe.meta) {
75
- for (const [path, methods] of Object.entries(f.routes)) {
76
- for (const [method, meta] of Object.entries(methods)) {
77
- if (meta.deprecated) {
78
- if (!this.deprecated?.[method]) this.deprecated[method] = []
79
- this.deprecated[method].push(path)
80
- }
81
- }
82
- }
65
+ import type { GalbePlugin } from 'galbe'
66
+ import { walkMetaRoutes } from 'galbe/utils'
67
+
68
+ const PLUGIN_ID = 'dev.galbe.deprecated'
69
+
70
+ export default () => {
71
+ let deprecateds = new Set<string>()
72
+ return {
73
+ name: PLUGIN_ID,
74
+ // Init the plugin, check for deprecated metadata tags
75
+ init(_config, galbe) {
76
+ if (galbe.meta) {
77
+ walkMetaRoutes(galbe.meta, (method, path, meta) => {
78
+ if (meta.deprecated) deprecateds.add(JSON.stringify({ method, path }))
79
+ })
80
+ }
81
+ },
82
+ // Check if the current route is deprecated; if so, flag it as such and log it
83
+ onRoute(context) {
84
+ let r = context.route
85
+ if (!r) return
86
+ if (deprecateds.has(JSON.stringify({ method: r.method, path: r.path }))) {
87
+ context.state[PLUGIN_ID] = { deprecated: true }
88
+ console.warn(`Call to deprecated route "${r.method} ${r.path}"`)
89
+ }
90
+ },
91
+ // Add a header to the response if the route has been flagged as deprecated
92
+ afterHandle(response, context) {
93
+ let r = context.route
94
+ if (!r) return
95
+ console.log('yooo', r.method, r.path)
96
+ if (deprecateds.has(JSON.stringify({ method: r.method, path: r.path }))) {
97
+ console.log('OK...')
98
+ response.headers.set('x-deprecated', 'true')
83
99
  }
84
100
  }
85
- }
86
- // Check if the current route is deprecated; if so, flag it as such and log it
87
- onRoute(context: Context) {
88
- let route = context.route
89
- if (this.deprecated?.[route.method]?.includes(route.path)) {
90
- context.state[this.name] = { deprecated: true }
91
- console.warn(`Call to deprecated route [${route.method}]${route.path}`)
92
- }
93
- }
94
- // Add a header if the request has previously been flagged as deprecated
95
- afterHandle(response: Response, context: Context) {
96
- if (context.state?.[this.name]?.deprecated) {
97
- response.headers.set('x-deprecated', 'true')
98
- }
99
- }
101
+ } as GalbePlugin
100
102
  }
101
-
102
- export default new MyPlugin()
103
103
  ```
104
104
 
105
105
  ```ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "galbe",
3
- "version": "0.4.1",
3
+ "version": "0.5.0",
4
4
  "description": "Fast, lightweight and highly customizable JavaScript web framework based on Bun",
5
5
  "author": "Pierre Caillaud M (https://github.com/pierre-cm)",
6
6
  "type": "module",
package/src/routes.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { GalbeConfig, Route } from './types'
1
+ import type { GalbeConfig, Method, Route } from './types'
2
2
 
3
3
  import { readdir, lstat } from 'fs/promises'
4
4
  import { extname } from 'path'
@@ -13,7 +13,7 @@ export const DEFAULT_ROUTE_PATTERN = 'src/**/*.route.{js,ts}'
13
13
  export type RouteMeta = { head?: string } & Record<string, boolean | string | string[]>
14
14
  export type RoutesMeta = {
15
15
  header: Record<string, boolean | string | string[]>
16
- routes: Record<string, Record<string, RouteMeta>>
16
+ routes: Record<string, Partial<Record<Method, RouteMeta>>>
17
17
  }
18
18
  export type RouteInstanciationCallback = <T extends 'add' | 'error'>(event: {
19
19
  type: T
@@ -204,7 +204,7 @@ export const metaAnalysis = async (filePath: string): Promise<RoutesMeta> => {
204
204
  // @ts-ignore
205
205
  const path = node.arguments[0].value
206
206
  // @ts-ignore
207
- const method = node.callee.property.name
207
+ const method = node.callee.property.name as Method
208
208
  const line = node.loc?.start.line || -1
209
209
  const col = node.loc?.start.column || -1
210
210
  const com = comments?.[line]?.[col - 1] ? comments[line][col - 1] : ''
package/src/util.ts CHANGED
@@ -1,5 +1,5 @@
1
- import type { Route, RouteNode } from '.'
2
- import type { RouteMeta } from './routes'
1
+ import type { Method, Route, RouteNode } from '.'
2
+ import type { RouteFileMeta, RouteMeta } from './routes'
3
3
 
4
4
  const METHOD_COLOR: Record<string, string> = {
5
5
  get: '\x1b[32m',
@@ -24,12 +24,31 @@ export const logRoute = (
24
24
  )
25
25
  }
26
26
 
27
+ /**
28
+ * Walk over the routes tree. A callback is called for each route with Route infos.
29
+ */
27
30
  export const walkRoutes = (node: RouteNode, cb: (route: Route) => void) => {
28
31
  if (node?.routes) Object.values(node.routes).forEach(r => cb(r))
29
32
  for (let c of Object.values(node?.children || {})) walkRoutes(c, cb)
30
33
  if (node?.param) walkRoutes(node.param, cb)
31
34
  }
32
35
 
36
+ /**
37
+ * Walk over the routes metadata tree. A callback is called for each route metadata with RouteMeta infos.
38
+ */
39
+ export const walkMetaRoutes = (
40
+ meta: RouteFileMeta[],
41
+ cb: (method: Method, path: string, routeMeta: RouteMeta) => void
42
+ ) => {
43
+ for (const f of meta) {
44
+ for (const [path, methods] of Object.entries(f.routes)) {
45
+ for (const [method, meta] of Object.entries(methods)) {
46
+ cb(method as Method, path, meta)
47
+ }
48
+ }
49
+ }
50
+ }
51
+
33
52
  export const isIterator = (obj: any) => typeof obj?.next === 'function'
34
53
 
35
54
  export const HttpStatus = {