@@ -101,28 +101,15 @@ function handleReference(
101101 return rewriteCapturedSafeParse ( safeParseCall , localName , typeName , sourceFile , diagnostics ) ;
102102 }
103103
104- diagnostics . push (
105- actionRequired (
106- sourceFile . getFilePath ( ) ,
107- ref ,
108- `${ localName } .safeParse() not available in v2. Use \`isSpecType.${ typeName } (value)\` for boolean validation, ` +
109- `or \`specTypeSchemas.${ typeName } ['~standard'].validate(value)\` for full result.`
110- )
111- ) ;
112- return false ;
104+ return rewriteUnsupportedSchemaCall ( ref , safeParseCall , localName , typeName , 'safeParse' , sourceFile , diagnostics ) ;
113105 }
114106
115- // Pattern: XSchema.parse(v) — diagnostic only
107+ // Pattern: XSchema.parse(v) — rewrite to the StandardSchema validate() primitive (or, when the
108+ // result is used, swap the identifier) so we never leave behind an import of a non-exported schema.
116109 if ( isParsePattern ( ref ) ) {
117- diagnostics . push (
118- actionRequired (
119- sourceFile . getFilePath ( ) ,
120- ref ,
121- `${ localName } .parse() not available in v2. Use \`isSpecType.${ typeName } (value)\` for validation, ` +
122- `or \`specTypeSchemas.${ typeName } ['~standard'].validate(value)\` and check for issues.`
123- )
124- ) ;
125- return false ;
110+ const parseAccess = ref . getParent ( ) as import ( 'ts-morph' ) . PropertyAccessExpression ;
111+ const parseCall = parseAccess . getParent ( ) as import ( 'ts-morph' ) . CallExpression ;
112+ return rewriteUnsupportedSchemaCall ( ref , parseCall , localName , typeName , 'parse' , sourceFile , diagnostics ) ;
126113 }
127114
128115 // Pattern: XSchema used as value (function arg, assignment, etc.)
@@ -327,6 +314,68 @@ function rewriteCapturedSafeParse(
327314 return true ;
328315}
329316
317+ /**
318+ * Handles spec-schema usages that have no behavior-preserving v2 equivalent: the Zod-only
319+ * methods `.parse()` and (uncaptured) `.safeParse()`. In v2 these schemas are StandardSchemaV1
320+ * values that are NOT named public exports, so leaving the original import in place produces an
321+ * unresolved-import error (e.g. `PromptSchema` is not exported by `@modelcontextprotocol/server`).
322+ *
323+ * - Result discarded (validation for side-effect only): rewrite `XSchema.parse(v)` →
324+ * `specTypeSchemas.T['~standard'].validate(v)` so the code compiles. NOTE: `validate()` does not
325+ * throw, so `.parse()`'s throw-on-invalid behavior is lost — flagged via an actionRequired comment.
326+ * - Result used: swap only the identifier to `specTypeSchemas.T` so the import resolves; the
327+ * `.parse()`/`.safeParse()` call and its result shape still need a manual fix (flagged).
328+ *
329+ * Either way the original (now non-exported) schema import is dropped by the caller's
330+ * removeUnusedImport, so no dangling import survives.
331+ */
332+ function rewriteUnsupportedSchemaCall (
333+ ref : import ( 'ts-morph' ) . Node ,
334+ callNode : import ( 'ts-morph' ) . CallExpression ,
335+ localName : string ,
336+ typeName : string ,
337+ method : 'parse' | 'safeParse' ,
338+ sourceFile : SourceFile ,
339+ diagnostics : Diagnostic [ ]
340+ ) : boolean {
341+ const resultDiscarded = Node . isExpressionStatement ( callNode . getParent ( ) ) ;
342+
343+ if ( resultDiscarded ) {
344+ const argText = callNode
345+ . getArguments ( )
346+ . map ( a => a . getText ( ) )
347+ . join ( ', ' ) ;
348+ const semantics =
349+ method === 'parse'
350+ ? 'validate() does NOT throw on invalid input (parse() did) — if you relied on that, add `if (result.issues) throw …`.'
351+ : 'the result shape changed from { success, data, error } to { value, issues }.' ;
352+ diagnostics . push (
353+ actionRequired (
354+ sourceFile . getFilePath ( ) ,
355+ callNode ,
356+ `Rewrote ${ localName } .${ method } () to specTypeSchemas.${ typeName } ['~standard'].validate(): ` +
357+ `v2 spec schemas are StandardSchemaV1, not Zod. Note: ${ semantics } `
358+ )
359+ ) ;
360+ callNode . replaceWithText ( `specTypeSchemas.${ typeName } ['~standard'].validate(${ argText } )` ) ;
361+ ensureImport ( sourceFile , 'specTypeSchemas' ) ;
362+ return true ;
363+ }
364+
365+ diagnostics . push (
366+ actionRequired (
367+ sourceFile . getFilePath ( ) ,
368+ ref ,
369+ `${ localName } .${ method } () is not available on v2 spec schemas (StandardSchemaV1, not Zod). ` +
370+ `Replaced ${ localName } with specTypeSchemas.${ typeName } ; rewrite the .${ method } (...) call using ` +
371+ `specTypeSchemas.${ typeName } ['~standard'].validate(...) (returns { value, issues }, does not throw).`
372+ )
373+ ) ;
374+ ref . replaceWithText ( `specTypeSchemas.${ typeName } ` ) ;
375+ ensureImport ( sourceFile , 'specTypeSchemas' ) ;
376+ return true ;
377+ }
378+
330379function ensureImport ( sourceFile : SourceFile , symbol : string ) : void {
331380 const existingImport = sourceFile . getImportDeclarations ( ) . find ( imp => {
332381 if ( ! isAnyMcpSpecifier ( imp . getModuleSpecifierValue ( ) ) ) return false ;
0 commit comments