@pikku/inspector 0.9.5 → 0.10.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 (133) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/add/add-channel.d.ts +17 -0
  3. package/dist/{add-channel.js → add/add-channel.js} +60 -34
  4. package/dist/add/add-cli.d.ts +9 -0
  5. package/dist/add/add-cli.js +566 -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 -4
  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} +2 -2
  11. package/dist/{add-file-with-factory.js → add/add-file-with-factory.js} +38 -5
  12. package/dist/add/add-functions.d.ts +6 -0
  13. package/dist/{add-functions.js → add/add-functions.js} +77 -10
  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} +26 -13
  16. package/dist/add/add-mcp-prompt.d.ts +2 -0
  17. package/dist/add/add-mcp-prompt.js +74 -0
  18. package/dist/add/add-mcp-resource.d.ts +2 -0
  19. package/dist/add/add-mcp-resource.js +84 -0
  20. package/dist/add/add-mcp-tool.d.ts +2 -0
  21. package/dist/add/add-mcp-tool.js +80 -0
  22. package/dist/add/add-middleware.d.ts +5 -0
  23. package/dist/add/add-middleware.js +290 -0
  24. package/dist/add/add-permission.d.ts +5 -0
  25. package/dist/add/add-permission.js +292 -0
  26. package/dist/add/add-queue-worker.d.ts +2 -0
  27. package/dist/add/add-queue-worker.js +52 -0
  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} +16 -11
  31. package/dist/error-codes.d.ts +35 -0
  32. package/dist/error-codes.js +40 -0
  33. package/dist/index.d.ts +6 -0
  34. package/dist/index.js +4 -0
  35. package/dist/inspector.d.ts +2 -3
  36. package/dist/inspector.js +38 -8
  37. package/dist/types.d.ts +108 -1
  38. package/dist/utils/ensure-function-metadata.d.ts +6 -0
  39. package/dist/utils/ensure-function-metadata.js +18 -0
  40. package/dist/utils/extract-function-name.d.ts +31 -0
  41. package/dist/{utils.js → utils/extract-function-name.js} +35 -149
  42. package/dist/utils/extract-services.d.ts +6 -0
  43. package/dist/utils/extract-services.js +29 -0
  44. package/dist/utils/filter-inspector-state.d.ts +6 -0
  45. package/dist/utils/filter-inspector-state.js +382 -0
  46. package/dist/utils/filter-utils.d.ts +19 -0
  47. package/dist/utils/filter-utils.js +109 -0
  48. package/dist/utils/find-root-dir.d.ts +23 -0
  49. package/dist/utils/find-root-dir.js +55 -0
  50. package/dist/utils/get-files-and-methods.d.ts +22 -0
  51. package/dist/utils/get-files-and-methods.js +61 -0
  52. package/dist/utils/get-property-value.d.ts +12 -0
  53. package/dist/{get-property-value.js → utils/get-property-value.js} +20 -0
  54. package/dist/utils/middleware.d.ts +39 -0
  55. package/dist/utils/middleware.js +157 -0
  56. package/dist/utils/permissions.d.ts +43 -0
  57. package/dist/utils/permissions.js +178 -0
  58. package/dist/utils/post-process.d.ts +16 -0
  59. package/dist/utils/post-process.js +132 -0
  60. package/dist/utils/serialize-inspector-state.d.ts +179 -0
  61. package/dist/utils/serialize-inspector-state.js +170 -0
  62. package/dist/utils/type-utils.d.ts +3 -0
  63. package/dist/utils/type-utils.js +50 -0
  64. package/dist/visit.d.ts +3 -3
  65. package/dist/visit.js +35 -31
  66. package/package.json +5 -6
  67. package/src/{add-channel.ts → add/add-channel.ts} +108 -56
  68. package/src/add/add-cli.ts +822 -0
  69. package/src/{add-file-extends-core-type.ts → add/add-file-extends-core-type.ts} +23 -5
  70. package/src/{add-file-with-config.ts → add/add-file-with-config.ts} +2 -2
  71. package/src/{add-file-with-factory.ts → add/add-file-with-factory.ts} +49 -6
  72. package/src/{add-functions.ts → add/add-functions.ts} +89 -19
  73. package/src/{add-http-route.ts → add/add-http-route.ts} +66 -32
  74. package/src/add/add-mcp-prompt.ts +128 -0
  75. package/src/add/add-mcp-prompt.ts.tmp +0 -0
  76. package/src/add/add-mcp-resource.ts +145 -0
  77. package/src/add/add-mcp-resource.ts.tmp +0 -0
  78. package/src/add/add-mcp-tool.ts +137 -0
  79. package/src/add/add-middleware.ts +385 -0
  80. package/src/add/add-permission.ts +391 -0
  81. package/src/add/add-queue-worker.ts +92 -0
  82. package/src/{add-rpc-invocations.ts → add/add-rpc-invocations.ts} +1 -1
  83. package/src/{add-schedule.ts → add/add-schedule.ts} +30 -28
  84. package/src/error-codes.ts +43 -0
  85. package/src/index.ts +12 -0
  86. package/src/inspector.ts +41 -17
  87. package/src/types.ts +128 -1
  88. package/src/utils/ensure-function-metadata.ts +24 -0
  89. package/src/{utils.ts → utils/extract-function-name.ts} +44 -206
  90. package/src/utils/extract-services.ts +35 -0
  91. package/src/utils/filter-inspector-state.test.ts +1433 -0
  92. package/src/utils/filter-inspector-state.ts +526 -0
  93. package/src/{utils.test.ts → utils/filter-utils.test.ts} +351 -2
  94. package/src/utils/filter-utils.ts +152 -0
  95. package/src/utils/find-root-dir.ts +68 -0
  96. package/src/utils/get-files-and-methods.ts +151 -0
  97. package/src/{get-property-value.ts → utils/get-property-value.ts} +27 -0
  98. package/src/utils/middleware.ts +241 -0
  99. package/src/utils/permissions.test.ts +327 -0
  100. package/src/utils/permissions.ts +262 -0
  101. package/src/utils/post-process.ts +178 -0
  102. package/src/utils/serialize-inspector-state.ts +375 -0
  103. package/src/utils/test-data/inspector-state.json +1680 -0
  104. package/src/utils/type-utils.ts +74 -0
  105. package/src/visit.ts +50 -34
  106. package/tsconfig.tsbuildinfo +1 -1
  107. package/dist/add-channel.d.ts +0 -13
  108. package/dist/add-functions.d.ts +0 -7
  109. package/dist/add-mcp-prompt.d.ts +0 -3
  110. package/dist/add-mcp-prompt.js +0 -61
  111. package/dist/add-mcp-resource.d.ts +0 -3
  112. package/dist/add-mcp-resource.js +0 -68
  113. package/dist/add-mcp-tool.d.ts +0 -3
  114. package/dist/add-mcp-tool.js +0 -64
  115. package/dist/add-middleware.d.ts +0 -7
  116. package/dist/add-middleware.js +0 -35
  117. package/dist/add-permission.d.ts +0 -7
  118. package/dist/add-permission.js +0 -35
  119. package/dist/add-queue-worker.d.ts +0 -3
  120. package/dist/add-queue-worker.js +0 -48
  121. package/dist/add-schedule.d.ts +0 -3
  122. package/dist/get-property-value.d.ts +0 -3
  123. package/dist/utils.d.ts +0 -39
  124. package/src/add-mcp-prompt.ts +0 -104
  125. package/src/add-mcp-resource.ts +0 -116
  126. package/src/add-mcp-tool.ts +0 -107
  127. package/src/add-middleware.ts +0 -51
  128. package/src/add-permission.ts +0 -53
  129. package/src/add-queue-worker.ts +0 -92
  130. /package/dist/{add-rpc-invocations.js → add/add-rpc-invocations.js} +0 -0
  131. /package/dist/{does-type-extend-core-type.d.ts → utils/does-type-extend-core-type.d.ts} +0 -0
  132. /package/dist/{does-type-extend-core-type.js → utils/does-type-extend-core-type.js} +0 -0
  133. /package/src/{does-type-extend-core-type.ts → utils/does-type-extend-core-type.ts} +0 -0
@@ -1,8 +1,7 @@
1
1
  import * as ts from 'typescript'
2
- import { InspectorFilters, InspectorLogger } from './types.js'
3
- import { PikkuWiringTypes, FunctionServicesMeta } from '@pikku/core'
2
+ import { toRelativePath } from './find-root-dir.js'
4
3
 
5
- type ExtractedFunctionName = {
4
+ export type ExtractedFunctionName = {
6
5
  pikkuFuncName: string
7
6
  name: string
8
7
  explicitName: string | null
@@ -18,7 +17,8 @@ type ExtractedFunctionName = {
18
17
  */
19
18
  export function makeDeterministicAnonName(
20
19
  start: ts.Node,
21
- checker: ts.TypeChecker
20
+ checker: ts.TypeChecker,
21
+ rootDir: string
22
22
  ): string {
23
23
  let node: ts.Node = start
24
24
  let target: ts.Node = start
@@ -47,7 +47,8 @@ export function makeDeterministicAnonName(
47
47
  target = decl.initializer
48
48
  // Return early - we found the function directly
49
49
  const sf = target.getSourceFile()
50
- const file = sf.fileName.replace(/[^A-Za-z0-9_]/g, '_')
50
+ const relativePath = toRelativePath(sf.fileName, rootDir)
51
+ const file = relativePath.replace(/[^A-Za-z0-9_]/g, '_')
51
52
  const { line, character } = ts.getLineAndCharacterOfPosition(
52
53
  sf,
53
54
  target.getStart()
@@ -93,7 +94,8 @@ export function makeDeterministicAnonName(
93
94
  target = decl.initializer
94
95
  // Return early - we found the function directly
95
96
  const sf = target.getSourceFile()
96
- const file = sf.fileName.replace(/[^A-Za-z0-9_]/g, '_')
97
+ const relativePath = toRelativePath(sf.fileName, rootDir)
98
+ const file = relativePath.replace(/[^A-Za-z0-9_]/g, '_')
97
99
  const { line, character } = ts.getLineAndCharacterOfPosition(
98
100
  sf,
99
101
  target.getStart()
@@ -105,7 +107,8 @@ export function makeDeterministicAnonName(
105
107
  target = decl
106
108
  // Return early
107
109
  const sf = target.getSourceFile()
108
- const file = sf.fileName.replace(/[^A-Za-z0-9_]/g, '_')
110
+ const relativePath = toRelativePath(sf.fileName, rootDir)
111
+ const file = relativePath.replace(/[^A-Za-z0-9_]/g, '_')
109
112
  const { line, character } = ts.getLineAndCharacterOfPosition(
110
113
  sf,
111
114
  target.getStart()
@@ -240,7 +243,8 @@ export function makeDeterministicAnonName(
240
243
  }
241
244
 
242
245
  const sf = target.getSourceFile()
243
- const file = sf.fileName.replace(/[^A-Za-z0-9_]/g, '_')
246
+ const relativePath = toRelativePath(sf.fileName, rootDir)
247
+ const file = relativePath.replace(/[^A-Za-z0-9_]/g, '_')
244
248
  const { line, character } = ts.getLineAndCharacterOfPosition(
245
249
  sf,
246
250
  target.getStart()
@@ -257,7 +261,8 @@ export function makeDeterministicAnonName(
257
261
  */
258
262
  export function extractFunctionName(
259
263
  callExpr: ts.Node,
260
- checker: ts.TypeChecker
264
+ checker: ts.TypeChecker,
265
+ rootDir: string
261
266
  ): ExtractedFunctionName {
262
267
  const parent: any = callExpr.parent
263
268
 
@@ -306,7 +311,8 @@ export function extractFunctionName(
306
311
  // Use the function directly for position calculation
307
312
  result.pikkuFuncName = makeDeterministicAnonName(
308
313
  firstArg,
309
- checker
314
+ checker,
315
+ rootDir
310
316
  )
311
317
 
312
318
  // Continue with name extraction
@@ -338,9 +344,8 @@ export function extractFunctionName(
338
344
  }
339
345
  }
340
346
 
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
347
+ // Keep track of the original call expression for position-based naming
348
+ let originalCallExpr = callExpr
344
349
 
345
350
  // For direct pikku function calls where callExpr is the call expression itself
346
351
  if (ts.isCallExpression(callExpr)) {
@@ -373,7 +378,7 @@ export function extractFunctionName(
373
378
  ts.isArrowFunction(firstArg) ||
374
379
  ts.isFunctionExpression(firstArg)
375
380
  ) {
376
- mainFunc = firstArg // Use the arrow function directly instead of the call expression
381
+ // mainFunc = firstArg // Use the arrow function directly instead of the call expression
377
382
  }
378
383
  }
379
384
  }
@@ -420,7 +425,7 @@ export function extractFunctionName(
420
425
  (ts.isArrowFunction(firstArg) ||
421
426
  ts.isFunctionExpression(firstArg))
422
427
  ) {
423
- mainFunc = firstArg
428
+ // mainFunc = firstArg
424
429
 
425
430
  // Check if the variable is exported
426
431
  if (
@@ -439,7 +444,7 @@ export function extractFunctionName(
439
444
  ts.isFunctionExpression(funcDecl.initializer) ||
440
445
  ts.isArrowFunction(funcDecl.initializer)
441
446
  ) {
442
- mainFunc = funcDecl.initializer
447
+ // mainFunc = funcDecl.initializer
443
448
 
444
449
  // Check if the variable is exported
445
450
  if (
@@ -455,7 +460,7 @@ export function extractFunctionName(
455
460
  break
456
461
  }
457
462
  } else if (ts.isFunctionDeclaration(funcDecl)) {
458
- mainFunc = funcDecl
463
+ // mainFunc = funcDecl
459
464
 
460
465
  // Check if the function is exported
461
466
  if (
@@ -479,7 +484,7 @@ export function extractFunctionName(
479
484
  }
480
485
  } else {
481
486
  // If we can't resolve the symbol, use the identifier itself
482
- mainFunc = prop.initializer
487
+ // mainFunc = prop.initializer
483
488
  }
484
489
  break
485
490
  } else if (
@@ -487,7 +492,7 @@ export function extractFunctionName(
487
492
  ts.isArrowFunction(prop.initializer)
488
493
  ) {
489
494
  // func: () => {} or func: function() {} - use directly
490
- mainFunc = prop.initializer
495
+ // mainFunc = prop.initializer
491
496
  break
492
497
  }
493
498
  } else if (
@@ -522,7 +527,7 @@ export function extractFunctionName(
522
527
  (ts.isArrowFunction(firstArg) ||
523
528
  ts.isFunctionExpression(firstArg))
524
529
  ) {
525
- mainFunc = firstArg
530
+ // mainFunc = firstArg
526
531
 
527
532
  // Check if the variable is exported
528
533
  if (
@@ -541,7 +546,7 @@ export function extractFunctionName(
541
546
  ts.isFunctionExpression(shorthandDecl.initializer) ||
542
547
  ts.isArrowFunction(shorthandDecl.initializer)
543
548
  ) {
544
- mainFunc = shorthandDecl.initializer
549
+ // mainFunc = shorthandDecl.initializer
545
550
 
546
551
  // Check if the variable is exported
547
552
  if (
@@ -557,7 +562,7 @@ export function extractFunctionName(
557
562
  break
558
563
  }
559
564
  } else if (ts.isFunctionDeclaration(shorthandDecl)) {
560
- mainFunc = shorthandDecl
565
+ // mainFunc = shorthandDecl
561
566
 
562
567
  // Check if the function is exported
563
568
  if (
@@ -605,6 +610,10 @@ export function extractFunctionName(
605
610
  ts.isIdentifier(decl.initializer.expression) &&
606
611
  decl.initializer.expression.text.startsWith('pikku')
607
612
  ) {
613
+ // Update originalCallExpr to use the call expression position
614
+ // instead of the variable declaration position
615
+ originalCallExpr = decl.initializer
616
+
608
617
  // Check for object with 'name' property in first argument
609
618
  const firstArg = decl.initializer.arguments[0]
610
619
  if (firstArg && ts.isObjectLiteralExpression(firstArg)) {
@@ -628,7 +637,7 @@ export function extractFunctionName(
628
637
  (ts.isArrowFunction(firstArg) ||
629
638
  ts.isFunctionExpression(firstArg))
630
639
  ) {
631
- mainFunc = firstArg
640
+ // mainFunc = firstArg
632
641
  }
633
642
  }
634
643
 
@@ -645,7 +654,7 @@ export function extractFunctionName(
645
654
  ts.isFunctionExpression(decl.initializer) ||
646
655
  ts.isArrowFunction(decl.initializer)
647
656
  ) {
648
- mainFunc = decl.initializer
657
+ // mainFunc = decl.initializer
649
658
 
650
659
  // Check if the variable is exported
651
660
  if (isNamedExport(decl) && ts.isIdentifier(decl.name)) {
@@ -655,7 +664,7 @@ export function extractFunctionName(
655
664
  }
656
665
  }
657
666
  } else if (ts.isFunctionDeclaration(decl)) {
658
- mainFunc = decl
667
+ // mainFunc = decl
659
668
 
660
669
  // Check if the function is exported
661
670
  if (
@@ -674,8 +683,14 @@ export function extractFunctionName(
674
683
  }
675
684
  }
676
685
 
677
- // Now generate the deterministic function name based on the resolved function
678
- result.pikkuFuncName = makeDeterministicAnonName(mainFunc, checker)
686
+ // Generate the deterministic function name based on the original call expression
687
+ // (the config), not the resolved inner function. This ensures the metadata key
688
+ // matches what will be looked up at runtime when referencing the config object.
689
+ result.pikkuFuncName = makeDeterministicAnonName(
690
+ originalCallExpr,
691
+ checker,
692
+ rootDir
693
+ )
679
694
 
680
695
  // Continue with regular name extraction for remaining cases
681
696
  // 1) const foo = pikkuFunc(...)
@@ -731,7 +746,7 @@ export function extractFunctionName(
731
746
  /**
732
747
  * Helper function to populate the 'name' field based on priority
733
748
  */
734
- function populateNameByPriority(result: ExtractedFunctionName): void {
749
+ export function populateNameByPriority(result: ExtractedFunctionName): void {
735
750
  // Priority 1: If we have an explict name, use that
736
751
  if (result.explicitName) {
737
752
  result.name = result.explicitName
@@ -754,7 +769,7 @@ function populateNameByPriority(result: ExtractedFunctionName): void {
754
769
  /**
755
770
  * Helper function to check if a variable declaration is a named export
756
771
  */
757
- function isNamedExport(declaration: ts.VariableDeclaration): boolean {
772
+ export function isNamedExport(declaration: ts.VariableDeclaration): boolean {
758
773
  let parent: any = declaration.parent
759
774
  if (!parent) return false
760
775
 
@@ -774,180 +789,3 @@ function isNamedExport(declaration: ts.VariableDeclaration): boolean {
774
789
 
775
790
  return false
776
791
  }
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
+ }