profile
viewpoint

Ask questionsDemand for VSCode Extension?

Was playing around with VSCode and Zod based on #53 -- seeing if there is enough demand for this to put time into the concept. It is slow in the preview as I built that out in about 1 hour, but seems it could be nice - and make it easier to use Zod since you wouldn't really need to even learn all the specifics - you could just create your TypeScript Type then translate it.

It utilizes the TypeScript Compiler API to read the AST and infer from there.

Since this is just using the TypeScript compiler API - this could pretty easily become a browser tool as well which you could just paste in your type and get a valid zod schema out from it.

On that note, this is more of a Typescript Plugin than a VSCode Extension - since the vscode part of it is just providing the menu option to run the TS Compiler and it uses the TS Compiler to build Typescript Code.

export const generatePrimitive = ({ kind, name, props, zodImportValue }: {
  kind: ts.SyntaxKind;
  name: string;
  zodImportValue: string;
  props: { isOptional: boolean; errorMessage: undefined | string; isNullable?: boolean }
}) => {
  let flags = '';

  if (props.isOptional) {
    flags += '.optional()';
  }
  if (props.isNullable) {
    flags += '.nullable()';
  }

  let errorMessage = props.errorMessage ? wrapQuotes(props.errorMessage) : '';

  switch (kind) {
    case ts.SyntaxKind.NumericLiteral:
      return `${zodImportValue}.literal(${name})${flags}`;
    case ts.SyntaxKind.StringLiteral:
      return `${zodImportValue}.literal(${wrapQuotes(name)})${flags}`;
    case ts.SyntaxKind.StringKeyword:
      return `${zodImportValue}.string()${flags}`;
    case ts.SyntaxKind.BooleanKeyword:
      return `${zodImportValue}.boolean()${flags}`;
    case ts.SyntaxKind.NullKeyword:
      return `${zodImportValue}.null()${flags}`;
    case ts.SyntaxKind.UndefinedKeyword:
      return `${zodImportValue}.undefined()${flags}`;
    case ts.SyntaxKind.NumberKeyword:
      return `${zodImportValue}.number()${flags}`;
    case ts.SyntaxKind.AnyKeyword: 
      return `${zodImportValue}.any()${flags}`;
    case ts.SyntaxKind.BigIntKeyword:
      return `${zodImportValue}.bigint()${flags}`;
    case ts.SyntaxKind.VoidKeyword:
      return `${zodImportValue}.void()${flags}`;
    case ts.SyntaxKind.ClassKeyword: {
      if (name === 'Date') {
        return `${zodImportValue}.date()${flags}`;
      }
      // TODO : Handle Class & InstanceOf based on symbol & import detection context
    }
    default:
     return `${zodImportValue}.any(${errorMessage})`;
  }
};


The code above just uses strings to build it which was easier in this case. For those potentially interested, to move to using the TypeScript Compiler / AST to build it all, the generated type in the gif would be something like:

[
  ts.createVariableStatement(
    undefined,
    ts.createVariableDeclarationList(
      [ts.createVariableDeclaration(
        ts.createIdentifier("TestSchema"),
        undefined,
        ts.createCall(
          ts.createPropertyAccess(
            ts.createIdentifier("z"),
            ts.createIdentifier("object")
          ),
          undefined,
          [ts.createObjectLiteral(
            [
              ts.createPropertyAssignment(
                ts.createIdentifier("three"),
                ts.createCall(
                  ts.createPropertyAccess(
                    ts.createCall(
                      ts.createPropertyAccess(
                        ts.createIdentifier("z"),
                        ts.createIdentifier("literal")
                      ),
                      undefined,
                      [ts.createStringLiteral("hi")]
                    ),
                    ts.createIdentifier("optional")
                  ),
                  undefined,
                  []
                )
              ),
              ts.createPropertyAssignment(
                ts.createIdentifier("one"),
                ts.createCall(
                  ts.createPropertyAccess(
                    ts.createIdentifier("z"),
                    ts.createIdentifier("number")
                  ),
                  undefined,
                  []
                )
              ),
              ts.createPropertyAssignment(
                ts.createIdentifier("two"),
                ts.createCall(
                  ts.createPropertyAccess(
                    ts.createIdentifier("z"),
                    ts.createIdentifier("literal")
                  ),
                  undefined,
                  [ts.createNumericLiteral("3")]
                )
              ),
              ts.createPropertyAssignment(
                ts.createIdentifier("four"),
                ts.createCall(
                  ts.createPropertyAccess(
                    ts.createIdentifier("z"),
                    ts.createIdentifier("string")
                  ),
                  undefined,
                  []
                )
              ),
              ts.createPropertyAssignment(
                ts.createIdentifier("five"),
                ts.createCall(
                  ts.createPropertyAccess(
                    ts.createIdentifier("z"),
                    ts.createIdentifier("date")
                  ),
                  undefined,
                  []
                )
              )
            ],
            true
          )]
        )
      )],
      ts.NodeFlags.Const
    )
  ),
  ts.createTypeAliasDeclaration(
    undefined,
    undefined,
    ts.createIdentifier("Test"),
    undefined,
    ts.createTypeReferenceNode(
      ts.createQualifiedName(
        ts.createIdentifier("z"),
        ts.createIdentifier("infer")
      ),
      [ts.createTypeQueryNode(ts.createIdentifier("TestSchema"))]
    )
  )
];

-->

const TestSchema = z.object({
	three: z.literal('hi').optional(),
	one: z.number(),
	two: z.literal(3),
	four: z.string(),
	five: z.date()
})

type Test = z.infer<typeof TestSchema>;
vriad/zod

Answer questions chrbala

Interesting concept! I would personally prefer to see GraphQL schema -> Zod types, but interesting either way! I suppose it's also possible to generate GraphQL -> TS -> Zod in some kind of pipeline as well. In general, I'd expect to auto-generate Zod types which then get manually edited. Certainly it's more complicated than just the proposal here, and I'm not sure exactly what it would look like in terms of UX.

useful!

Related questions

No questions were found.
source:https://uonfu.com/
Github User Rank List