@kernlang/review 3.4.6-canary.44.1.a85ee2e8 → 3.4.6-canary.46.1.19dcfc19

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 (106) hide show
  1. package/dist/mappers/ts-concepts/extractors/dependency.d.ts +3 -0
  2. package/dist/mappers/ts-concepts/extractors/dependency.js +28 -0
  3. package/dist/mappers/ts-concepts/extractors/dependency.js.map +1 -0
  4. package/dist/mappers/ts-concepts/extractors/effect.d.ts +3 -0
  5. package/dist/mappers/ts-concepts/extractors/effect.js +93 -0
  6. package/dist/mappers/ts-concepts/extractors/effect.js.map +1 -0
  7. package/dist/mappers/ts-concepts/extractors/entrypoint-express/index.d.ts +3 -0
  8. package/dist/mappers/ts-concepts/extractors/entrypoint-express/index.js +117 -0
  9. package/dist/mappers/ts-concepts/extractors/entrypoint-express/index.js.map +1 -0
  10. package/dist/mappers/ts-concepts/extractors/entrypoint-express/mount.d.ts +2 -0
  11. package/dist/mappers/ts-concepts/extractors/entrypoint-express/mount.js +105 -0
  12. package/dist/mappers/ts-concepts/extractors/entrypoint-express/mount.js.map +1 -0
  13. package/dist/mappers/ts-concepts/extractors/entrypoint-express/pagination.d.ts +7 -0
  14. package/dist/mappers/ts-concepts/extractors/entrypoint-express/pagination.js +128 -0
  15. package/dist/mappers/ts-concepts/extractors/entrypoint-express/pagination.js.map +1 -0
  16. package/dist/mappers/ts-concepts/extractors/entrypoint-express/route-handler.d.ts +25 -0
  17. package/dist/mappers/ts-concepts/extractors/entrypoint-express/route-handler.js +110 -0
  18. package/dist/mappers/ts-concepts/extractors/entrypoint-express/route-handler.js.map +1 -0
  19. package/dist/mappers/ts-concepts/extractors/entrypoint-express/success-status.d.ts +5 -0
  20. package/dist/mappers/ts-concepts/extractors/entrypoint-express/success-status.js +150 -0
  21. package/dist/mappers/ts-concepts/extractors/entrypoint-express/success-status.js.map +1 -0
  22. package/dist/mappers/ts-concepts/extractors/entrypoint-express/validation.d.ts +14 -0
  23. package/dist/mappers/ts-concepts/extractors/entrypoint-express/validation.js +172 -0
  24. package/dist/mappers/ts-concepts/extractors/entrypoint-express/validation.js.map +1 -0
  25. package/dist/mappers/ts-concepts/extractors/entrypoint-nextjs.d.ts +3 -0
  26. package/dist/mappers/ts-concepts/extractors/entrypoint-nextjs.js +100 -0
  27. package/dist/mappers/ts-concepts/extractors/entrypoint-nextjs.js.map +1 -0
  28. package/dist/mappers/ts-concepts/extractors/error-handle.d.ts +3 -0
  29. package/dist/mappers/ts-concepts/extractors/error-handle.js +113 -0
  30. package/dist/mappers/ts-concepts/extractors/error-handle.js.map +1 -0
  31. package/dist/mappers/ts-concepts/extractors/error-raise.d.ts +3 -0
  32. package/dist/mappers/ts-concepts/extractors/error-raise.js +47 -0
  33. package/dist/mappers/ts-concepts/extractors/error-raise.js.map +1 -0
  34. package/dist/mappers/ts-concepts/extractors/function-decls.d.ts +3 -0
  35. package/dist/mappers/ts-concepts/extractors/function-decls.js +145 -0
  36. package/dist/mappers/ts-concepts/extractors/function-decls.js.map +1 -0
  37. package/dist/mappers/ts-concepts/extractors/guard.d.ts +3 -0
  38. package/dist/mappers/ts-concepts/extractors/guard.js +94 -0
  39. package/dist/mappers/ts-concepts/extractors/guard.js.map +1 -0
  40. package/dist/mappers/ts-concepts/extractors/react-wrappers.d.ts +3 -0
  41. package/dist/mappers/ts-concepts/extractors/react-wrappers.js +55 -0
  42. package/dist/mappers/ts-concepts/extractors/react-wrappers.js.map +1 -0
  43. package/dist/mappers/ts-concepts/extractors/state-mutation.d.ts +3 -0
  44. package/dist/mappers/ts-concepts/extractors/state-mutation.js +100 -0
  45. package/dist/mappers/ts-concepts/extractors/state-mutation.js.map +1 -0
  46. package/dist/mappers/ts-concepts/helpers/ast.d.ts +14 -0
  47. package/dist/mappers/ts-concepts/helpers/ast.js +162 -0
  48. package/dist/mappers/ts-concepts/helpers/ast.js.map +1 -0
  49. package/dist/mappers/ts-concepts/helpers/const-resolution.d.ts +7 -0
  50. package/dist/mappers/ts-concepts/helpers/const-resolution.js +186 -0
  51. package/dist/mappers/ts-concepts/helpers/const-resolution.js.map +1 -0
  52. package/dist/mappers/ts-concepts/helpers/error-paths.d.ts +16 -0
  53. package/dist/mappers/ts-concepts/helpers/error-paths.js +308 -0
  54. package/dist/mappers/ts-concepts/helpers/error-paths.js.map +1 -0
  55. package/dist/mappers/ts-concepts/helpers/network-call.d.ts +46 -0
  56. package/dist/mappers/ts-concepts/helpers/network-call.js +398 -0
  57. package/dist/mappers/ts-concepts/helpers/network-call.js.map +1 -0
  58. package/dist/mappers/ts-concepts/helpers/types.d.ts +30 -0
  59. package/dist/mappers/ts-concepts/helpers/types.js +426 -0
  60. package/dist/mappers/ts-concepts/helpers/types.js.map +1 -0
  61. package/dist/mappers/ts-concepts/helpers/wrapped-client.d.ts +23 -0
  62. package/dist/mappers/ts-concepts/helpers/wrapped-client.js +95 -0
  63. package/dist/mappers/ts-concepts/helpers/wrapped-client.js.map +1 -0
  64. package/dist/mappers/ts-concepts/index.d.ts +9 -0
  65. package/dist/mappers/ts-concepts/index.js +39 -0
  66. package/dist/mappers/ts-concepts/index.js.map +1 -0
  67. package/dist/mappers/ts-concepts/signatures.d.ts +40 -0
  68. package/dist/mappers/ts-concepts/signatures.js +233 -0
  69. package/dist/mappers/ts-concepts/signatures.js.map +1 -0
  70. package/dist/mappers/ts-concepts.d.ts +1 -9
  71. package/dist/mappers/ts-concepts.js +1 -3552
  72. package/dist/mappers/ts-concepts.js.map +1 -1
  73. package/dist/python-fallback/extractors/dependency.d.ts +4 -0
  74. package/dist/python-fallback/extractors/dependency.js +22 -0
  75. package/dist/python-fallback/extractors/dependency.js.map +1 -0
  76. package/dist/python-fallback/extractors/error.d.ts +4 -0
  77. package/dist/python-fallback/extractors/error.js +44 -0
  78. package/dist/python-fallback/extractors/error.js.map +1 -0
  79. package/dist/python-fallback/extractors/fastapi-pagination.d.ts +10 -0
  80. package/dist/python-fallback/extractors/fastapi-pagination.js +161 -0
  81. package/dist/python-fallback/extractors/fastapi-pagination.js.map +1 -0
  82. package/dist/python-fallback/extractors/fastapi-status.d.ts +12 -0
  83. package/dist/python-fallback/extractors/fastapi-status.js +104 -0
  84. package/dist/python-fallback/extractors/fastapi-status.js.map +1 -0
  85. package/dist/python-fallback/extractors/pydantic.d.ts +13 -0
  86. package/dist/python-fallback/extractors/pydantic.js +59 -0
  87. package/dist/python-fallback/extractors/pydantic.js.map +1 -0
  88. package/dist/python-fallback/extractors/routes.d.ts +6 -0
  89. package/dist/python-fallback/extractors/routes.js +34 -0
  90. package/dist/python-fallback/extractors/routes.js.map +1 -0
  91. package/dist/python-fallback/helpers/lines.d.ts +22 -0
  92. package/dist/python-fallback/helpers/lines.js +60 -0
  93. package/dist/python-fallback/helpers/lines.js.map +1 -0
  94. package/dist/python-fallback/helpers/types.d.ts +7 -0
  95. package/dist/python-fallback/helpers/types.js +135 -0
  96. package/dist/python-fallback/helpers/types.js.map +1 -0
  97. package/dist/python-fallback/index.d.ts +2 -0
  98. package/dist/python-fallback/index.js +270 -0
  99. package/dist/python-fallback/index.js.map +1 -0
  100. package/dist/python-fallback/signatures.d.ts +15 -0
  101. package/dist/python-fallback/signatures.js +76 -0
  102. package/dist/python-fallback/signatures.js.map +1 -0
  103. package/dist/python-fallback.d.ts +1 -2
  104. package/dist/python-fallback.js +1 -928
  105. package/dist/python-fallback.js.map +1 -1
  106. package/package.json +2 -2
@@ -0,0 +1,3 @@
1
+ import type { ConceptEdge } from '@kernlang/core';
2
+ import type { SourceFile } from 'ts-morph';
3
+ export declare function extractDependencyEdges(sf: SourceFile, filePath: string, edges: ConceptEdge[]): void;
@@ -0,0 +1,28 @@
1
+ import { conceptId } from '@kernlang/core';
2
+ import { span } from '../helpers/ast.js';
3
+ import { NODE_STDLIB } from '../signatures.js';
4
+ export function extractDependencyEdges(sf, filePath, edges) {
5
+ for (const imp of sf.getImportDeclarations()) {
6
+ const specifier = imp.getModuleSpecifierValue();
7
+ const start = imp.getStart();
8
+ let subtype = 'external';
9
+ if (specifier.startsWith('.') || specifier.startsWith('/')) {
10
+ subtype = 'internal';
11
+ }
12
+ else if (NODE_STDLIB.has(specifier.split('/')[0]) || specifier.startsWith('node:')) {
13
+ subtype = 'stdlib';
14
+ }
15
+ edges.push({
16
+ id: conceptId(filePath, 'dependency', start),
17
+ kind: 'dependency',
18
+ sourceId: filePath,
19
+ targetId: specifier,
20
+ primarySpan: span(filePath, imp),
21
+ evidence: imp.getText().substring(0, 120),
22
+ confidence: 1.0,
23
+ language: 'ts',
24
+ payload: { kind: 'dependency', subtype, specifier },
25
+ });
26
+ }
27
+ }
28
+ //# sourceMappingURL=dependency.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dependency.js","sourceRoot":"","sources":["../../../../src/mappers/ts-concepts/extractors/dependency.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,MAAM,UAAU,sBAAsB,CAAC,EAAc,EAAE,QAAgB,EAAE,KAAoB;IAC3F,KAAK,MAAM,GAAG,IAAI,EAAE,CAAC,qBAAqB,EAAE,EAAE,CAAC;QAC7C,MAAM,SAAS,GAAG,GAAG,CAAC,uBAAuB,EAAE,CAAC;QAChD,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,EAAE,CAAC;QAE7B,IAAI,OAAO,GAAuC,UAAU,CAAC;QAC7D,IAAI,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAC3D,OAAO,GAAG,UAAU,CAAC;QACvB,CAAC;aAAM,IAAI,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YACrF,OAAO,GAAG,QAAQ,CAAC;QACrB,CAAC;QAED,KAAK,CAAC,IAAI,CAAC;YACT,EAAE,EAAE,SAAS,CAAC,QAAQ,EAAE,YAAY,EAAE,KAAK,CAAC;YAC5C,IAAI,EAAE,YAAY;YAClB,QAAQ,EAAE,QAAQ;YAClB,QAAQ,EAAE,SAAS;YACnB,WAAW,EAAE,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC;YAChC,QAAQ,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC;YACzC,UAAU,EAAE,GAAG;YACf,QAAQ,EAAE,IAAI;YACd,OAAO,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE;SACpD,CAAC,CAAC;IACL,CAAC;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { ConceptNode } from '@kernlang/core';
2
+ import { type SourceFile } from 'ts-morph';
3
+ export declare function extractEffects(sf: SourceFile, filePath: string, nodes: ConceptNode[]): void;
@@ -0,0 +1,93 @@
1
+ import { conceptId } from '@kernlang/core';
2
+ import { SyntaxKind } from 'ts-morph';
3
+ import { getContainerId, isInAsyncContext, span } from '../helpers/ast.js';
4
+ import { buildConstLiteralMap } from '../helpers/const-resolution.js';
5
+ import { extractHandledErrorStatusCodes, extractHandlesApiErrors, isResponseAsserted } from '../helpers/error-paths.js';
6
+ import { extractAuthPropagation, extractBodyKind, extractHasAuthHeader, extractHost, extractHttpMethod, extractQueryParams, extractSentFields, extractTarget, } from '../helpers/network-call.js';
7
+ import { collectClientIdentifiers } from '../helpers/wrapped-client.js';
8
+ import { CLIENT_HTTP_METHODS, DB_CALLS, FS_CALLS, NETWORK_CALLS, NETWORK_METHODS } from '../signatures.js';
9
+ export function extractEffects(sf, filePath, nodes) {
10
+ const clientIdents = collectClientIdentifiers(sf);
11
+ const constLiterals = buildConstLiteralMap(sf);
12
+ for (const call of sf.getDescendantsOfKind(SyntaxKind.CallExpression)) {
13
+ const callee = call.getExpression();
14
+ let funcName = '';
15
+ let objName = '';
16
+ if (callee.getKind() === SyntaxKind.Identifier) {
17
+ funcName = callee.getText();
18
+ }
19
+ else if (callee.getKind() === SyntaxKind.PropertyAccessExpression) {
20
+ const pa = callee;
21
+ funcName = pa.getName();
22
+ objName = pa.getExpression().getText();
23
+ }
24
+ // Network effects
25
+ const isDirectNetwork = NETWORK_CALLS.has(funcName);
26
+ const isKnownLibraryMethod = NETWORK_METHODS.has(funcName) && /axios|got|ky|http|request|superagent/i.test(objName);
27
+ const isWrappedClientCall = CLIENT_HTTP_METHODS.has(funcName) && clientIdents.has(objName);
28
+ if (isDirectNetwork || isKnownLibraryMethod || isWrappedClientCall) {
29
+ const isAsync = isInAsyncContext(call);
30
+ const target = extractTarget(call, constLiterals);
31
+ const sentFieldsInfo = extractSentFields(call, funcName);
32
+ const queryParamsInfo = extractQueryParams(call, constLiterals);
33
+ const hasAuthHeader = extractHasAuthHeader(call, funcName);
34
+ nodes.push({
35
+ id: conceptId(filePath, 'effect', call.getStart()),
36
+ kind: 'effect',
37
+ primarySpan: span(filePath, call),
38
+ evidence: call.getText().substring(0, 120),
39
+ confidence: isDirectNetwork ? 1.0 : isWrappedClientCall ? 0.75 : 0.8,
40
+ language: 'ts',
41
+ containerId: getContainerId(call, filePath),
42
+ payload: {
43
+ kind: 'effect',
44
+ subtype: 'network',
45
+ async: isAsync,
46
+ target,
47
+ host: extractHost(target),
48
+ handledErrorStatusCodes: extractHandledErrorStatusCodes(call),
49
+ responseAsserted: isResponseAsserted(call, isWrappedClientCall),
50
+ bodyKind: extractBodyKind(call, funcName),
51
+ method: extractHttpMethod(call, funcName, isDirectNetwork, isKnownLibraryMethod, isWrappedClientCall),
52
+ hasAuthHeader,
53
+ sentFields: sentFieldsInfo.fields,
54
+ sentFieldsResolved: sentFieldsInfo.resolved,
55
+ sentFieldTypes: sentFieldsInfo.types,
56
+ handlesApiErrors: extractHandlesApiErrors(call, isWrappedClientCall),
57
+ authPropagation: extractAuthPropagation(call, funcName, objName, isWrappedClientCall, hasAuthHeader),
58
+ queryParams: queryParamsInfo.params,
59
+ queryParamsResolved: queryParamsInfo.resolved,
60
+ },
61
+ });
62
+ continue;
63
+ }
64
+ // DB effects
65
+ if (DB_CALLS.has(funcName) && /db|prisma|mongo|pool|client|knex|sequelize|typeorm|drizzle/i.test(objName)) {
66
+ nodes.push({
67
+ id: conceptId(filePath, 'effect', call.getStart()),
68
+ kind: 'effect',
69
+ primarySpan: span(filePath, call),
70
+ evidence: call.getText().substring(0, 120),
71
+ confidence: 0.85,
72
+ language: 'ts',
73
+ containerId: getContainerId(call, filePath),
74
+ payload: { kind: 'effect', subtype: 'db', async: isInAsyncContext(call) },
75
+ });
76
+ continue;
77
+ }
78
+ // FS effects
79
+ if (FS_CALLS.has(funcName)) {
80
+ nodes.push({
81
+ id: conceptId(filePath, 'effect', call.getStart()),
82
+ kind: 'effect',
83
+ primarySpan: span(filePath, call),
84
+ evidence: call.getText().substring(0, 120),
85
+ confidence: 0.95,
86
+ language: 'ts',
87
+ containerId: getContainerId(call, filePath),
88
+ payload: { kind: 'effect', subtype: 'fs', async: funcName.includes('Sync') ? false : isInAsyncContext(call) },
89
+ });
90
+ }
91
+ }
92
+ }
93
+ //# sourceMappingURL=effect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"effect.js","sourceRoot":"","sources":["../../../../src/mappers/ts-concepts/extractors/effect.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { ConceptNode } from '@kernlang/core';
2
+ import { type SourceFile } from 'ts-morph';
3
+ export declare function extractEntrypoints(sf: SourceFile, filePath: string, nodes: ConceptNode[]): void;
@@ -0,0 +1,117 @@
1
+ import { conceptId } from '@kernlang/core';
2
+ import { SyntaxKind } from 'ts-morph';
3
+ import { getContainerId, isSameConceptSourceFile, span } from '../../helpers/ast.js';
4
+ import { ROUTE_METHODS } from '../../signatures.js';
5
+ import { extractRouteMount } from './mount.js';
6
+ import { analyzeExpressRouteHandler, EMPTY_ROUTE_ANALYSIS, resolveExpressRouteHandler } from './route-handler.js';
7
+ import { extractHandlerBodyFields } from './validation.js';
8
+ export function extractEntrypoints(sf, filePath, nodes) {
9
+ // Express/Fastify route handlers: app.get('/path', handler)
10
+ for (const call of sf.getDescendantsOfKind(SyntaxKind.CallExpression)) {
11
+ const callee = call.getExpression();
12
+ if (callee.getKind() !== SyntaxKind.PropertyAccessExpression)
13
+ continue;
14
+ const pa = callee;
15
+ const methodName = pa.getName();
16
+ const objText = pa.getExpression().getText();
17
+ if (!/app|router|server/i.test(objText))
18
+ continue;
19
+ const args = call.getArguments();
20
+ if (args.length < 2)
21
+ continue;
22
+ if (methodName === 'use') {
23
+ const mount = extractRouteMount(call, filePath);
24
+ if (mount)
25
+ nodes.push(mount);
26
+ continue;
27
+ }
28
+ if (!ROUTE_METHODS.has(methodName))
29
+ continue;
30
+ // First arg is the route path
31
+ let routePath;
32
+ if (args[0].getKind() === SyntaxKind.StringLiteral) {
33
+ routePath = args[0].getLiteralValue();
34
+ }
35
+ // Inline, same-file named, or statically imported handler. The id we
36
+ // compute for same-file handlers must match the function_declaration
37
+ // concept emitted for the same function, so downstream rules can
38
+ // dereference `handlerConceptId`.
39
+ const resolvedHandler = resolveExpressRouteHandler(args, filePath);
40
+ const handlerFn = resolvedHandler?.fn;
41
+ const handlerConceptId = resolvedHandler && isSameConceptSourceFile(resolvedHandler.conceptFilePath, filePath)
42
+ ? conceptId(filePath, 'function_declaration', resolvedHandler.conceptStart)
43
+ : undefined;
44
+ const bodyFieldsInfo = handlerFn
45
+ ? extractHandlerBodyFields(handlerFn)
46
+ : {
47
+ fields: undefined,
48
+ resolved: false,
49
+ types: undefined,
50
+ };
51
+ const routeAnalysis = handlerFn
52
+ ? analyzeExpressRouteHandler(handlerFn, args, methodName.toUpperCase(), routePath)
53
+ : EMPTY_ROUTE_ANALYSIS;
54
+ nodes.push({
55
+ id: conceptId(filePath, 'entrypoint', call.getStart()),
56
+ kind: 'entrypoint',
57
+ primarySpan: span(filePath, call),
58
+ evidence: call.getText().substring(0, 120),
59
+ confidence: 0.95,
60
+ language: 'ts',
61
+ containerId: getContainerId(call, filePath),
62
+ payload: {
63
+ kind: 'entrypoint',
64
+ subtype: 'route',
65
+ name: routePath || methodName,
66
+ httpMethod: methodName.toUpperCase(),
67
+ handlerConceptId,
68
+ bodyFields: bodyFieldsInfo.fields,
69
+ bodyFieldsResolved: bodyFieldsInfo.resolved,
70
+ bodyFieldTypes: bodyFieldsInfo.types,
71
+ errorStatusCodes: routeAnalysis.errorStatusCodes,
72
+ successStatusCodes: routeAnalysis.successStatusCodes,
73
+ successStatusCodesResolved: routeAnalysis.successStatusCodesResolved,
74
+ paginationStrategy: routeAnalysis.paginationStrategy,
75
+ paginationStrategyResolved: routeAnalysis.paginationStrategyResolved,
76
+ hasUnboundedCollectionQuery: routeAnalysis.hasUnboundedCollectionQuery,
77
+ hasDbWrite: routeAnalysis.hasDbWrite,
78
+ hasIdempotencyProtection: routeAnalysis.hasIdempotencyProtection,
79
+ hasBodyValidation: routeAnalysis.hasBodyValidation,
80
+ validatedBodyFields: routeAnalysis.validatedBodyFields,
81
+ bodyValidationResolved: routeAnalysis.bodyValidationResolved,
82
+ validatedBodyFieldTypes: routeAnalysis.validatedBodyFieldTypes,
83
+ },
84
+ });
85
+ }
86
+ // export default function — only if it looks like a handler (has req/res params or returns JSX)
87
+ for (const exportDecl of sf.getExportedDeclarations()) {
88
+ const [name, decls] = exportDecl;
89
+ if (name !== 'default')
90
+ continue;
91
+ for (const decl of decls) {
92
+ if (decl.getKind() === SyntaxKind.FunctionDeclaration) {
93
+ const fn = decl;
94
+ const params = fn.getParameters();
95
+ const paramNames = params.map((p) => p.getName());
96
+ const isHandler = paramNames.some((n) => /req|request|ctx|context|event/i.test(n));
97
+ const isComponent = fn.getName()?.[0]?.toUpperCase() === fn.getName()?.[0];
98
+ if (isHandler || isComponent) {
99
+ nodes.push({
100
+ id: conceptId(filePath, 'entrypoint', decl.getStart()),
101
+ kind: 'entrypoint',
102
+ primarySpan: span(filePath, decl),
103
+ evidence: decl.getText().substring(0, 100),
104
+ confidence: isHandler ? 0.9 : 0.7,
105
+ language: 'ts',
106
+ payload: {
107
+ kind: 'entrypoint',
108
+ subtype: isHandler ? 'handler' : 'export',
109
+ name: fn.getName() || 'default',
110
+ },
111
+ });
112
+ }
113
+ }
114
+ }
115
+ }
116
+ }
117
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/mappers/ts-concepts/extractors/entrypoint-express/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { ConceptNode } from '@kernlang/core';
2
+ export declare function extractRouteMount(call: import('ts-morph').CallExpression, mountFile: string): ConceptNode | undefined;
@@ -0,0 +1,105 @@
1
+ import { conceptId } from '@kernlang/core';
2
+ import { SyntaxKind } from 'ts-morph';
3
+ import { getContainerId, span } from '../../helpers/ast.js';
4
+ // Express `app.use('/api/prefix', ...middlewares, subRouter)`: emit a
5
+ // route-mount concept so `collectRoutesAcrossGraph` can join the sub-router's
6
+ // bare paths (`router.get('/foo')`) with the mount prefix (`/api/prefix/foo`).
7
+ // Mirrors the FastAPI `app.include_router()` emission in review-python.
8
+ // Caller must have already filtered to `.use()` calls whose object matches
9
+ // `app|router|server`.
10
+ export function extractRouteMount(call, mountFile) {
11
+ const args = call.getArguments();
12
+ if (args.length < 2)
13
+ return undefined;
14
+ if (args[0].getKind() !== SyntaxKind.StringLiteral)
15
+ return undefined;
16
+ const prefix = args[0].getLiteralValue();
17
+ if (!prefix.startsWith('/'))
18
+ return undefined;
19
+ // The sub-router is the LAST arg; intermediate args are middlewares.
20
+ const last = args[args.length - 1];
21
+ if (last.getKind() !== SyntaxKind.Identifier)
22
+ return undefined;
23
+ const ident = last;
24
+ const routerName = ident.getText();
25
+ const sourceModule = resolveImportedFileSuffix(ident, mountFile);
26
+ return {
27
+ id: conceptId(mountFile, 'entrypoint', call.getStart()),
28
+ kind: 'entrypoint',
29
+ primarySpan: span(mountFile, call),
30
+ evidence: call.getText().substring(0, 120),
31
+ confidence: 0.9,
32
+ language: 'ts',
33
+ containerId: getContainerId(call, mountFile),
34
+ payload: {
35
+ kind: 'entrypoint',
36
+ subtype: 'route-mount',
37
+ name: prefix,
38
+ routerName,
39
+ sourceModule,
40
+ },
41
+ };
42
+ }
43
+ // Given an identifier used in a mount call, resolve it back to the file it
44
+ // was imported from, and return a trailing path suffix (relative to the mount
45
+ // file's directory, with extension) usable by `cross-stack-utils`'s
46
+ // `routeFile.endsWith('/' + sourceModule)` matcher.
47
+ function resolveImportedFileSuffix(ident, mountFile) {
48
+ const symbol = ident.getSymbol();
49
+ if (!symbol)
50
+ return undefined;
51
+ for (const decl of symbol.getDeclarations()) {
52
+ const kind = decl.getKind();
53
+ if (kind !== SyntaxKind.ImportClause && kind !== SyntaxKind.ImportSpecifier)
54
+ continue;
55
+ const importDecl = decl.getFirstAncestorByKind(SyntaxKind.ImportDeclaration);
56
+ if (!importDecl)
57
+ continue;
58
+ const resolved = importDecl.getModuleSpecifierSourceFile();
59
+ if (resolved) {
60
+ return pathSuffixBetween(mountFile, resolved.getFilePath());
61
+ }
62
+ const specifier = importDecl.getModuleSpecifierValue();
63
+ const guess = guessResolvedSuffix(specifier, mountFile);
64
+ if (guess)
65
+ return guess;
66
+ }
67
+ return undefined;
68
+ }
69
+ function pathSuffixBetween(mountFile, targetFile) {
70
+ const parts = targetFile.split('/');
71
+ const mountParts = mountFile.split('/');
72
+ let commonLen = 0;
73
+ while (commonLen < parts.length - 1 &&
74
+ commonLen < mountParts.length - 1 &&
75
+ parts[commonLen] === mountParts[commonLen]) {
76
+ commonLen++;
77
+ }
78
+ const tail = parts.slice(commonLen).join('/');
79
+ return tail || parts.slice(-2).join('/');
80
+ }
81
+ function guessResolvedSuffix(specifier, mountFile) {
82
+ if (!specifier.startsWith('.'))
83
+ return undefined;
84
+ const mountDir = mountFile.split('/').slice(0, -1).join('/');
85
+ const segments = [];
86
+ for (const seg of specifier.split('/')) {
87
+ if (seg === '' || seg === '.')
88
+ continue;
89
+ if (seg === '..') {
90
+ if (mountDir.length === 0)
91
+ continue;
92
+ segments.pop();
93
+ }
94
+ else {
95
+ segments.push(seg);
96
+ }
97
+ }
98
+ if (segments.length === 0)
99
+ return undefined;
100
+ const base = segments[segments.length - 1];
101
+ const swapped = base.replace(/\.(js|mjs|cjs)$/i, '.ts');
102
+ segments[segments.length - 1] = /\.(ts|tsx)$/i.test(swapped) ? swapped : `${swapped}.ts`;
103
+ return segments.join('/');
104
+ }
105
+ //# sourceMappingURL=mount.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mount.js","sourceRoot":"","sources":["../../../../../src/mappers/ts-concepts/extractors/entrypoint-express/mount.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { ExpressRouteHandlerFn } from './route-handler.js';
2
+ export declare function extractExpressPaginationStrategy(handlerFn: ExpressRouteHandlerFn): {
3
+ strategy: 'page' | 'offset' | 'cursor' | 'mixed' | 'none' | undefined;
4
+ resolved: boolean;
5
+ };
6
+ export declare function hasUnboundedExpressCollectionQuery(handlerFn: ExpressRouteHandlerFn, method: string, routePath: string | undefined): boolean;
7
+ export declare function handlerHasDbWrite(handlerFn: ExpressRouteHandlerFn): boolean;
@@ -0,0 +1,128 @@
1
+ import { Node, SyntaxKind } from 'ts-morph';
2
+ import { classifyPaginationAnchor } from '../../../../concept-rules/cross-stack-utils.js';
3
+ import { DB_COLLECTION_READ_CALLS, DB_WRITE_CALLS, PAGINATION_RE } from '../../signatures.js';
4
+ // ── Express pagination-strategy extraction ───────────────────────────────
5
+ // Walks for `req.query.X` / `req.query['X']` / destructuring `const {a, b} =
6
+ // req.query`, classifies each key against anchor sets, and returns the strategy.
7
+ // Size keys (`limit`, `take`, `pageSize`, `perPage`) are pagination *parameters*
8
+ // but not anchor families on their own — a server reading only `limit` is
9
+ // classified as `'none'` (it doesn't pin a strategy).
10
+ //
11
+ // Anchor sets are imported from `concept-rules/cross-stack-utils` so the
12
+ // server-side classification stays in lockstep with the client-side one used
13
+ // by `pagination-key-drift`.
14
+ function classifyAnchor(key) {
15
+ return classifyPaginationAnchor(key);
16
+ }
17
+ export function extractExpressPaginationStrategy(handlerFn) {
18
+ const families = new Set();
19
+ let sawDynamicAccess = false;
20
+ // Pattern 1: `req.query.X` / `req.query[<lit>]` / destructuring
21
+ for (const access of handlerFn.getDescendantsOfKind(SyntaxKind.PropertyAccessExpression)) {
22
+ if (access.getName() !== 'query')
23
+ continue;
24
+ const reqIdent = access.getExpression();
25
+ if (!/\b(req|request)\b/i.test(reqIdent.getText()))
26
+ continue;
27
+ const parent = access.getParent();
28
+ // Form 1: `req.query.X` — direct dotted read
29
+ if (parent && Node.isPropertyAccessExpression(parent) && parent.getExpression() === access) {
30
+ const family = classifyAnchor(parent.getName());
31
+ if (family)
32
+ families.add(family);
33
+ continue;
34
+ }
35
+ // Form 2: `req.query['X']` — element access with literal
36
+ if (parent && Node.isElementAccessExpression(parent) && parent.getExpression() === access) {
37
+ const arg = parent.getArgumentExpression();
38
+ if (arg && Node.isStringLiteral(arg)) {
39
+ const family = classifyAnchor(arg.getLiteralValue());
40
+ if (family)
41
+ families.add(family);
42
+ }
43
+ else {
44
+ sawDynamicAccess = true;
45
+ }
46
+ continue;
47
+ }
48
+ // Form 3: `const { page, limit } = req.query` — destructuring
49
+ if (parent && Node.isVariableDeclaration(parent) && parent.getInitializer() === access) {
50
+ const nameNode = parent.getNameNode();
51
+ if (Node.isObjectBindingPattern(nameNode)) {
52
+ for (const elem of nameNode.getElements()) {
53
+ if (elem.getDotDotDotToken()) {
54
+ sawDynamicAccess = true;
55
+ continue;
56
+ }
57
+ const keyNode = elem.getPropertyNameNode() ?? elem.getNameNode();
58
+ if (Node.isIdentifier(keyNode)) {
59
+ const family = classifyAnchor(keyNode.getText());
60
+ if (family)
61
+ families.add(family);
62
+ }
63
+ else if (Node.isStringLiteral(keyNode)) {
64
+ const family = classifyAnchor(keyNode.getLiteralValue());
65
+ if (family)
66
+ families.add(family);
67
+ }
68
+ }
69
+ continue;
70
+ }
71
+ sawDynamicAccess = true;
72
+ continue;
73
+ }
74
+ sawDynamicAccess = true;
75
+ }
76
+ if (sawDynamicAccess) {
77
+ return { strategy: undefined, resolved: false };
78
+ }
79
+ if (families.size === 0) {
80
+ return { strategy: 'none', resolved: true };
81
+ }
82
+ if (families.size > 1)
83
+ return { strategy: 'mixed', resolved: true };
84
+ const only = families.values().next().value;
85
+ return { strategy: only, resolved: true };
86
+ }
87
+ export function hasUnboundedExpressCollectionQuery(handlerFn, method, routePath) {
88
+ if (method !== 'GET')
89
+ return false;
90
+ if (routePath && /[:{]/.test(routePath))
91
+ return false;
92
+ const text = handlerFn.getText();
93
+ if (PAGINATION_RE.test(text) || /\b(req|request)\.query\b/.test(text))
94
+ return false;
95
+ if (!handlerHasDbCollectionRead(handlerFn))
96
+ return false;
97
+ if (!/\.json\s*\(|send\s*\(/.test(text))
98
+ return false;
99
+ const lastSegment = routePath?.split('/').filter(Boolean).pop();
100
+ return Boolean(lastSegment?.endsWith('s')) || /\bfindMany\b|\.find\s*\(|\.toArray\s*\(/.test(text);
101
+ }
102
+ function handlerHasDbCollectionRead(handlerFn) {
103
+ return handlerFn.getDescendantsOfKind(SyntaxKind.CallExpression).some((call) => {
104
+ const callee = call.getExpression();
105
+ if (callee.getKind() !== SyntaxKind.PropertyAccessExpression)
106
+ return false;
107
+ const pa = callee;
108
+ if (!DB_COLLECTION_READ_CALLS.has(pa.getName()))
109
+ return false;
110
+ return isDbLikeReceiver(pa.getExpression().getText());
111
+ });
112
+ }
113
+ export function handlerHasDbWrite(handlerFn) {
114
+ return handlerFn.getDescendantsOfKind(SyntaxKind.CallExpression).some((call) => {
115
+ const callee = call.getExpression();
116
+ if (callee.getKind() !== SyntaxKind.PropertyAccessExpression)
117
+ return false;
118
+ const pa = callee;
119
+ if (!DB_WRITE_CALLS.has(pa.getName()))
120
+ return false;
121
+ return isDbLikeReceiver(pa.getExpression().getText());
122
+ });
123
+ }
124
+ function isDbLikeReceiver(receiver) {
125
+ return (/\b(db|prisma|mongo|collection|repo|repository|model|client|knex|sequelize|typeorm|pool)\b/i.test(receiver) ||
126
+ /^[A-Z][A-Za-z0-9_]*(Model)?$/.test(receiver));
127
+ }
128
+ //# sourceMappingURL=pagination.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pagination.js","sourceRoot":"","sources":["../../../../../src/mappers/ts-concepts/extractors/entrypoint-express/pagination.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import type { FieldTypeMap } from '../../helpers/types.js';
2
+ export type ExpressRouteHandlerFn = import('ts-morph').ArrowFunction | import('ts-morph').FunctionExpression | import('ts-morph').FunctionDeclaration;
3
+ export interface ExpressRouteHandlerResolution {
4
+ fn: ExpressRouteHandlerFn;
5
+ conceptStart: number;
6
+ conceptFilePath: string;
7
+ }
8
+ export interface RouteHandlerAnalysis {
9
+ errorStatusCodes?: readonly number[];
10
+ successStatusCodes?: readonly number[];
11
+ successStatusCodesResolved?: boolean;
12
+ paginationStrategy?: 'page' | 'offset' | 'cursor' | 'mixed' | 'none';
13
+ paginationStrategyResolved?: boolean;
14
+ hasUnboundedCollectionQuery?: boolean;
15
+ hasDbWrite?: boolean;
16
+ hasIdempotencyProtection?: boolean;
17
+ hasBodyValidation?: boolean;
18
+ validatedBodyFields?: readonly string[];
19
+ bodyValidationResolved?: boolean;
20
+ validatedBodyFieldTypes?: FieldTypeMap;
21
+ }
22
+ export declare const EMPTY_ROUTE_ANALYSIS: RouteHandlerAnalysis;
23
+ export declare function analyzeExpressRouteHandler(handlerFn: ExpressRouteHandlerFn, routeArgs: readonly import('ts-morph').Node[], method: string, routePath: string | undefined): RouteHandlerAnalysis;
24
+ export declare function resolveExpressRouteHandler(routeArgs: readonly import('ts-morph').Node[], filePath: string): ExpressRouteHandlerResolution | undefined;
25
+ export declare function extractExpressErrorStatusCodes(handlerFn: ExpressRouteHandlerFn): readonly number[] | undefined;