untyped

repository·main·Indexed 19 days ago

https://github.com/unjs/untyped

A utility for defining reference objects to generate JSON schemas, TypeScript types, and Markdown documentation. It features data normalization via $resolve methods, automatic default value handling, and a CLI for loading schemas from entry files. Key functions include resolveSchema for processing definitions, generateTypes for creating .d.ts files, and generateMarkdown for programmatic documentation.

Tokens
4K
Snippets
19
Records
24
Agent score
68%

What's inside untyped

  1. Define a reference object for types and defaults

    main

    To use untyped, you must first define a reference object. This object describes the structure of your data, including types, default values, and optional $resolve normalizer methods.

    Special keys available within the object:

    • $resolve: A function used to normalize or transform a value.
    • $default: The default value to use.
    • $schema: Metadata for the field (e.g., a title).
    const defaultPlanet = {
      name: "earth",
      specs: {
        gravity: {
          $resolve: (val) => Number.parseFloat(val),
          $default: "9.8",
        },
        moons: {
          $resolve: (val = ["moon"]) => [val].flat(),
          $schema: {
            title: "planet moons",
          },
        },
      },
    };
  2. Install untyped

    main

    You can install untyped using your preferred package manager. For automatic detection of your package manager, use nypm.

    # ✨ Auto-detect
    npx nypm install untyped
    
    # npm
    npm install untyped
    
    # yarn
    yarn add untyped
    
    # pnpm
    pnpm add untyped
    
    # bun
    bun install untyped
    
    # deno
    deno install npm:untyped
  3. Use special keys for schema metadata

    main

    When defining your input objects, you can use specific keys to control schema generation:

    • $schema: Used to provide existing schema information.
    • $default: Defines a static default value for a property.
    • $resolve: A function used for asynchronous default value resolution. It receives the current default value and a callback to fetch values from the root object.
    • @required (in tags): If a property's tags array contains the string @required, that property will be added to the schema's required array.
    const input = {
      // Static default
      port: { $default: 3000 },
    
      // Dynamic default via $resolve
      user: async (current, getRootValue) => {
        const root = await getRootValue('root_context');
        return root.defaultUser;
      },
    
      // Required field via tags
      apiKey: {
        tags: ['@required']
      }
    };
  4. Resolve a schema with `resolveSchema`

    main

    The resolveSchema function takes a reference object and resolves it into a structured JSON schema. This schema includes processed types, defaults, and metadata.

    import { resolveSchema } from "untyped";
    
    const schema = await resolveSchema(defaultPlanet);
  5. Generate Markdown documentation with `generateMarkdown`

    main

    The generateMarkdown function converts a resolved schema into a Markdown string, providing a readable list of types and default values for each property.

    import { resolveSchema, generateMarkdown } from "untyped";
    
    const markdown = generateMarkdown(await resolveSchema(defaultPlanet));
  6. Generate TypeScript types with `generateTypes`

    main

    The generateTypes function converts a resolved schema into a TypeScript interface string. It includes JSDoc comments for default values and schema metadata (like titles).

    import { resolveSchema, generateTypes } from "untyped";
    
    const types = generateTypes(await resolveSchema(defaultPlanet));
  7. Configure `generateTypes` options

    main

    When calling generateTypes, you can pass a GenerateTypesOptions object to customize the output:

    OptionTypeDefaultDescription
    interfaceNamestring"Untyped"The name of the generated TypeScript interface.
    addExportbooleantrueWhether to prepend the export keyword to the interface.
    addDefaultsbooleantrueWhether to include @default JSDoc tags for schema default values.
    defaultDescriptionstringundefinedA fallback description used for JSDoc if the schema property lacks a description.
    indentationnumber0The number of spaces used for indentation.
    allowExtraKeysbooleanundefinedIf true, adds [key: string]: any to the interface. If false, it prevents extra keys.
    partialbooleanfalseIf true, all properties in the generated interface will be marked as optional (?).
    const options: GenerateTypesOptions = {
      interfaceName: 'User',
      addExport: true,
      addDefaults: true,
      indentation: 2,
      allowExtraKeys: true,
      partial: false
    };
  8. Configure resolveSchema options

    main

    The resolveSchema function accepts an optional ResolveSchemaOptions object to modify its behavior.

    OptionTypeDefaultDescription
    ignoreDefaultsbooleanfalseIf true, the resulting schema will not include default values for properties.
  9. Generate Markdown documentation from a schema with `generateMarkdown`

    main

    The generateMarkdown function converts a Schema object into a single Markdown string. This is useful for programmatically creating documentation for your typed structures. It recursively traverses the schema, handling objects by nesting headers and representing types, defaults, titles, and descriptions in Markdown format. For function types, it includes a TypeScript signature.

    import { generateMarkdown } from 'untyped/generator/md';
    
    // Assuming 'schema' is a valid Schema object
    const markdown = generateMarkdown(schema);
    console.log(markdown);
  10. Apply defaults to an input object with applyDefaults()

    main

    The applyDefaults function uses a reference object (the schema definition) to populate missing values in an input object with their corresponding default values. This is useful for ensuring an input object conforms to a schema by filling in gaps.

    import { applyDefaults } from 'untyped';
    
    const schemaRef = {
      name: { $default: 'default-name' },
      count: { $default: 0 }
    };
    
    const input = { name: 'actual-name' };
    
    // input will be mutated to include { count: 0 }
    await applyDefaults(schemaRef, input);