@kernlang/review 3.4.4 → 3.4.5-canary.15.1.9efc3d4b
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/dist/concept-rules/body-shape-drift.js +43 -7
- package/dist/concept-rules/body-shape-drift.js.map +1 -1
- package/dist/external-tools.js +79 -1
- package/dist/external-tools.js.map +1 -1
- package/dist/mappers/ts-concepts.js +273 -8
- package/dist/mappers/ts-concepts.js.map +1 -1
- package/dist/python-fallback.js +155 -8
- package/dist/python-fallback.js.map +1 -1
- package/dist/taint-ast.js +125 -6
- package/dist/taint-ast.js.map +1 -1
- package/dist/taint-types.js +12 -6
- package/dist/taint-types.js.map +1 -1
- package/package.json +2 -2
|
@@ -74,12 +74,23 @@ export function bodyShapeDrift(ctx) {
|
|
|
74
74
|
continue;
|
|
75
75
|
if (route.node.payload.kind !== 'entrypoint')
|
|
76
76
|
continue;
|
|
77
|
-
|
|
77
|
+
// V1 fired only when the handler's `req.body.X` reads were resolved.
|
|
78
|
+
// We now also accept schema-validated routes (`Schema.parse(req.body)`
|
|
79
|
+
// with no per-field `req.body.X` access) — the schema's tags drive
|
|
80
|
+
// /type alone, while missing-fields stays gated on handler reads.
|
|
81
|
+
const handlerResolved = route.node.payload.bodyFieldsResolved === true;
|
|
82
|
+
const validationResolved = route.node.payload.bodyValidationResolved === true;
|
|
83
|
+
if (!handlerResolved && !validationResolved)
|
|
78
84
|
continue;
|
|
79
|
-
const
|
|
80
|
-
|
|
85
|
+
const handlerFields = handlerResolved ? (route.node.payload.bodyFields ?? []) : [];
|
|
86
|
+
const validatedFields = validationResolved ? (route.node.payload.validatedBodyFields ?? []) : [];
|
|
87
|
+
if (handlerFields.length === 0 && validatedFields.length === 0)
|
|
81
88
|
continue;
|
|
82
|
-
|
|
89
|
+
// Missing-fields detection — handler-read evidence only. A schema
|
|
90
|
+
// declaring a field doesn't mean the handler will fail without it
|
|
91
|
+
// (the schema might reject the request, but that's a different
|
|
92
|
+
// failure mode best surfaced by a separate rule).
|
|
93
|
+
const missing = handlerFields.filter((f) => !call.sentFields.includes(f));
|
|
83
94
|
// Type-mismatch step: when both ends are typed (neither side 'unknown'),
|
|
84
95
|
// a tag disagreement on a name that DOES overlap is a high-precision
|
|
85
96
|
// bug — `userId: string` (client) vs `userId: number` (server) silently
|
|
@@ -97,18 +108,43 @@ export function bodyShapeDrift(ctx) {
|
|
|
97
108
|
const callMethod = call.method?.toUpperCase();
|
|
98
109
|
const methodsAgree = !!routeMethod && !!callMethod && routeMethod === callMethod;
|
|
99
110
|
const serverTypes = route.node.payload.bodyFieldTypes;
|
|
111
|
+
const validatedTypes = route.node.payload.validatedBodyFieldTypes;
|
|
100
112
|
const clientTypes = call.sentFieldTypes;
|
|
101
113
|
const typeMismatches = [];
|
|
102
|
-
|
|
103
|
-
|
|
114
|
+
// Server-side type resolution prefers the handler-read tag from
|
|
115
|
+
// `bodyFieldTypes` (the actual TS type the handler sees). When that
|
|
116
|
+
// is `'unknown'` — typical when `req.body` is the Express-default
|
|
117
|
+
// `any` — fall back to a Zod-validated tag from
|
|
118
|
+
// `validatedBodyFieldTypes` if one exists. Catches the common shape:
|
|
119
|
+
// const Schema = z.object({ active: z.boolean() });
|
|
120
|
+
// app.post('/x', (req, res) => { const d = Schema.parse(req.body); ... });
|
|
121
|
+
// where the handler doesn't TS-type req.body but the schema knows
|
|
122
|
+
// the field types.
|
|
123
|
+
//
|
|
124
|
+
// Iterates the UNION of handler-read and schema-validated field
|
|
125
|
+
// names so schema-only handlers (no per-field `req.body.X` reads)
|
|
126
|
+
// still get type checks against the schema.
|
|
127
|
+
if (methodsAgree && clientTypes && (serverTypes || validatedTypes)) {
|
|
128
|
+
const compareFields = new Set([...handlerFields, ...validatedFields]);
|
|
129
|
+
for (const f of compareFields) {
|
|
104
130
|
if (!call.sentFields.includes(f))
|
|
105
131
|
continue;
|
|
106
|
-
const
|
|
132
|
+
const handlerTag = serverTypes?.[f];
|
|
133
|
+
const validatedTag = validatedTypes?.[f];
|
|
134
|
+
const serverTag = handlerTag && handlerTag !== 'unknown' ? handlerTag : validatedTag;
|
|
107
135
|
const clientTag = clientTypes[f];
|
|
108
136
|
if (!serverTag || !clientTag)
|
|
109
137
|
continue;
|
|
110
138
|
if (serverTag === 'unknown' || clientTag === 'unknown')
|
|
111
139
|
continue;
|
|
140
|
+
// Client sending `null` against a nullable server type is fine,
|
|
141
|
+
// but coarseners drop null branches (`Optional[str]` → 'string',
|
|
142
|
+
// `string | null` → 'string') for the non-null mismatch case.
|
|
143
|
+
// Skip /type when the client value IS null — we can't prove a
|
|
144
|
+
// mismatch from coarse tags alone. Codex caught this on the
|
|
145
|
+
// Pydantic mirror review.
|
|
146
|
+
if (clientTag === 'null')
|
|
147
|
+
continue;
|
|
112
148
|
if (serverTag !== clientTag)
|
|
113
149
|
typeMismatches.push({ field: f, client: clientTag, server: serverTag });
|
|
114
150
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"body-shape-drift.js","sourceRoot":"","sources":["../../src/concept-rules/body-shape-drift.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAIH,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EACL,WAAW,EACX,gCAAgC,EAChC,wBAAwB,EACxB,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAanD,MAAM,UAAU,cAAc,CAAC,GAAuB;IACpD,IAAI,CAAC,GAAG,CAAC,WAAW,IAAI,GAAG,CAAC,WAAW,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAE9D,MAAM,YAAY,GAAG,wBAAwB,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAC/D,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAEzC,MAAM,WAAW,GAAiB,EAAE,CAAC;IACrC,KAAK,MAAM,CAAC,EAAE,UAAU,CAAC,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;QAC7C,KAAK,MAAM,IAAI,IAAI,UAAU,CAAC,KAAK,EAAE,CAAC;YACpC,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,KAAK,SAAS;gBAAE,SAAS;YAC7G,IAAI,IAAI,CAAC,OAAO,CAAC,kBAAkB,KAAK,IAAI;gBAAE,SAAS;YACvD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC;YACvC,IAAI,CAAC,MAAM;gBAAE,SAAS;YACtB,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;YACnC,IAAI,OAAO,MAAM,KAAK,QAAQ;gBAAE,SAAS;YACzC,MAAM,UAAU,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;YAC9C,IAAI,CAAC,UAAU,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC;gBAAE,SAAS;YAC3D,WAAW,CAAC,IAAI,CAAC;gBACf,MAAM;gBACN,cAAc,EAAE,UAAU;gBAC1B,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM;gBAC3B,UAAU,EAAE,MAAM;gBAClB,cAAc,EAAE,IAAI,CAAC,OAAO,CAAC,cAAc;gBAC3C,IAAI;aACL,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAExC,MAAM,QAAQ,GAAoB,EAAE,CAAC;IACrC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAE/B,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/B,IAAI,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,KAAK,GAAG,CAAC,QAAQ;YAAE,SAAS;QAE1D,MAAM,KAAK,GAAG,iBAAiB,CAAC,IAAI,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC;QACnE,IAAI,CAAC,KAAK,EAAE,IAAI;YAAE,SAAS;QAC3B,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,YAAY;YAAE,SAAS;QACvD,
|
|
1
|
+
{"version":3,"file":"body-shape-drift.js","sourceRoot":"","sources":["../../src/concept-rules/body-shape-drift.ts"],"names":[],"mappings":"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"}
|
package/dist/external-tools.js
CHANGED
|
@@ -169,10 +169,27 @@ export function runTSCDiagnostics(project, options = {}, health) {
|
|
|
169
169
|
// ts2580 / ts2591 — "Cannot find name 'process'/'require'/'module'. Install @types/node?"
|
|
170
170
|
// (TS emits 2580 when the name resolves via global lib shims, 2591 when it doesn't —
|
|
171
171
|
// both point at the same user-side remedy, both are environmental from review's POV.)
|
|
172
|
+
// ts2304 / ts2552 with a Node-global name — same class as 2580/2591, but TS only emits
|
|
173
|
+
// the Install-@types/node hint for a small denylist of names. URL, URLSearchParams,
|
|
174
|
+
// __dirname, __filename, Buffer, NodeJS, AbortController, etc. fail through 2304/2552
|
|
175
|
+
// instead. kern-guard runs review on shallow-cloned repos with no node_modules — the
|
|
176
|
+
// same root cause as 2580/2591 but a much wider FP surface (kern-sight PR #7 hit it
|
|
177
|
+
// on plain `let url: URL`). Suppress when the missing name matches a known
|
|
178
|
+
// @types/node-provided global; non-matching 2304/2552 still surface as type errors.
|
|
172
179
|
const isLoadingNoise = code === 6059 || code === 6307;
|
|
173
180
|
const isEnvironmentalNoise = code === 2792 || code === 17004 || code === 2580 || code === 2591;
|
|
181
|
+
// TS2503 ("Cannot find namespace 'X'") is the same class for type-position
|
|
182
|
+
// uses like `let x: NodeJS.Timeout` — the @types/node `NodeJS` namespace
|
|
183
|
+
// isn't reachable. TS2584 ("Cannot find name 'console'. Do you need to
|
|
184
|
+
// change your target library?") fires for `console` specifically and
|
|
185
|
+
// belongs in the same noise class. Both are environmental, gated on
|
|
186
|
+
// the same review-mode flag. Gemini + Codex caught these.
|
|
187
|
+
const isNodeGlobalUnresolved = (code === 2304 || code === 2552 || code === 2503 || code === 2584) && isNodeGlobalCannotFindName(messageStr);
|
|
174
188
|
if (options.downgradeProjectLoadingErrors &&
|
|
175
|
-
(isLoadingNoise ||
|
|
189
|
+
(isLoadingNoise ||
|
|
190
|
+
isEnvironmentalNoise ||
|
|
191
|
+
isNodeGlobalUnresolved ||
|
|
192
|
+
isReviewModeModuleResolutionNoise(code, messageStr, filePath))) {
|
|
176
193
|
continue;
|
|
177
194
|
}
|
|
178
195
|
findings.push({
|
|
@@ -200,6 +217,67 @@ export function runTSCDiagnostics(project, options = {}, health) {
|
|
|
200
217
|
}
|
|
201
218
|
return findings;
|
|
202
219
|
}
|
|
220
|
+
// Names provided as globals by @types/node. When a TS2304/TS2552 references
|
|
221
|
+
// one of these, the missing-types diagnosis is the same as TS2580/TS2591
|
|
222
|
+
// for `process`/`require`/`module` — @types/node isn't reachable, which is
|
|
223
|
+
// expected when reviewing a shallow-cloned repo with no node_modules.
|
|
224
|
+
//
|
|
225
|
+
// The list deliberately stops at "names dev code commonly types directly".
|
|
226
|
+
// More exotic Node globals (Worker, MessageChannel, etc.) typically appear
|
|
227
|
+
// only in code that already imports them — leaving them out keeps real
|
|
228
|
+
// usage errors visible.
|
|
229
|
+
const NODE_GLOBAL_NAMES = new Set([
|
|
230
|
+
// URL / module-system globals
|
|
231
|
+
'URL',
|
|
232
|
+
'URLSearchParams',
|
|
233
|
+
'__dirname',
|
|
234
|
+
'__filename',
|
|
235
|
+
'Buffer',
|
|
236
|
+
'NodeJS',
|
|
237
|
+
// Modern Node globals — Node 18+ exposes `fetch`/Web-platform fetch types as globals
|
|
238
|
+
'fetch',
|
|
239
|
+
'Request',
|
|
240
|
+
'Response',
|
|
241
|
+
'Headers',
|
|
242
|
+
'FormData',
|
|
243
|
+
'Blob',
|
|
244
|
+
'File',
|
|
245
|
+
// Timers — return types depend on @types/node (`NodeJS.Timeout`)
|
|
246
|
+
'setTimeout',
|
|
247
|
+
'setInterval',
|
|
248
|
+
'clearTimeout',
|
|
249
|
+
'clearInterval',
|
|
250
|
+
'setImmediate',
|
|
251
|
+
'clearImmediate',
|
|
252
|
+
'queueMicrotask',
|
|
253
|
+
// Web crypto / encoding (global in Node 18+)
|
|
254
|
+
'crypto',
|
|
255
|
+
'TextEncoder',
|
|
256
|
+
'TextDecoder',
|
|
257
|
+
'atob',
|
|
258
|
+
'btoa',
|
|
259
|
+
// Abort & events
|
|
260
|
+
'AbortController',
|
|
261
|
+
'AbortSignal',
|
|
262
|
+
'Event',
|
|
263
|
+
'EventTarget',
|
|
264
|
+
// Misc
|
|
265
|
+
'performance',
|
|
266
|
+
'structuredClone',
|
|
267
|
+
'global',
|
|
268
|
+
'console',
|
|
269
|
+
'navigator',
|
|
270
|
+
]);
|
|
271
|
+
// True when a TS2304/TS2552/TS2503 message references one of the
|
|
272
|
+
// @types/node-provided globals above. Handles both:
|
|
273
|
+
// - "Cannot find name 'X'." (TS2304 / TS2552 — value position)
|
|
274
|
+
// - "Cannot find namespace 'X'." (TS2503 — type position, e.g. `NodeJS.Timeout`)
|
|
275
|
+
function isNodeGlobalCannotFindName(message) {
|
|
276
|
+
const m = message.match(/^Cannot find (?:name|namespace) '([^']+)'\.?/);
|
|
277
|
+
if (!m)
|
|
278
|
+
return false;
|
|
279
|
+
return NODE_GLOBAL_NAMES.has(m[1]);
|
|
280
|
+
}
|
|
203
281
|
function isReviewModeModuleResolutionNoise(code, message, importerFilePath) {
|
|
204
282
|
if (code !== 2307)
|
|
205
283
|
return false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"external-tools.js","sourceRoot":"","sources":["../src/external-tools.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"external-tools.js","sourceRoot":"","sources":["../src/external-tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -438,6 +438,7 @@ function extractEntrypoints(sf, filePath, nodes) {
|
|
|
438
438
|
hasBodyValidation: routeAnalysis.hasBodyValidation,
|
|
439
439
|
validatedBodyFields: routeAnalysis.validatedBodyFields,
|
|
440
440
|
bodyValidationResolved: routeAnalysis.bodyValidationResolved,
|
|
441
|
+
validatedBodyFieldTypes: routeAnalysis.validatedBodyFieldTypes,
|
|
441
442
|
},
|
|
442
443
|
});
|
|
443
444
|
}
|
|
@@ -488,6 +489,7 @@ function analyzeExpressRouteHandler(handlerFn, routeArgs, method, routePath) {
|
|
|
488
489
|
hasBodyValidation: validation.has,
|
|
489
490
|
validatedBodyFields: validation.fields,
|
|
490
491
|
bodyValidationResolved: validation.resolved,
|
|
492
|
+
validatedBodyFieldTypes: validation.types,
|
|
491
493
|
};
|
|
492
494
|
}
|
|
493
495
|
function resolveExpressRouteHandler(routeArgs, filePath) {
|
|
@@ -629,6 +631,7 @@ function isDbLikeReceiver(receiver) {
|
|
|
629
631
|
}
|
|
630
632
|
function extractExpressValidation(handlerFn, routeArgs) {
|
|
631
633
|
const fields = new Set();
|
|
634
|
+
const types = {};
|
|
632
635
|
let hasValidation = false;
|
|
633
636
|
let resolved = false;
|
|
634
637
|
for (const arg of routeArgs) {
|
|
@@ -655,11 +658,26 @@ function extractExpressValidation(handlerFn, routeArgs) {
|
|
|
655
658
|
const arg = call.getArguments()[0];
|
|
656
659
|
if (!arg || arg.getKind() !== SyntaxKind.ObjectLiteralExpression)
|
|
657
660
|
continue;
|
|
658
|
-
const
|
|
661
|
+
const callee = call.getExpression().getText();
|
|
662
|
+
const isZod = callee === 'z.object';
|
|
663
|
+
// Only Zod produces reliable wire-shape tags via the chain coarsener.
|
|
664
|
+
// Joi/Yup/Valibot chains coarsen through the generic literal-fields path
|
|
665
|
+
// which (correctly) returns 'unknown' for the schema-builder calls. We
|
|
666
|
+
// gather field NAMES from both, but only TYPES from Zod — recording
|
|
667
|
+
// 'unknown' tags would lock the field set into a less-useful map.
|
|
668
|
+
const extracted = isZod
|
|
669
|
+
? extractZodSchemaFields(arg)
|
|
670
|
+
: extractLiteralObjectFields(arg);
|
|
659
671
|
if (!extracted.resolved || !extracted.fields)
|
|
660
672
|
continue;
|
|
661
673
|
for (const field of extracted.fields)
|
|
662
674
|
fields.add(field);
|
|
675
|
+
if (isZod && extracted.types) {
|
|
676
|
+
for (const [name, tag] of Object.entries(extracted.types)) {
|
|
677
|
+
if (tag !== 'unknown')
|
|
678
|
+
types[name] = tag;
|
|
679
|
+
}
|
|
680
|
+
}
|
|
663
681
|
hasValidation = true;
|
|
664
682
|
resolved = true;
|
|
665
683
|
}
|
|
@@ -667,6 +685,7 @@ function extractExpressValidation(handlerFn, routeArgs) {
|
|
|
667
685
|
has: hasValidation,
|
|
668
686
|
fields: fields.size > 0 ? Array.from(fields).sort() : undefined,
|
|
669
687
|
resolved,
|
|
688
|
+
types: Object.keys(types).length > 0 ? Object.freeze(types) : undefined,
|
|
670
689
|
};
|
|
671
690
|
}
|
|
672
691
|
function extractExpressValidatorFields(node) {
|
|
@@ -689,15 +708,69 @@ function isSchemaObjectCall(call) {
|
|
|
689
708
|
const callee = call.getExpression().getText();
|
|
690
709
|
return callee === 'z.object' || callee === 'Joi.object' || callee.endsWith('.object');
|
|
691
710
|
}
|
|
711
|
+
// Object-level Zod modifiers that don't change which fields are validated
|
|
712
|
+
// for the purposes of /type comparison. `.partial()` / `.required()` only
|
|
713
|
+
// flip optionality — same fields, same types. `.strict()` / `.passthrough()`
|
|
714
|
+
// / `.strip()` change extra-field handling but preserve the recorded set.
|
|
715
|
+
// Modifiers that DO change the field set (`omit`, `pick`, `extend`, `merge`)
|
|
716
|
+
// are deliberately absent — encountering them in the chain bails extraction
|
|
717
|
+
// to avoid recording stale or missing field tags.
|
|
718
|
+
const SCHEMA_PRESERVING_OBJECT_MODIFIERS = new Set([
|
|
719
|
+
'partial',
|
|
720
|
+
'required',
|
|
721
|
+
'passthrough',
|
|
722
|
+
'strict',
|
|
723
|
+
'strip',
|
|
724
|
+
'refine',
|
|
725
|
+
'superRefine',
|
|
726
|
+
'transform',
|
|
727
|
+
'describe',
|
|
728
|
+
'brand',
|
|
729
|
+
'readonly',
|
|
730
|
+
'optional',
|
|
731
|
+
'nullable',
|
|
732
|
+
'nullish',
|
|
733
|
+
'default',
|
|
734
|
+
'catch',
|
|
735
|
+
]);
|
|
736
|
+
// Decide whether THIS specific `z.object({...})` call is the schema being
|
|
737
|
+
// `.parse(req.body)`'d, by walking strictly along its method chain rather
|
|
738
|
+
// than text-searching ancestor blocks. Codex caught the old text-based
|
|
739
|
+
// version: any unrelated `z.object(...)` whose enclosing block also
|
|
740
|
+
// contained a separate `.parse(req.body)` (e.g. response validators) was
|
|
741
|
+
// mis-tagged as the request schema, producing false /type findings.
|
|
742
|
+
//
|
|
743
|
+
// True ONLY when:
|
|
744
|
+
// 1. Each chained method between this z.object and the terminating call
|
|
745
|
+
// is a known shape-preserving modifier (so the recorded field tags
|
|
746
|
+
// still describe what the schema validates), AND
|
|
747
|
+
// 2. The terminating call is `.parse|.safeParse|.validate(req.body)`.
|
|
692
748
|
function schemaCallValidatesRequestBody(call) {
|
|
693
|
-
let
|
|
694
|
-
for (let depth = 0; depth <
|
|
695
|
-
|
|
696
|
-
if (!
|
|
749
|
+
let cur = call;
|
|
750
|
+
for (let depth = 0; depth < 8; depth++) {
|
|
751
|
+
const parent = cur.getParent();
|
|
752
|
+
if (!parent)
|
|
697
753
|
return false;
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
754
|
+
if (parent.getKind() !== SyntaxKind.PropertyAccessExpression)
|
|
755
|
+
return false;
|
|
756
|
+
const grand = parent.getParent();
|
|
757
|
+
if (!grand || grand.getKind() !== SyntaxKind.CallExpression)
|
|
758
|
+
return false;
|
|
759
|
+
const pa = parent;
|
|
760
|
+
const callExpr = grand;
|
|
761
|
+
// pa must be the CALLEE (cur.method(...)), not an argument (foo(cur.method)).
|
|
762
|
+
if (callExpr.getExpression() !== pa)
|
|
763
|
+
return false;
|
|
764
|
+
const methodName = pa.getName();
|
|
765
|
+
if (methodName === 'parse' || methodName === 'safeParse' || methodName === 'validate') {
|
|
766
|
+
const arg = callExpr.getArguments()[0];
|
|
767
|
+
if (!arg)
|
|
768
|
+
return false;
|
|
769
|
+
return /^(req|request)\.body\b/.test(arg.getText());
|
|
770
|
+
}
|
|
771
|
+
if (!SCHEMA_PRESERVING_OBJECT_MODIFIERS.has(methodName))
|
|
772
|
+
return false;
|
|
773
|
+
cur = grand;
|
|
701
774
|
}
|
|
702
775
|
return false;
|
|
703
776
|
}
|
|
@@ -1797,6 +1870,198 @@ function coarsenValueExpression(expr) {
|
|
|
1797
1870
|
// `BinaryExpression`, etc.
|
|
1798
1871
|
return coarsenTsType(expr.getType());
|
|
1799
1872
|
}
|
|
1873
|
+
// Zod call-chain modifiers — methods that wrap a base type without changing
|
|
1874
|
+
// its coarse on-the-wire shape. We peel these off until we hit the base
|
|
1875
|
+
// constructor (`z.string`, `z.number`, …).
|
|
1876
|
+
const ZOD_MODIFIERS = new Set([
|
|
1877
|
+
'optional',
|
|
1878
|
+
'nullable',
|
|
1879
|
+
'nullish',
|
|
1880
|
+
'min',
|
|
1881
|
+
'max',
|
|
1882
|
+
'length',
|
|
1883
|
+
'default',
|
|
1884
|
+
'nonempty',
|
|
1885
|
+
'refine',
|
|
1886
|
+
'transform',
|
|
1887
|
+
'describe',
|
|
1888
|
+
'brand',
|
|
1889
|
+
'pipe',
|
|
1890
|
+
'catch',
|
|
1891
|
+
'readonly',
|
|
1892
|
+
'positive',
|
|
1893
|
+
'negative',
|
|
1894
|
+
'nonnegative',
|
|
1895
|
+
'nonpositive',
|
|
1896
|
+
'multipleOf',
|
|
1897
|
+
'finite',
|
|
1898
|
+
'safe',
|
|
1899
|
+
'trim',
|
|
1900
|
+
'lowercase',
|
|
1901
|
+
'uppercase',
|
|
1902
|
+
'startsWith',
|
|
1903
|
+
'endsWith',
|
|
1904
|
+
'regex',
|
|
1905
|
+
'email',
|
|
1906
|
+
'url',
|
|
1907
|
+
'uuid',
|
|
1908
|
+
'cuid',
|
|
1909
|
+
'cuid2',
|
|
1910
|
+
'datetime',
|
|
1911
|
+
'ip',
|
|
1912
|
+
'emoji',
|
|
1913
|
+
// `.or(...)` / `.and(...)` are intentionally absent: they widen the
|
|
1914
|
+
// accepted shape (`z.string().or(z.number())` accepts both), so peeling
|
|
1915
|
+
// them like a passthrough modifier creates a false-positive on the
|
|
1916
|
+
// OTHER branch. They fall through to the default → 'unknown' below.
|
|
1917
|
+
// Codex flagged this as a real precision miss.
|
|
1918
|
+
]);
|
|
1919
|
+
// True when the given expression is `z.coerce` (or any `*.coerce`) — used
|
|
1920
|
+
// to reject `z.coerce.<primitive>()` calls in the Zod coarsener.
|
|
1921
|
+
function isZodCoerceReceiver(expr) {
|
|
1922
|
+
if (expr.getKind() !== SyntaxKind.PropertyAccessExpression)
|
|
1923
|
+
return false;
|
|
1924
|
+
return expr.getName() === 'coerce';
|
|
1925
|
+
}
|
|
1926
|
+
// Coarsen a Zod schema call expression (`z.string().optional()`) to the same
|
|
1927
|
+
// FieldTypeTag union used elsewhere. Walks chained modifier calls inward to
|
|
1928
|
+
// the base type-producing method, tags it, and returns. Unknown chains
|
|
1929
|
+
// collapse to `'unknown'` rather than guessing.
|
|
1930
|
+
function coarsenZodCall(expr) {
|
|
1931
|
+
let cur = expr;
|
|
1932
|
+
// Bound the walk so a runaway chain can't loop. 16 is generous — even
|
|
1933
|
+
// pathological Zod chains (`.min().max().refine().transform()...`) stay well
|
|
1934
|
+
// below this in practice.
|
|
1935
|
+
for (let depth = 0; depth < 16; depth++) {
|
|
1936
|
+
if (cur.getKind() !== SyntaxKind.CallExpression)
|
|
1937
|
+
return 'unknown';
|
|
1938
|
+
const call = cur;
|
|
1939
|
+
const callee = call.getExpression();
|
|
1940
|
+
if (callee.getKind() !== SyntaxKind.PropertyAccessExpression) {
|
|
1941
|
+
// Bare call like `MySchema()` or `customSchema()` — we can't classify it.
|
|
1942
|
+
return 'unknown';
|
|
1943
|
+
}
|
|
1944
|
+
const pa = callee;
|
|
1945
|
+
const methodName = pa.getName();
|
|
1946
|
+
if (ZOD_MODIFIERS.has(methodName)) {
|
|
1947
|
+
cur = pa.getExpression();
|
|
1948
|
+
continue;
|
|
1949
|
+
}
|
|
1950
|
+
// Reject `z.coerce.X()` regardless of which X: coerce explicitly
|
|
1951
|
+
// accepts cross-primitive inputs (string ↔ number ↔ boolean ↔ bigint
|
|
1952
|
+
// ↔ date) and converts them. The wire shape is therefore unknowable —
|
|
1953
|
+
// tagging `z.coerce.number()` as 'number' fired FPs on clients
|
|
1954
|
+
// legitimately sending strings ("42" → 42). Codex caught this.
|
|
1955
|
+
if (isZodCoerceReceiver(pa.getExpression()))
|
|
1956
|
+
return 'unknown';
|
|
1957
|
+
switch (methodName) {
|
|
1958
|
+
case 'string':
|
|
1959
|
+
case 'enum':
|
|
1960
|
+
case 'nativeEnum':
|
|
1961
|
+
return 'string';
|
|
1962
|
+
case 'date':
|
|
1963
|
+
// Zod's `z.date()` only accepts JS Date objects, NOT JSON strings.
|
|
1964
|
+
// On the wire, dates serialise as strings — so a client sending
|
|
1965
|
+
// `{date: '2024-01-01'}` against `z.date()` would fail at runtime
|
|
1966
|
+
// even though both ends "agree on string". Tagging 'unknown' keeps
|
|
1967
|
+
// /type silent here; users typically reach for `z.coerce.date()`
|
|
1968
|
+
// (which the modifier path handles by drilling into z.coerce.date).
|
|
1969
|
+
return 'unknown';
|
|
1970
|
+
case 'number':
|
|
1971
|
+
case 'bigint':
|
|
1972
|
+
case 'int':
|
|
1973
|
+
return 'number';
|
|
1974
|
+
case 'boolean':
|
|
1975
|
+
return 'boolean';
|
|
1976
|
+
case 'null':
|
|
1977
|
+
return 'null';
|
|
1978
|
+
case 'array':
|
|
1979
|
+
case 'set':
|
|
1980
|
+
case 'tuple':
|
|
1981
|
+
return 'array';
|
|
1982
|
+
case 'object':
|
|
1983
|
+
case 'record':
|
|
1984
|
+
case 'map':
|
|
1985
|
+
case 'discriminatedUnion':
|
|
1986
|
+
return 'object';
|
|
1987
|
+
case 'literal': {
|
|
1988
|
+
// `z.literal('admin')` — coarsen the literal arg to its primitive tag.
|
|
1989
|
+
const arg = call.getArguments()[0];
|
|
1990
|
+
if (!arg)
|
|
1991
|
+
return 'unknown';
|
|
1992
|
+
return coarsenValueExpression(arg);
|
|
1993
|
+
}
|
|
1994
|
+
case 'union': {
|
|
1995
|
+
// `z.union([z.string(), z.number()])` — only stable if every branch
|
|
1996
|
+
// coarsens to the same non-null tag, else 'unknown'. Mirrors
|
|
1997
|
+
// `coarsenTsType`'s union handling: drop `z.null()` branches
|
|
1998
|
+
// first, then check tag agreement on what remains. This keeps
|
|
1999
|
+
// `z.union([z.string(), z.null()])` reading as 'string' so a
|
|
2000
|
+
// client sending `number` against it still flags. Gemini-flagged
|
|
2001
|
+
// precision miss in v1.
|
|
2002
|
+
//
|
|
2003
|
+
// ANY 'unknown' branch poisons the result — we'd be guessing
|
|
2004
|
+
// optimistically otherwise. Drop only literal nulls.
|
|
2005
|
+
const arg = call.getArguments()[0];
|
|
2006
|
+
if (!arg || arg.getKind() !== SyntaxKind.ArrayLiteralExpression)
|
|
2007
|
+
return 'unknown';
|
|
2008
|
+
const elements = arg.getElements();
|
|
2009
|
+
if (elements.length === 0)
|
|
2010
|
+
return 'unknown';
|
|
2011
|
+
const allTags = elements.map(coarsenZodCall);
|
|
2012
|
+
if (allTags.includes('unknown'))
|
|
2013
|
+
return 'unknown';
|
|
2014
|
+
const branches = allTags.filter((t) => t !== 'null');
|
|
2015
|
+
if (branches.length === 0)
|
|
2016
|
+
return 'null';
|
|
2017
|
+
const tags = new Set(branches);
|
|
2018
|
+
if (tags.size === 1)
|
|
2019
|
+
return [...tags][0];
|
|
2020
|
+
return 'unknown';
|
|
2021
|
+
}
|
|
2022
|
+
default:
|
|
2023
|
+
return 'unknown';
|
|
2024
|
+
}
|
|
2025
|
+
}
|
|
2026
|
+
return 'unknown';
|
|
2027
|
+
}
|
|
2028
|
+
// Walk a Zod schema literal (the object passed to `z.object({...})`) and
|
|
2029
|
+
// produce {fieldName -> FieldTypeTag}. Mirrors `extractLiteralObjectFields`
|
|
2030
|
+
// but uses `coarsenZodCall` for value classification — the values here are
|
|
2031
|
+
// Zod chains (`z.string().optional()`), not plain TS literals.
|
|
2032
|
+
function extractZodSchemaFields(obj) {
|
|
2033
|
+
const fields = [];
|
|
2034
|
+
const types = {};
|
|
2035
|
+
for (const prop of obj.getProperties()) {
|
|
2036
|
+
const kind = prop.getKind();
|
|
2037
|
+
if (kind === SyntaxKind.SpreadAssignment) {
|
|
2038
|
+
return { fields: undefined, resolved: false, types: undefined };
|
|
2039
|
+
}
|
|
2040
|
+
if (kind !== SyntaxKind.PropertyAssignment) {
|
|
2041
|
+
// Shorthand / method assignments aren't valid Zod shape entries; bail
|
|
2042
|
+
// rather than emit half-resolved types.
|
|
2043
|
+
return { fields: undefined, resolved: false, types: undefined };
|
|
2044
|
+
}
|
|
2045
|
+
const pa = prop;
|
|
2046
|
+
const nameNode = pa.getNameNode();
|
|
2047
|
+
const nameKind = nameNode.getKind();
|
|
2048
|
+
if (nameKind === SyntaxKind.ComputedPropertyName) {
|
|
2049
|
+
return { fields: undefined, resolved: false, types: undefined };
|
|
2050
|
+
}
|
|
2051
|
+
if (nameKind !== SyntaxKind.Identifier && nameKind !== SyntaxKind.StringLiteral) {
|
|
2052
|
+
return { fields: undefined, resolved: false, types: undefined };
|
|
2053
|
+
}
|
|
2054
|
+
const fieldName = nameNode.getText().replace(/['"]/g, '');
|
|
2055
|
+
fields.push(fieldName);
|
|
2056
|
+
const init = pa.getInitializer();
|
|
2057
|
+
types[fieldName] = init ? coarsenZodCall(init) : 'unknown';
|
|
2058
|
+
}
|
|
2059
|
+
return {
|
|
2060
|
+
fields,
|
|
2061
|
+
resolved: true,
|
|
2062
|
+
types,
|
|
2063
|
+
};
|
|
2064
|
+
}
|
|
1800
2065
|
function declKey(decl) {
|
|
1801
2066
|
return `${decl.getSourceFile().getFilePath()}:${decl.getStart()}`;
|
|
1802
2067
|
}
|