@pikku/inspector 0.10.0 → 0.10.2

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 CHANGED
@@ -1,5 +1,59 @@
1
1
  # @pikku/inspector
2
2
 
3
+ ## 0.10.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 1967172: Update code generation to support channel middleware enhancements
8
+
9
+ **Code Generation Updates:**
10
+
11
+ - Update channel type serialization to include middleware support
12
+ - Improve WebSocket wrapper generation for middleware handling
13
+ - Update CLI channel client generation with better type support
14
+ - Enhance services and schema generation for channel configurations
15
+
16
+ **Inspector Updates:**
17
+
18
+ - Improve channel metadata extraction for middleware
19
+ - Better type analysis for channel lifecycle functions
20
+ - Enhanced post-processing for channel configurations
21
+
22
+ - 753481a: Add bootstrap command, performance optimizations, and CLI improvements
23
+
24
+ **New Features:**
25
+
26
+ - Add `pikku bootstrap` command for type-only generation (~13.5% faster than `pikku all`)
27
+ - Add configurable `ignoreFiles` option to pikku.config.json with sensible defaults (_.gen.ts, _.test.ts, \*.spec.ts)
28
+ - Export pikkuCLIRender helper from serialize-cli-types.ts with JSDoc documentation
29
+
30
+ **Performance Improvements:**
31
+
32
+ - Add aggressive TypeScript compiler options (skipDefaultLibCheck, types: []) - ~37% faster TypeScript setup
33
+ - Add detailed performance timing to inspector phases (--logLevel=debug)
34
+ - Optimize file inspection with ignore patterns - ~10-20% faster overall
35
+
36
+ **Enhancements:**
37
+
38
+ - Fix --logLevel flag to properly apply log level to logger
39
+ - Update middleware logging to use structured log format
40
+ - Improve CLI renderers to consistently use destructured logger service
41
+ - Fix middleware file generation when middleware groups exist
42
+
43
+ - 44d71a8: fix: fixing inspector ensuring pikkuConfig is set
44
+ - Updated dependencies [ea652dc]
45
+ - Updated dependencies [4349ec5]
46
+ - Updated dependencies [44d71a8]
47
+ - @pikku/core@0.10.2
48
+
49
+ ## 0.10.1
50
+
51
+ ### Patch Changes
52
+
53
+ - 778267e: fix: fixing inspector ensuring pikkuConfig is set
54
+ - Updated dependencies [778267e]
55
+ - @pikku/core@0.10.1
56
+
3
57
  ## 0.10.0
4
58
 
5
59
  This release includes significant improvements across the framework including tree-shaking support, middleware/permission factories, enhanced CLI functionality, improved TypeScript type safety, and comprehensive test strategies.
@@ -94,7 +94,15 @@ export function addMessagesRoutes(logger, obj, state, checker) {
94
94
  const init = getInitializerOf(routeElem);
95
95
  if (!init)
96
96
  continue;
97
- const routeKey = routeElem.name.getText();
97
+ // Get the route key, stripping quotes if it's a string literal
98
+ const routeName = routeElem.name;
99
+ if (!routeName)
100
+ continue;
101
+ let routeKey = routeName.getText();
102
+ // For string literals like 'greet' or "greet", strip the quotes
103
+ if (ts.isStringLiteral(routeName)) {
104
+ routeKey = routeName.text;
105
+ }
98
106
  // For shorthand properties, we need to resolve the identifier to its declaration
99
107
  if (ts.isShorthandPropertyAssignment(routeElem)) {
100
108
  // Get the symbol for the shorthand property
@@ -133,8 +141,16 @@ export function addMessagesRoutes(logger, obj, state, checker) {
133
141
  // Look up in the registry
134
142
  const fnMeta = state.functions.meta[handlerName];
135
143
  if (fnMeta) {
144
+ // Resolve middleware for this route
145
+ const routeTags = ts.isObjectLiteralExpression(init)
146
+ ? getPropertyTags(init, 'channel', channelKey, logger)
147
+ : undefined;
148
+ const routeMiddleware = ts.isObjectLiteralExpression(init)
149
+ ? resolveMiddleware(state, init, routeTags, checker)
150
+ : undefined;
136
151
  result[channelKey][routeKey] = {
137
152
  pikkuFuncName: handlerName,
153
+ middleware: routeMiddleware,
138
154
  };
139
155
  continue;
140
156
  }
@@ -147,8 +163,16 @@ export function addMessagesRoutes(logger, obj, state, checker) {
147
163
  // Look up in the registry
148
164
  const fnMeta = state.functions.meta[handlerName];
149
165
  if (fnMeta) {
166
+ // Resolve middleware for this route
167
+ const routeTags = ts.isObjectLiteralExpression(init)
168
+ ? getPropertyTags(init, 'channel', channelKey, logger)
169
+ : undefined;
170
+ const routeMiddleware = ts.isObjectLiteralExpression(init)
171
+ ? resolveMiddleware(state, init, routeTags, checker)
172
+ : undefined;
150
173
  result[channelKey][routeKey] = {
151
174
  pikkuFuncName: handlerName,
175
+ middleware: routeMiddleware,
152
176
  };
153
177
  continue;
154
178
  }
@@ -172,8 +196,16 @@ export function addMessagesRoutes(logger, obj, state, checker) {
172
196
  const handlerName = pikkuFuncName;
173
197
  const fnMeta = state.functions.meta[handlerName];
174
198
  if (fnMeta) {
199
+ // Resolve middleware for this route
200
+ const routeTags = ts.isObjectLiteralExpression(init)
201
+ ? getPropertyTags(init, 'channel', channelKey, logger)
202
+ : undefined;
203
+ const routeMiddleware = ts.isObjectLiteralExpression(init)
204
+ ? resolveMiddleware(state, init, routeTags, checker)
205
+ : undefined;
175
206
  result[channelKey][routeKey] = {
176
207
  pikkuFuncName: handlerName,
208
+ middleware: routeMiddleware,
177
209
  };
178
210
  continue;
179
211
  }
@@ -183,8 +215,16 @@ export function addMessagesRoutes(logger, obj, state, checker) {
183
215
  const handlerName = pikkuFuncName;
184
216
  const fnMeta = state.functions.meta[handlerName];
185
217
  if (fnMeta) {
218
+ // Resolve middleware for this route
219
+ const routeTags = ts.isObjectLiteralExpression(init)
220
+ ? getPropertyTags(init, 'channel', channelKey, logger)
221
+ : undefined;
222
+ const routeMiddleware = ts.isObjectLiteralExpression(init)
223
+ ? resolveMiddleware(state, init, routeTags, checker)
224
+ : undefined;
186
225
  result[channelKey][routeKey] = {
187
226
  pikkuFuncName: handlerName,
227
+ middleware: routeMiddleware,
188
228
  };
189
229
  continue;
190
230
  }
@@ -239,8 +279,16 @@ export function addMessagesRoutes(logger, obj, state, checker) {
239
279
  // Now use this handlerName to look up in the registry
240
280
  const fnMeta = state.functions.meta[handlerName];
241
281
  if (fnMeta) {
282
+ // Resolve middleware for this route
283
+ const routeTags = ts.isObjectLiteralExpression(init)
284
+ ? getPropertyTags(init, 'channel', channelKey, logger)
285
+ : undefined;
286
+ const routeMiddleware = ts.isObjectLiteralExpression(init)
287
+ ? resolveMiddleware(state, init, routeTags, checker)
288
+ : undefined;
242
289
  result[channelKey][routeKey] = {
243
290
  pikkuFuncName: handlerName,
291
+ middleware: routeMiddleware,
244
292
  };
245
293
  continue; // Skip the normal processing below
246
294
  }
@@ -259,8 +307,17 @@ export function addMessagesRoutes(logger, obj, state, checker) {
259
307
  logger.critical(ErrorCode.FUNCTION_METADATA_NOT_FOUND, `No function metadata found for handler '${handlerName}'`);
260
308
  continue;
261
309
  }
310
+ // Resolve middleware and permissions for this route
311
+ // Check if the route config is an object literal with middleware/permissions
312
+ const routeTags = ts.isObjectLiteralExpression(init)
313
+ ? getPropertyTags(init, 'channel', channelKey, logger)
314
+ : undefined;
315
+ const routeMiddleware = ts.isObjectLiteralExpression(init)
316
+ ? resolveMiddleware(state, init, routeTags, checker)
317
+ : undefined;
262
318
  result[channelKey][routeKey] = {
263
319
  pikkuFuncName: handlerName,
320
+ middleware: routeMiddleware,
264
321
  };
265
322
  }
266
323
  }
@@ -295,24 +352,21 @@ export const addChannel = (logger, node, checker, state, options) => {
295
352
  const docs = getPropertyValue(obj, 'docs');
296
353
  const tags = getPropertyTags(obj, 'Channel', route, logger);
297
354
  const query = getPropertyValue(obj, 'query');
298
- const connect = getPropertyAssignmentInitializer(obj, 'onConnect', false, checker);
299
- const disconnect = getPropertyAssignmentInitializer(obj, 'onDisconnect', false, checker);
355
+ const connect = getPropertyAssignmentInitializer(obj, 'onConnect', true, checker);
356
+ const disconnect = getPropertyAssignmentInitializer(obj, 'onDisconnect', true, checker);
300
357
  // default onMessage handler
301
358
  let message = null;
302
- const onMsgProp = getPropertyAssignmentInitializer(obj, 'onMessage', false, checker);
359
+ const onMsgProp = getPropertyAssignmentInitializer(obj, 'onMessage', true, checker);
303
360
  if (onMsgProp) {
304
- const handlerName = onMsgProp &&
305
- getHandlerNameFromExpression(onMsgProp, checker, state.rootDir);
306
- const fnMeta = handlerName && state.functions.meta[handlerName];
361
+ const { pikkuFuncName } = extractFunctionName(onMsgProp, checker, state.rootDir);
362
+ const fnMeta = state.functions.meta[pikkuFuncName];
307
363
  if (!fnMeta) {
308
- console.error(`No function metadata for onMessage handler '${handlerName}'`);
309
- throw new Error();
310
- }
311
- else {
312
- message = {
313
- pikkuFuncName: extractFunctionName(onMsgProp, checker, state.rootDir).pikkuFuncName,
314
- };
364
+ logger.critical(ErrorCode.FUNCTION_METADATA_NOT_FOUND, `No function metadata found for onMessage handler '${pikkuFuncName}'`);
365
+ return;
315
366
  }
367
+ message = {
368
+ pikkuFuncName,
369
+ };
316
370
  }
317
371
  // nested message-routes
318
372
  const messageWirings = addMessagesRoutes(logger, obj, state, checker);
@@ -1,10 +1,63 @@
1
1
  import * as ts from 'typescript';
2
2
  import { extractServicesFromFunction } from '../utils/extract-services.js';
3
+ // Mapping of wrapper function names to their corresponding types
4
+ const wrapperFunctionMap = {
5
+ pikkuConfig: 'CreateConfig',
6
+ pikkuServices: 'CreateSingletonServices',
7
+ pikkuSessionServices: 'CreateSessionServices',
8
+ };
3
9
  export const addFileWithFactory = (node, checker, methods = new Map(), expectedTypeName, state) => {
4
10
  if (ts.isVariableDeclaration(node)) {
5
11
  const fileName = node.getSourceFile().fileName;
6
12
  const variableTypeNode = node.type;
7
13
  const variableName = node.name.getText();
14
+ // Check for wrapper function calls FIRST (e.g., pikkuConfig(...), pikkuServices(...))
15
+ // This handles both cases: with and without explicit type annotations
16
+ if (node.initializer && ts.isCallExpression(node.initializer)) {
17
+ const callExpression = node.initializer;
18
+ const expression = callExpression.expression;
19
+ if (ts.isIdentifier(expression)) {
20
+ const wrapperFunctionName = expression.text;
21
+ const inferredType = wrapperFunctionMap[wrapperFunctionName];
22
+ if (inferredType === expectedTypeName) {
23
+ // Get the type declaration path from the wrapper function
24
+ const typeSymbol = checker.getSymbolAtLocation(expression);
25
+ let typeDeclarationPath = null;
26
+ if (typeSymbol &&
27
+ typeSymbol.declarations &&
28
+ typeSymbol.declarations[0]) {
29
+ const declaration = typeSymbol.declarations[0];
30
+ const sourceFile = declaration.getSourceFile();
31
+ typeDeclarationPath = sourceFile.fileName;
32
+ }
33
+ const variables = methods.get(fileName) || [];
34
+ variables.push({
35
+ variable: variableName,
36
+ type: inferredType,
37
+ typePath: typeDeclarationPath,
38
+ });
39
+ methods.set(fileName, variables);
40
+ // Extract singleton services for CreateSessionServices factories
41
+ if (expectedTypeName === 'CreateSessionServices' &&
42
+ state &&
43
+ callExpression.arguments.length > 0) {
44
+ const firstArg = callExpression.arguments[0];
45
+ let functionNode;
46
+ if (ts.isArrowFunction(firstArg)) {
47
+ functionNode = firstArg;
48
+ }
49
+ else if (ts.isFunctionExpression(firstArg)) {
50
+ functionNode = firstArg;
51
+ }
52
+ if (functionNode) {
53
+ const servicesMeta = extractServicesFromFunction(functionNode);
54
+ state.sessionServicesMeta.set(variableName, servicesMeta.services);
55
+ }
56
+ }
57
+ return; // Early return since we found a match
58
+ }
59
+ }
60
+ }
8
61
  if (variableTypeNode && ts.isTypeReferenceNode(variableTypeNode)) {
9
62
  const typeNameNode = variableTypeNode.typeName || null;
10
63
  let typeDeclarationPath = null;
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { inspect } from './inspector.js';
1
+ export { inspect, getInitialInspectorState } from './inspector.js';
2
2
  export { getFilesAndMethods } from './utils/get-files-and-methods.js';
3
3
  export type { TypesMap } from './types-map.js';
4
4
  export type * from './types.js';
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- export { inspect } from './inspector.js';
1
+ export { inspect, getInitialInspectorState } from './inspector.js';
2
2
  export { getFilesAndMethods } from './utils/get-files-and-methods.js';
3
3
  export { ErrorCode } from './error-codes.js';
4
4
  export { serializeInspectorState, deserializeInspectorState, } from './utils/serialize-inspector-state.js';
@@ -1,2 +1,8 @@
1
1
  import { InspectorState, InspectorLogger, InspectorOptions } from './types.js';
2
+ /**
3
+ * Creates an initial/empty inspector state with all required properties initialized
4
+ * @param rootDir - The root directory for the project
5
+ * @returns A fresh InspectorState with empty collections
6
+ */
7
+ export declare function getInitialInspectorState(rootDir: string): InspectorState;
2
8
  export declare const inspect: (logger: InspectorLogger, routeFiles: string[], options?: InspectorOptions) => InspectorState;
package/dist/inspector.js CHANGED
@@ -1,19 +1,17 @@
1
1
  import * as ts from 'typescript';
2
+ import { performance } from 'perf_hooks';
2
3
  import { visitSetup, visitRoutes } from './visit.js';
3
4
  import { TypesMap } from './types-map.js';
4
5
  import { getFilesAndMethods } from './utils/get-files-and-methods.js';
5
6
  import { findCommonAncestor } from './utils/find-root-dir.js';
6
7
  import { aggregateRequiredServices } from './utils/post-process.js';
7
- export const inspect = (logger, routeFiles, options = {}) => {
8
- const program = ts.createProgram(routeFiles, {
9
- target: ts.ScriptTarget.ESNext,
10
- module: ts.ModuleKind.CommonJS,
11
- });
12
- const checker = program.getTypeChecker();
13
- const sourceFiles = program.getSourceFiles();
14
- // Infer root directory from source files
15
- const rootDir = findCommonAncestor(routeFiles);
16
- const state = {
8
+ /**
9
+ * Creates an initial/empty inspector state with all required properties initialized
10
+ * @param rootDir - The root directory for the project
11
+ * @returns A fresh InspectorState with empty collections
12
+ */
13
+ export function getInitialInspectorState(rootDir) {
14
+ return {
17
15
  rootDir,
18
16
  singletonServicesTypeImportMap: new Map(),
19
17
  sessionServicesTypeImportMap: new Map(),
@@ -91,21 +89,57 @@ export const inspect = (logger, routeFiles, options = {}) => {
91
89
  usedFunctions: new Set(),
92
90
  usedMiddleware: new Set(),
93
91
  usedPermissions: new Set(),
92
+ allSingletonServices: [],
93
+ allSessionServices: [],
94
94
  },
95
95
  };
96
+ }
97
+ export const inspect = (logger, routeFiles, options = {}) => {
98
+ const startProgram = performance.now();
99
+ const program = ts.createProgram(routeFiles, {
100
+ target: ts.ScriptTarget.ESNext,
101
+ module: ts.ModuleKind.CommonJS,
102
+ skipLibCheck: true,
103
+ skipDefaultLibCheck: true,
104
+ moduleResolution: ts.ModuleResolutionKind.Node10,
105
+ types: [],
106
+ allowJs: false,
107
+ checkJs: false,
108
+ });
109
+ logger.debug(`Created program in ${(performance.now() - startProgram).toFixed(2)}ms`);
110
+ const startChecker = performance.now();
111
+ const checker = program.getTypeChecker();
112
+ logger.debug(`Got type checker in ${(performance.now() - startChecker).toFixed(2)}ms`);
113
+ const startSourceFiles = performance.now();
114
+ const sourceFiles = program.getSourceFiles();
115
+ logger.debug(`Got source files in ${(performance.now() - startSourceFiles).toFixed(2)}ms`);
116
+ // Infer root directory from source files
117
+ const rootDir = findCommonAncestor(routeFiles);
118
+ const state = getInitialInspectorState(rootDir);
96
119
  // First sweep: add all functions
120
+ const startSetup = performance.now();
97
121
  for (const sourceFile of sourceFiles) {
98
122
  ts.forEachChild(sourceFile, (child) => visitSetup(logger, checker, child, state, options));
99
123
  }
100
- // Second sweep: add all transports
101
- for (const sourceFile of sourceFiles) {
102
- ts.forEachChild(sourceFile, (child) => visitRoutes(logger, checker, child, state, options));
124
+ logger.debug(`Visit setup phase completed in ${(performance.now() - startSetup).toFixed(2)}ms`);
125
+ if (!options.setupOnly) {
126
+ // Second sweep: add all transports
127
+ const startRoutes = performance.now();
128
+ for (const sourceFile of sourceFiles) {
129
+ ts.forEachChild(sourceFile, (child) => visitRoutes(logger, checker, child, state, options));
130
+ }
131
+ logger.debug(`Visit routes phase completed in ${(performance.now() - startRoutes).toFixed(2)}ms`);
103
132
  }
104
133
  // Populate filesAndMethods
134
+ const startFilesAndMethods = performance.now();
105
135
  const { result, errors } = getFilesAndMethods(state, options.types);
106
136
  state.filesAndMethods = result;
107
137
  state.filesAndMethodsErrors = errors;
108
- // Post-processing: Aggregate required services from wired functions/middleware/permissions
109
- aggregateRequiredServices(state);
138
+ logger.debug(`Get files and methods completed in ${(performance.now() - startFilesAndMethods).toFixed(2)}ms`);
139
+ if (!options.setupOnly) {
140
+ const startAggregate = performance.now();
141
+ aggregateRequiredServices(state);
142
+ logger.debug(`Aggregate required services completed in ${(performance.now() - startAggregate).toFixed(2)}ms`);
143
+ }
110
144
  return state;
111
145
  };
package/dist/types.d.ts CHANGED
@@ -86,6 +86,7 @@ export type InspectorFilters = {
86
86
  httpMethods?: string[];
87
87
  };
88
88
  export type InspectorOptions = Partial<{
89
+ setupOnly: boolean;
89
90
  types: Partial<{
90
91
  configFileType: string;
91
92
  userSessionType: string;
@@ -200,5 +201,7 @@ export interface InspectorState {
200
201
  usedFunctions: Set<string>;
201
202
  usedMiddleware: Set<string>;
202
203
  usedPermissions: Set<string>;
204
+ allSingletonServices: string[];
205
+ allSessionServices: string[];
203
206
  };
204
207
  }
@@ -19,9 +19,9 @@ const getMetaTypes = (type, map, desiredType, errors) => {
19
19
  if (totalValues.length === 0) {
20
20
  const helpMessage = type === 'CoreConfig'
21
21
  ? `No ${type} found. Make sure you have exported a createConfig function in your codebase:\n\n` +
22
- `export const createConfig: CreateConfig<Config> = async () => {\n` +
22
+ `export const createConfig = pikkuConfig(async () => {\n` +
23
23
  ` return {}\n` +
24
- `}\n\n` +
24
+ `})\n\n` +
25
25
  `Possible issues:\n` +
26
26
  `- srcDirectories in pikku.config.json doesn't include the file with the createConfig method`
27
27
  : `No ${type} found`;
@@ -13,4 +13,4 @@ export declare function extractWireNames(list?: MiddlewareMetadata[] | Permissio
13
13
  * Note: usedFunctions, usedMiddleware, and usedPermissions are tracked directly
14
14
  * in the add-* methods during AST traversal for efficiency.
15
15
  */
16
- export declare function aggregateRequiredServices(state: InspectorState): void;
16
+ export declare function aggregateRequiredServices(state: InspectorState | Omit<InspectorState, 'typesLookup'>): void;
@@ -1,3 +1,4 @@
1
+ import { extractTypeKeys } from './type-utils.js';
1
2
  /**
2
3
  * Helper to extract wire-level middleware/permission names from metadata.
3
4
  * Only extracts type:'wire' variants (individual middleware/permissions).
@@ -39,6 +40,33 @@ function expandAndAddGroupServices(list, state, addServices, isMiddleware) {
39
40
  }
40
41
  }
41
42
  }
43
+ /**
44
+ * Extracts all service names from SingletonServices and Services types.
45
+ * This provides the complete list of available services for code generation.
46
+ * Only runs if typesLookup is available (omitted in deserialized states).
47
+ */
48
+ function extractAllServices(state) {
49
+ // Skip if typesLookup is not available (e.g., deserialized state)
50
+ if (!('typesLookup' in state)) {
51
+ return;
52
+ }
53
+ // Extract all singleton services from the SingletonServices type
54
+ const singletonServicesTypes = state.typesLookup.get('SingletonServices');
55
+ if (singletonServicesTypes && singletonServicesTypes.length > 0) {
56
+ const singletonServiceNames = extractTypeKeys(singletonServicesTypes[0]);
57
+ state.serviceAggregation.allSingletonServices = singletonServiceNames.sort();
58
+ }
59
+ // Extract all services from the Services type
60
+ const servicesTypes = state.typesLookup.get('Services');
61
+ if (servicesTypes && servicesTypes.length > 0) {
62
+ const allServiceNames = extractTypeKeys(servicesTypes[0]);
63
+ // Session services are those in Services but not in SingletonServices
64
+ const singletonSet = new Set(state.serviceAggregation.allSingletonServices);
65
+ state.serviceAggregation.allSessionServices = allServiceNames
66
+ .filter((name) => !singletonSet.has(name))
67
+ .sort();
68
+ }
69
+ }
42
70
  /**
43
71
  * Aggregates all required services from wired functions, middleware, and permissions.
44
72
  * Must be called after AST traversal completes.
@@ -47,6 +75,8 @@ function expandAndAddGroupServices(list, state, addServices, isMiddleware) {
47
75
  * in the add-* methods during AST traversal for efficiency.
48
76
  */
49
77
  export function aggregateRequiredServices(state) {
78
+ // First, extract all available services from types
79
+ extractAllServices(state);
50
80
  const { requiredServices, usedFunctions, usedMiddleware, usedPermissions } = state.serviceAggregation;
51
81
  // Internal services (always excluded from tree-shaking)
52
82
  const internalServices = new Set(['rpc', 'mcp', 'channel', 'userSession']);
@@ -165,6 +165,8 @@ export interface SerializableInspectorState {
165
165
  usedFunctions: string[];
166
166
  usedMiddleware: string[];
167
167
  usedPermissions: string[];
168
+ allSingletonServices: string[];
169
+ allSessionServices: string[];
168
170
  };
169
171
  }
170
172
  /**
@@ -80,6 +80,8 @@ export function serializeInspectorState(state) {
80
80
  usedFunctions: Array.from(state.serviceAggregation.usedFunctions),
81
81
  usedMiddleware: Array.from(state.serviceAggregation.usedMiddleware),
82
82
  usedPermissions: Array.from(state.serviceAggregation.usedPermissions),
83
+ allSingletonServices: state.serviceAggregation.allSingletonServices,
84
+ allSessionServices: state.serviceAggregation.allSessionServices,
83
85
  },
84
86
  };
85
87
  }
@@ -165,6 +167,8 @@ export function deserializeInspectorState(data) {
165
167
  usedFunctions: new Set(data.serviceAggregation.usedFunctions),
166
168
  usedMiddleware: new Set(data.serviceAggregation.usedMiddleware),
167
169
  usedPermissions: new Set(data.serviceAggregation.usedPermissions),
170
+ allSingletonServices: data.serviceAggregation.allSingletonServices,
171
+ allSessionServices: data.serviceAggregation.allSessionServices,
168
172
  },
169
173
  };
170
174
  }
@@ -22,17 +22,19 @@ export function getPropertyAssignmentInitializer(obj, propName, followShorthand
22
22
  prop.name.text === propName) {
23
23
  if (!checker)
24
24
  return prop.name; // best effort without a checker
25
- let sym = checker.getSymbolAtLocation(prop.name);
25
+ // Use the proper TypeScript API for shorthand property resolution
26
+ let sym = checker.getShorthandAssignmentValueSymbol(prop);
26
27
  if (sym && sym.flags & ts.SymbolFlags.Alias) {
27
28
  sym = checker.getAliasedSymbol(sym);
28
29
  }
29
30
  const decl = sym?.declarations?.[0];
30
- // const foo = () => {}
31
+ // const foo = () => {} or const foo = pikkuFunc(...)
31
32
  if (decl &&
32
33
  ts.isVariableDeclaration(decl) &&
33
34
  decl.initializer &&
34
35
  (ts.isArrowFunction(decl.initializer) ||
35
- ts.isFunctionExpression(decl.initializer))) {
36
+ ts.isFunctionExpression(decl.initializer) ||
37
+ ts.isCallExpression(decl.initializer))) {
36
38
  return decl.initializer;
37
39
  }
38
40
  // function foo() {}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pikku/inspector",
3
- "version": "0.10.0",
3
+ "version": "0.10.2",
4
4
  "author": "yasser.fadl@gmail.com",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -16,7 +16,7 @@
16
16
  "test:coverage": "bash run-tests.sh --coverage"
17
17
  },
18
18
  "dependencies": {
19
- "@pikku/core": "^0.10.0",
19
+ "@pikku/core": "^0.10.2",
20
20
  "path-to-regexp": "^8.3.0",
21
21
  "typescript": "^5.9"
22
22
  },