@pikku/inspector 0.9.4 → 0.9.6-next.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.
Files changed (95) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/{add-channel.d.ts → add/add-channel.d.ts} +2 -2
  3. package/dist/{add-channel.js → add/add-channel.js} +12 -5
  4. package/dist/add/add-cli.d.ts +5 -0
  5. package/dist/add/add-cli.js +461 -0
  6. package/dist/{add-file-extends-core-type.d.ts → add/add-file-extends-core-type.d.ts} +2 -2
  7. package/dist/{add-file-extends-core-type.js → add/add-file-extends-core-type.js} +17 -5
  8. package/dist/{add-file-with-config.d.ts → add/add-file-with-config.d.ts} +1 -1
  9. package/dist/{add-file-with-config.js → add/add-file-with-config.js} +1 -1
  10. package/dist/{add-file-with-factory.d.ts → add/add-file-with-factory.d.ts} +1 -1
  11. package/dist/{add-file-with-factory.js → add/add-file-with-factory.js} +4 -4
  12. package/dist/add/add-functions.d.ts +6 -0
  13. package/dist/{add-functions.js → add/add-functions.js} +26 -6
  14. package/dist/{add-http-route.d.ts → add/add-http-route.d.ts} +2 -3
  15. package/dist/{add-http-route.js → add/add-http-route.js} +10 -4
  16. package/dist/add/add-mcp-prompt.d.ts +2 -0
  17. package/dist/{add-mcp-prompt.js → add/add-mcp-prompt.js} +10 -4
  18. package/dist/add/add-mcp-resource.d.ts +2 -0
  19. package/dist/{add-mcp-resource.js → add/add-mcp-resource.js} +10 -4
  20. package/dist/add/add-mcp-tool.d.ts +2 -0
  21. package/dist/{add-mcp-tool.js → add/add-mcp-tool.js} +10 -4
  22. package/dist/add/add-middleware.d.ts +5 -0
  23. package/dist/add/add-middleware.js +251 -0
  24. package/dist/add/add-permission.d.ts +6 -0
  25. package/dist/{add-permission.js → add/add-permission.js} +4 -3
  26. package/dist/add/add-queue-worker.d.ts +2 -0
  27. package/dist/{add-queue-worker.js → add/add-queue-worker.js} +10 -4
  28. package/dist/{add-rpc-invocations.d.ts → add/add-rpc-invocations.d.ts} +1 -1
  29. package/dist/add/add-schedule.d.ts +2 -0
  30. package/dist/{add-schedule.js → add/add-schedule.js} +10 -4
  31. package/dist/index.d.ts +2 -0
  32. package/dist/index.js +1 -0
  33. package/dist/inspector.d.ts +2 -3
  34. package/dist/inspector.js +19 -8
  35. package/dist/types.d.ts +79 -0
  36. package/dist/{utils.d.ts → utils/extract-function-name.d.ts} +7 -15
  37. package/dist/{utils.js → utils/extract-function-name.js} +23 -142
  38. package/dist/utils/extract-services.d.ts +6 -0
  39. package/dist/utils/extract-services.js +29 -0
  40. package/dist/utils/filter-utils.d.ts +9 -0
  41. package/dist/utils/filter-utils.js +45 -0
  42. package/dist/utils/get-files-and-methods.d.ts +21 -0
  43. package/dist/utils/get-files-and-methods.js +60 -0
  44. package/dist/utils/middleware.d.ts +39 -0
  45. package/dist/utils/middleware.js +157 -0
  46. package/dist/utils/type-utils.d.ts +3 -0
  47. package/dist/utils/type-utils.js +50 -0
  48. package/dist/visit.d.ts +3 -3
  49. package/dist/visit.js +33 -30
  50. package/package.json +3 -4
  51. package/run-tests.sh +1 -1
  52. package/src/{add-channel.ts → add/add-channel.ts} +19 -19
  53. package/src/add/add-cli.ts +663 -0
  54. package/src/{add-file-extends-core-type.ts → add/add-file-extends-core-type.ts} +21 -6
  55. package/src/{add-file-with-config.ts → add/add-file-with-config.ts} +2 -2
  56. package/src/{add-file-with-factory.ts → add/add-file-with-factory.ts} +5 -5
  57. package/src/{add-functions.ts → add/add-functions.ts} +30 -15
  58. package/src/{add-http-route.ts → add/add-http-route.ts} +23 -14
  59. package/src/{add-mcp-prompt.ts → add/add-mcp-prompt.ts} +18 -15
  60. package/src/{add-mcp-resource.ts → add/add-mcp-resource.ts} +18 -15
  61. package/src/{add-mcp-tool.ts → add/add-mcp-tool.ts} +18 -15
  62. package/src/add/add-middleware.ts +326 -0
  63. package/src/{add-permission.ts → add/add-permission.ts} +4 -8
  64. package/src/{add-queue-worker.ts → add/add-queue-worker.ts} +17 -14
  65. package/src/{add-rpc-invocations.ts → add/add-rpc-invocations.ts} +1 -1
  66. package/src/{add-schedule.ts → add/add-schedule.ts} +17 -14
  67. package/src/index.ts +5 -0
  68. package/src/inspector.ts +20 -17
  69. package/src/types.ts +92 -0
  70. package/src/{utils.ts → utils/extract-function-name.ts} +25 -199
  71. package/src/utils/extract-services.ts +35 -0
  72. package/src/{utils.test.ts → utils/filter-utils.test.ts} +2 -2
  73. package/src/utils/filter-utils.ts +72 -0
  74. package/src/utils/get-files-and-methods.ts +143 -0
  75. package/src/utils/middleware.ts +234 -0
  76. package/src/utils/type-utils.ts +74 -0
  77. package/src/visit.ts +47 -33
  78. package/tsconfig.tsbuildinfo +1 -1
  79. package/dist/add-functions.d.ts +0 -7
  80. package/dist/add-mcp-prompt.d.ts +0 -3
  81. package/dist/add-mcp-resource.d.ts +0 -3
  82. package/dist/add-mcp-tool.d.ts +0 -3
  83. package/dist/add-middleware.d.ts +0 -7
  84. package/dist/add-middleware.js +0 -35
  85. package/dist/add-permission.d.ts +0 -7
  86. package/dist/add-queue-worker.d.ts +0 -3
  87. package/dist/add-schedule.d.ts +0 -3
  88. package/src/add-middleware.ts +0 -51
  89. /package/dist/{add-rpc-invocations.js → add/add-rpc-invocations.js} +0 -0
  90. /package/dist/{does-type-extend-core-type.d.ts → utils/does-type-extend-core-type.d.ts} +0 -0
  91. /package/dist/{does-type-extend-core-type.js → utils/does-type-extend-core-type.js} +0 -0
  92. /package/dist/{get-property-value.d.ts → utils/get-property-value.d.ts} +0 -0
  93. /package/dist/{get-property-value.js → utils/get-property-value.js} +0 -0
  94. /package/src/{does-type-extend-core-type.ts → utils/does-type-extend-core-type.ts} +0 -0
  95. /package/src/{get-property-value.ts → utils/get-property-value.ts} +0 -0
package/src/types.ts CHANGED
@@ -1,8 +1,10 @@
1
+ import * as ts from 'typescript'
1
2
  import { ChannelsMeta } from '@pikku/core/channel'
2
3
  import { HTTPWiringsMeta } from '@pikku/core/http'
3
4
  import { ScheduledTasksMeta } from '@pikku/core/scheduler'
4
5
  import { queueWorkersMeta } from '@pikku/core/queue'
5
6
  import { MCPResourceMeta, MCPToolMeta, MCPPromptMeta } from '@pikku/core'
7
+ import { CLIMeta } from '@pikku/core'
6
8
  import { TypesMap } from './types-map.js'
7
9
  import { FunctionsMeta, FunctionServicesMeta } from '@pikku/core'
8
10
 
@@ -20,15 +22,29 @@ export type MetaInputTypes = Map<
20
22
  }
21
23
  >
22
24
 
25
+ export interface MiddlewareGroupMeta {
26
+ exportName: string | null // null if not exported
27
+ sourceFile: string
28
+ position: number
29
+ services: FunctionServicesMeta
30
+ middlewareCount: number
31
+ isFactory: boolean // true if wrapped in () => add...()
32
+ }
33
+
23
34
  export interface InspectorHTTPState {
24
35
  metaInputTypes: MetaInputTypes
25
36
  meta: HTTPWiringsMeta
26
37
  files: Set<string>
38
+ // HTTP middleware calls tracking - route pattern -> group metadata
39
+ // Pattern '*' matches all routes (from addHTTPMiddleware('*', [...]))
40
+ // Pattern '/api/*' matches specific routes (from addHTTPMiddleware('/api/*', [...]))
41
+ routeMiddleware: Map<string, MiddlewareGroupMeta>
27
42
  }
28
43
 
29
44
  export interface InspectorFunctionState {
30
45
  typesMap: TypesMap
31
46
  meta: FunctionsMeta
47
+ files: Map<string, { path: string; exportedName: string }>
32
48
  }
33
49
 
34
50
  export interface InspectorChannelState {
@@ -37,6 +53,7 @@ export interface InspectorChannelState {
37
53
  }
38
54
 
39
55
  export interface InspectorMiddlewareState {
56
+ // Individual middleware function metadata
40
57
  meta: Record<
41
58
  string,
42
59
  {
@@ -44,8 +61,12 @@ export interface InspectorMiddlewareState {
44
61
  sourceFile: string
45
62
  position: number
46
63
  exportedName: string | null
64
+ factory?: boolean // true if wrapped with pikkuMiddlewareFactory
47
65
  }
48
66
  >
67
+ // Tag-based middleware calls tracking - tag -> group metadata
68
+ // e.g., export const adminMiddleware = () => addMiddleware('admin', [...])
69
+ tagMiddleware: Map<string, MiddlewareGroupMeta>
49
70
  }
50
71
 
51
72
  export interface InspectorPermissionState {
@@ -66,19 +87,86 @@ export type InspectorFilters = {
66
87
  directories?: string[]
67
88
  }
68
89
 
90
+ export type InspectorOptions = Partial<{
91
+ types: Partial<{
92
+ configFileType: string
93
+ userSessionType: string
94
+ singletonServicesFactoryType: string
95
+ sessionServicesFactoryType: string
96
+ }>
97
+ filters: InspectorFilters
98
+ }>
99
+
69
100
  export interface InspectorLogger {
70
101
  info: (message: string) => void
71
102
  error: (message: string) => void
72
103
  warn: (message: string) => void
73
104
  debug: (message: string) => void
74
105
  }
106
+
107
+ export type AddWiring = (
108
+ logger: InspectorLogger,
109
+ node: ts.Node,
110
+ checker: ts.TypeChecker,
111
+ state: InspectorState,
112
+ options: InspectorOptions
113
+ ) => void
114
+ export interface InspectorFilesAndMethods {
115
+ userSessionType?: {
116
+ file: string
117
+ variable: string
118
+ type: string
119
+ typePath: string
120
+ }
121
+ sessionServicesType?: {
122
+ file: string
123
+ variable: string
124
+ type: string
125
+ typePath: string
126
+ }
127
+ singletonServicesType?: {
128
+ file: string
129
+ variable: string
130
+ type: string
131
+ typePath: string
132
+ }
133
+ pikkuConfigType?: {
134
+ file: string
135
+ variable: string
136
+ type: string
137
+ typePath: string
138
+ }
139
+ pikkuConfigFactory?: {
140
+ file: string
141
+ variable: string
142
+ type: string
143
+ typePath: string
144
+ }
145
+ singletonServicesFactory?: {
146
+ file: string
147
+ variable: string
148
+ type: string
149
+ typePath: string
150
+ }
151
+ sessionServicesFactory?: {
152
+ file: string
153
+ variable: string
154
+ type: string
155
+ typePath: string
156
+ }
157
+ }
158
+
75
159
  export interface InspectorState {
76
160
  singletonServicesTypeImportMap: PathToNameAndType
77
161
  sessionServicesTypeImportMap: PathToNameAndType
78
162
  userSessionTypeImportMap: PathToNameAndType
163
+ configTypeImportMap: PathToNameAndType
79
164
  singletonServicesFactories: PathToNameAndType
80
165
  sessionServicesFactories: PathToNameAndType
81
166
  configFactories: PathToNameAndType
167
+ filesAndMethods: InspectorFilesAndMethods
168
+ filesAndMethodsErrors: Map<string, PathToNameAndType>
169
+ typesLookup: Map<string, ts.Type[]> // Lookup for types by name (e.g., function input types, Config type)
82
170
  http: InspectorHTTPState
83
171
  functions: InspectorFunctionState
84
172
  channels: InspectorChannelState
@@ -103,6 +191,10 @@ export interface InspectorState {
103
191
  promptsMeta: MCPPromptMeta
104
192
  files: Set<string>
105
193
  }
194
+ cli: {
195
+ meta: CLIMeta
196
+ files: Set<string>
197
+ }
106
198
  middleware: InspectorMiddlewareState
107
199
  permissions: InspectorPermissionState
108
200
  }
@@ -1,8 +1,6 @@
1
1
  import * as ts from 'typescript'
2
- import { InspectorFilters, InspectorLogger } from './types.js'
3
- import { PikkuWiringTypes, FunctionServicesMeta } from '@pikku/core'
4
2
 
5
- type ExtractedFunctionName = {
3
+ export type ExtractedFunctionName = {
6
4
  pikkuFuncName: string
7
5
  name: string
8
6
  explicitName: string | null
@@ -338,9 +336,8 @@ export function extractFunctionName(
338
336
  }
339
337
  }
340
338
 
341
- // First, figure out what function we're really dealing with
342
- let mainFunc = callExpr
343
- let originalCallExpr = callExpr // Keep track of the original call expression for name extraction
339
+ // Keep track of the original call expression for position-based naming
340
+ let originalCallExpr = callExpr
344
341
 
345
342
  // For direct pikku function calls where callExpr is the call expression itself
346
343
  if (ts.isCallExpression(callExpr)) {
@@ -373,7 +370,7 @@ export function extractFunctionName(
373
370
  ts.isArrowFunction(firstArg) ||
374
371
  ts.isFunctionExpression(firstArg)
375
372
  ) {
376
- mainFunc = firstArg // Use the arrow function directly instead of the call expression
373
+ // mainFunc = firstArg // Use the arrow function directly instead of the call expression
377
374
  }
378
375
  }
379
376
  }
@@ -420,7 +417,7 @@ export function extractFunctionName(
420
417
  (ts.isArrowFunction(firstArg) ||
421
418
  ts.isFunctionExpression(firstArg))
422
419
  ) {
423
- mainFunc = firstArg
420
+ // mainFunc = firstArg
424
421
 
425
422
  // Check if the variable is exported
426
423
  if (
@@ -439,7 +436,7 @@ export function extractFunctionName(
439
436
  ts.isFunctionExpression(funcDecl.initializer) ||
440
437
  ts.isArrowFunction(funcDecl.initializer)
441
438
  ) {
442
- mainFunc = funcDecl.initializer
439
+ // mainFunc = funcDecl.initializer
443
440
 
444
441
  // Check if the variable is exported
445
442
  if (
@@ -455,7 +452,7 @@ export function extractFunctionName(
455
452
  break
456
453
  }
457
454
  } else if (ts.isFunctionDeclaration(funcDecl)) {
458
- mainFunc = funcDecl
455
+ // mainFunc = funcDecl
459
456
 
460
457
  // Check if the function is exported
461
458
  if (
@@ -479,7 +476,7 @@ export function extractFunctionName(
479
476
  }
480
477
  } else {
481
478
  // If we can't resolve the symbol, use the identifier itself
482
- mainFunc = prop.initializer
479
+ // mainFunc = prop.initializer
483
480
  }
484
481
  break
485
482
  } else if (
@@ -487,7 +484,7 @@ export function extractFunctionName(
487
484
  ts.isArrowFunction(prop.initializer)
488
485
  ) {
489
486
  // func: () => {} or func: function() {} - use directly
490
- mainFunc = prop.initializer
487
+ // mainFunc = prop.initializer
491
488
  break
492
489
  }
493
490
  } else if (
@@ -522,7 +519,7 @@ export function extractFunctionName(
522
519
  (ts.isArrowFunction(firstArg) ||
523
520
  ts.isFunctionExpression(firstArg))
524
521
  ) {
525
- mainFunc = firstArg
522
+ // mainFunc = firstArg
526
523
 
527
524
  // Check if the variable is exported
528
525
  if (
@@ -541,7 +538,7 @@ export function extractFunctionName(
541
538
  ts.isFunctionExpression(shorthandDecl.initializer) ||
542
539
  ts.isArrowFunction(shorthandDecl.initializer)
543
540
  ) {
544
- mainFunc = shorthandDecl.initializer
541
+ // mainFunc = shorthandDecl.initializer
545
542
 
546
543
  // Check if the variable is exported
547
544
  if (
@@ -557,7 +554,7 @@ export function extractFunctionName(
557
554
  break
558
555
  }
559
556
  } else if (ts.isFunctionDeclaration(shorthandDecl)) {
560
- mainFunc = shorthandDecl
557
+ // mainFunc = shorthandDecl
561
558
 
562
559
  // Check if the function is exported
563
560
  if (
@@ -605,6 +602,10 @@ export function extractFunctionName(
605
602
  ts.isIdentifier(decl.initializer.expression) &&
606
603
  decl.initializer.expression.text.startsWith('pikku')
607
604
  ) {
605
+ // Update originalCallExpr to use the call expression position
606
+ // instead of the variable declaration position
607
+ originalCallExpr = decl.initializer
608
+
608
609
  // Check for object with 'name' property in first argument
609
610
  const firstArg = decl.initializer.arguments[0]
610
611
  if (firstArg && ts.isObjectLiteralExpression(firstArg)) {
@@ -628,7 +629,7 @@ export function extractFunctionName(
628
629
  (ts.isArrowFunction(firstArg) ||
629
630
  ts.isFunctionExpression(firstArg))
630
631
  ) {
631
- mainFunc = firstArg
632
+ // mainFunc = firstArg
632
633
  }
633
634
  }
634
635
 
@@ -645,7 +646,7 @@ export function extractFunctionName(
645
646
  ts.isFunctionExpression(decl.initializer) ||
646
647
  ts.isArrowFunction(decl.initializer)
647
648
  ) {
648
- mainFunc = decl.initializer
649
+ // mainFunc = decl.initializer
649
650
 
650
651
  // Check if the variable is exported
651
652
  if (isNamedExport(decl) && ts.isIdentifier(decl.name)) {
@@ -655,7 +656,7 @@ export function extractFunctionName(
655
656
  }
656
657
  }
657
658
  } else if (ts.isFunctionDeclaration(decl)) {
658
- mainFunc = decl
659
+ // mainFunc = decl
659
660
 
660
661
  // Check if the function is exported
661
662
  if (
@@ -674,8 +675,10 @@ export function extractFunctionName(
674
675
  }
675
676
  }
676
677
 
677
- // Now generate the deterministic function name based on the resolved function
678
- result.pikkuFuncName = makeDeterministicAnonName(mainFunc, checker)
678
+ // Generate the deterministic function name based on the original call expression
679
+ // (the config), not the resolved inner function. This ensures the metadata key
680
+ // matches what will be looked up at runtime when referencing the config object.
681
+ result.pikkuFuncName = makeDeterministicAnonName(originalCallExpr, checker)
679
682
 
680
683
  // Continue with regular name extraction for remaining cases
681
684
  // 1) const foo = pikkuFunc(...)
@@ -731,7 +734,7 @@ export function extractFunctionName(
731
734
  /**
732
735
  * Helper function to populate the 'name' field based on priority
733
736
  */
734
- function populateNameByPriority(result: ExtractedFunctionName): void {
737
+ export function populateNameByPriority(result: ExtractedFunctionName): void {
735
738
  // Priority 1: If we have an explict name, use that
736
739
  if (result.explicitName) {
737
740
  result.name = result.explicitName
@@ -754,7 +757,7 @@ function populateNameByPriority(result: ExtractedFunctionName): void {
754
757
  /**
755
758
  * Helper function to check if a variable declaration is a named export
756
759
  */
757
- function isNamedExport(declaration: ts.VariableDeclaration): boolean {
760
+ export function isNamedExport(declaration: ts.VariableDeclaration): boolean {
758
761
  let parent: any = declaration.parent
759
762
  if (!parent) return false
760
763
 
@@ -774,180 +777,3 @@ function isNamedExport(declaration: ts.VariableDeclaration): boolean {
774
777
 
775
778
  return false
776
779
  }
777
-
778
- // Until here
779
- export const extractTypeKeys = (type: ts.Type): string[] => {
780
- return type.getProperties().map((symbol) => symbol.getName())
781
- }
782
-
783
- export function getPropertyAssignmentInitializer(
784
- obj: ts.ObjectLiteralExpression,
785
- propName: string,
786
- followShorthand = false,
787
- checker?: ts.TypeChecker
788
- ): ts.Expression | undefined {
789
- for (const prop of obj.properties) {
790
- // ① foo: () => {}
791
- if (
792
- ts.isPropertyAssignment(prop) &&
793
- ts.isIdentifier(prop.name) &&
794
- prop.name.text === propName
795
- ) {
796
- return prop.initializer
797
- }
798
-
799
- // ② foo() { … }
800
- if (
801
- ts.isMethodDeclaration(prop) &&
802
- ts.isIdentifier(prop.name) &&
803
- prop.name.text === propName
804
- ) {
805
- return prop.name // the method node *is* the function
806
- }
807
-
808
- // ③ { foo } (shorthand)
809
- if (
810
- followShorthand &&
811
- ts.isShorthandPropertyAssignment(prop) &&
812
- prop.name.text === propName
813
- ) {
814
- if (!checker) return prop.name // best effort without a checker
815
-
816
- let sym = checker.getSymbolAtLocation(prop.name)
817
- if (sym && sym.flags & ts.SymbolFlags.Alias) {
818
- sym = checker.getAliasedSymbol(sym)
819
- }
820
-
821
- const decl = sym?.declarations?.[0]
822
-
823
- // const foo = () => {}
824
- if (
825
- decl &&
826
- ts.isVariableDeclaration(decl) &&
827
- decl.initializer &&
828
- (ts.isArrowFunction(decl.initializer) ||
829
- ts.isFunctionExpression(decl.initializer))
830
- ) {
831
- return decl.initializer
832
- }
833
-
834
- // function foo() {}
835
- if (
836
- decl &&
837
- (ts.isFunctionDeclaration(decl) ||
838
- ts.isArrowFunction(decl) ||
839
- ts.isFunctionExpression(decl))
840
- ) {
841
- return decl as ts.Expression
842
- }
843
-
844
- // fallback – just give back the identifier
845
- return prop.name
846
- }
847
- }
848
-
849
- return undefined
850
- }
851
-
852
- export const matchesFilters = (
853
- filters: InspectorFilters,
854
- params: { tags?: string[] },
855
- meta: {
856
- type: PikkuWiringTypes
857
- name: string
858
- filePath?: string
859
- },
860
- logger: InspectorLogger
861
- ) => {
862
- // If no filters are provided, allow everything
863
- if (Object.keys(filters).length === 0) {
864
- return true
865
- }
866
-
867
- // If all filter arrays are empty, allow everything
868
- if (
869
- (!filters.tags || filters.tags.length === 0) &&
870
- (!filters.types || filters.types.length === 0) &&
871
- (!filters.directories || filters.directories.length === 0)
872
- ) {
873
- return true
874
- }
875
-
876
- // Check type filter
877
- if (filters.types && filters.types.length > 0) {
878
- if (!filters.types.includes(meta.type)) {
879
- logger.debug(`⒡ Filtered by type: ${meta.type}:${meta.name}`)
880
- return false
881
- }
882
- }
883
-
884
- // Check directory filter
885
- if (filters.directories && filters.directories.length > 0) {
886
- if (!meta.filePath) {
887
- logger.debug(
888
- `⒡ Filtered by directory: ${meta.type}:${meta.name} (${meta.filePath})`
889
- )
890
- return false
891
- }
892
-
893
- const matchesDirectory = filters.directories.some((dir) => {
894
- // Normalize paths for comparison
895
- const normalizedFilePath = meta.filePath!.replace(/\\/g, '/')
896
- const normalizedDir = dir.replace(/\\/g, '/')
897
- return normalizedFilePath.includes(normalizedDir)
898
- })
899
-
900
- if (!matchesDirectory) {
901
- logger.debug(
902
- `⒡ Filtered by directory: ${meta.type}:${meta.name} (${meta.filePath})`
903
- )
904
- return false
905
- }
906
- }
907
-
908
- // Check tag filter
909
- if (filters.tags && filters.tags.length > 0) {
910
- if (
911
- !params.tags ||
912
- !filters.tags.some((tag) => params.tags!.includes(tag))
913
- ) {
914
- logger.debug(`⒡ Filtered by tags: ${meta.type}:${meta.name}`)
915
- return false
916
- }
917
- }
918
-
919
- return true
920
- }
921
-
922
- /**
923
- * Extract services from a function's first parameter destructuring pattern
924
- */
925
- export function extractServicesFromFunction(
926
- handlerNode: ts.FunctionExpression | ts.ArrowFunction
927
- ): FunctionServicesMeta {
928
- const services: FunctionServicesMeta = {
929
- optimized: true,
930
- services: [],
931
- }
932
-
933
- const firstParam = handlerNode.parameters[0]
934
- if (firstParam) {
935
- if (ts.isObjectBindingPattern(firstParam.name)) {
936
- for (const elem of firstParam.name.elements) {
937
- const original =
938
- elem.propertyName && ts.isIdentifier(elem.propertyName)
939
- ? elem.propertyName.text
940
- : ts.isIdentifier(elem.name)
941
- ? elem.name.text
942
- : undefined
943
- if (original) {
944
- services.services.push(original)
945
- }
946
- }
947
- } else if (ts.isIdentifier(firstParam.name)) {
948
- services.optimized = false
949
- }
950
- }
951
-
952
- return services
953
- }
@@ -0,0 +1,35 @@
1
+ import * as ts from 'typescript'
2
+ import { FunctionServicesMeta } from '@pikku/core'
3
+
4
+ /**
5
+ * Extract services from a function's first parameter destructuring pattern
6
+ */
7
+ export function extractServicesFromFunction(
8
+ handlerNode: ts.FunctionExpression | ts.ArrowFunction
9
+ ): FunctionServicesMeta {
10
+ const services: FunctionServicesMeta = {
11
+ optimized: true,
12
+ services: [],
13
+ }
14
+
15
+ const firstParam = handlerNode.parameters[0]
16
+ if (firstParam) {
17
+ if (ts.isObjectBindingPattern(firstParam.name)) {
18
+ for (const elem of firstParam.name.elements) {
19
+ const original =
20
+ elem.propertyName && ts.isIdentifier(elem.propertyName)
21
+ ? elem.propertyName.text
22
+ : ts.isIdentifier(elem.name)
23
+ ? elem.name.text
24
+ : undefined
25
+ if (original) {
26
+ services.services.push(original)
27
+ }
28
+ }
29
+ } else if (ts.isIdentifier(firstParam.name)) {
30
+ services.optimized = false
31
+ }
32
+ }
33
+
34
+ return services
35
+ }
@@ -1,8 +1,8 @@
1
1
  import { test, describe } from 'node:test'
2
2
  import { strict as assert } from 'node:assert'
3
- import { matchesFilters } from './utils.js'
4
- import { InspectorFilters } from './types.js'
5
3
  import { PikkuWiringTypes } from '@pikku/core'
4
+ import { InspectorFilters } from '../types'
5
+ import { matchesFilters } from './filter-utils'
6
6
 
7
7
  describe('matchesFilters', () => {
8
8
  // Mock logger for testing
@@ -0,0 +1,72 @@
1
+ import { InspectorFilters, InspectorLogger } from '../types.js'
2
+ import { PikkuWiringTypes } from '@pikku/core'
3
+
4
+ export const matchesFilters = (
5
+ filters: InspectorFilters,
6
+ params: { tags?: string[] },
7
+ meta: {
8
+ type: PikkuWiringTypes
9
+ name: string
10
+ filePath?: string
11
+ },
12
+ logger: InspectorLogger
13
+ ) => {
14
+ // If no filters are provided, allow everything
15
+ if (Object.keys(filters).length === 0) {
16
+ return true
17
+ }
18
+
19
+ // If all filter arrays are empty, allow everything
20
+ if (
21
+ (!filters.tags || filters.tags.length === 0) &&
22
+ (!filters.types || filters.types.length === 0) &&
23
+ (!filters.directories || filters.directories.length === 0)
24
+ ) {
25
+ return true
26
+ }
27
+
28
+ // Check type filter
29
+ if (filters.types && filters.types.length > 0) {
30
+ if (!filters.types.includes(meta.type)) {
31
+ logger.debug(`⒡ Filtered by type: ${meta.type}:${meta.name}`)
32
+ return false
33
+ }
34
+ }
35
+
36
+ // Check directory filter
37
+ if (filters.directories && filters.directories.length > 0) {
38
+ if (!meta.filePath) {
39
+ logger.debug(
40
+ `⒡ Filtered by directory: ${meta.type}:${meta.name} (${meta.filePath})`
41
+ )
42
+ return false
43
+ }
44
+
45
+ const matchesDirectory = filters.directories.some((dir) => {
46
+ // Normalize paths for comparison
47
+ const normalizedFilePath = meta.filePath!.replace(/\\/g, '/')
48
+ const normalizedDir = dir.replace(/\\/g, '/')
49
+ return normalizedFilePath.includes(normalizedDir)
50
+ })
51
+
52
+ if (!matchesDirectory) {
53
+ logger.debug(
54
+ `⒡ Filtered by directory: ${meta.type}:${meta.name} (${meta.filePath})`
55
+ )
56
+ return false
57
+ }
58
+ }
59
+
60
+ // Check tag filter
61
+ if (filters.tags && filters.tags.length > 0) {
62
+ if (
63
+ !params.tags ||
64
+ !filters.tags.some((tag) => params.tags!.includes(tag))
65
+ ) {
66
+ logger.debug(`⒡ Filtered by tags: ${meta.type}:${meta.name}`)
67
+ return false
68
+ }
69
+ }
70
+
71
+ return true
72
+ }