@pikku/inspector 0.9.6-next.0 → 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.
- package/CHANGELOG.md +6 -0
- package/dist/add/add-channel.d.ts +5 -1
- package/dist/add/add-channel.js +51 -32
- package/dist/add/add-cli.d.ts +4 -0
- package/dist/add/add-cli.js +128 -23
- package/dist/add/add-file-extends-core-type.js +3 -2
- package/dist/add/add-file-with-factory.d.ts +2 -2
- package/dist/add/add-file-with-factory.js +34 -1
- package/dist/add/add-functions.js +52 -5
- package/dist/add/add-http-route.js +19 -12
- package/dist/add/add-mcp-prompt.js +20 -13
- package/dist/add/add-mcp-resource.js +24 -14
- package/dist/add/add-mcp-tool.js +23 -13
- package/dist/add/add-middleware.js +51 -12
- package/dist/add/add-permission.d.ts +1 -2
- package/dist/add/add-permission.js +275 -19
- package/dist/add/add-queue-worker.js +10 -12
- package/dist/add/add-schedule.js +9 -10
- package/dist/error-codes.d.ts +35 -0
- package/dist/error-codes.js +40 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +3 -0
- package/dist/inspector.js +20 -1
- package/dist/types.d.ts +31 -3
- package/dist/utils/ensure-function-metadata.d.ts +6 -0
- package/dist/utils/ensure-function-metadata.js +18 -0
- package/dist/utils/extract-function-name.d.ts +2 -2
- package/dist/utils/extract-function-name.js +13 -8
- package/dist/utils/filter-inspector-state.d.ts +6 -0
- package/dist/utils/filter-inspector-state.js +382 -0
- package/dist/utils/filter-utils.d.ts +10 -0
- package/dist/utils/filter-utils.js +66 -2
- package/dist/utils/find-root-dir.d.ts +23 -0
- package/dist/utils/find-root-dir.js +55 -0
- package/dist/utils/get-files-and-methods.d.ts +2 -1
- package/dist/utils/get-files-and-methods.js +2 -1
- package/dist/utils/get-property-value.d.ts +9 -0
- package/dist/utils/get-property-value.js +20 -0
- package/dist/utils/middleware.d.ts +1 -1
- package/dist/utils/middleware.js +7 -7
- package/dist/utils/permissions.d.ts +43 -0
- package/dist/utils/permissions.js +178 -0
- package/dist/utils/post-process.d.ts +16 -0
- package/dist/utils/post-process.js +132 -0
- package/dist/utils/serialize-inspector-state.d.ts +179 -0
- package/dist/utils/serialize-inspector-state.js +170 -0
- package/dist/visit.js +3 -2
- package/package.json +4 -4
- package/src/add/add-channel.ts +92 -40
- package/src/add/add-cli.ts +188 -29
- package/src/add/add-file-extends-core-type.ts +5 -2
- package/src/add/add-file-with-factory.ts +45 -2
- package/src/add/add-functions.ts +60 -5
- package/src/add/add-http-route.ts +46 -21
- package/src/add/add-mcp-prompt.ts +42 -21
- package/src/add/add-mcp-prompt.ts.tmp +0 -0
- package/src/add/add-mcp-resource.ts +50 -24
- package/src/add/add-mcp-resource.ts.tmp +0 -0
- package/src/add/add-mcp-tool.ts +48 -21
- package/src/add/add-middleware.ts +74 -15
- package/src/add/add-permission.ts +364 -22
- package/src/add/add-queue-worker.ts +22 -25
- package/src/add/add-schedule.ts +19 -20
- package/src/error-codes.ts +43 -0
- package/src/index.ts +7 -0
- package/src/inspector.ts +22 -1
- package/src/types.ts +38 -3
- package/src/utils/ensure-function-metadata.ts +24 -0
- package/src/utils/extract-function-name.ts +20 -8
- package/src/utils/filter-inspector-state.test.ts +1433 -0
- package/src/utils/filter-inspector-state.ts +526 -0
- package/src/utils/filter-utils.test.ts +350 -1
- package/src/utils/filter-utils.ts +82 -2
- package/src/utils/find-root-dir.ts +68 -0
- package/src/utils/get-files-and-methods.ts +8 -0
- package/src/utils/get-property-value.ts +27 -0
- package/src/utils/middleware.ts +14 -7
- package/src/utils/permissions.test.ts +327 -0
- package/src/utils/permissions.ts +262 -0
- package/src/utils/post-process.ts +178 -0
- package/src/utils/serialize-inspector-state.ts +375 -0
- package/src/utils/test-data/inspector-state.json +1680 -0
- package/src/visit.ts +4 -2
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import * as ts from 'typescript'
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import {
|
|
3
|
+
getPropertyValue,
|
|
4
|
+
getPropertyTags,
|
|
5
|
+
} from '../utils/get-property-value.js'
|
|
6
|
+
import { extractWireNames } from '../utils/post-process.js'
|
|
7
|
+
import { ensureFunctionMetadata } from '../utils/ensure-function-metadata.js'
|
|
4
8
|
import { AddWiring } from '../types.js'
|
|
5
9
|
import { extractFunctionName } from '../utils/extract-function-name.js'
|
|
6
10
|
import { getPropertyAssignmentInitializer } from '../utils/type-utils.js'
|
|
7
|
-
import { matchesFilters } from '../utils/filter-utils.js'
|
|
8
11
|
import { resolveMiddleware } from '../utils/middleware.js'
|
|
12
|
+
import { resolvePermissions } from '../utils/permissions.js'
|
|
13
|
+
import { ErrorCode } from '../error-codes.js'
|
|
9
14
|
|
|
10
15
|
export const addMCPPrompt: AddWiring = (
|
|
11
16
|
logger,
|
|
@@ -38,7 +43,7 @@ export const addMCPPrompt: AddWiring = (
|
|
|
38
43
|
const descriptionValue = getPropertyValue(obj, 'description') as
|
|
39
44
|
| string
|
|
40
45
|
| null
|
|
41
|
-
const tags = (
|
|
46
|
+
const tags = getPropertyTags(obj, 'MCP prompt', nameValue, logger)
|
|
42
47
|
|
|
43
48
|
const funcInitializer = getPropertyAssignmentInitializer(
|
|
44
49
|
obj,
|
|
@@ -47,42 +52,45 @@ export const addMCPPrompt: AddWiring = (
|
|
|
47
52
|
checker
|
|
48
53
|
)
|
|
49
54
|
if (!funcInitializer) {
|
|
50
|
-
|
|
55
|
+
logger.critical(
|
|
56
|
+
ErrorCode.MISSING_FUNC,
|
|
57
|
+
`No valid 'func' property for MCP prompt '${nameValue}'.`
|
|
58
|
+
)
|
|
51
59
|
return
|
|
52
60
|
}
|
|
53
61
|
|
|
54
62
|
const pikkuFuncName = extractFunctionName(
|
|
55
63
|
funcInitializer,
|
|
56
|
-
checker
|
|
64
|
+
checker,
|
|
65
|
+
state.rootDir
|
|
57
66
|
).pikkuFuncName
|
|
58
67
|
|
|
68
|
+
// Ensure function metadata exists (creates stub for inline functions)
|
|
69
|
+
ensureFunctionMetadata(state, pikkuFuncName, nameValue || undefined)
|
|
70
|
+
|
|
59
71
|
if (!nameValue) {
|
|
60
|
-
|
|
72
|
+
logger.critical(
|
|
73
|
+
ErrorCode.MISSING_NAME,
|
|
74
|
+
"MCP prompt is missing the required 'name' property."
|
|
75
|
+
)
|
|
61
76
|
return
|
|
62
77
|
}
|
|
63
78
|
|
|
64
79
|
if (!descriptionValue) {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
const filePath = node.getSourceFile().fileName
|
|
70
|
-
|
|
71
|
-
if (
|
|
72
|
-
!matchesFilters(
|
|
73
|
-
options.filters || {},
|
|
74
|
-
{ tags },
|
|
75
|
-
{ type: PikkuWiringTypes.mcp, name: nameValue, filePath },
|
|
76
|
-
logger
|
|
80
|
+
logger.critical(
|
|
81
|
+
ErrorCode.MISSING_DESCRIPTION,
|
|
82
|
+
`MCP prompt '${nameValue}' is missing a description.`
|
|
77
83
|
)
|
|
78
|
-
) {
|
|
79
84
|
return
|
|
80
85
|
}
|
|
81
86
|
|
|
82
87
|
// lookup existing function metadata
|
|
83
88
|
const fnMeta = state.functions.meta[pikkuFuncName]
|
|
84
89
|
if (!fnMeta) {
|
|
85
|
-
|
|
90
|
+
logger.critical(
|
|
91
|
+
ErrorCode.FUNCTION_METADATA_NOT_FOUND,
|
|
92
|
+
`No function metadata found for '${pikkuFuncName}'.`
|
|
93
|
+
)
|
|
86
94
|
return
|
|
87
95
|
}
|
|
88
96
|
const inputSchema = fnMeta.inputs?.[0] || null
|
|
@@ -91,6 +99,18 @@ export const addMCPPrompt: AddWiring = (
|
|
|
91
99
|
// --- resolve middleware ---
|
|
92
100
|
const middleware = resolveMiddleware(state, obj, tags, checker)
|
|
93
101
|
|
|
102
|
+
// --- resolve permissions ---
|
|
103
|
+
const permissions = resolvePermissions(state, obj, tags, checker)
|
|
104
|
+
|
|
105
|
+
// --- track used functions/middleware/permissions for service aggregation ---
|
|
106
|
+
state.serviceAggregation.usedFunctions.add(pikkuFuncName)
|
|
107
|
+
extractWireNames(middleware).forEach((name) =>
|
|
108
|
+
state.serviceAggregation.usedMiddleware.add(name)
|
|
109
|
+
)
|
|
110
|
+
extractWireNames(permissions).forEach((name) =>
|
|
111
|
+
state.serviceAggregation.usedPermissions.add(name)
|
|
112
|
+
)
|
|
113
|
+
|
|
94
114
|
state.mcpEndpoints.files.add(node.getSourceFile().fileName)
|
|
95
115
|
|
|
96
116
|
state.mcpEndpoints.promptsMeta[nameValue] = {
|
|
@@ -102,6 +122,7 @@ export const addMCPPrompt: AddWiring = (
|
|
|
102
122
|
outputSchema,
|
|
103
123
|
arguments: [], // Will be populated by CLI during serialization
|
|
104
124
|
middleware,
|
|
125
|
+
permissions,
|
|
105
126
|
}
|
|
106
127
|
}
|
|
107
128
|
}
|
|
File without changes
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import * as ts from 'typescript'
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import {
|
|
3
|
+
getPropertyValue,
|
|
4
|
+
getPropertyTags,
|
|
5
|
+
} from '../utils/get-property-value.js'
|
|
6
|
+
import { extractWireNames } from '../utils/post-process.js'
|
|
7
|
+
import { ensureFunctionMetadata } from '../utils/ensure-function-metadata.js'
|
|
4
8
|
import { AddWiring } from '../types.js'
|
|
5
9
|
import { extractFunctionName } from '../utils/extract-function-name.js'
|
|
6
10
|
import { getPropertyAssignmentInitializer } from '../utils/type-utils.js'
|
|
7
|
-
import { matchesFilters } from '../utils/filter-utils.js'
|
|
8
11
|
import { resolveMiddleware } from '../utils/middleware.js'
|
|
12
|
+
import { resolvePermissions } from '../utils/permissions.js'
|
|
13
|
+
import { ErrorCode } from '../error-codes.js'
|
|
9
14
|
|
|
10
15
|
export const addMCPResource: AddWiring = (
|
|
11
16
|
logger,
|
|
@@ -40,7 +45,13 @@ export const addMCPResource: AddWiring = (
|
|
|
40
45
|
| string
|
|
41
46
|
| null
|
|
42
47
|
const streamingValue = getPropertyValue(obj, 'streaming') as boolean | null
|
|
43
|
-
const tags = (
|
|
48
|
+
const tags = getPropertyTags(obj, 'MCP resource', uriValue, logger)
|
|
49
|
+
|
|
50
|
+
if (streamingValue === true) {
|
|
51
|
+
logger.warn(
|
|
52
|
+
`MCP resource '${uriValue}' has streaming enabled, but streaming is not yet supported.`
|
|
53
|
+
)
|
|
54
|
+
}
|
|
44
55
|
|
|
45
56
|
const funcInitializer = getPropertyAssignmentInitializer(
|
|
46
57
|
obj,
|
|
@@ -49,51 +60,53 @@ export const addMCPResource: AddWiring = (
|
|
|
49
60
|
checker
|
|
50
61
|
)
|
|
51
62
|
if (!funcInitializer) {
|
|
52
|
-
|
|
53
|
-
|
|
63
|
+
logger.critical(
|
|
64
|
+
ErrorCode.MISSING_FUNC,
|
|
65
|
+
`No valid 'func' property for MCP resource '${uriValue}'.`
|
|
54
66
|
)
|
|
55
67
|
return
|
|
56
68
|
}
|
|
57
69
|
|
|
58
70
|
const pikkuFuncName = extractFunctionName(
|
|
59
71
|
funcInitializer,
|
|
60
|
-
checker
|
|
72
|
+
checker,
|
|
73
|
+
state.rootDir
|
|
61
74
|
).pikkuFuncName
|
|
62
75
|
|
|
76
|
+
// Ensure function metadata exists (creates stub for inline functions)
|
|
77
|
+
ensureFunctionMetadata(state, pikkuFuncName, uriValue || undefined)
|
|
78
|
+
|
|
63
79
|
if (!uriValue) {
|
|
64
|
-
|
|
80
|
+
logger.critical(
|
|
81
|
+
ErrorCode.MISSING_URI,
|
|
82
|
+
"MCP resource is missing the required 'uri' property."
|
|
83
|
+
)
|
|
65
84
|
return
|
|
66
85
|
}
|
|
67
86
|
|
|
68
87
|
if (!titleValue) {
|
|
69
|
-
|
|
70
|
-
|
|
88
|
+
logger.critical(
|
|
89
|
+
ErrorCode.MISSING_TITLE,
|
|
90
|
+
`MCP resource '${uriValue}' is missing the required 'title' property.`
|
|
71
91
|
)
|
|
72
92
|
return
|
|
73
93
|
}
|
|
74
94
|
|
|
75
95
|
if (!descriptionValue) {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
const filePath = node.getSourceFile().fileName
|
|
81
|
-
|
|
82
|
-
if (
|
|
83
|
-
!matchesFilters(
|
|
84
|
-
options.filters || {},
|
|
85
|
-
{ tags },
|
|
86
|
-
{ type: PikkuWiringTypes.mcp, name: uriValue, filePath },
|
|
87
|
-
logger
|
|
96
|
+
logger.critical(
|
|
97
|
+
ErrorCode.MISSING_DESCRIPTION,
|
|
98
|
+
`MCP resource '${uriValue}' is missing a description.`
|
|
88
99
|
)
|
|
89
|
-
) {
|
|
90
100
|
return
|
|
91
101
|
}
|
|
92
102
|
|
|
93
103
|
// lookup existing function metadata
|
|
94
104
|
const fnMeta = state.functions.meta[pikkuFuncName]
|
|
95
105
|
if (!fnMeta) {
|
|
96
|
-
|
|
106
|
+
logger.critical(
|
|
107
|
+
ErrorCode.FUNCTION_METADATA_NOT_FOUND,
|
|
108
|
+
`No function metadata found for '${pikkuFuncName}'.`
|
|
109
|
+
)
|
|
97
110
|
return
|
|
98
111
|
}
|
|
99
112
|
const inputSchema = fnMeta.inputs?.[0] || null
|
|
@@ -102,6 +115,18 @@ export const addMCPResource: AddWiring = (
|
|
|
102
115
|
// --- resolve middleware ---
|
|
103
116
|
const middleware = resolveMiddleware(state, obj, tags, checker)
|
|
104
117
|
|
|
118
|
+
// --- resolve permissions ---
|
|
119
|
+
const permissions = resolvePermissions(state, obj, tags, checker)
|
|
120
|
+
|
|
121
|
+
// --- track used functions/middleware/permissions for service aggregation ---
|
|
122
|
+
state.serviceAggregation.usedFunctions.add(pikkuFuncName)
|
|
123
|
+
extractWireNames(middleware).forEach((name) =>
|
|
124
|
+
state.serviceAggregation.usedMiddleware.add(name)
|
|
125
|
+
)
|
|
126
|
+
extractWireNames(permissions).forEach((name) =>
|
|
127
|
+
state.serviceAggregation.usedPermissions.add(name)
|
|
128
|
+
)
|
|
129
|
+
|
|
105
130
|
state.mcpEndpoints.files.add(node.getSourceFile().fileName)
|
|
106
131
|
|
|
107
132
|
state.mcpEndpoints.resourcesMeta[uriValue] = {
|
|
@@ -114,6 +139,7 @@ export const addMCPResource: AddWiring = (
|
|
|
114
139
|
inputSchema,
|
|
115
140
|
outputSchema,
|
|
116
141
|
middleware,
|
|
142
|
+
permissions,
|
|
117
143
|
}
|
|
118
144
|
}
|
|
119
145
|
}
|
|
File without changes
|
package/src/add/add-mcp-tool.ts
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import * as ts from 'typescript'
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import {
|
|
3
|
+
getPropertyValue,
|
|
4
|
+
getPropertyTags,
|
|
5
|
+
} from '../utils/get-property-value.js'
|
|
6
|
+
import { extractWireNames } from '../utils/post-process.js'
|
|
7
|
+
import { ensureFunctionMetadata } from '../utils/ensure-function-metadata.js'
|
|
4
8
|
import { AddWiring } from '../types.js'
|
|
5
9
|
import { extractFunctionName } from '../utils/extract-function-name.js'
|
|
6
10
|
import { getPropertyAssignmentInitializer } from '../utils/type-utils.js'
|
|
7
|
-
import { matchesFilters } from '../utils/filter-utils.js'
|
|
8
11
|
import { resolveMiddleware } from '../utils/middleware.js'
|
|
12
|
+
import { resolvePermissions } from '../utils/permissions.js'
|
|
13
|
+
import { ErrorCode } from '../error-codes.js'
|
|
9
14
|
|
|
10
15
|
export const addMCPTool: AddWiring = (
|
|
11
16
|
logger,
|
|
@@ -40,7 +45,13 @@ export const addMCPTool: AddWiring = (
|
|
|
40
45
|
| string
|
|
41
46
|
| null
|
|
42
47
|
const streamingValue = getPropertyValue(obj, 'streaming') as boolean | null
|
|
43
|
-
const tags = (
|
|
48
|
+
const tags = getPropertyTags(obj, 'MCP tool', nameValue, logger)
|
|
49
|
+
|
|
50
|
+
if (streamingValue === true) {
|
|
51
|
+
logger.warn(
|
|
52
|
+
`MCP tool '${nameValue}' has streaming enabled, but streaming is not yet supported.`
|
|
53
|
+
)
|
|
54
|
+
}
|
|
44
55
|
|
|
45
56
|
const funcInitializer = getPropertyAssignmentInitializer(
|
|
46
57
|
obj,
|
|
@@ -49,42 +60,45 @@ export const addMCPTool: AddWiring = (
|
|
|
49
60
|
checker
|
|
50
61
|
)
|
|
51
62
|
if (!funcInitializer) {
|
|
52
|
-
|
|
63
|
+
logger.critical(
|
|
64
|
+
ErrorCode.MISSING_FUNC,
|
|
65
|
+
`No valid 'func' property for MCP tool '${nameValue}'.`
|
|
66
|
+
)
|
|
53
67
|
return
|
|
54
68
|
}
|
|
55
69
|
|
|
56
70
|
const pikkuFuncName = extractFunctionName(
|
|
57
71
|
funcInitializer,
|
|
58
|
-
checker
|
|
72
|
+
checker,
|
|
73
|
+
state.rootDir
|
|
59
74
|
).pikkuFuncName
|
|
60
75
|
|
|
76
|
+
// Ensure function metadata exists (creates stub for inline functions)
|
|
77
|
+
ensureFunctionMetadata(state, pikkuFuncName, nameValue || undefined)
|
|
78
|
+
|
|
61
79
|
if (!nameValue) {
|
|
62
|
-
|
|
80
|
+
logger.critical(
|
|
81
|
+
ErrorCode.MISSING_NAME,
|
|
82
|
+
"MCP tool is missing the required 'name' property."
|
|
83
|
+
)
|
|
63
84
|
return
|
|
64
85
|
}
|
|
65
86
|
|
|
66
87
|
if (!descriptionValue) {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
const filePath = node.getSourceFile().fileName
|
|
72
|
-
|
|
73
|
-
if (
|
|
74
|
-
!matchesFilters(
|
|
75
|
-
options.filters || {},
|
|
76
|
-
{ tags },
|
|
77
|
-
{ type: PikkuWiringTypes.mcp, name: nameValue, filePath },
|
|
78
|
-
logger
|
|
88
|
+
logger.critical(
|
|
89
|
+
ErrorCode.MISSING_DESCRIPTION,
|
|
90
|
+
`MCP tool '${nameValue}' is missing a description.`
|
|
79
91
|
)
|
|
80
|
-
) {
|
|
81
92
|
return
|
|
82
93
|
}
|
|
83
94
|
|
|
84
95
|
// lookup existing function metadata
|
|
85
96
|
const fnMeta = state.functions.meta[pikkuFuncName]
|
|
86
97
|
if (!fnMeta) {
|
|
87
|
-
|
|
98
|
+
logger.critical(
|
|
99
|
+
ErrorCode.FUNCTION_METADATA_NOT_FOUND,
|
|
100
|
+
`No function metadata found for '${pikkuFuncName}'.`
|
|
101
|
+
)
|
|
88
102
|
return
|
|
89
103
|
}
|
|
90
104
|
const inputSchema = fnMeta.inputs?.[0] || null
|
|
@@ -93,6 +107,18 @@ export const addMCPTool: AddWiring = (
|
|
|
93
107
|
// --- resolve middleware ---
|
|
94
108
|
const middleware = resolveMiddleware(state, obj, tags, checker)
|
|
95
109
|
|
|
110
|
+
// --- resolve permissions ---
|
|
111
|
+
const permissions = resolvePermissions(state, obj, tags, checker)
|
|
112
|
+
|
|
113
|
+
// --- track used functions/middleware/permissions for service aggregation ---
|
|
114
|
+
state.serviceAggregation.usedFunctions.add(pikkuFuncName)
|
|
115
|
+
extractWireNames(middleware).forEach((name) =>
|
|
116
|
+
state.serviceAggregation.usedMiddleware.add(name)
|
|
117
|
+
)
|
|
118
|
+
extractWireNames(permissions).forEach((name) =>
|
|
119
|
+
state.serviceAggregation.usedPermissions.add(name)
|
|
120
|
+
)
|
|
121
|
+
|
|
96
122
|
state.mcpEndpoints.files.add(node.getSourceFile().fileName)
|
|
97
123
|
|
|
98
124
|
state.mcpEndpoints.toolsMeta[nameValue] = {
|
|
@@ -105,6 +131,7 @@ export const addMCPTool: AddWiring = (
|
|
|
105
131
|
inputSchema,
|
|
106
132
|
outputSchema,
|
|
107
133
|
middleware,
|
|
134
|
+
permissions,
|
|
108
135
|
}
|
|
109
136
|
}
|
|
110
137
|
}
|
|
@@ -6,6 +6,8 @@ import {
|
|
|
6
6
|
} from '../utils/extract-function-name.js'
|
|
7
7
|
import { extractServicesFromFunction } from '../utils/extract-services.js'
|
|
8
8
|
import { extractMiddlewarePikkuNames } from '../utils/middleware.js'
|
|
9
|
+
import { getPropertyValue } from '../utils/get-property-value.js'
|
|
10
|
+
import { getPropertyAssignmentInitializer } from '../utils/type-utils.js'
|
|
9
11
|
|
|
10
12
|
/**
|
|
11
13
|
* Inspect pikkuMiddleware calls, addMiddleware calls, and addHTTPMiddleware calls
|
|
@@ -22,28 +24,62 @@ export const addMiddleware: AddWiring = (logger, node, checker, state) => {
|
|
|
22
24
|
|
|
23
25
|
// Handle pikkuMiddleware(...) - individual middleware function definition
|
|
24
26
|
if (expression.text === 'pikkuMiddleware') {
|
|
25
|
-
const
|
|
26
|
-
if (!
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
const arg = args[0]
|
|
28
|
+
if (!arg) return
|
|
29
|
+
|
|
30
|
+
let actualHandler: ts.ArrowFunction | ts.FunctionExpression
|
|
31
|
+
let name: string | undefined
|
|
32
|
+
let description: string | undefined
|
|
33
|
+
|
|
34
|
+
// Check if using object syntax: pikkuMiddleware({ func: ..., name: '...', description: '...' })
|
|
35
|
+
if (ts.isObjectLiteralExpression(arg)) {
|
|
36
|
+
// Extract name and description metadata
|
|
37
|
+
const nameValue = getPropertyValue(arg, 'name')
|
|
38
|
+
const descValue = getPropertyValue(arg, 'description')
|
|
39
|
+
name = typeof nameValue === 'string' ? nameValue : undefined
|
|
40
|
+
description = typeof descValue === 'string' ? descValue : undefined
|
|
41
|
+
|
|
42
|
+
// Extract the func property
|
|
43
|
+
const fnProp = getPropertyAssignmentInitializer(
|
|
44
|
+
arg,
|
|
45
|
+
'func',
|
|
46
|
+
true,
|
|
47
|
+
checker
|
|
48
|
+
)
|
|
49
|
+
if (
|
|
50
|
+
!fnProp ||
|
|
51
|
+
(!ts.isArrowFunction(fnProp) && !ts.isFunctionExpression(fnProp))
|
|
52
|
+
) {
|
|
53
|
+
logger.error(
|
|
54
|
+
`• pikkuMiddleware object missing required 'func' property.`
|
|
55
|
+
)
|
|
56
|
+
return
|
|
57
|
+
}
|
|
58
|
+
actualHandler = fnProp
|
|
59
|
+
} else if (ts.isArrowFunction(arg) || ts.isFunctionExpression(arg)) {
|
|
60
|
+
actualHandler = arg
|
|
61
|
+
} else {
|
|
32
62
|
logger.error(`• Handler for pikkuMiddleware is not a function.`)
|
|
33
63
|
return
|
|
34
64
|
}
|
|
35
65
|
|
|
36
|
-
const services = extractServicesFromFunction(
|
|
37
|
-
const { pikkuFuncName, exportedName } = extractFunctionName(
|
|
66
|
+
const services = extractServicesFromFunction(actualHandler)
|
|
67
|
+
const { pikkuFuncName, exportedName } = extractFunctionName(
|
|
68
|
+
node,
|
|
69
|
+
checker,
|
|
70
|
+
state.rootDir
|
|
71
|
+
)
|
|
38
72
|
state.middleware.meta[pikkuFuncName] = {
|
|
39
73
|
services,
|
|
40
74
|
sourceFile: node.getSourceFile().fileName,
|
|
41
75
|
position: node.getStart(),
|
|
42
76
|
exportedName,
|
|
77
|
+
name,
|
|
78
|
+
description,
|
|
43
79
|
}
|
|
44
80
|
|
|
45
81
|
logger.debug(
|
|
46
|
-
`• Found middleware with services: ${services.services.join(', ')}`
|
|
82
|
+
`• Found middleware with services: ${services.services.join(', ')}${name ? ` (name: ${name})` : ''}${description ? ` (description: ${description})` : ''}`
|
|
47
83
|
)
|
|
48
84
|
return
|
|
49
85
|
}
|
|
@@ -63,6 +99,7 @@ export const addMiddleware: AddWiring = (logger, node, checker, state) => {
|
|
|
63
99
|
|
|
64
100
|
// Extract services by looking inside the factory function body
|
|
65
101
|
// The factory should return pikkuMiddleware(...), so we need to find that call
|
|
102
|
+
// If no wrapper is found, extract from the factory's returned function directly
|
|
66
103
|
let services = { optimized: false, services: [] as string[] }
|
|
67
104
|
|
|
68
105
|
const findPikkuMiddlewareCall = (
|
|
@@ -86,9 +123,29 @@ export const addMiddleware: AddWiring = (logger, node, checker, state) => {
|
|
|
86
123
|
) {
|
|
87
124
|
services = extractServicesFromFunction(middlewareHandler)
|
|
88
125
|
}
|
|
126
|
+
} else {
|
|
127
|
+
// No pikkuMiddleware wrapper found - extract from factory's return value directly
|
|
128
|
+
// Factory pattern: (config) => (services, interaction, next) => { ... }
|
|
129
|
+
if (
|
|
130
|
+
ts.isArrowFunction(factoryNode) ||
|
|
131
|
+
ts.isFunctionExpression(factoryNode)
|
|
132
|
+
) {
|
|
133
|
+
const factoryBody = factoryNode.body
|
|
134
|
+
// Check if the body is an arrow function (direct return)
|
|
135
|
+
if (
|
|
136
|
+
ts.isArrowFunction(factoryBody) ||
|
|
137
|
+
ts.isFunctionExpression(factoryBody)
|
|
138
|
+
) {
|
|
139
|
+
services = extractServicesFromFunction(factoryBody)
|
|
140
|
+
}
|
|
141
|
+
}
|
|
89
142
|
}
|
|
90
143
|
|
|
91
|
-
const { pikkuFuncName, exportedName } = extractFunctionName(
|
|
144
|
+
const { pikkuFuncName, exportedName } = extractFunctionName(
|
|
145
|
+
node,
|
|
146
|
+
checker,
|
|
147
|
+
state.rootDir
|
|
148
|
+
)
|
|
92
149
|
state.middleware.meta[pikkuFuncName] = {
|
|
93
150
|
services,
|
|
94
151
|
sourceFile: node.getSourceFile().fileName,
|
|
@@ -135,7 +192,8 @@ export const addMiddleware: AddWiring = (logger, node, checker, state) => {
|
|
|
135
192
|
// Extract middleware pikkuFuncNames from array
|
|
136
193
|
const middlewareNames = extractMiddlewarePikkuNames(
|
|
137
194
|
middlewareArrayArg,
|
|
138
|
-
checker
|
|
195
|
+
checker,
|
|
196
|
+
state.rootDir
|
|
139
197
|
)
|
|
140
198
|
|
|
141
199
|
if (middlewareNames.length === 0) {
|
|
@@ -182,7 +240,7 @@ export const addMiddleware: AddWiring = (logger, node, checker, state) => {
|
|
|
182
240
|
|
|
183
241
|
// If not a factory, get export name from the call expression itself
|
|
184
242
|
if (!isFactory) {
|
|
185
|
-
const extracted = extractFunctionName(node, checker)
|
|
243
|
+
const extracted = extractFunctionName(node, checker, state.rootDir)
|
|
186
244
|
exportedName = extracted.exportedName
|
|
187
245
|
}
|
|
188
246
|
|
|
@@ -245,7 +303,8 @@ export const addMiddleware: AddWiring = (logger, node, checker, state) => {
|
|
|
245
303
|
// Extract middleware pikkuFuncNames from array
|
|
246
304
|
const middlewareNames = extractMiddlewarePikkuNames(
|
|
247
305
|
middlewareArrayArg,
|
|
248
|
-
checker
|
|
306
|
+
checker,
|
|
307
|
+
state.rootDir
|
|
249
308
|
)
|
|
250
309
|
|
|
251
310
|
if (middlewareNames.length === 0) {
|
|
@@ -293,7 +352,7 @@ export const addMiddleware: AddWiring = (logger, node, checker, state) => {
|
|
|
293
352
|
|
|
294
353
|
// If not a factory, get export name from the call expression itself
|
|
295
354
|
if (!isFactory) {
|
|
296
|
-
const extracted = extractFunctionName(node, checker)
|
|
355
|
+
const extracted = extractFunctionName(node, checker, state.rootDir)
|
|
297
356
|
exportedName = extracted.exportedName
|
|
298
357
|
}
|
|
299
358
|
|