quicktype

repository·master·Indexed 11 days ago

https://github.com/glideapps/quicktype

A tool that generates strongly-typed models and serializers from JSON, JSON Schema, TypeScript, and GraphQL queries across many programming languages. Available as a CLI, a VS Code extension, and a JavaScript/Node.js library via the quicktype-core package (version 24.0.0).

Tokens
22.9K
Snippets
64
Records
101
Agent score
96%

What's inside quicktype

  1. How quicktype differs from other JSON converters

    master

    quicktype provides several advanced features compared to standard converters:

    • Advanced Type Inference: Infers optionals, dates, UUIDs, enums, integers, unions, and maps (via Markov chains).
    • Heterogeneous Data Support: Creates union types (or synthetic unions) for data that changes shape.
    • Type Unification: Can process multiple samples (e.g., a directory of files) to create a single unified type definition across all samples.
    • Marshalling Code: Generates functions to convert between JSON strings and your language's types.
    • Client-side Execution: The web version runs entirely in your browser, so your data is never sent to a server.
    • Typed Input: Supports TypeScript and JSON Schema as inputs for more precise control.
  2. Understand memory reporting (Max Heap)

    master

    The benchmark reports memory.maximumHeapUsedBytes, which is the largest process.memoryUsage().heapUsed value observed during measured runs.

    Sampling Points:

    • Before and after input parsing.
    • After every instrumented quicktype pass.
    • After rendering.
    • After output serialization.

    Note: Because Node does not expose an exact high-water mark, allocations that are created and released entirely within a single synchronous pass might not be captured in this value.

  3. How transformed string types work in quicktype

    master

    quicktype can transform JSON strings into data types that are not natively represented as strings in JSON, or into other JSON-representable types.

    There are two categories of transformed string types:

    1. JSON-representable transformations: Converting a stringified value into another JSON type (e.g., a stringified integer into a numeric type).
    2. Non-JSON-representable transformations: Converting a string into a type that exists in the target language but is represented as a string in JSON (e.g., converting a date/time string into a native DateTime object).

    Currently, C# has the most advanced support for these transformations, specifically for date/time types and stringified integers.

  4. Understand and prevent JSON Schema comment injection

    master

    Comment injection occurs when raw text from a JSON Schema description field is placed into generated source code comments without proper escaping. This can break the syntax of the generated file (e.g., prematurely closing a comment block) or cause compilation errors.

    Vulnerable Schema Fields

    In JSON Schema, the following fields are collected and typically rendered as documentation comments in target languages:

    • description on an object/class
    • description on a property/field
    • description on an enum schema
    • description on a union schema or other named types

    Note that title is generally used for naming types and is not treated as raw documentation text for comments.

  5. Use Handlebars templates with quicktype

    master

    quicktype supports processing Handlebars templates. Templates are processed in the context of a specific target language, allowing the output to interact with the types generated for that language. This enables you to customize the code generation by accessing information about the inferred types, such as their kind (e.g., class, enum, union), properties, and names.

    Note: This feature was a prototype and may not be available in all current versions of quicktype. If it is not working in your current version, you may need to check specific historical commits.

  6. Understand quicktype type naming

    master

    If your generated types have unexpected names, it is usually due to:

    • Language conflicts: The preferred name conflicts with a reserved word in the target language (e.g., String in C#).
    • Name collisions: Multiple types in your data share the same name.
    • Ambiguity: The type has too many potential names for a commonality to be found.

    Tip: If using JSON Schema, use the title property to suggest a specific name for the type.

  7. Understand the benchmark phase breakdown

    master

    The end-to-end timer measures the time from before input parsing until after the generated source is serialized. The benchmark provides a breakdown of these phases (calculated at the median end-to-end time):

    • Parse: Compressed JSON parsing (for JSON samples) or YAML/JSON parsing (for JSON Schema).
    • Infer/schema: Type inference from JSON, or conversion from a parsed schema to quicktype's initial type graph.
    • Transform: Graph rewrites, map and enum inference, transformations, garbage collection, and name gathering.
    • Codegen: Target-language rendering and serialization.
    • Other: Input/graph setup, callback overhead, and uninstrumented control flow.
  8. Create an entirely new TargetLanguage and Renderer from scratch

    master

    If you need to support a language not currently in quicktype, you must implement both a TargetLanguage and a Renderer from the ground up.

    1. Define the Language Configuration

    Create a configuration object containing:

    • displayName: The human-readable name.
    • names: An array of names used to identify the language.
    • extension: The common file extension for this language.

    2. Define Language Options

    Use quicktype-core option classes to define user-configurable flags. Available default classes include:

    • StringOption
    • BooleanOption
    • EnumOption

    3. Implement the TargetLanguage

    Extend TargetLanguage<typeof config> and implement:

    • getOptions(): Returns your defined language options.
    • makeRenderer(): Returns an instance of your custom Renderer.

    4. Implement the Renderer

    Extend ConvenienceRenderer and implement the necessary rendering logic in its methods.

    import { TargetLanguage, BooleanOption, RenderContext } from "quicktype-core";
    
    // 1. Language config
    const brandNewLanguageConfig = {
        displayName: "Scratch",
        names: ["scratch"],
        extension: "sb"
    } as const;
    
    // 2. Language options
    const brandNewLanguageOptions = {
        allowFoo: new BooleanOption("allow-foo", "Allows Foo", true)
    };
    
    // 3. TargetLanguage implementation
    class BrandNewLanguage extends TargetLanguage<typeof brandNewLanguageConfig> {
        public constructor() {
            super(brandNewLanguageConfig);
        }
    
        public getOptions(): typeof brandNewLanguageOptions {
            return brandNewLanguageOptions;
        }
    
        protected makeRenderer(
            renderContext: RenderContext,
            untypedOptionValues: Record<string, unknown>
        ): BrandNewRenderer {
            return new BrandNewRenderer(this, renderContext, getOptionValues(brandNewLanguageOptions, untypedOptionValues));
        }
    }
    
    // 4. Renderer implementation
    import { ConvenienceRenderer } from "quicktype-core";
    
    export class BrandNewRenderer extends ConvenienceRenderer {
        public constructor(targetLanguage: TargetLanguage, renderContext: RenderContext) {
            super(targetLanguage, renderContext);
        }
        // Implement render methods here
    }
  9. Run the canonical real-world benchmark

    master

    The canonical benchmark runs specific, large-scale real-world datasets (such as USGS GeoJSON, GitHub OpenAPI, and NVD CVE feeds) through both TypeScript and Rust renderers.

    Key Details:

    • Memory: Node is allocated an 8 GiB heap for these runs.
    • Caching: Inputs are downloaded and cached in the OS user cache directory. They are not timed. To re-download current copies, use the --refresh flag.
    • Custom Cache: You can change the cache location using the QUICKTYPE_BENCHMARK_CACHE environment variable or the --cache-dir DIR flag.
    • Options: Supports --warmup, --iterations, and --json flags.
    # Run canonical benchmark
    npm run benchmark:canonical
    
    # Refresh downloaded inputs
    npm run benchmark:canonical -- --refresh
    
    # Specify a custom cache directory
    npm run benchmark:canonical -- --cache-dir /path/to/dir
  10. Use live-reloading for development feedback

    master

    When developing a new output language (renderer), you can use npm start to watch for changes, recompile, and automatically rerun quicktype. Any arguments passed after -- are passed directly to the quicktype command. This allows you to see generated output in real-time as you edit your renderer code.

    npm start -- "--lang fortran pokedex.json"
  11. Run the quicktype test suite

    master

    Use the following commands to run different levels of the test suite:

    • Full test suite: Runs unit tests and all fixtures.
    • Unit tests only: Runs only the Vitest unit tests.
    • Language fixtures: Runs tests for a specific language using the FIXTURE environment variable.
    • Specific samples: Runs tests for a single sample or a directory of samples by appending the path after the fixture command.
    # Run full test suite (unit tests plus all fixtures)
    npm test
    
    # Run only the Vitest unit tests
    npm run test:unit
    
    # Test a specific language (see test/languages.ts)
    FIXTURE=golang npm run test:fixtures
    
    # Test a single sample or directory
    FIXTURE=swift npm run test:fixtures -- pokedex.json
    FIXTURE=swift npm run test:fixtures -- test/inputs/json/samples
  12. Generate code from TypeScript (Experimental)

    master

    You can use TypeScript files as input to quicktype. This is useful if you want to define types manually or generate them from existing TypeScript interfaces.

    # First, infer a TypeScript file from a sample (or just write one!)
    quicktype pokedex.json -o pokedex.ts --just-types
    
    # Review the TypeScript, make changes, etc.
    quicktype pokedex.ts -o src/ios/models.swift