@@ -3,10 +3,17 @@ import fs from 'fs';
33import path from 'path' ;
44
55import { glob } from 'glob' ;
6+ import { set } from 'lodash' ;
67
78import { AnyServiceLocals , ServiceExpress , ServiceLocals } from '../types' ;
89import { ConfigurationSchema } from '../config/schema' ;
910
11+ const REPL_PROP = '$$repl$$' ;
12+
13+ interface WithReplProp {
14+ [ REPL_PROP ] ?: string ;
15+ }
16+
1017export function serviceRepl < SLocals extends AnyServiceLocals = ServiceLocals < ConfigurationSchema > > (
1118 app : ServiceExpress < SLocals > ,
1219 codepath : string | undefined ,
@@ -51,23 +58,20 @@ function loadReplFunctions<SLocals extends AnyServiceLocals = ServiceLocals<Conf
5158 // Read the file content as text
5259 const fileContent = fs . readFileSync ( file , 'utf-8' ) ;
5360
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 ) ) {
5663 // 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 ) ) ;
5865
59- // Look for functions with the __isReplFunction marker
66+ // Look for functions with the REPL_PROP marker
6067 Object . values ( module ) . forEach ( ( exported ) => {
6168 if ( ! exported ) {
6269 return ;
6370 }
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 ) ) ;
7175 }
7276 }
7377 } ) ;
@@ -78,17 +82,32 @@ function loadReplFunctions<SLocals extends AnyServiceLocals = ServiceLocals<Conf
7882 } ) ;
7983}
8084
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+
8189/**
8290 * This decorator-like function can be applied to functions and the service will load and expose
8391 * 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');
84100 */
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 ) {
89105 const functionName = name || fn . name ;
90106 if ( ! functionName ) {
91107 throw new Error ( 'Function must have a name or a name must be provided.' ) ;
92108 }
93- ( fn as unknown as { __openApiServiceReplFunction : string } ) . __openApiServiceReplFunction = functionName ;
109+ Object . defineProperty ( fn , REPL_PROP , {
110+ enumerable : false ,
111+ value : functionName ,
112+ } ) ;
94113}
0 commit comments