Read only
    function transform(file, api, options) {
      const j = api.jscodeshift;
      const root = j(file.source);
    
      // Helper: replaces deprecated error params with new unified "error"
      function replaceErrorParams(args) {
        return args.map(arg => {
          if (!j.ObjectExpression.check(arg)) return arg;
          
          const newProps = [];
          let requiredError, invalidTypeError, messageProp, errorMap;
    
          arg.properties.forEach(prop => {
            if (j.ObjectProperty.check(prop) && j.Identifier.check(prop.key)) {
              
              const keyName = prop.key.name;
              if (keyName === 'required_error') requiredError = prop.value;
              else if (keyName === 'invalid_type_error') invalidTypeError = prop.value;
              else if (keyName === 'message') messageProp = prop.value;
              else if (keyName === 'errorMap') errorMap = prop.value;
              else newProps.push(prop);
            } else {
              newProps.push(prop);
            }
          });
    
          if (requiredError || invalidTypeError) {
            const errorFn = j.arrowFunctionExpression(
              [j.identifier('issue')],
              j.blockStatement([
                j.ifStatement(
                  j.binaryExpression(
                    '===',
                    j.memberExpression(j.identifier('issue'), j.identifier('input')),
                    j.identifier('undefined')
                  ),
                  j.blockStatement([j.returnStatement(requiredError || j.literal(""))]),
                  invalidTypeError ? j.blockStatement([j.returnStatement(invalidTypeError)]) : null
                )
              ].filter(Boolean))
            );
            newProps.push(j.property('init', j.identifier('error'), errorFn));
          } else if (messageProp) {
            newProps.push(j.property('init', j.identifier('error'), messageProp));
          } else if (errorMap) {
            newProps.push(j.property('init', j.identifier('error'), j.arrowFunctionExpression(
              [j.identifier('issue')],
              j.blockStatement([
                j.ifStatement(
                  j.binaryExpression(
                    '===',
                    j.memberExpression(j.identifier('issue'), j.identifier('code')),
                    j.literal('too_small')
                  ),
                  j.blockStatement([
                    j.returnStatement(
                       j.stringLiteral('@hypermod: Provide appropriate validation message')
                    )
                  ]),
                )
              ])
            )));
          }
    
          return j.objectExpression(newProps);
        });
      }
    
      // Replace deprecated .strict(), .passthrough(), .strip()
      root
        .find(j.CallExpression)
        .forEach(path => {
          const callee = path.node.callee;
          if (j.MemberExpression.check(callee) && j.Identifier.check(callee.property)) {
            const method = callee.property.name;
            const object = callee.object;
    
            if (method === 'strict') {
              path.replace(j.callExpression(
                j.identifier('z.strictObject'),
                object.arguments || [object]
              ));
            } else if (method === 'passthrough') {
              path.replace(j.callExpression(
                j.identifier('z.looseObject'),
                object.arguments || [object]
              ));
            } else if (method === 'strip') {
              // z.object() defaults to strip, so drop it
              path.replace(object);
            }
          }
        });
    
      // Replace deprecated z.string().email() with z.email()
      root
        .find(j.CallExpression)
        .forEach(path => {
          const callee = path.node.callee;
          if (
            j.MemberExpression.check(callee) &&
            j.Identifier.check(callee.property) &&
            ['email', 'uuid', 'url', 'emoji', 'base64', 'base64url', 'nanoid', 'cuid', 'cuid2', 'ulid', 'ipv4', 'ipv6', 'cidr'].includes(callee.property.name)
          ) {
            path.replace(j.callExpression(j.identifier(`z.${callee.property.name}`), []));
          }
        });
    
      // Update method call options e.g. .min(5, { message: ... })
      root
        .find(j.CallExpression)
        .forEach(path => {
          const callee = path.node.callee;
          if (j.MemberExpression.check(callee)) {
            const args = path.node.arguments;
            if (args.length > 0) {
              path.node.arguments = replaceErrorParams(args);
            }
          }
        });
    
      // Update top-level schema definitions like z.string({ ... })
      root
        .find(j.CallExpression, {
          callee: { type: 'Identifier', name: 'string' }
        })
        .forEach(path => {
          if (path.node.arguments.length > 0) {
            path.node.arguments = replaceErrorParams(path.node.arguments);
          }
        });
    
      return root.toSource(options);
    };
    
    export default transform;
    
    
    Input
    import { z } from 'zod';
    
    // 1. message -> error
    const schema1 = z.string().min(5, { message: 'Too short.' });
    
    // 2. required_error and invalid_type_error -> error function
    const schema2 = z.string({
      required_error: 'This field is required',
      invalid_type_error: 'Not a string',
    });
    
    // 3. errorMap -> error function (TODO)
    const schema3 = z.string({
      errorMap: (issue, ctx) => {
        if (issue.code === 'too_small') {
          return { message: `Value must be >${issue.minimum}` };
        }
        return { message: ctx.defaultError };
      },
    });
    
    // 4. Deprecated .strict(), .passthrough(), .strip()
    const obj1 = z.object({ name: z.string() }).strict();
    const obj2 = z.object({ name: z.string() }).passthrough();
    const obj3 = z.object({ name: z.string() }).strip();
    
    // 5. Deprecated z.string().email() etc
    const schema4 = z.string().email();
    const schema5 = z.string().uuid();
    const schema6 = z.string().url();
    const schema7 = z.string().ipv4();
    const schema8 = z.string().cidr();
    
    // 6. z.record() single argument
    const rec1 = z.record(z.string());
    
    // 7. z.literal(symbol)
    const sym = Symbol('s');
    const symLit = z.literal(sym);
    
    // 8. z.function() (TODO)
    const funcSchema = z.function()
      .args(z.string())
      .returns(z.number());
    Output
    loading
    Read-only
    Open on CodeSandboxOpen Sandbox