@@ -3,10 +3,17 @@ import fs from 'fs';
3
3
import path from 'path' ;
4
4
5
5
import { glob } from 'glob' ;
6
+ import { set } from 'lodash' ;
6
7
7
8
import { AnyServiceLocals , ServiceExpress , ServiceLocals } from '../types' ;
8
9
import { ConfigurationSchema } from '../config/schema' ;
9
10
11
+ const REPL_PROP = '$$repl$$' ;
12
+
13
+ interface WithReplProp {
14
+ [ REPL_PROP ] ?: string ;
15
+ }
16
+
10
17
export function serviceRepl < SLocals extends AnyServiceLocals = ServiceLocals < ConfigurationSchema > > (
11
18
app : ServiceExpress < SLocals > ,
12
19
codepath : string | undefined ,
@@ -51,23 +58,20 @@ function loadReplFunctions<SLocals extends AnyServiceLocals = ServiceLocals<Conf
51
58
// Read the file content as text
52
59
const fileContent = fs . readFileSync ( file , 'utf-8' ) ;
53
60
54
- // Check if @ repl is present
55
- if ( / a d d T o R e p l \( / . test ( fileContent ) ) {
61
+ // Check if repl$ is present, in a very rudimentary way
62
+ if ( / r e p l \$ \( / . test ( fileContent ) ) {
56
63
// eslint-disable-next-line global-require, import/no-dynamic-require, @typescript-eslint/no-var-requires
57
- const module = require ( file ) ; // Only require if @repl is found
64
+ const module = require ( path . resolve ( file ) ) ;
58
65
59
- // Look for functions with the __isReplFunction marker
66
+ // Look for functions with the REPL_PROP marker
60
67
Object . values ( module ) . forEach ( ( exported ) => {
61
68
if ( ! exported ) {
62
69
return ;
63
70
}
64
- if ( typeof exported === 'function' || typeof exported === 'object' ) {
65
- const obj = exported as Record < string , unknown > ;
66
- for ( const key of Object . keys ( obj ) ) {
67
- if ( ( obj [ key ] as { __openApiServiceReplFunction ?: boolean } ) . __openApiServiceReplFunction ) {
68
- const fn = obj [ key ] as ( app : ServiceExpress < SLocals > , ...args : unknown [ ] ) => unknown ;
69
- rl . context [ key ] = ( ...args : unknown [ ] ) => fn ( app , ...args ) ;
70
- }
71
+ if ( typeof exported === 'function' ) {
72
+ const replName = ( exported as WithReplProp ) [ REPL_PROP ] ;
73
+ if ( replName ) {
74
+ set ( rl . context , replName , exported . bind ( null , app ) ) ;
71
75
}
72
76
}
73
77
} ) ;
@@ -78,17 +82,32 @@ function loadReplFunctions<SLocals extends AnyServiceLocals = ServiceLocals<Conf
78
82
} ) ;
79
83
}
80
84
85
+ // Can't seem to sort out proper generics here, so we'll just use any since it's dev only
86
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
87
+ type ReplAny = any ;
88
+
81
89
/**
82
90
* This decorator-like function can be applied to functions and the service will load and expose
83
91
* the function when the repl is engaged.
92
+ *
93
+ * async function myFunction(app: MyService['App'], arg1: string, arg2: number) {
94
+ * }
95
+ * repl$(myFunction);
96
+ *
97
+ * or
98
+ *
99
+ * repl(myFunction, 'some.func.name');
84
100
*/
85
- export function addToRepl < SLocals extends AnyServiceLocals = ServiceLocals < ConfigurationSchema > > (
86
- fn : ( app : ServiceExpress < SLocals > , ... args : unknown [ ] ) => unknown ,
87
- name ?: string ,
88
- ) {
101
+ export function repl$ <
102
+ S extends ServiceExpress < ReplAny > ,
103
+ T extends ( app : S , ... args : ReplAny [ ] ) => ReplAny
104
+ > ( fn : T , name ?: string ) {
89
105
const functionName = name || fn . name ;
90
106
if ( ! functionName ) {
91
107
throw new Error ( 'Function must have a name or a name must be provided.' ) ;
92
108
}
93
- ( fn as unknown as { __openApiServiceReplFunction : string } ) . __openApiServiceReplFunction = functionName ;
109
+ Object . defineProperty ( fn , REPL_PROP , {
110
+ enumerable : false ,
111
+ value : functionName ,
112
+ } ) ;
94
113
}
0 commit comments