Repository: specta-rs/specta Branch: main Commit: a580a9865656 Files: 279 Total size: 2.9 MB Directory structure: gitextract_unw2xfqn/ ├── .github/ │ ├── FUNDING.yml │ ├── dependabot.yml │ ├── features.js │ └── workflows/ │ └── ci.yml ├── .gitignore ├── .rustfmt.toml ├── .taplo.toml ├── AGENTS.md ├── Cargo.toml ├── LICENSE ├── README.md ├── examples/ │ ├── basic-ts/ │ │ ├── Cargo.toml │ │ └── src/ │ │ └── main.rs │ ├── collect/ │ │ ├── Cargo.toml │ │ └── src/ │ │ └── main.rs │ └── scratchpad/ │ ├── Cargo.toml │ └── src/ │ └── main.rs ├── specta/ │ ├── Cargo.toml │ ├── build.rs │ └── src/ │ ├── collect.rs │ ├── datatype/ │ │ ├── attributes.rs │ │ ├── enum.rs │ │ ├── fields.rs │ │ ├── function.rs │ │ ├── generic.rs │ │ ├── list.rs │ │ ├── literal.rs │ │ ├── map.rs │ │ ├── named.rs │ │ ├── primitive.rs │ │ ├── reference.rs │ │ ├── struct.rs │ │ └── tuple.rs │ ├── datatype.rs │ ├── docs.md │ ├── format.rs │ ├── function/ │ │ ├── arg.rs │ │ ├── result.rs │ │ └── specta_fn.rs │ ├── function.rs │ ├── internal.rs │ ├── lib.rs │ ├── type/ │ │ ├── impls.rs │ │ ├── legacy_impls.rs │ │ └── macros.rs │ ├── type.rs │ └── types.rs ├── specta-go/ │ ├── Cargo.toml │ ├── bindings.go │ └── src/ │ ├── error.rs │ ├── go.rs │ ├── lib.rs │ ├── primitives.rs │ └── reserved_names.rs ├── specta-jsonschema/ │ ├── Cargo.toml │ ├── examples/ │ │ └── jsonschema.rs │ ├── src/ │ │ ├── error.rs │ │ ├── import.rs │ │ ├── json_schema.rs │ │ ├── layout.rs │ │ ├── lib.rs │ │ ├── primitives.rs │ │ └── schema_version.rs │ └── tests/ │ └── basic.rs ├── specta-kotlin/ │ ├── Cargo.toml │ └── src/ │ └── lib.rs ├── specta-macros/ │ ├── Cargo.toml │ ├── README.md │ └── src/ │ ├── lib.rs │ ├── specta.rs │ ├── type/ │ │ ├── attr/ │ │ │ ├── container.rs │ │ │ ├── field.rs │ │ │ ├── legacy.rs │ │ │ ├── mod.rs │ │ │ ├── rustc.rs │ │ │ └── variant.rs │ │ ├── enum.rs │ │ ├── field.rs │ │ ├── generics.rs │ │ ├── mod.rs │ │ ├── serde.rs │ │ └── struct.rs │ └── utils.rs ├── specta-openapi/ │ ├── Cargo.toml │ └── src/ │ └── lib.rs ├── specta-serde/ │ ├── Cargo.toml │ ├── README.md │ └── src/ │ ├── error.rs │ ├── inflection.rs │ ├── lib.rs │ ├── parser.rs │ ├── phased.rs │ ├── repr.rs │ └── validate.rs ├── specta-swift/ │ ├── Cargo.toml │ ├── README.md │ ├── Types.swift │ ├── examples/ │ │ ├── README.md │ │ ├── advanced_unions.rs │ │ ├── basic_types.rs │ │ ├── comments_example.rs │ │ ├── comprehensive_demo.rs │ │ ├── configuration_options.rs │ │ ├── generated/ │ │ │ ├── AdvancedUnions.swift │ │ │ ├── BasicTypes.swift │ │ │ ├── CamelCase.swift │ │ │ ├── CombinedConfig.swift │ │ │ ├── CommentsExample.swift │ │ │ ├── ComprehensiveDemo.swift │ │ │ ├── CustomHeader.swift │ │ │ ├── CustomTypes.swift │ │ │ ├── DefaultConfig.swift │ │ │ ├── OptionalType.swift │ │ │ ├── PascalCase.swift │ │ │ ├── ProtocolGenerics.swift │ │ │ ├── QuestionMark.swift │ │ │ ├── SimpleTypes.swift │ │ │ ├── SnakeCase.swift │ │ │ ├── Spaces2.swift │ │ │ ├── Spaces4.swift │ │ │ ├── SpecialTypes.swift │ │ │ ├── StringEnums.swift │ │ │ ├── Tabs.swift │ │ │ ├── TypealiasGenerics.swift │ │ │ ├── WithProtocols.swift │ │ │ └── WithSerde.swift │ │ ├── simple_usage.rs │ │ ├── special_types.rs │ │ └── string_enums.rs │ ├── src/ │ │ ├── error.rs │ │ ├── lib.rs │ │ ├── primitives.rs │ │ └── swift.rs │ └── tests/ │ ├── Cargo.toml │ ├── advanced_unions.rs │ ├── basic.rs │ ├── common_types.rs │ ├── comprehensive.rs │ ├── multiline_comments.rs │ ├── string_enum_implementation.rs │ ├── string_enum_test.rs │ ├── struct_reuse_test.rs │ ├── struct_variants.rs │ ├── unions.rs │ ├── uuid_simple.rs │ └── uuid_test.rs ├── specta-tags/ │ ├── Cargo.toml │ └── src/ │ └── lib.rs ├── specta-typescript/ │ ├── Cargo.toml │ ├── bindings.ts │ └── src/ │ ├── branded.rs │ ├── error.rs │ ├── exporter.rs │ ├── jsdoc.rs │ ├── legacy.rs │ ├── lib.rs │ ├── map_keys.rs │ ├── opaque.rs │ ├── primitives.rs │ ├── references.rs │ ├── reserved_names.rs │ ├── types.rs │ └── typescript.rs ├── specta-util/ │ ├── Cargo.toml │ └── src/ │ ├── array.rs │ ├── lib.rs │ ├── remapper.rs │ └── selection.rs ├── specta-zod/ │ ├── Cargo.toml │ └── src/ │ ├── error.rs │ ├── lib.rs │ ├── opaque.rs │ ├── primitives.rs │ ├── references.rs │ ├── reserved_names.rs │ ├── types.rs │ └── zod.rs └── tests/ ├── Cargo.toml └── tests/ ├── bound.rs ├── errors.rs ├── functions.rs ├── jsdoc.rs ├── layouts.rs ├── legacy_impls.rs ├── macro/ │ ├── compile_error.rs │ └── compile_error.stderr ├── mod.rs ├── references.rs ├── serde_conversions.rs ├── serde_identifiers.rs ├── serde_other.rs ├── snapshots/ │ ├── test__bound__bound-associated-type-issue-138.snap │ ├── test__jsdoc__export-many-raw.snap │ ├── test__jsdoc__export-many-serde.snap │ ├── test__jsdoc__export-many-serde_phases.snap │ ├── test__jsdoc__export-raw.snap │ ├── test__jsdoc__export-serde.snap │ ├── test__jsdoc__export-serde_phases.snap │ ├── test__jsdoc__inline-raw.snap │ ├── test__jsdoc__inline-serde.snap │ ├── test__jsdoc__inline-serde_phases.snap │ ├── test__jsdoc__jsdoc-export-to-files-both.snap │ ├── test__jsdoc__jsdoc-export-to-files-raw.snap │ ├── test__jsdoc__jsdoc-export-to-files-serde.snap │ ├── test__jsdoc__jsdoc-export-to-files-serde_phases.snap │ ├── test__jsdoc__jsdoc-export-to-flatfile-raw.snap │ ├── test__jsdoc__jsdoc-export-to-flatfile-serde.snap │ ├── test__jsdoc__jsdoc-export-to-flatfile-serde_phases.snap │ ├── test__jsdoc__jsdoc-export-to-moduleprefixedname-raw.snap │ ├── test__jsdoc__jsdoc-export-to-moduleprefixedname-serde.snap │ ├── test__jsdoc__jsdoc-export-to-moduleprefixedname-serde_phases.snap │ ├── test__jsdoc__jsdoc-export-to-namespaces-raw.snap │ ├── test__jsdoc__jsdoc-export-to-namespaces-serde.snap │ ├── test__jsdoc__jsdoc-export-to-namespaces-serde_phases.snap │ ├── test__jsdoc__primitives-many-inline-raw.snap │ ├── test__jsdoc__primitives-many-inline-serde.snap │ ├── test__jsdoc__primitives-many-inline-serde_phases.snap │ ├── test__jsdoc__reference-raw.snap │ ├── test__jsdoc__reference-serde.snap │ ├── test__jsdoc__reference-serde_phases.snap │ ├── test__layouts__layouts-duplicate-files.snap │ ├── test__layouts__layouts-duplicate-module-prefixed.snap │ ├── test__layouts__layouts-duplicate-namespaces.snap │ ├── test__layouts__layouts-empty-module-path-files.snap │ ├── test__layouts__layouts-empty-module-path-flat.snap │ ├── test__layouts__layouts-empty-module-path-module-prefixed.snap │ ├── test__layouts__layouts-empty-module-path-namespaces.snap │ ├── test__layouts__layouts-non-duplicate-default.snap │ ├── test__layouts__layouts-non-duplicate-files.snap │ ├── test__layouts__layouts-non-duplicate-flat.snap │ ├── test__layouts__layouts-non-duplicate-module-prefixed.snap │ ├── test__layouts__layouts-non-duplicate-namespaces.snap │ ├── test__legacy_impls__legacy_impls.snap │ ├── test__serde_conversions__serde-conversions-format-phases-exports-field-only-phased-override.snap │ ├── test__serde_conversions__serde-conversions-format-phases-splits-container-and-dependents.snap │ ├── test__serde_identifiers__serde-identifiers-field-typescript.snap │ ├── test__serde_identifiers__serde-identifiers-variant-typescript.snap │ ├── test__serde_other__serde-other-adjacent-tag-typescript.snap │ ├── test__serde_other__serde-other-internal-tag-typescript.snap │ ├── test__swift__swift-export-raw.snap │ ├── test__swift__swift-export-serde.snap │ ├── test__swift__swift-export-serde_phases.snap │ ├── test__types__serde-default-container-typescript.snap │ ├── test__types__serde-default-field-typescript.snap │ ├── test__types__serde-mixed-untagged-phased-typescript.snap │ ├── test__types__serde-mixed-untagged-struct-typescript.snap │ ├── test__types__serde-mixed-untagged-typescript.snap │ ├── test__typescript__export-many-raw.snap │ ├── test__typescript__export-many-serde.snap │ ├── test__typescript__export-many-serde_phases.snap │ ├── test__typescript__export-raw.snap │ ├── test__typescript__export-serde.snap │ ├── test__typescript__export-serde_phases.snap │ ├── test__typescript__inline-raw.snap │ ├── test__typescript__inline-serde.snap │ ├── test__typescript__inline-serde_phases.snap │ ├── test__typescript__reference-raw.snap │ ├── test__typescript__reference-serde.snap │ ├── test__typescript__reference-serde_phases.snap │ ├── test__typescript__ts-export-raw.snap │ ├── test__typescript__ts-export-serde.snap │ ├── test__typescript__ts-export-serde_phases.snap │ ├── test__typescript__ts-export-to-files-raw.snap │ ├── test__typescript__ts-export-to-files-serde.snap │ ├── test__typescript__ts-export-to-files-serde_phases.snap │ ├── test__typescript__ts-export-to-flatfile-raw.snap │ ├── test__typescript__ts-export-to-flatfile-serde.snap │ ├── test__typescript__ts-export-to-flatfile-serde_phases.snap │ ├── test__typescript__ts-export-to-moduleprefixedname-raw.snap │ ├── test__typescript__ts-export-to-moduleprefixedname-serde.snap │ ├── test__typescript__ts-export-to-moduleprefixedname-serde_phases.snap │ ├── test__typescript__ts-export-to-namespaces-raw.snap │ ├── test__typescript__ts-export-to-namespaces-serde.snap │ └── test__typescript__ts-export-to-namespaces-serde_phases.snap ├── swift.rs ├── types.rs ├── typescript.rs ├── utils.rs └── zod.rs ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/FUNDING.yml ================================================ github: [oscartbeaumont] custom: ["https://paypal.me/oscartbeaumont"] ================================================ FILE: .github/dependabot.yml ================================================ version: 2 multi-ecosystem-groups: specta-deps: schedule: interval: "weekly" updates: - package-ecosystem: "github-actions" directory: "/" multi-ecosystem-group: "specta-deps" patterns: ["*"] - package-ecosystem: "cargo" directory: "/" multi-ecosystem-group: "specta-deps" patterns: ["*"] ================================================ FILE: .github/features.js ================================================ // This script generates the documentation for the Cargo features from the comments in the `Cargo.toml` file. // It dumps the result into the `src/docs.md` file. This means the docs are readable in the published version of the crate and also allows the docs to be broken into a separate file (unlike `document-features`) const fs = require("fs"); const path = require("path"); const START_MARKER = "[//]: # (FEATURE_FLAGS_START)"; const END_MARKER = "[//]: # (FEATURE_FLAGS_END)"; const docsPath = path.join(__dirname, "..", "src", "docs.md"); const cargoToml = fs.readFileSync( path.join(__dirname, "..", "Cargo.toml"), "utf8" ); const docs = fs.readFileSync(docsPath, "utf8"); if (!docs.includes(START_MARKER) || !docs.includes(END_MARKER)) throw new Error("Missing markers in 'docs.md'"); const lines = cargoToml.split("\n").map((line) => line.trim()); const featuresIndex = lines.indexOf("[features]"); if (featuresIndex === -1) throw new Error("Missing '[features]' in 'Cargo.toml'"); const featuresPart = lines.slice(featuresIndex + 1); const endIndex = featuresPart.findIndex( (line) => line.startsWith("[") && line.endsWith("]") ); const featuresLine = featuresPart.slice(0, endIndex); let comments = ""; let group = null; let result = {}; for (const line of featuresLine) { if (line == "") { continue; } if (line.startsWith("##!")) { group = ""; result[group] = {}; } else if (line.startsWith("##")) { comments += line.slice(2).trim() + "\n"; } else if (line.startsWith("#!")) { group = line.substring(2).trim(); result[group] = {}; } else if (line.startsWith("#")) { continue; } else { const parts = line.split("="); if (parts.length !== 2) throw new Error(`Invalid feature line: '${line}'`); if (group !== null) { result[group][parts[0].trim()] = comments; comments = ""; } } } let markdown_result = Object.entries(result) .map( ([name, deps]) => `${name}\n\n${Object.entries(deps) .map( ([name, comment]) => `- \`${name}\` - ${comment.replace("\n", " ").trim()}` ) .join("\n")}` ) .join("\n\n"); const resultDocs = docs.replace( docs.substring( docs.indexOf(START_MARKER), docs.lastIndexOf(END_MARKER) + END_MARKER.length ), START_MARKER + "\n" + markdown_result + "\n\n" + END_MARKER ); fs.writeFileSync(docsPath, resultDocs); ================================================ FILE: .github/workflows/ci.yml ================================================ name: CI on: workflow_dispatch: push: branches: - main pull_request: env: CARGO_TERM_COLOR: always jobs: build: strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v6 - name: Setup if: matrix.os == 'ubuntu-latest' run: sudo apt-get update && sudo apt-get install libgtk-3-dev webkit2gtk-4.1 libayatana-appindicator3-dev - name: Install Rust toolchain run: rustup toolchain install stable --profile minimal - name: Rust cache uses: Swatinem/rust-cache@v2 - name: Build run: cargo build --all-features - name: Run tests run: cargo test --all-features clippy: runs-on: ubuntu-latest permissions: contents: read checks: write pull-requests: write steps: - uses: actions/checkout@v6 - name: Setup run: sudo apt-get update && sudo apt-get install libgtk-3-dev webkit2gtk-4.1 libayatana-appindicator3-dev - name: Install Rust toolchain run: rustup toolchain install stable --profile minimal --component clippy - name: Rust cache uses: Swatinem/rust-cache@v2 - uses: actions-rs/clippy-check@v1 with: token: ${{ secrets.GITHUB_TOKEN }} args: --all-features ================================================ FILE: .gitignore ================================================ # Generated by Cargo # will have compiled files and executables target/ test-target/ # These are backup files generated by rustfmt **/*.rs.bk # System Files .DS_Store # Node node_modules .pnpm-debug.log* *.tsbuildinfo /packages/*/dist /bindings.ts /bindings2.ts /tests/.temp # Used by examples as a place to export files. /specta-typescript/out ================================================ FILE: .rustfmt.toml ================================================ # https://github.com/specta-rs/specta/pull/222 ================================================ FILE: .taplo.toml ================================================ [formatting] column_width = 150 ================================================ FILE: AGENTS.md ================================================ Specta is a Rust library for easily exporting Rust types to other languages (TypeScript, Swift, Rust, OpenAPI, etc.). It's a workspace with multiple crates: ``` specta/ ├── specta/ # Core library ├── specta-macros/ # Macros for the core library ├── specta-typescript/ # TypeScript exporter (stable) ├── specta-swift/ # Swift exporter (stable) ├── specta-openapi/ # OpenAPI (partial) ├── specta-serde/ # Serde utilities ├── specta-util/ # Utilities for end-users. Less semver guarantees. ├── tests/ # Integration tests ├── Cargo.toml # Workspace manifest ``` Specta is format agnostic so the `specta` and `specta-macros` crate should avoid hardcoding serde-specific behaviors. We use `insta` for snapshot testing Use Rust 2024 edition Document feature gates with `#[cfg_attr(docsrs, doc(cfg(feature = "...")))]` Prefer to put tests in the dedicated crate Don't run `cargo doc --open` as it opens a browser you can't read. Maybe prefer a web fetch to https://docs.rs/{crate_name} Prefer Rust module guidelines including using `module.rs` instead of `module/mod.rs` When testing bugs create a unit test to ensure it's fixed. If I give you a GitHub link can you include it in comments. Don't use `/tmp` for temporary projects in should stay within the workspace. You are a senior engineer. You should follow Clippy and Rust best practices. Write code that is concise and readable. Make use of Rust's method chaining where it would result in cleaner code. ================================================ FILE: Cargo.toml ================================================ [workspace] members = ["specta", "specta-*", "tests", "examples/*"] resolver = "2" [workspace.lints.rust] unsafe_code = { level = "warn", priority = -1 } # ctor requires unsafe but is an optional feature missing_docs = { level = "warn", priority = -1 } unexpected_cfgs = { level = "warn", check-cfg = ['cfg(is_nightly)'] } [workspace.lints.clippy] all = { level = "warn", priority = -1 } cargo = { level = "warn", priority = -1 } unwrap_used = { level = "warn", priority = -1 } panic = { level = "warn", priority = -1 } todo = { level = "warn", priority = -1 } panic_in_result_fn = { level = "warn", priority = -1 } multiple_crate_versions = { level = "allow", priority = 0 } # I hate these. For internal code I don't care. too_many_arguments = { level = "allow", priority = 0 } type_complexity = { level = "allow", priority = 0 } [profile.dev.package] insta.opt-level = 3 similar.opt-level = 3 ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2022 Oscar Beaumont Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================
Specta Logo

Specta

Easily export your Rust types to other languages

Discord Crates.io crates.io docs.rs License

## Features - Export structs and enums to multiple languages - Get function types to use in libraries like [tauri-specta](https://github.com/specta-rs/tauri-specta) - Supports wide range of common crates in Rust ecosystem - Supports type inference - can determine type of `fn demo() -> impl Type` ## Language Support | Language | Status | Exporter | Features | | --------------- | -------------- | ----------------------------------------------------------------- | ------------------------------------------------- | | **TypeScript** | ✅ **Stable** | [`specta-typescript`](https://crates.io/crates/specta-typescript) | Full type support, generics, unions | | **Swift** | ✅ **Stable** | [`specta-swift`](https://crates.io/crates/specta-swift) | Idiomatic Swift, custom Codable, Duration support | | **Rust** | 🚧 **Partial** | [`specta-rust`](https://crates.io/crates/specta-rust) | Basic types work, structs/enums in progress | | **OpenAPI** | 🚧 **Partial** | [`specta-openapi`](https://crates.io/crates/specta-openapi) | Primitives work, complex types in progress | | **Go** | 🚧 **Planned** | [`specta-go`](https://crates.io/crates/specta-go) | Go structs and interfaces | | **Kotlin** | 🚧 **Planned** | [`specta-kotlin`](https://crates.io/crates/specta-kotlin) | Kotlin data classes and sealed classes | | **JSON Schema** | 🚧 **Planned** | [`specta-jsonschema`](https://crates.io/crates/specta-jsonschema) | JSON Schema generation | | **Zod** | 🚧 **Planned** | [`specta-zod`](https://crates.io/crates/specta-zod) | Zod schema validation | | **Python** | 🚧 **Planned** | `specta-python` | Python dataclasses and type hints | | **C#** | 🚧 **Planned** | `specta-csharp` | C# classes and enums | | **Java** | 🚧 **Planned** | `specta-java` | Java POJOs and enums | ### Legend - ✅ **Stable**: Production-ready with comprehensive test coverage - 🚧 **Partial**: Basic functionality implemented, complex types in progress - 🚧 **Planned**: In development or planned for future release ## Implementation Status The Specta ecosystem is actively developed with varying levels of completeness: - **Production Ready (2)**: TypeScript and Swift exporters are fully functional with comprehensive test coverage - **Partially Implemented (2)**: Rust and OpenAPI exporters have basic functionality working, with complex types in progress - **Planned (7)**: Go, Kotlin, JSON Schema, Zod, Python, C#, and Java exporters are in development For the most up-to-date status of each exporter, check the individual crate documentation and issue trackers. ## Ecosystem Specta can be used in your application either directly or through a library which simplifies the process of using it. - [rspc](https://github.com/specta-rs/rspc) - Easily building end-to-end typesafe APIs - [tauri-specta](https://github.com/specta-rs/tauri-specta) - Typesafe Tauri commands and events - [TauRPC](https://github.com/MatsDK/TauRPC) - Tauri extension to give you a fully-typed IPC layer. ## Usage Add the [`specta`](https://docs.rs/specta) crate along with any Specta language exporter crate: ```bash # Core Specta library cargo add specta # Language exporters (choose one or more) cargo add specta_typescript # TypeScript (stable) cargo add specta_swift # Swift (stable) cargo add specta_rust # Rust (partial - basic types) cargo add specta_openapi # OpenAPI/Swagger (partial - primitives) # cargo add specta_go # Go (planned) # cargo add specta_kotlin # Kotlin (planned) # cargo add specta_jsonschema # JSON Schema (planned) # cargo add specta_zod # Zod schemas (planned) ``` Then you can use Specta like following: ### TypeScript Example ```rust use specta::{Type, Types}; use specta_typescript::Typescript; #[derive(Type)] pub struct TypeOne { pub a: String, pub b: GenericType, #[serde(rename = "cccccc")] pub c: MyEnum, } #[derive(Type)] pub struct GenericType { pub my_field: String, pub generic: A, } #[derive(Type)] pub enum MyEnum { A, B, C, } fn main() { let types = Types::default() // You don't need to specify `GenericType` or `MyEnum` because they are referenced by `TypeOne` .register::(); Typescript::default() .export_to("./bindings.ts", &types) .unwrap(); // if you need more control over file saving assert_eq!( Typescript::default().export(&types).unwrap(), r#"// This file has been generated by Specta. DO NOT EDIT. export type GenericType = { my_field: string; generic: A }; export type MyEnum = "A" | "B" | "C"; export type TypeOne = { a: string; b: GenericType; cccccc: MyEnum }; "# ); } ``` ### Multi-Language Export Example You can export the same types to multiple languages: ```rust use specta::{Type, Types}; use specta_typescript::Typescript; use specta_swift::Swift; #[derive(Type)] pub struct User { pub id: u32, pub name: String, pub email: Option, } fn main() { let types = Types::default() .register::(); // Export to TypeScript (stable) Typescript::default() .export_to("./types.ts", &types) .unwrap(); // Export to Swift (stable) Swift::default() .export_to("./Types.swift", &types) .unwrap(); // Note: Other exporters are in development } ``` A common use case is to export all types for which `specta::Type` is derived into a single file: ```rust //! NOTE: This example requires the `export` feature on the `specta` crate use specta::Type; use specta_typescript::Typescript; #[derive(Type)] pub enum MyEither { Left(L), Right(R), } #[derive(Type)] pub struct GenericType { pub my_field: String, pub generic: A, } #[derive(Type)] pub enum MyEnum { A, B, C, } #[derive(Type)] #[specta(collect = false)] pub struct DontExportMe { field: String, } fn main() { Typescript::default() .export_to("./bindings.ts", &specta::export()) .unwrap(); } ``` Check out the [docs](https://docs.rs/specta) for more information. ## Motivation This library was originally created to power the type exporting functionality of [rspc](https://rspc.dev), but after building it we realized that it could be useful for other projects as well so we decided to move it into a dedicated library. A huge thanks to [Brendonovich](https://github.com/brendonovich) for doing a heap of early development on this library. ================================================ FILE: examples/basic-ts/Cargo.toml ================================================ [package] name = "example-basic-ts" version = "0.0.0" edition = "2024" publish = false [dependencies] specta = { path = "../../specta", features = ["derive"] } specta-typescript = { path = "../../specta-typescript" } specta-serde = { path = "../../specta-serde" } serde = { version = "1", features = ["derive"] } serde_with = { version = "3", features = ["macros"] } serde_repr = "0.1.20" ================================================ FILE: examples/basic-ts/src/main.rs ================================================ use serde::{Deserialize, Serialize}; use specta::{Type, Types}; use specta_typescript::Typescript; // Specta works by deriving `Type` for the Rust types you want to export. // // `Serialize` and `Deserialize` are not required by Specta itself, but they are // common in real applications and allow Specta to understand serde attributes // when exporting through `specta_serde::Format` below. #[derive(Serialize, Deserialize, Type)] pub struct User { id: u32, name: String, // Serde attributes are respected when using `specta_serde::Format`. // This field will be exported to TypeScript as `emailAddress`. #[serde(rename = "emailAddress")] email_address: String, // Optional Rust values become `T | null` in TypeScript. avatar_url: Option, } #[derive(Serialize, Deserialize, Type)] pub struct Post { id: u32, title: String, author: User, tags: Vec, status: PostStatus, } #[derive(Serialize, Deserialize, Type)] #[serde(rename_all = "camelCase")] pub enum PostStatus { Draft, InReview, Published, } fn main() { // Register every root type you want to export. Specta automatically follows // references, so registering `Post` is enough to include `User` and // `PostStatus`, but registering roots explicitly is often clearer in apps. let types = Types::default() .register::() .register::() .register::(); // Export the registered Rust types as TypeScript definitions. // // `specta_serde::Format` tells Specta to apply serde's wire-format rules, // such as `rename`, `rename_all`, `tag`, `untagged`, and `flatten`. // // You can also use `specta_serde::FormatPhases` to allow types to be // narrowed based on if your serializing or deserializing. let output = Typescript::default() .export(&types, specta_serde::Format) .expect("failed to export TypeScript types"); println!("{output}"); } ================================================ FILE: examples/collect/Cargo.toml ================================================ [package] name = "example-collect" version = "0.0.0" edition = "2024" publish = false [dependencies] specta = { path = "../../specta", features = ["derive", "collect"] } specta-typescript = { path = "../../specta-typescript" } specta-serde = { path = "../../specta-serde" } ================================================ FILE: examples/collect/src/main.rs ================================================ #![allow(unused)] use specta::Type; use specta_typescript::Typescript; #[derive(Type)] pub struct User { id: String, name: String, } #[derive(Type)] pub struct Post { id: String, author: User, comments: Vec, } #[derive(Type)] pub struct Comment { body: String, } // This type can still derive `Type`, but it is left out of `specta::collect()`. #[derive(Type)] #[specta(collect = false)] pub struct InternalMetrics { latency_ms: u64, } fn main() -> Result<(), Box> { let output = Typescript::default().export(&specta::collect(), specta_serde::Format)?; println!("{output}"); Ok(()) } ================================================ FILE: examples/scratchpad/Cargo.toml ================================================ [package] name = "example-scratchpad" version = "0.0.0" edition = "2024" publish = false [dependencies] specta = { path = "../../specta", features = ["derive"] } specta-typescript = { path = "../../specta-typescript" } specta-serde = { path = "../../specta-serde" } serde = { version = "1", features = ["derive"] } ================================================ FILE: examples/scratchpad/src/main.rs ================================================ //! A playground for quickly reproducing issue. #![allow(warnings)] use specta::Types; fn main() { let mut types = Types::default(); let out = specta_typescript::Typescript::new() .export(&types, specta_serde::PhasesFormat) .unwrap(); println!("{}", out); } ================================================ FILE: specta/Cargo.toml ================================================ [package] name = "specta" description = "Easily export your Rust types to other languages" version = "2.0.0-rc.24" authors = ["Oscar Beaumont "] edition = "2024" license = "MIT" include = ["/src", "/examples", "/build.rs", "/LICENCE", "/README.md"] repository = "https://github.com/specta-rs/specta" documentation = "https://docs.rs/specta/latest/specta" keywords = ["async", "specta", "rspc", "typescript", "typesafe"] categories = ["web-programming", "asynchronous"] readme = "../README.md" # /bin/sh RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features [package.metadata."docs.rs"] all-features = true rustdoc-args = ["--cfg", "docsrs"] # Run `node ./.github/features.js` to update the docs [features] default = ["std"] #! Core Features ## Enable support for the Rust standard library. Enabled by default. std = [] ## Derive macros derive = ["dep:specta-macros"] ## Support for collecting up a global type map collect = ["dep:small_ctor", "specta-macros/DO_NOT_USE_collect"] #! Features ## Support for exporting the types of Rust functions. function = ["specta-macros?/DO_NOT_USE_function", "dep:paste"] #! Compatibility ## Support for [serde-json](https://github.com/serde-rs/json) serde_json = ["dep:serde_json"] ## Support for [serde_yaml](https://github.com/dtolnay/serde-yaml) serde_yaml = ["dep:serde_yaml"] ## Support for [toml](https://github.com/toml-rs/toml) toml = ["dep:toml", "std"] #! External types ## [uuid](https://docs.rs/uuid) crate uuid = ["dep:uuid"] ## [uuid](https://docs.rs/ulid) crate ulid = ["dep:ulid"] ## [chrono](https://docs.rs/chrono) crate chrono = ["dep:chrono"] ## [time](https://docs.rs/time) crate time = ["dep:time"] # [jiff](https://docs.rs/jiff) crate jiff = ["dep:jiff"] ## [bigdecimal](https://docs.rs/bigdecimal) crate bigdecimal = ["dep:bigdecimal"] ## [rust_decimal](https://docs.rs/rust_decimal) crate rust_decimal = ["dep:rust_decimal"] ## [indexmap](https://docs.rs/indexmap) crate indexmap = ["dep:indexmap"] ## [ordered-float](https://docs.rs/ordered-float) crate ordered-float = ["dep:ordered-float"] ## [heapless](https://docs.rs/heapless) crate heapless = ["dep:heapless"] ## [semver](https://docs.rs/semver) crate semver = ["dep:semver"] ## [smol_str](https://docs.rs/smol_str) crate smol_str = ["dep:smol_str"] ## [arrayvec](https://docs.rs/arrayvec) crate arrayvec = ["dep:arrayvec"] ## [smallvec](https://docs.rs/smallvec) crate smallvec = ["dep:smallvec"] ## [ipnetwork](https://docs.rs/ipnetwork) crate ipnetwork = ["dep:ipnetwork"] ## [mac_address](https://docs.rs/mac_address) crate mac_address = ["dep:mac_address"] ## [bit-vec](https://docs.rs/bit-vec) crate bit-vec = ["dep:bit-vec"] ## [bson](https://docs.rs/bson) crate bson = ["dep:bson"] ## [bytes](https://docs.rs/bytes) crate bytes = ["dep:bytes"] ## [uhlc](https://docs.rs/uhlc) crate uhlc = ["dep:uhlc"] ## [bytesize](https://docs.rs/bytesize) crate bytesize = ["dep:bytesize"] ## [glam](https://docs.rs/glam) crate glam = ["dep:glam"] ## [tokio](https://docs.rs/tokio) crate tokio = ["dep:tokio"] ## [url](https://docs.rs/url) crate url = ["dep:url"] ## [either](https://docs.rs/either) crate either = ["dep:either"] ## [error-stack](https://docs.rs/error-stack) crate error-stack = ["dep:error-stack"] # [bevy_ecs](https://docs.rs/bevy_ecs) crate bevy_ecs = ["dep:bevy_ecs"] # [bevy_input](https://docs.rs/bevy_input) crate bevy_input = ["dep:bevy_input", "dep:bevy_ecs", "dep:glam", "smol_str"] # [camino](https://docs.rs/camino) crate camino = ["dep:camino"] ## [geojson](https://docs.rs/geojson) crate geojson = ["dep:geojson", "serde_json"] [lints] workspace = true [dependencies] specta-macros = { version = "=2.0.0-rc.24", optional = true, path = "../specta-macros" } paste = { version = "1", optional = true } small_ctor = { version = "0.1.2", optional = true } # TODO: To be deprecated serde_json = { version = "1", optional = true, default-features = false, features = ["std"] } serde_yaml = { version = "0.9", optional = true, default-features = false, features = [] } toml = { version = "1.1", optional = true, default-features = false, features = ["serde"] } ulid = { version = "1", optional = true, default-features = false, features = [] } uuid = { version = "1", optional = true, default-features = false, features = [ ] } # TODO: Downgraded for Bevy (argh) chrono = { version = "0.4", optional = true, default-features = false, features = ["clock"] } time = { version = "0.3", optional = true, default-features = false, features = [] } bigdecimal = { version = "0.4", optional = true, default-features = false, features = [] } rust_decimal = { version = "1", optional = true, default-features = false, features = [] } indexmap = { version = "2", optional = true, default-features = false, features = [ "std", ] } # TODO: Don't require `std` ordered-float = { version = ">=3, <6", optional = true, default-features = false } heapless = { version = ">=0.7, <0.10", optional = true, default-features = false, features = [] } semver = { version = "1", optional = true, default-features = false, features = [] } smol_str = { version = "0.3", optional = true, default-features = false, features = [] } arrayvec = { version = ">=0.6, <0.8", optional = true, default-features = false, features = [] } smallvec = { version = "1", optional = true, default-features = false, features = [] } ipnetwork = { version = "0.21", optional = true, default-features = false, features = [] } mac_address = { version = "1", optional = true, default-features = false, features = [] } bit-vec = { version = "0.9", optional = true, default-features = false, features = [] } bson = { version = "3", optional = true, default-features = false, features = ["compat-3-0-0"] } bytes = { version = "1", optional = true, default-features = false, features = [] } uhlc = { version = "0.9", optional = true, default-features = false, features = [] } bytesize = { version = "2", optional = true, default-features = false, features = [] } glam = { version = "0.32", optional = true, default-features = false, features = ["std"] } tokio = { version = "1", optional = true, default-features = false, features = ["sync"] } url = { version = "2", optional = true, default-features = false } either = { version = "1", optional = true, default-features = false } error-stack = { version = "0.7", optional = true, default-features = false } bevy_ecs = { version = "0.18", optional = true, default-features = false, features = ["std"] } bevy_input = { version = "0.18", optional = true, default-features = false, features = [ "std", "bevy_reflect", "keyboard", "mouse", "touch", "gestures", "gamepad", ] } jiff = { version = "0.2", optional = true, default-features = false } camino = { version = "1", optional = true, default-features = false } geojson = { version = "1.0", optional = true, default-features = false } [build-dependencies] rustc_version = "0.4.1" [dev-dependencies] specta-serde = { path = "../specta-serde" } specta-typescript = { path = "../specta-typescript" } ================================================ FILE: specta/build.rs ================================================ //! Build script for configuring nightly-only cfg flags. //! //! This build script enables the `is_nightly` cfg when running on a nightly //! compiler (or when `RUSTC_BOOTSTRAP` is set) so crate code can conditionally //! compile nightly-specific behavior. //! //! It would be nice if this was built into Cargo 😅 fn main() { let is_nightly = std::env::var("RUSTC_BOOTSTRAP").is_ok() || rustc_version::version_meta() .map(|m| m.channel == rustc_version::Channel::Nightly) .unwrap_or(false); if is_nightly { println!("cargo:rustc-cfg=is_nightly"); } } ================================================ FILE: specta/src/collect.rs ================================================ use std::sync::{Mutex, OnceLock, PoisonError}; use crate::{Type, Types}; // Global type store for collecting custom types to export. // // We intentionally store functions over a `Types` directly to ensure any internal panics aren't done in CTOR. #[allow(clippy::type_complexity)] static TYPES: OnceLock>> = OnceLock::new(); /// Get the global type store containing all automatically collected types. /// /// All types with the [`Type`](macro@crate::Type) macro will automatically be registered here unless they have been explicitly disabled with `#[specta(collect = false)]`. /// /// Note that when enabling the `export` feature, you will not be able to enable the `unsafe_code` lint as [`small_ctor`] (which is used internally) is marked unsafe. /// /// # Example /// /// ```no_run /// use specta::Type; /// use specta_typescript::Typescript; /// /// #[derive(Type)] /// pub struct User { /// id: String, /// name: String, /// } /// /// #[derive(Type)] /// pub struct Post { /// id: String, /// author: User, /// comments: Vec, /// } /// /// #[derive(Type)] /// pub struct Comment { /// body: String, /// } /// /// // This type can still derive `Type`, but it is left out of `specta::collect()`. /// #[derive(Type)] /// #[specta(collect = false)] /// pub struct InternalMetrics { /// latency_ms: u64, /// } /// /// fn main() -> Result<(), Box> { /// let output = Typescript::default().export(&specta::collect(), specta_serde::Format)?; /// /// println!("{output}"); /// /// Ok(()) /// } /// ``` pub fn collect() -> Types { let types = TYPES .get_or_init(Default::default) .lock() .unwrap_or_else(PoisonError::into_inner); let mut map = Types::default(); for export in types.iter() { export(&mut map); } map } #[doc(hidden)] pub mod internal { use super::*; // Called within ctor functions to register a type. pub fn register() { TYPES .get_or_init(Default::default) .lock() .unwrap_or_else(PoisonError::into_inner) .push(|types| { // The side-effect of this is registering the type. T::definition(types); }); } // We expose this for the macros #[cfg(feature = "collect")] pub use small_ctor; } ================================================ FILE: specta/src/datatype/attributes.rs ================================================ use std::{ any::Any, borrow::Cow, collections::{HashMap, hash_map::DefaultHasher}, fmt, hash::{Hash, Hasher}, sync::Arc, }; trait DynAttributeValue: Send + Sync { fn value_any(&self) -> &dyn Any; fn eq_dyn(&self, other: &dyn DynAttributeValue) -> bool; fn hash_dyn(&self, state: &mut dyn Hasher); fn fmt_dyn(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result; } struct NamedAttributeValue(T); impl DynAttributeValue for NamedAttributeValue where T: Any + Clone + Eq + Hash + fmt::Debug + Send + Sync + 'static, { fn value_any(&self) -> &dyn Any { &self.0 } fn eq_dyn(&self, other: &dyn DynAttributeValue) -> bool { other .value_any() .downcast_ref::() .is_some_and(|other| self.0 == *other) } fn hash_dyn(&self, state: &mut dyn Hasher) { let mut hasher = DefaultHasher::new(); self.0.hash(&mut hasher); state.write_u64(hasher.finish()); } fn fmt_dyn(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } /// A named map of type-erased metadata attached to datatype nodes. /// /// `Attributes` is primarily used by advanced consumers that need to inspect /// metadata recorded on [`DataType`](super::DataType) nodes at runtime. Each /// entry is stored under a string key and can later be retrieved either as a /// raw [`Any`] value or by downcasting to the original type. /// /// Stored values must be owned and implement [`Clone`], [`Eq`], [`Hash`], and /// [`fmt::Debug`] so attributes remain comparable, hashable, and printable as /// part of the surrounding datatype graph. /// #[derive(Default)] pub struct Attributes(HashMap, Arc>); impl Clone for Attributes { fn clone(&self) -> Self { Self( self.0 .iter() .map(|(key, value)| (key.clone(), value.clone())) .collect(), ) } } impl Attributes { /// Returns the number of stored attribute entries. pub fn len(&self) -> usize { self.0.len() } /// Returns `true` when the collection has no entries. pub fn is_empty(&self) -> bool { self.0.is_empty() } /// Inserts or replaces an attribute value. /// /// Values are stored in a type-erased form, but they must still implement /// [`Clone`], [`Eq`], [`Hash`], and [`fmt::Debug`] so the containing /// [`Attributes`] remains cloneable, comparable, hashable, and printable. /// pub fn insert(&mut self, key: impl Into>, value: T) where T: Any + Clone + Eq + Hash + fmt::Debug + Send + Sync + 'static, { self.0 .insert(key.into(), Arc::new(NamedAttributeValue(value))); } /// Extends `self` with entries from `other`. /// /// If both collections contain the same key, the value from `other` /// replaces the existing entry in `self`. /// pub fn extend(&mut self, other: Self) { self.0.extend(other.0); } /// Removes the entry under `key`, returning `true` when an entry was /// present. /// pub fn remove(&mut self, key: &str) -> bool { self.0.remove(key).is_some() } /// Returns `true` if an attribute entry is present for `key`. pub fn contains_key(&self, key: &str) -> bool { self.0.contains_key(key) } /// Returns the raw type-erased value for a named attribute. /// /// This is useful when the expected type is not known until runtime. /// Prefer [`Attributes::get_named_as`] when you know the concrete type. /// pub fn get_named(&self, key: &str) -> Option<&dyn Any> { self.0.get(key).map(|value| value.value_any()) } /// Returns a typed reference to the named attribute value. /// /// Returns `None` when the key is missing or when the stored value has a /// different type than `T`. /// pub fn get_named_as(&self, key: &str) -> Option<&T> { self.0 .get(key) .and_then(|value| value.value_any().downcast_ref::()) } } impl PartialEq for Attributes { fn eq(&self, other: &Self) -> bool { self.0.len() == other.0.len() && self.0.iter().all(|(key, value)| { other .0 .get(key) .is_some_and(|other| value.eq_dyn(other.as_ref())) }) } } impl Eq for Attributes {} impl Hash for Attributes { fn hash(&self, state: &mut H) { let mut entries = self .0 .iter() .map(|(key, value)| { let mut hasher = DefaultHasher::new(); key.hash(&mut hasher); value.hash_dyn(&mut hasher); hasher.finish() }) .collect::>(); entries.sort_unstable(); self.0.len().hash(state); entries.hash(state); } } impl fmt::Debug for Attributes { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut entries = self.0.iter().collect::>(); entries.sort_by(|(left, _), (right, _)| left.cmp(right)); let mut map = f.debug_map(); for (key, value) in entries { map.entry(key, &fmt::from_fn(|f| value.fmt_dyn(f))); } map.finish() } } ================================================ FILE: specta/src/datatype/enum.rs ================================================ use std::borrow::Cow; use crate::datatype::Field; use super::{Attributes, DataType, Deprecated, Fields, NamedFields, UnnamedFields}; /// Runtime representation of a Rust [`enum`](https://doc.rust-lang.org/std/keyword.enum.html). /// /// Enums are configured with a set of variants, each with a name and a type. /// The variants can be either unit variants (no fields), tuple variants (fields in a tuple), or struct variants (fields in a struct). /// /// Each variant has a name and one of the layouts described by [`Fields`]. /// Format integrations may use [`Enum::attributes`] to record representation /// metadata, such as Serde's enum representation attributes. #[derive(Default, Debug, Clone, PartialEq, Eq, Hash)] #[non_exhaustive] pub struct Enum { /// Named variants in source order. pub variants: Vec<(Cow<'static, str>, Variant)>, /// Macro attributes applied to the enum container. pub attributes: Attributes, } impl From for DataType { fn from(t: Enum) -> Self { Self::Enum(t) } } /// Runtime representation of a single enum variant. #[derive(Debug, Clone, PartialEq, Eq, Hash)] #[non_exhaustive] pub struct Variant { /// Whether the variant was skipped with an attribute such as /// `#[serde(skip)]` or `#[specta(skip)]`. /// /// You might think, well why not apply this in the macro and just not emit the variant? /// Well in Serde `A(String)` and `A(#[serde(skip)] (), String)` export as different Typescript types so the exporter needs runtime knowledge of this. pub skip: bool, /// Documentation comments for the variant. pub docs: Cow<'static, str>, /// Deprecated metadata for the variant. pub deprecated: Option, /// The type of the variant. pub fields: Fields, /// Runtime attributes for this variant. pub attributes: Attributes, } impl Variant { /// Constructs a unit enum variant. pub fn unit() -> Self { Self { skip: false, docs: "".into(), deprecated: None, fields: Fields::Unit, attributes: Attributes::default(), } } /// Starts building a struct enum variant with named fields. pub fn named() -> VariantBuilder { VariantBuilder { v: Self { skip: false, docs: "".into(), deprecated: None, fields: Fields::Named(NamedFields { fields: Default::default(), }), attributes: Attributes::default(), }, variant: NamedFields { fields: vec![] }, } } /// Starts building a tuple enum variant with unnamed fields. pub fn unnamed() -> VariantBuilder { VariantBuilder { v: Self { skip: false, docs: "".into(), deprecated: None, fields: Fields::Unnamed(UnnamedFields { fields: Default::default(), }), attributes: Attributes::default(), }, variant: UnnamedFields { fields: Default::default(), }, } } } /// Builder for constructing [`Variant`] values. #[derive(Debug, Clone)] pub struct VariantBuilder { pub(crate) v: Variant, pub(crate) variant: V, } impl VariantBuilder { /// Marks the variant as skipped. pub fn skip(mut self) -> Self { self.v.skip = true; self } /// Sets documentation for the variant. pub fn docs(mut self, docs: Cow<'static, str>) -> Self { self.v.docs = docs; self } /// Sets deprecation metadata for the variant. pub fn deprecated(mut self, reason: Deprecated) -> Self { self.v.deprecated = Some(reason); self } /// Sets runtime attributes on the variant. pub fn attributes(mut self, attributes: Attributes) -> Self { self.v.attributes = attributes; self } /// Sets runtime attributes on the variant in-place. pub fn attributes_mut(&mut self, attributes: Attributes) { self.v.attributes = attributes; } } impl VariantBuilder { /// Adds an unnamed field to the variant. pub fn field(mut self, field: Field) -> Self { self.variant.fields.push(field); self } /// Adds an unnamed field to the variant and returns the updated builder. pub fn field_mut(mut self, field: Field) -> Self { self.variant.fields.push(field); self } /// Finalizes the unnamed variant builder into a [`Variant`]. pub fn build(mut self) -> Variant { self.v.fields = Fields::Unnamed(self.variant); self.v } } impl VariantBuilder { /// Adds a named field to the variant. pub fn field(mut self, name: impl Into>, field: Field) -> Self { self.variant.fields.push((name.into(), field)); self } /// Adds a named field to the variant and returns the updated builder. pub fn field_mut(mut self, name: impl Into>, field: Field) -> Self { self.variant.fields.push((name.into(), field)); self } /// Finalizes the named variant builder into a [`Variant`]. pub fn build(mut self) -> Variant { self.v.fields = Fields::Named(self.variant); self.v } } impl From> for Variant { fn from(val: VariantBuilder) -> Self { val.build() } } ================================================ FILE: specta/src/datatype/fields.rs ================================================ //! Field types are used by both enums and structs. use crate::datatype::Struct; use super::{Attributes, DataType, Deprecated}; use std::borrow::Cow; /// Field layout for a struct or enum variant. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum Fields { /// Unit struct. /// /// Represented in Rust as `pub struct Unit;` and in TypeScript as `null`. Unit, /// Struct with unnamed fields. /// /// Represented in Rust as `pub struct Unit();` and in TypeScript as `[]`. Unnamed(UnnamedFields), /// Struct with named fields. /// /// Represented in Rust as `pub struct Unit {}` and in TypeScript as `{}`. Named(NamedFields), } /// Metadata for a struct field or enum variant field. #[derive(Default, Debug, Clone, PartialEq, Eq, Hash)] #[non_exhaustive] pub struct Field { /// Whether the field was marked optional, for example with /// `#[specta(optional)]`. pub optional: bool, /// Deprecated attribute for the field. pub deprecated: Option, /// Documentation comments for the field. pub docs: Cow<'static, str>, /// Runtime attributes for this field. pub attributes: Attributes, /// Type for the field. /// /// This is `None` when the field was skipped with an attribute such as /// `#[serde(skip)]` or `#[specta(skip)]`. Exporters should preserve enough /// information to distinguish skipped fields from absent fields because some /// serialization formats still let skipped fields affect layout. /// /// You might think, well why not apply this in the macro and just not emit the variant? /// Well in Serde `A(String)` and `A(#[serde(skip)] (), String)` export as different Typescript types so the exporter needs runtime knowledge of this. pub ty: Option, } impl Field { /// Constructs a new non-optional field with the given type. /// /// Use [`Field::default`] to construct skipped-field metadata where `ty` is /// initially `None`. pub fn new(ty: DataType) -> Self { Field { optional: false, deprecated: None, docs: "".into(), ty: Some(ty), attributes: Attributes::default(), } } } /// Fields for an unnamed tuple struct or tuple enum variant. #[derive(Debug, Clone, PartialEq, Eq, Hash)] #[non_exhaustive] pub struct UnnamedFields { /// Field metadata in source order. pub fields: Vec, } /// Fields for a named struct or struct enum variant. #[derive(Debug, Clone, PartialEq, Eq, Hash)] #[non_exhaustive] pub struct NamedFields { /// Field names and metadata in source order. pub fields: Vec<(Cow<'static, str>, Field)>, } #[derive(Debug, Clone)] /// Builder for constructing [`DataType::Struct`] values. /// /// The type parameter tracks whether the builder is currently collecting named /// or unnamed fields. pub struct StructBuilder { pub(crate) fields: F, } impl StructBuilder { /// Adds a named field and returns the updated builder. pub fn field(mut self, name: impl Into>, field: Field) -> Self { self.fields.fields.push((name.into(), field)); self } /// Adds a named field in-place. pub fn field_mut(&mut self, name: impl Into>, field: Field) { self.fields.fields.push((name.into(), field)); } /// Finalizes this builder into a [`DataType::Struct`] with named fields. pub fn build(self) -> DataType { DataType::Struct(Struct { fields: Fields::Named(self.fields), attributes: Default::default(), }) } } impl StructBuilder { /// Adds an unnamed field and returns the updated builder. pub fn field(mut self, field: Field) -> Self { self.fields.fields.push(field); self } /// Adds an unnamed field in-place. pub fn field_mut(&mut self, field: Field) { self.fields.fields.push(field); } /// Finalizes this builder into a [`DataType::Struct`] with unnamed fields. pub fn build(self) -> DataType { DataType::Struct(Struct { fields: Fields::Unnamed(self.fields), attributes: Default::default(), }) } } ================================================ FILE: specta/src/datatype/function.rs ================================================ use std::borrow::Cow; use super::{DataType, Deprecated}; /// Runtime type information for a function annotated with `#[specta]`. /// /// Values are produced by [`fn_datatype!`](crate::function::fn_datatype) and /// [`collect_functions!`](crate::function::collect_functions). Function metadata /// is intentionally separate from [`Types`](crate::Types): the function's /// argument and result datatypes reference entries collected into the `Types` /// value passed to those macros. #[derive(Debug, Clone)] #[non_exhaustive] pub struct Function { /// Whether the function is async. pub asyncness: bool, /// The function's name. pub name: Cow<'static, str>, /// The name and type of each of the function's arguments. pub args: Vec<(Cow<'static, str>, DataType)>, /// The return type of the function. pub result: Option, /// The function's documentation. Detects both `///` and `#[doc = ...]` style documentation. pub docs: Cow<'static, str>, /// The deprecated status of the function. pub deprecated: Option, } impl Function { /// Whether the function is async. pub fn asyncness(&self) -> bool { self.asyncness } /// The function's name. pub fn name(&self) -> &str { &self.name } /// The name and type of each of the function's arguments. pub fn args(&self) -> &[(Cow<'static, str>, DataType)] { &self.args } /// The return type of the function. pub fn result(&self) -> Option<&DataType> { self.result.as_ref() } } ================================================ FILE: specta/src/datatype/generic.rs ================================================ use std::borrow::Cow; use crate::datatype::DataType; /// Reference to a named generic parameter. /// /// Exporters usually render this as the generic name, such as `T`. /// /// # Invariants /// /// A `Generic` should only appear inside the canonical `ty` field of the /// [`NamedDataType`](crate::datatype::NamedDataType) that declares it. Ordinary /// [`Type::definition`](crate::Type::definition) results should use concrete /// datatypes or references with instantiated generics. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Generic(Cow<'static, str>); impl Generic { /// Builds a new generic parameter reference with the given source-level name. /// /// The same name must appear in the parent [`GenericDefinition`] list. pub const fn new(name: Cow<'static, str>) -> Self { Self(name) } /// The source-level name of this generic parameter. pub fn name(&self) -> &Cow<'static, str> { &self.0 } /// Get a stable reference identifier for this generic parameter. pub fn reference(&self) -> Self { self.clone() } } impl From for DataType { fn from(v: Generic) -> Self { DataType::Generic(v) } } /// Metadata describing a generic parameter declared by a /// [`NamedDataType`](crate::datatype::NamedDataType). #[derive(Debug, Clone, PartialEq, Eq, Hash)] #[non_exhaustive] pub struct GenericDefinition { /// The source-level name of the generic parameter. pub name: Cow<'static, str>, /// An optional default type for the generic parameter. pub default: Option, } impl GenericDefinition { /// Constructs metadata for a generic parameter. pub const fn new(name: Cow<'static, str>, default: Option) -> Self { Self { name, default } } /// Get a stable reference identifier for this generic parameter. pub fn reference(&self) -> Generic { Generic::new(self.name.clone()) } } ================================================ FILE: specta/src/datatype/list.rs ================================================ use super::DataType; /// Sequential collection type, such as [`Vec`](std::vec::Vec), arrays, slices, /// or set-like collections. #[derive(Debug, Clone, PartialEq, Eq, Hash)] #[non_exhaustive] pub struct List { /// Type of each element in the list. pub ty: Box, /// Fixed number of elements when known. /// /// `None` represents a variable-length collection. pub length: Option, /// Whether elements are expected to be unique, as with set-like types. pub unique: bool, } impl List { /// Create a new list of a given type. pub fn new(ty: DataType) -> Self { Self { ty: Box::new(ty), length: None, unique: false, } } } impl From for DataType { fn from(t: List) -> Self { Self::List(t) } } ================================================ FILE: specta/src/datatype/literal.rs ================================================ //! This works but isn't being shipped for now as we don't need it for const generics anymore. //! Also it suffers from the following concerns: //! - For a floating point number if it's a `NaN` or `Infinity` or `-Infinity` we should yield an error in the Typescript exporter as we can't export it to a Typescript type. //! - What do we do about bigint primitives. Mainly Tauri Specta/TauRPC need to be able to deal with this somehow? //! use std::{ any::Any, borrow::Cow, fmt, hash::{self, Hash}, sync::Arc, }; use crate::{ Type, Types, datatype::{DataType, Reference}, }; /// A type-erased literal value stored inside an opaque [`Reference`]. #[derive(Clone)] pub struct Literal(Arc); impl Literal { /// Construct a literal [`DataType`] from a concrete value. /// /// T can be any of [`i8`], [`i16`], [`i32`], [`i64`], [`i128`], [`isize`], [`u8`], [`u16`], [`u32`], [`u64`], [`u128`], [`usize`], [`f32`], [`f64`], [`bool`], [`char`], [`&'static str`], [`String`], [`Cow<'static, str>`]. /// /// On nightly, [`f16`] and [`f128`] are also supported. pub fn new(value: T) -> DataType { DataType::Reference(Reference::opaque(Literal::from(value))) } /// Returns the underlying datatype represented by this literal value. pub fn definition(&self, types: &mut Types) -> DataType { self.0.definition(types) } /// Attempt to downcast the stored literal to a concrete type. pub fn downcast_ref(&self) -> Option<&T> { self.0.as_any().downcast_ref::() } } /// Trait used by type-erased literal values. /// /// Sealed so we can add implementations in minor releases pub trait LiteralType: Any + Send + Sync + 'static { /// Returns the underlying datatype represented by this literal value. fn definition(&self, types: &mut Types) -> DataType; fn eq_dyn(&self, other: &dyn LiteralType) -> bool; fn hash_dyn(&self, state: &mut dyn hash::Hasher); fn fmt_dyn(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result; fn as_any(&self) -> &dyn Any; } impl From for Literal { fn from(value: T) -> Self { Self(Arc::new(value)) } } impl fmt::Debug for Literal { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt_dyn(f) } } impl PartialEq for Literal { fn eq(&self, other: &Self) -> bool { self.0.eq_dyn(other.0.as_ref()) } } impl Eq for Literal {} impl hash::Hash for Literal { fn hash(&self, state: &mut H) { self.0.hash_dyn(state) } } macro_rules! impl_literal_type { ($($ty:ty),+ $(,)?) => { $( impl LiteralType for $ty { fn definition(&self, types: &mut Types) -> DataType { <$ty as Type>::definition(types) } fn eq_dyn(&self, other: &dyn LiteralType) -> bool { other.as_any().downcast_ref::() == Some(self) } fn hash_dyn(&self, mut state: &mut dyn hash::Hasher) { Hash::hash(self, &mut state); } fn fmt_dyn(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(self, f) } fn as_any(&self) -> &dyn Any { self } } )+ }; } impl_literal_type!( i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize, bool, char, &'static str, String, Cow<'static, str>, ); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] enum FloatKey { NegInfinity, NegZero, Finite(Bits), Infinity, NaN, } trait FloatLiteral: Copy + PartialEq + Type + fmt::Debug + Send + Sync + 'static { type Bits: Copy + Eq + Hash; const INFINITY: Self; const NEG_INFINITY: Self; const NEG_ZERO_BITS: Self::Bits; fn is_nan(self) -> bool; fn is_negative_zero(self) -> bool; fn to_bits(self) -> Self::Bits; } impl From for FloatKey { fn from(value: T) -> Self { if value.is_nan() { Self::NaN } else if value == T::INFINITY { Self::Infinity } else if value == T::NEG_INFINITY { Self::NegInfinity } else if value.is_negative_zero() { Self::NegZero } else { Self::Finite(value.to_bits()) } } } macro_rules! impl_float_literal { ($ty:ty, $bits:ty) => { impl FloatLiteral for $ty { type Bits = $bits; const INFINITY: Self = <$ty>::INFINITY; const NEG_INFINITY: Self = <$ty>::NEG_INFINITY; const NEG_ZERO_BITS: Self::Bits = (-0.0 as $ty).to_bits(); fn is_nan(self) -> bool { self.is_nan() } fn is_negative_zero(self) -> bool { self.to_bits() == Self::NEG_ZERO_BITS } fn to_bits(self) -> Self::Bits { self.to_bits() } } impl LiteralType for $ty { fn definition(&self, types: &mut Types) -> DataType { <$ty as Type>::definition(types) } fn eq_dyn(&self, other: &dyn LiteralType) -> bool { other .as_any() .downcast_ref::() .is_some_and(|other| FloatKey::from(*self) == FloatKey::from(*other)) } fn hash_dyn(&self, mut state: &mut dyn hash::Hasher) { FloatKey::from(*self).hash(&mut state); } fn fmt_dyn(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(self, f) } fn as_any(&self) -> &dyn Any { self } } }; } impl_float_literal!(f32, u32); impl_float_literal!(f64, u64); #[cfg(is_nightly)] impl_float_literal!(f16, u16); #[cfg(is_nightly)] impl_float_literal!(f128, u128); ================================================ FILE: specta/src/datatype/map.rs ================================================ use super::DataType; /// Key-value collection type, such as [`HashMap`](std::collections::HashMap) or /// another map-like container. /// /// The first datatype is the key type and the second datatype is the value type. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Map(Box<(DataType, DataType)>); impl Map { /// Create a new map with the given key and value types. pub fn new(key_ty: DataType, value_ty: DataType) -> Self { Self(Box::new((key_ty, value_ty))) } /// The type of the map keys. pub fn key_ty(&self) -> &DataType { &self.0.0 } /// Get a mutable reference to the type of the map keys. pub fn key_ty_mut(&mut self) -> &mut DataType { &mut self.0.0 } /// Set the type of the map keys. pub fn set_key_ty(&mut self, key_ty: DataType) { self.0.0 = key_ty; } /// The type of the map values. pub fn value_ty(&self) -> &DataType { &self.0.1 } /// Get a mutable reference to the type of the map values. pub fn value_ty_mut(&mut self) -> &mut DataType { &mut self.0.1 } /// Set the type of the map values. pub fn set_value_ty(&mut self, value_ty: DataType) { self.0.1 = value_ty; } } impl From for DataType { fn from(t: Map) -> Self { Self::Map(t) } } ================================================ FILE: specta/src/datatype/named.rs ================================================ use std::{ borrow::Cow, hash::{DefaultHasher, Hash, Hasher}, mem, panic::{self, AssertUnwindSafe, Location}, ptr, sync::Arc, }; use crate::{ Types, datatype::{ DataType, Generic, NamedReference, NamedReferenceType, Reference, generic::GenericDefinition, reference::NamedId, }, }; /// Resolves any named types created by `func` as inline references. /// This is emitted when `#[specta(inline)]` is used on a field so the inner fields `Type` implementation knows to inline. pub fn inline(types: &mut Types, func: impl FnOnce(&mut Types) -> R) -> R { let prev = mem::replace(&mut types.should_inline, true); let result = panic::catch_unwind(AssertUnwindSafe(|| func(types))); types.should_inline = prev; match result { Ok(result) => result, Err(payload) => panic::resume_unwind(payload), } } /// Named datatype with its own export identity. /// /// Exporters commonly render these as top-level declarations, such as /// `export type MyType = ...` in TypeScript. Other datatypes refer back to a /// named datatype through [`Reference::Named`]. /// /// # Invariants /// /// The `id` is the stable identity used by [`Types`] and [`NamedReference`]. The /// human-readable `name` alone is not guaranteed to be globally unique. #[derive(Debug, Clone, PartialEq, Eq)] #[non_exhaustive] pub struct NamedDataType { /// Stable identity for resolving references to this datatype. pub(crate) id: NamedId, /// Exported type name. pub name: Cow<'static, str>, /// Documentation comments attached to the source type. pub docs: Cow<'static, str>, /// Deprecation metadata attached to the source type. pub deprecated: Option, /// Rust module path where the source type was defined. pub module_path: Cow<'static, str>, /// Source location where this named datatype was created. pub location: Location<'static>, /// Generic parameters declared by this named datatype. pub generics: Cow<'static, [GenericDefinition]>, /// The generalised datatype of this specific named data type. /// This is what will be used for creating `export Type = ...;` statements. /// /// This will be `None` for types which are container inlined as they aren't exported. pub ty: Option, } impl NamedDataType { /// Constructs a new named datatype and register it into the [`Types`] collection. #[track_caller] pub fn new( name: impl Into>, types: &mut Types, build: impl FnOnce(&mut Types, &mut NamedDataType), ) -> Self { let location = Location::caller(); let mut ndt = Self { id: NamedId::Dynamic(Arc::new(())), name: name.into(), docs: Cow::Borrowed(""), deprecated: None, module_path: file_path_to_module_path(location.file()) .map(Into::into) .unwrap_or(Cow::Borrowed("virtual")), location: location.to_owned(), generics: Cow::Borrowed(&[]), ty: None, }; build(types, &mut ndt); types.types.insert(ndt.id.clone(), Some(ndt.clone())); types.len += 1; ndt } /// Initializes a named type using a static sentinel as its identity. /// /// This is used by `#[derive(Type)]` and the built-in `Type` implementation macros and must be used carefully. /// ///
/// /// **WARNING:** Do not call this outside of `specta` as its signature and behavior may change in minor releases!!!! /// ///
/// /// This registers the canonical [`NamedDataType`] for `sentinel` at most once, then returns a /// use-site [`Reference`]. During first registration, `None` is inserted into [`Types`] before /// `build_ndt` runs so recursive named lookups can observe that the type is already being /// resolved instead of re-entering `build_ndt` (which would stack overflow). /// /// The returned reference depends on the current inline context: /// /// - When not inlining, this returns [`NamedReferenceType::Reference`] with /// `instantiation_generics` as the concrete generic arguments for this use site. /// - When inlining, this calls `build_ty` and returns [`NamedReferenceType::Inline`] containing /// the resulting datatype. /// - If inline expansion recursively reaches the same sentinel and generic arguments, this /// returns [`NamedReferenceType::Recursive`] so exporters can avoid infinite expansion. /// /// `has_const_param` only affects the temporary resolution context used while `build_ndt` /// builds the canonical named type. That context controls implementations such as fixed-size /// arrays, so they intentionally don't become part of the global type identity /// (We don't want one call-sites const generic in the shared datatype on the `NamedDataType`). /// /// `passthrough` is for wrapper/container types whose own definition is inline but whose inner /// type should only see the caller's inline context. When passthrough expansion recursively /// reaches the same wrapper, it clears `Types::should_inline` before calling `build_ty` so the /// inner named type can break the cycle with a reference. /// /// `build_ndt` fills metadata and, for exported named types, `NamedDataType::ty`. `build_ty` /// builds the datatype used by inline references. If `build_ndt` panics, this removes the /// placeholder entry and restores the previous resolution context before resuming the panic. #[doc(hidden)] #[track_caller] pub fn init_with_sentinel( sentinel: &'static str, instantiation_generics: &[(Generic, DataType)], has_const_param: bool, passthrough: bool, types: &mut Types, build_ndt: fn(&mut Types, &mut NamedDataType), mut build_ty: fn(&mut Types) -> DataType, ) -> Reference { let id = NamedId::Static(sentinel); let location = Location::caller().to_owned(); let caller_inline = types.should_inline; let mut inline = caller_inline || passthrough; // If we have never encountered this type, register it to type map if !types.types.contains_key(&id) { let mut ndt = NamedDataType { id: id.clone(), location, // `build_ndt` will just override all of this. generics: Cow::Borrowed(&[]), ty: None, name: Cow::Borrowed(""), docs: Cow::Borrowed(""), deprecated: None, module_path: Cow::Borrowed(""), }; types.types.insert(id.clone(), None); let prev_inline = mem::replace(&mut types.should_inline, false); let prev_has_const_params = mem::replace(&mut types.has_const_params, has_const_param); let result = panic::catch_unwind(AssertUnwindSafe(|| build_ndt(types, &mut ndt))); types.should_inline = prev_inline; types.has_const_params = prev_has_const_params; if let Err(payload) = result { if types.types.contains_key(&id) { types.types.remove(&id); } panic::resume_unwind(payload); }; // We patch the Tauri `Type` implementation. let is_tauri_type = ndt.name == "TAURI_CHANNEL" && ndt.module_path.starts_with("tauri::"); if is_tauri_type { ndt.ty = None; inline = true; build_ty = |_| { unreachable!("Specta `build_ty` shouldn't be callable with `tauri::Channel`") } } types.types.insert(id.clone(), Some(ndt)); types.len += 1; // We patch the Tauri `Type` implementation. if is_tauri_type { return Reference::Named(NamedReference { id, inner: NamedReferenceType::Reference { generics: instantiation_generics.to_owned(), }, }); } } if inline { let hash = { let mut h = DefaultHasher::new(); sentinel.hash(&mut h); ptr::hash(sentinel, &mut h); for (generic_r, generic) in instantiation_generics { generic_r.hash(&mut h); generic.hash(&mut h); } h.finish() }; if types.stack.contains(&hash) { // For container inline types we wanna passthrough instead of rejecting on the container. if passthrough { let prev_inline = mem::replace(&mut types.should_inline, false); let result = panic::catch_unwind(AssertUnwindSafe(|| build_ty(types))); types.should_inline = prev_inline; match result { Ok(DataType::Reference(reference)) => return reference, Ok(_) => {} Err(payload) => panic::resume_unwind(payload), } } return Reference::Named(NamedReference { id, inner: NamedReferenceType::Recursive, }); } // Say for `Box` if we put `#[specta(inline)]` on it we will, // naively inline the `Box` instead of `T`. // // "wrapper" types enable this to properly to passthrough inline to the inner type's resolution. let child_inline = passthrough && caller_inline; let prev_inline = (types.should_inline != child_inline) .then(|| mem::replace(&mut types.should_inline, child_inline)); types.stack.push(hash); let result = panic::catch_unwind(AssertUnwindSafe(|| build_ty(types))); if let Some(prev_inline) = prev_inline { types.should_inline = prev_inline; }; types.stack.pop(); let dt = match result { Ok(DataType::Reference(reference)) if passthrough && !caller_inline => { return reference; } Ok(dt) => Box::new(dt), Err(payload) => panic::resume_unwind(payload), }; Reference::Named(NamedReference { id, inner: NamedReferenceType::Inline { dt }, }) } else { Reference::Named(NamedReference { id, inner: NamedReferenceType::Reference { generics: instantiation_generics.to_owned(), }, }) } } /// Constructs a [`Reference`] to this named datatype. /// The reference returned by this will error in the language exporter if `Self.ty` is `None` as the type can't generate a named export. pub fn reference(&self, generics: Vec<(Generic, DataType)>) -> Reference { Reference::Named(NamedReference { id: self.id.clone(), inner: NamedReferenceType::Reference { generics }, }) } } /// Runtime representation of Rust's `#[deprecated]` metadata. #[derive(Debug, Clone, Default, PartialEq, Eq, Hash)] #[non_exhaustive] pub struct Deprecated { /// Optional deprecation note or replacement guidance. pub note: Option>, /// Optional version where the item became deprecated. pub since: Option>, } impl Deprecated { /// Constructs deprecation metadata without details. /// /// Corresponds to `#[deprecated]`. pub const fn new() -> Self { Self { note: None, since: None, } } /// Constructs deprecation metadata with a note. /// /// Corresponds to `#[deprecated = "Use something else"]`. pub fn with_note(note: Cow<'static, str>) -> Self { Self { note: Some(note), since: None, } } /// Constructs deprecation metadata with a note and optional `since` version. /// /// Corresponds to `#[deprecated(since = "1.0.0", note = "Use something else")]`. pub fn with_since_note(since: Option>, note: Cow<'static, str>) -> Self { Self { note: Some(note), since, } } } fn file_path_to_module_path(file_path: &str) -> Option { let normalized = file_path.replace('\\', "/"); // Try different prefixes let (prefix, path) = if let Some(p) = normalized.strip_prefix("src/") { ("crate", p) } else if let Some(p) = normalized.strip_prefix("tests/") { ("tests", p) } else { return None; }; let path = path.strip_suffix(".rs")?; let path = path.strip_suffix("/mod").unwrap_or(path); let module_path = path.replace('/', "::"); if module_path.is_empty() { Some(prefix.to_string()) } else { Some(format!("{}::{}", prefix, module_path)) } } #[cfg(test)] mod tests { use super::file_path_to_module_path; #[test] fn file_path_to_module_path_supports_unix_and_windows_separators() { assert_eq!( file_path_to_module_path("src/datatype/named.rs"), Some("crate::datatype::named".to_string()) ); assert_eq!( file_path_to_module_path("src\\datatype\\named.rs"), Some("crate::datatype::named".to_string()) ); assert_eq!( file_path_to_module_path("tests/tests/types.rs"), Some("tests::tests::types".to_string()) ); assert_eq!( file_path_to_module_path("tests\\tests\\types.rs"), Some("tests::tests::types".to_string()) ); } } ================================================ FILE: specta/src/datatype/primitive.rs ================================================ use super::DataType; /// Rust built-in primitive type. #[allow(non_camel_case_types)] #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum Primitive { /// [`i8`] primitive. i8, /// [`i16`] primitive. i16, /// [`i32`] primitive. i32, /// [`i64`] primitive. i64, /// [`i128`] primitive. i128, /// [`isize`] primitive. isize, /// [`u8`] primitive. u8, /// [`u16`] primitive. u16, /// [`u32`] primitive. u32, /// [`u64`] primitive. u64, /// [`u128`] primitive. u128, /// [`usize`] primitive. usize, /// [`f16`] primitive (nightly-only). f16, /// [`f32`] primitive. f32, /// [`f64`] primitive. f64, /// [`f128`] primitive (nightly-only). f128, /// [`bool`] primitive. bool, /// [`char`] primitive. char, /// [`str`] primitive. str, } impl From for DataType { fn from(t: Primitive) -> Self { Self::Primitive(t) } } ================================================ FILE: specta/src/datatype/reference.rs ================================================ use std::{ any::{Any, TypeId}, fmt, hash, sync::Arc, }; use crate::datatype::Generic; use super::DataType; /// Reference to another datatype. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum Reference { /// Reference to a named type collected in a [`Types`](crate::Types). /// /// This can either render as a named reference, such as `TypeName`, or as /// an inlined datatype depending on [`NamedReference::inner`]. Named(NamedReference), /// Reference to an opaque exporter-specific type. Opaque(OpaqueReference), } /// Reference to a [`NamedDataType`](crate::datatype::NamedDataType). #[derive(Debug, Clone, PartialEq, Eq, Hash)] #[non_exhaustive] pub struct NamedReference { pub(crate) id: NamedId, /// How this named type should be referenced at the use site. pub inner: NamedReferenceType, } /// Use-site representation for a [`NamedReference`]. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum NamedReferenceType { /// Recursive reference encountered while resolving an inline type. /// /// Exporters can use this marker to avoid infinitely expanding recursive /// inline definitions that they would stack overflow resolving. Recursive, /// Inline the contained datatype at the reference site. /// These are emitted when `#[specta(inline)]` is used on a field or container. #[non_exhaustive] Inline { /// Datatype to render in place of the named reference. dt: Box, }, /// Render a reference to the named datatype. #[non_exhaustive] Reference { /// Concrete generic arguments for this use site. generics: Vec<(Generic, DataType)>, }, } /// Reference to a type not understood by Specta's core datatype model. /// /// These are implemented by the language exporter to implement cool features like /// [`specta_typescript::branded!`](https://docs.rs/specta-typescript/latest/specta_typescript/macro.branded.html), /// [`specta_typescript::define`](https://docs.rs/specta-typescript/latest/specta_typescript/fn.define.html), and more. /// /// # Invariants /// /// Equality and hashing are delegated to the stored opaque state. If two opaque /// references should be distinct, their state values must compare and hash /// distinctly. /// /// This is an advanced feature designed for language exporters and framework /// integrations. Most end users should prefer ordinary [`DataType`] variants. #[derive(Clone)] pub struct OpaqueReference(Arc); trait DynOpaqueReference: Any + Send + Sync { fn type_name(&self) -> &'static str; fn hash(&self, hasher: &mut dyn hash::Hasher); fn eq(&self, other: &dyn Any) -> bool; fn as_any(&self) -> &dyn Any; } #[derive(Debug)] struct OpaqueReferenceInner(T); impl DynOpaqueReference for OpaqueReferenceInner { fn type_name(&self) -> &'static str { std::any::type_name::() } fn hash(&self, mut hasher: &mut dyn hash::Hasher) { self.0.hash(&mut hasher) } fn eq(&self, other: &dyn Any) -> bool { other .downcast_ref::() .map(|other| self.0 == *other) .unwrap_or_default() } fn as_any(&self) -> &dyn Any { &self.0 } } impl fmt::Debug for OpaqueReference { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("OpaqueReference") .field(&self.0.type_name()) .finish() } } impl PartialEq for OpaqueReference { fn eq(&self, other: &Self) -> bool { self.0.eq(other.0.as_any()) } } impl Eq for OpaqueReference {} impl hash::Hash for OpaqueReference { fn hash(&self, state: &mut H) { self.0.hash(state) } } impl OpaqueReference { /// Returns the Rust type name of the stored opaque state. pub fn type_name(&self) -> &'static str { self.0.type_name() } /// Returns the [`TypeId`] of the stored opaque state. pub fn type_id(&self) -> TypeId { self.0.as_any().type_id() } /// Attempts to downcast the opaque state to `T`. pub fn downcast_ref(&self) -> Option<&T> { self.0.as_any().downcast_ref::() } } impl Reference { /// Constructs a new reference to an opaque type. /// /// An opaque type cannot be represented with the core [`DataType`] model and /// requires specific exporter integration. /// /// Opaque [`Reference`]s are compared using the state's [`PartialEq`] /// implementation. For example, `Reference::opaque(()) == /// Reference::opaque(())`, so unique references need unique state. pub fn opaque(state: T) -> Self { Self::Opaque(OpaqueReference(Arc::new(OpaqueReferenceInner(state)))) } /// Returns whether two references point to the same underlying type. /// /// This differs from [`Eq`], [`PartialEq`], and [`Hash`] because those compare /// the full [`Reference`] which includes generic arguments and inline state. pub fn ty_eq(&self, other: &Reference) -> bool { match (self, other) { (Reference::Named(a), Reference::Named(b)) => a.id == b.id, (Reference::Opaque(a), Reference::Opaque(b)) => *a == *b, _ => false, } } } impl From for DataType { fn from(r: Reference) -> Self { Self::Reference(r) } } /// Unique identifier for a [NamedDataType]. /// /// For static types (from derive macros), we use a unique string based on the /// type's module path and name. For dynamic types, we use an Arc pointer. #[derive(Clone)] pub(crate) enum NamedId { // A unique string identifying the type (module_path::TypeName). Static(&'static str), Dynamic(Arc<()>), } impl PartialEq for NamedId { fn eq(&self, other: &Self) -> bool { match (self, other) { (NamedId::Static(a), NamedId::Static(b)) => a == b, (NamedId::Dynamic(a), NamedId::Dynamic(b)) => Arc::ptr_eq(a, b), _ => false, } } } impl Eq for NamedId {} impl hash::Hash for NamedId { fn hash(&self, state: &mut H) { match self { NamedId::Static(s) => s.hash(state), NamedId::Dynamic(p) => std::ptr::hash(Arc::as_ptr(p), state), } } } impl fmt::Debug for NamedId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { NamedId::Static(s) => write!(f, "s:{}", s), NamedId::Dynamic(p) => write!(f, "d{:p}", Arc::as_ptr(p)), } } } ================================================ FILE: specta/src/datatype/struct.rs ================================================ use crate::datatype::{Attributes, DataType, Fields}; use super::StructBuilder; use super::{NamedFields, UnnamedFields}; /// Runtime representation of a Rust [`struct`](https://doc.rust-lang.org/std/keyword.struct.html). #[derive(Debug, Clone, PartialEq, Eq, Hash)] #[non_exhaustive] pub struct Struct { /// Field layout for the struct. pub fields: Fields, /// Runtime attributes attached to the struct container. pub attributes: Attributes, } // Do not implement `Default` for `Struct` as it's unclear what that would be. `Unit`, yes but still. impl Struct { /// Construct a new unit struct. pub fn unit() -> Self { Self { fields: Fields::Unit, attributes: Default::default(), } } /// Starts building a struct with named fields. pub fn named() -> StructBuilder { StructBuilder { fields: NamedFields { fields: Default::default(), }, } } /// Starts building a tuple struct with unnamed fields. pub fn unnamed() -> StructBuilder { StructBuilder { fields: UnnamedFields { fields: Default::default(), }, } } } impl From for DataType { fn from(t: Struct) -> Self { Self::Struct(t) } } ================================================ FILE: specta/src/datatype/tuple.rs ================================================ use super::DataType; /// Represents a Rust [tuple](https://doc.rust-lang.org/std/primitive.tuple.html) type. /// /// The empty tuple `()` is represented as a tuple with no elements. Exporters may /// render that specially, such as `null` in the TypeScript exporter. #[derive(Debug, Clone, PartialEq, Eq, Hash)] #[non_exhaustive] pub struct Tuple { /// Datatypes for each tuple element, in source order. pub elements: Vec, } impl Tuple { /// Create a new tuple with the given elements. pub fn new(elements: Vec) -> Self { Self { elements } } } impl From for DataType { fn from(t: Tuple) -> Self { Self::Tuple(t) } } ================================================ FILE: specta/src/datatype.rs ================================================ //! Types related to working with [`DataType`]. Exposed for advanced users. mod attributes; mod r#enum; mod fields; mod function; mod generic; mod list; mod map; mod named; mod primitive; mod reference; mod r#struct; mod tuple; pub use attributes::Attributes; pub use r#enum::{Enum, Variant, VariantBuilder}; pub use fields::{Field, Fields, NamedFields, StructBuilder, UnnamedFields}; pub use function::Function; pub use generic::{Generic, Generic as GenericReference, GenericDefinition}; pub use list::List; // pub use literal::Literal; pub use map::Map; pub use named::{Deprecated, NamedDataType, inline}; pub use primitive::Primitive; pub use reference::{NamedReference, NamedReferenceType, OpaqueReference, Reference}; pub use r#struct::Struct; pub use tuple::Tuple; pub(crate) use reference::NamedId; /// Runtime type-erased representation of a Rust type. /// /// A language exporter takes this general format and converts it into a language specific syntax. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum DataType { /// A primitive scalar type like integers, floats, booleans, chars, or strings. Primitive(Primitive), /// A sequential collection type. List(List), /// A map/dictionary type. Map(Map), /// A struct type with named, unnamed, or unit fields. Struct(Struct), /// An enum type. Enum(Enum), /// A tuple type. Tuple(Tuple), /// A nullable wrapper around another type. Nullable(Box), /// A structural intersection of multiple object-like types. Intersection(Vec), /// A placeholder for a generic type defined on the parent [`NamedDataType`]. /// Rendered as `T`. These should never be returned from [`Type::definition`](crate::Type::definition), they should only appear in [`NamedDataType`]'s `ty` field. Generic(Generic), /// A reference to another named or opaque type. Reference(Reference), } ================================================ FILE: specta/src/docs.md ================================================ Easily export your Rust types to other languages. Specta provides a system for type introspection and a set of language exporters which allow you to export your Rust types to other languages! **Get started** by checking out the language exporter's, start with [Typescript](https://docs.rs/specta-typescript). ## Features - Export structs and enums to [Typescript](https://www.typescriptlang.org) - Get function types to use in libraries like [tauri-specta](https://github.com/specta-rs/tauri-specta) - Supports wide range of common crates in Rust ecosystem - Supports type inference - can determine type of `fn demo() -> impl Type`. ## Ecosystem Specta can be used in your application either directly or through a library which simplifies the process of using it. - [rspc](https://github.com/specta-rs/rspc) - A framework for building typesafe web backends in Rust - [tauri-specta](https://github.com/specta-rs/tauri-specta) - Completely typesafe Tauri commands - [TauRPC](https://github.com/MatsDK/TauRPC) - Typesafe IPC layer for Tauri applications - [orpc-rs](https://github.com/ahonn/orpc-rs) - Rust implementation of [oRPC](https://orpc.dev) — type-safe RPC with first-class Tauri support. ## Languages Specta is designed to be able to export from Rust to any other language. | Language | Status | | ------------------------------------------------------ | ------------- | | [specta-typescript](https://docs.rs/specta-typescript) | **stable** | | [specta-go](https://docs.rs/specta-go) | alpha | | [specta-swift](https://docs.rs/specta-swift) | alpha | | [specta-openapi](https://docs.rs/specta-openapi) | wip | | [specta-jsonschema](https://docs.rs/specta-jsonschema) | wip | | [specta-zod](https://docs.rs/specta-zod) | wip | | [specta-kotlin](https://docs.rs/specta-kotlin) | _coming soon_ | | specta-jsdoc | _coming soon_ | | specta-rust | _coming soon_ | | specta-valibot | _coming soon_ | ## Formats Specta is format agnostic. Format-specific behavior is handled by companion crates before handing transformed types to language exporters. | Format | Status | | ------ | ------------- | | [specta-serde](https://docs.rs/specta-serde) | **stable** | ## Feature flags [//]: # (FEATURE_FLAGS_START) - `function` - Support for exporting the types of Rust functions. - `collect` - Support for collecting up a global type map Languages - `typescript` - Support for [TypeScript](https://www.typescriptlang.org) language exporting - `js_doc` - Support for [JSDoc](https://jsdoc.app) exporting helpers. Also requires `typescript` feature to be enabled. Compatibility - `serde` - Support for [serde](https://serde.rs) - `serde_json` - Support for [serde-json](https://github.com/serde-rs/json) - `serde_yaml` - Support for [serde_yaml](https://github.com/dtolnay/serde-yaml) - `toml` - Support for [toml](https://github.com/toml-rs/toml) - `tauri` - Support for [Tauri](https://tauri.app). This is required when using the `#[specta]` attribute with Tauri Commands. External types - `ulid` - [ulid](https://docs.rs/ulid) crate - `uuid` - [uuid](https://docs.rs/uuid) crate - `chrono` - [chrono](https://docs.rs/chrono) crate - `time` - [time](https://docs.rs/time) crate - `jiff` - [jiff](https://docs.rs/jiff) crate - `bigdecimal` - [bigdecimal](https://docs.rs/bigdecimal) crate - `rust_decimal` - [rust_decimal](https://docs.rs/rust_decimal) crate - `indexmap` - [indexmap](https://docs.rs/indexmap) crate - `ordered-float` - [ordered-float](https://docs.rs/ordered-float) crate - `heapless` - [heapless](https://docs.rs/heapless) crate - `semver` - [semver](https://docs.rs/semver) crate - `smol_str` - [smol_str](https://docs.rs/smol_str) crate - `arrayvec` - [arrayvec](https://docs.rs/arrayvec) crate - `smallvec` - [smallvec](https://docs.rs/smallvec) crate - `ipnetwork` - [ipnetwork](https://docs.rs/ipnetwork) crate - `mac_address` - [mac_address](https://docs.rs/mac_address) crate - `bit-vec` - [bit-vec](https://docs.rs/bit-vec) crate - `bson` - [bson](https://docs.rs/bson) crate - `uhlc` - [uhlc](https://docs.rs/uhlc) crate - `bytesize` - [bytesize](https://docs.rs/bytesize) crate - `glam` - [glam](https://docs.rs/glam) crate - `tokio` - [tokio](https://docs.rs/tokio) crate - `url` - [url](https://docs.rs/url) crate - `either` - [either](https://docs.rs/either) crate - `bevy_ecs` - [bevy_ecs](https://docs.rs/bevy_ecs) crate [//]: # (FEATURE_FLAGS_END) ## Alternatives #### Why not ts-rs? [ts-rs](https://github.com/Aleph-Alpha/ts-rs) is a great library, but it has a few limitations which became a problem when I was building [rspc](https://github.com/specta-rs/rspc). Namely it deals with types individually which means it is not possible to export a type and all of the other types it depends on. #### Why not Typeshare? [Typeshare](https://github.com/1Password/typeshare) is also great, but its approach is fundamentally different. While Specta uses traits and runtime information, Typeshare statically analyzes your Rust files. This results in a loss of information and lack of compatibility with types from other crates. ================================================ FILE: specta/src/format.rs ================================================ use std::{borrow::Cow, error}; use crate::{Types, datatype::DataType}; /// Error type returned by [`Format`] callbacks. pub type FormatError = Box; /// The format is used to inform Specta how the Serialize/Deserialization layer handles types. /// /// This allows them to rewrite the collected types and encountered datatypes to apply format-specific macro attributes or behaviour. /// /// Currently we have support for: /// - [serde](https://docs.rs/specta) via [`specta-serde`](https://docs.rs/specta-serde) /// pub trait Format { /// Apply a map function to the full [`Types`] collection. /// /// Returns [`Cow::Borrowed`] when no changes are needed, or /// [`Cow::Owned`] when the formatter produces a transformed collection. fn map_types(&'_ self, types: &Types) -> std::result::Result, FormatError>; /// Map an individual [`DataType`] with access to the surrounding [`Types`]. /// /// Returns [`Cow::Borrowed`] when no changes are needed, or /// [`Cow::Owned`] when the formatter produces a transformed datatype. fn map_type( &'_ self, types: &Types, dt: &DataType, ) -> std::result::Result, FormatError>; } impl Format for &T { fn map_types(&'_ self, types: &Types) -> std::result::Result, FormatError> { (**self).map_types(types) } fn map_type( &'_ self, types: &Types, dt: &DataType, ) -> std::result::Result, FormatError> { (**self).map_type(types, dt) } } impl Format for Box { fn map_types(&'_ self, types: &Types) -> std::result::Result, FormatError> { (**self).map_types(types) } fn map_type( &'_ self, types: &Types, dt: &DataType, ) -> std::result::Result, FormatError> { (**self).map_type(types, dt) } } // Assert dyn-safety const _: Option<&dyn Format> = None; ================================================ FILE: specta/src/function/arg.rs ================================================ use crate::{Type, Types, datatype::DataType}; /// Implemented by types that can be used as an argument in a function annotated with /// [`specta`](crate::specta). pub trait FunctionArg { /// Gets the type of an argument as a [`DataType`]. /// /// Some argument types should be ignored (eg. when doing dependency injection), /// so the value is optional. fn to_datatype(types: &mut Types) -> Option; } impl FunctionArg for T { fn to_datatype(types: &mut Types) -> Option { Some(T::definition(types)) } } ================================================ FILE: specta/src/function/result.rs ================================================ use std::future::Future; use crate::{Type, Types, datatype::DataType}; /// Implemented by types that can be returned from a function annotated with /// [`specta`](crate::specta). pub trait FunctionResult { /// Gets the function return type as a [`DataType`]. fn to_datatype(types: &mut Types) -> DataType; } #[doc(hidden)] pub enum FunctionValueMarker {} impl FunctionResult for T { fn to_datatype(types: &mut Types) -> DataType { T::definition(types) } } #[doc(hidden)] pub enum FunctionFutureMarker {} impl FunctionResult for F where F: Future, F::Output: Type, { fn to_datatype(types: &mut Types) -> DataType { F::Output::definition(types) } } ================================================ FILE: specta/src/function/specta_fn.rs ================================================ use std::borrow::Cow; use crate::{ Types, datatype::{Deprecated, Function}, }; use super::{FunctionArg, FunctionResult}; /// Implemented by functions that can be annotated with [`specta`](crate::specta). /// /// This trait is sealed as it won't need to be used externally. pub trait SpectaFn { /// Gets the type of a function as a [`Function`](crate::datatype::Function). fn to_datatype( asyncness: bool, name: Cow<'static, str>, types: &mut Types, fields: &[Cow<'static, str>], docs: Cow<'static, str>, deprecated: Option, no_return_type: bool, ) -> Function; } impl SpectaFn for fn() -> TResult where TResult: FunctionResult, { fn to_datatype( asyncness: bool, name: Cow<'static, str>, types: &mut Types, _fields: &[Cow<'static, str>], docs: Cow<'static, str>, deprecated: Option, no_return_type: bool, ) -> Function { Function { asyncness, name, args: vec![], result: (!no_return_type).then(|| TResult::to_datatype(types)), docs, deprecated, } } } macro_rules! impl_typed_command { ( impl $($i:ident),* ) => { paste::paste! { impl< TResult, TResultMarker, $($i: FunctionArg),* > SpectaFn for fn($($i),*) -> TResult where TResult: FunctionResult, { fn to_datatype( asyncness: bool, name: Cow<'static, str>, types: &mut Types, fields: &[Cow<'static, str>], docs: Cow<'static, str>, deprecated: Option, no_return_type: bool, ) -> Function { let mut fields = fields.into_iter(); Function { asyncness, name, docs, deprecated, args: [$( fields .next() .map_or_else( || None, |field| $i::to_datatype(types).map(|ty| (field.clone(), ty)) ) ),*,] .into_iter() .filter_map(|v| v) .collect::>(), result: (!no_return_type).then(|| TResult::to_datatype(types)), } } } } }; ( $i2:ident $(, $i:ident)* ) => { impl_typed_command!(impl $i2 $(, $i)* ); impl_typed_command!($($i),*); }; () => {}; } impl_typed_command!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10); ================================================ FILE: specta/src/function.rs ================================================ //! Support for collecting Rust function signatures. //! //! Specta does not export callable functions by itself. Instead, it records the //! names, arguments, return types, docs, and deprecation metadata needed by //! framework crates to generate bindings for their own function or command //! systems. mod arg; mod result; mod specta_fn; pub use arg::FunctionArg; pub use result::FunctionResult; #[doc(hidden)] pub use result::{FunctionFutureMarker, FunctionValueMarker}; pub(crate) use specta_fn::SpectaFn; /// Returns a [`Function`](crate::datatype::Function) for a given function that has been annotated with /// the `#[specta]` attribute. /// /// # Examples /// /// ```rust /// use specta::{*, datatype::*, function::fn_datatype}; /// /// #[specta] /// fn some_function(name: String, age: i32) -> bool { /// true /// } /// /// fn main() { /// let typ = fn_datatype!(some_function)(&mut Types::default()); /// /// assert_eq!(typ.name(), "some_function"); /// assert_eq!(typ.args().len(), 2); /// assert_eq!(typ.result(), Some(&DataType::Primitive(Primitive::bool))); /// } /// ``` /// /// # Recursion limit reached while expanding the macro `fn_datatype` /// /// This macro requires recursion internally to correctly function so you may run into the recursion limit. From my testing you can have 31 path segments before you hit the recursion limit. The size of the segment or the amount of generics in the segment should not affect this limit. /// /// If your having issues with this limit you can increase your [`recursion_limit`](https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute) by adding `#![recursion_limit = "1024"]` to your `main.rs`. If your able to hit this limit in other scenarios please [let us know](https://github.com/specta-rs/tauri-specta/issues/114) and we can apply some potential optimizations. /// #[doc(hidden)] #[macro_export] macro_rules! _fn_datatype { // Hide distracting implementation details from the generated rustdoc. ($($json:tt)*) => { $crate::function::_fn_datatype_internal!($($json)*) }; } #[doc(hidden)] #[macro_export] macro_rules! _fn_datatype_internal { ([$($path:tt)*] [$($full:tt)*] [$last:tt]) => { $crate::internal::paste! { $($path)* [<__specta__fn__ $last>]!(@export_fn; $($full)*) } }; ([$($path:tt)*] [$($full:tt)*] [$($last:tt)?] $t:tt :: <$($g:path),*> $($rest:tt)*) => { $crate::function::fn_datatype!([$($path)* $($last)*] [$($full)* $t::<$($g),*>] [$t] $($rest)*) }; ([$($path:tt)*] [$($full:tt)*] [$($last:tt)?] $t:tt $($rest:tt)*) => { $crate::function::fn_datatype!([$($path)* $($last)*] [$($full)* $t] [$t] $($rest)*) }; () => {{ compile_error!("fn_datatype must be provided a function path as an argument"); }}; ($($rest:tt)*) => { $crate::function::fn_datatype!([] [] [] $($rest)*) }; } /// Collects function types into a [`Vec`], /// and all downstream types into a [`Types`](crate::Types) instance. /// /// Specifying a `types` argument allows a custom [`Types`](crate::Types) to be used. /// /// # Examples /// /// ```rust /// use specta::*; /// /// #[specta] /// fn some_function(name: String, age: i32) -> bool { /// true /// } /// /// fn main() { /// let functions = function::collect_functions![some_function](&mut Types::default()); /// } /// ```` #[doc(hidden)] #[macro_export] macro_rules! _collect_functions { ($(,)?) => {{ fn export(_: &mut $crate::Types) -> Vec<$crate::datatype::Function> { vec![] } export }}; ($($b:tt $(:: $($p:ident)? $(<$($g:path),*>)? )* ),* $(,)?) => {{ fn export(types: &mut $crate::Types) -> Vec<$crate::datatype::Function> { vec![ $($crate::function::fn_datatype!($b $($(::$p)? $(::<$($g),*>)? )* )(types)),* ] } export }}; } #[doc(inline)] pub use _collect_functions as collect_functions; #[doc(inline)] pub use _fn_datatype as fn_datatype; #[doc(hidden)] pub use _fn_datatype_internal; ================================================ FILE: specta/src/internal.rs ================================================ //! This module contains functions that are public for the sole reason of the macros. //! //! They will not be documented and may go through breaking changes without a major version bump! //! //! DO NOT USE THEM! You have been warned! #[cfg(feature = "function")] pub use paste::paste; #[cfg(feature = "function")] mod functions { use std::borrow::Cow; use crate::{Types, datatype::Deprecated, datatype::Function, function::SpectaFn}; #[doc(hidden)] /// A helper for exporting a command to a [`CommandDataType`]. /// You shouldn't use this directly and instead should use [`fn_datatype!`](crate::fn_datatype). pub fn get_fn_datatype>( _: T, asyncness: bool, name: Cow<'static, str>, types: &mut Types, fields: &[Cow<'static, str>], docs: Cow<'static, str>, deprecated: Option, no_return_type: bool, ) -> Function { T::to_datatype( asyncness, name, types, fields, docs, deprecated, no_return_type, ) } } #[cfg(feature = "function")] pub use functions::*; ================================================ FILE: specta/src/lib.rs ================================================ #![doc = include_str!("./docs.md")] #![cfg_attr(docsrs, feature(doc_cfg))] #![doc( html_logo_url = "https://github.com/specta-rs/specta/raw/main/.github/logo-128.png", html_favicon_url = "https://github.com/specta-rs/specta/raw/main/.github/logo-128.png" )] #![cfg_attr(is_nightly, feature(f16))] #![cfg_attr(is_nightly, feature(f128))] #[cfg(feature = "collect")] #[cfg_attr(docsrs, doc(cfg(feature = "collect")))] #[doc(hidden)] pub mod collect; pub mod datatype; mod format; #[cfg(feature = "function")] #[cfg_attr(docsrs, doc(cfg(feature = "function")))] pub mod function; #[doc(hidden)] pub mod internal; mod r#type; mod types; #[doc(inline)] pub use format::{Format, FormatError}; #[doc(inline)] pub use r#type::Type; #[doc(inline)] pub use types::Types; #[doc(inline)] #[cfg(feature = "collect")] #[cfg_attr(docsrs, doc(cfg(feature = "collect")))] pub use collect::collect; #[doc(inline)] #[cfg(feature = "derive")] #[cfg_attr(docsrs, doc(cfg(feature = "derive")))] pub use specta_macros::Type; #[doc(hidden)] #[cfg(feature = "derive")] #[cfg_attr(docsrs, doc(cfg(feature = "derive")))] pub use specta_macros::parse_type_from_lit; #[doc(inline)] #[cfg(all(feature = "derive", feature = "function"))] #[cfg_attr(docsrs, doc(cfg(all(feature = "derive", feature = "function"))))] pub use specta_macros::specta; // TODO(v3): Remove this. This must be kept for Specta v1 as Tauri v2 depends on it. #[doc(hidden)] #[deprecated(note = "Migrate from `TypeMap` to `Types`")] pub type TypeMap = Types; ================================================ FILE: specta/src/type/impls.rs ================================================ use std::marker::PhantomData; use crate::{ Type, Types, datatype::{self, DataType, List}, r#type::macros::*, }; impl_primitives!( i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize f32 f64 bool char str ); #[cfg(is_nightly)] #[cfg_attr(docsrs, doc(cfg(is_nightly)))] impl Type for f16 { fn definition(_: &mut Types) -> DataType { DataType::Primitive(datatype::Primitive::f16) } } #[cfg(is_nightly)] #[cfg_attr(docsrs, doc(cfg(is_nightly)))] impl Type for f128 { fn definition(_: &mut Types) -> DataType { DataType::Primitive(datatype::Primitive::f128) } } // Technically we only support 12-tuples but the `T13` is required due to how the macro works impl_tuple!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13); #[allow(dead_code)] pub(crate) struct PrimitiveSet(PhantomData); impl Type for PrimitiveSet { fn definition(types: &mut Types) -> DataType { let mut l = List::new(::definition(types)); l.unique = true; DataType::List(l) } } #[allow(dead_code)] pub(crate) struct PrimitiveMap(PhantomData, PhantomData); impl Type for PrimitiveMap { fn definition(types: &mut Types) -> DataType { DataType::Map(crate::datatype::Map::new( K::definition(types), V::definition(types), )) } } #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] const _: () = { use crate::datatype::{Enum, Field}; impl_ndt!( std::string::String as str = inline; // Non-unique sets std::vec::Vec as [T] = passthrough; std::collections::VecDeque as [T] = passthrough; std::collections::BinaryHeap as [T] = passthrough; std::collections::LinkedList as [T] = passthrough; // Unique sets std::collections::HashSet as PrimitiveSet = passthrough; std::collections::BTreeSet as PrimitiveSet = passthrough; // Maps std::collections::HashMap as PrimitiveMap = passthrough; std::collections::BTreeMap as PrimitiveMap = passthrough; // Containers std::boxed::Box where { T: Type + ?Sized } as T = passthrough; std::rc::Rc where { T: Type + ?Sized } as T = passthrough; std::sync::Arc where { T: Type + ?Sized } as T = passthrough; std::cell::Cell where { T: Type + ?Sized } as T = passthrough; std::cell::RefCell where { T: Type + ?Sized } as T = passthrough; std::sync::Mutex where { T: Type + ?Sized } as T = passthrough; std::sync::RwLock where { T: Type + ?Sized } as T = passthrough; std::ffi::CString as str = inline; std::ffi::CStr as str = inline; std::ffi::OsString as str = inline; std::ffi::OsStr as str = inline; std::path::Path as str = inline; std::path::PathBuf as str = inline; std::net::IpAddr as str = inline; std::net::Ipv4Addr as str = inline; std::net::Ipv6Addr as str = inline; std::net::SocketAddr as str = inline; std::net::SocketAddrV4 as str = inline; std::net::SocketAddrV6 as str = inline; std::sync::atomic::AtomicBool as bool = inline; std::sync::atomic::AtomicI8 as i8 = inline; std::sync::atomic::AtomicI16 as i16 = inline; std::sync::atomic::AtomicI32 as i32 = inline; std::sync::atomic::AtomicIsize as isize = inline; std::sync::atomic::AtomicU8 as u8 = inline; std::sync::atomic::AtomicU16 as u16 = inline; std::sync::atomic::AtomicU32 as u32 = inline; std::sync::atomic::AtomicUsize as usize = inline; std::sync::atomic::AtomicI64 as i64 = inline; std::sync::atomic::AtomicU64 as u64 = inline; std::num::NonZeroU8 as u8 = inline; std::num::NonZeroU16 as u16 = inline; std::num::NonZeroU32 as u32 = inline; std::num::NonZeroU64 as u64 = inline; std::num::NonZeroUsize as usize = inline; std::num::NonZeroI8 as i8 = inline; std::num::NonZeroI16 as i16 = inline; std::num::NonZeroI32 as i32 = inline; std::num::NonZeroI64 as i64 = inline; std::num::NonZeroIsize as isize = inline; std::num::NonZeroU128 as u128 = inline; std::num::NonZeroI128 as i128 = inline; // Serde are cringe so this is how it is :( std::ops::Range as BaseRange = named; std::ops::RangeInclusive as BaseRange = named; std::time::SystemTime as BaseSystemTime = named; std::time::Duration as BaseDuration = named; std::convert::Infallible as BaseInfallible = inline; std::marker::PhantomData as () = inline; std::borrow::Cow<'a, T> where { T: Type + ?Sized + ToOwned + 'a } as T = inline; std::result::Result as BaseResult = named; ); struct BaseInfallible; impl Type for BaseInfallible { fn definition(_: &mut Types) -> DataType { // Serde does no support `Infallible` as it can't be constructed as a `&self` method is uncallable on it. DataType::Enum(Enum::default()) } } struct BaseSystemTime; impl Type for BaseSystemTime { fn definition(types: &mut Types) -> DataType { datatype::Struct::named() .field( "duration_since_epoch", Field::new(::definition(types)), ) .field( "duration_since_unix_epoch", Field::new(::definition(types)), ) .build() } } struct BaseDuration; impl Type for BaseDuration { fn definition(types: &mut Types) -> DataType { datatype::Struct::named() .field("secs", Field::new(::definition(types))) .field("nanos", Field::new(::definition(types))) .build() } } struct BaseRange(PhantomData); impl Type for BaseRange { fn definition(types: &mut Types) -> DataType { let ty = T::definition(types); datatype::Struct::named() .field("start", Field::new(ty.clone())) .field("end", Field::new(ty)) .build() } } struct BaseResult(PhantomData, PhantomData); impl Type for BaseResult { fn definition(types: &mut Types) -> DataType { datatype::Struct::named() .field("ok", Field::new(::definition(types))) .field("err", Field::new(::definition(types))) .build() } } }; #[cfg(feature = "tokio")] #[cfg_attr(docsrs, doc(cfg(feature = "tokio")))] impl_ndt!( tokio::sync::Mutex where { T: Type + ?Sized } as T = passthrough; tokio::sync::RwLock where { T: Type + ?Sized } as T = passthrough; ); impl Type for &T { fn definition(types: &mut Types) -> DataType { T::definition(types) } } impl Type for [T] { fn definition(types: &mut Types) -> DataType { let mut l = List::new(::definition(types)); l.unique = false; DataType::List(l) } } impl Type for [T; N] { fn definition(types: &mut Types) -> DataType { let mut l = List::new(T::definition(types)); // Refer to the documentation for `Types::has_const_params` to understand this. // If you wanna force this use `specta_utils::FixedArray` instead. if !types.has_const_params { l.length = Some(N); } DataType::List(l) } } impl Type for Option { fn definition(types: &mut Types) -> DataType { DataType::Nullable(Box::new(T::definition(types))) } } ================================================ FILE: specta/src/type/legacy_impls.rs ================================================ use crate::{Type, Types}; #[allow(unused_imports)] use crate::{datatype::*, r#type::impls::*, r#type::macros::impl_ndt}; // `String` requires `std` feature, while `str` does not. // We can't use `str` in a lot of places because it's not `Sized`, so this bridges that. #[allow(unused)] pub struct String; impl Type for String { fn definition(types: &mut Types) -> DataType { str::definition(types) } } #[cfg(feature = "indexmap")] #[cfg_attr(docsrs, doc(cfg(feature = "indexmap")))] const _: () = { impl_ndt!( indexmap::IndexSet as PrimitiveSet = passthrough; indexmap::IndexMap as PrimitiveMap = passthrough; ); }; #[cfg(feature = "ordered-float")] #[cfg_attr(docsrs, doc(cfg(feature = "ordered-float")))] impl_ndt!( ordered_float::OrderedFloat where { T: Type + ordered_float::FloatCore } as T = inline; ordered_float::NotNan where { T: Type + ordered_float::FloatCore } as T = inline; ); #[cfg(feature = "heapless")] #[cfg_attr(docsrs, doc(cfg(feature = "heapless")))] const _: () = { impl_ndt!( // Sequential containers heapless::Vec where { T: Type, LenT: heapless::LenType } as [T; N] = passthrough; heapless::Deque where { T: Type } as [T; N] = passthrough; heapless::HistoryBuf where { T: Type } as [T; N] = passthrough; heapless::BinaryHeap where { T: Type + Ord, K: heapless::binary_heap::Kind } as [T; N] = passthrough; // Sets heapless::IndexSet where { T: Type + Eq + core::hash::Hash, S: core::hash::BuildHasher } as PrimitiveSet = passthrough; // Maps heapless::IndexMap where { K: Type + Eq + core::hash::Hash, V: Type, S: core::hash::BuildHasher } as PrimitiveMap = passthrough; heapless::LinearMap where { K: Type + Eq, V: Type } as PrimitiveMap = passthrough; // String container heapless::String where { LenT: heapless::LenType } as str = inline; ); }; #[cfg(feature = "semver")] #[cfg_attr(docsrs, doc(cfg(feature = "semver")))] impl_ndt!( semver::Version as str = inline; semver::VersionReq as str = inline; semver::Comparator as str = inline; ); #[cfg(feature = "smol_str")] #[cfg_attr(docsrs, doc(cfg(feature = "smol_str")))] impl_ndt!(smol_str::SmolStr as str = inline); #[cfg(feature = "arrayvec")] #[cfg_attr(docsrs, doc(cfg(feature = "arrayvec")))] impl_ndt!( arrayvec::ArrayString as str = inline; arrayvec::ArrayVec as [T; N] = passthrough; ); #[cfg(feature = "smallvec")] #[cfg_attr(docsrs, doc(cfg(feature = "smallvec")))] impl_ndt!(smallvec::SmallVec where { T: smallvec::Array + Type } as [T] = passthrough); #[cfg(feature = "bytes")] #[cfg_attr(docsrs, doc(cfg(feature = "bytes")))] impl_ndt!( bytes::Bytes as [u8] = inline; bytes::BytesMut as [u8] = inline; ); #[cfg(feature = "serde_json")] #[cfg_attr(docsrs, doc(cfg(feature = "serde_json")))] const _: () = { use serde_json::{Map, Number, Value}; impl_ndt!( serde_json::Map as PrimitiveMap = passthrough; serde_json::Value as SerdeValue = inline; serde_json::Number as SerdeNumber = inline; ); struct SerdeValue; impl Type for SerdeValue { fn definition(types: &mut Types) -> DataType { DataType::Enum(Enum { variants: vec![ ("Null".into(), Variant::unit()), ( "Bool".into(), Variant::unnamed() .field(Field::new(bool::definition(types))) .build(), ), ( "Number".into(), Variant::unnamed() .field(Field::new(Number::definition(types))) .build(), ), ( "String".into(), Variant::unnamed() .field(Field::new(str::definition(types))) .build(), ), ( "Array".into(), Variant::unnamed() .field(Field::new(Vec::::definition(types))) .build(), ), ( "Object".into(), Variant::unnamed() .field(Field::new(Map::::definition(types))) .build(), ), ], attributes: Default::default(), }) } } struct SerdeNumber; impl Type for SerdeNumber { fn definition(_: &mut Types) -> DataType { DataType::Enum(Enum { variants: vec![ ( "f64".into(), Variant::unnamed() .field(Field::new(DataType::Primitive(Primitive::f64))) .build(), ), ( "i64".into(), Variant::unnamed() .field(Field::new(DataType::Primitive(Primitive::i64))) .build(), ), ( "u64".into(), Variant::unnamed() .field(Field::new(DataType::Primitive(Primitive::u64))) .build(), ), ], attributes: Attributes::default(), }) } } }; #[cfg(feature = "serde_yaml")] #[cfg_attr(docsrs, doc(cfg(feature = "serde_yaml")))] const _: () = { use serde_yaml::{Mapping, Number, Value, value::TaggedValue}; impl_ndt!( serde_yaml::Mapping as PrimitiveMap = passthrough; serde_yaml::Value as SerdeYamlValue = inline; serde_yaml::Number as SerdeYamlNumber = inline; serde_yaml::value::TaggedValue as SerdeYamlTaggedValue = inline; ); struct SerdeYamlValue; impl Type for SerdeYamlValue { fn definition(types: &mut Types) -> DataType { DataType::Enum(Enum { variants: vec![ ("Null".into(), Variant::unit()), ( "Bool".into(), Variant::unnamed() .field(Field::new(bool::definition(types))) .build(), ), ( "Number".into(), Variant::unnamed() .field(Field::new(Number::definition(types))) .build(), ), ( "String".into(), Variant::unnamed() .field(Field::new(str::definition(types))) .build(), ), ( "Sequence".into(), Variant::unnamed() .field(Field::new(Vec::::definition(types))) .build(), ), ( "Mapping".into(), Variant::unnamed() .field(Field::new(Mapping::definition(types))) .build(), ), ( "Tagged".into(), Variant::unnamed() .field(Field::new(Box::::definition(types))) .build(), ), ], attributes: Attributes::default(), }) } } struct SerdeYamlNumber; impl Type for SerdeYamlNumber { fn definition(_: &mut Types) -> DataType { DataType::Enum(Enum { variants: vec![ ( "f64".into(), Variant::unnamed() .field(Field::new(DataType::Primitive(Primitive::f64))) .build(), ), ( "i64".into(), Variant::unnamed() .field(Field::new(DataType::Primitive(Primitive::i64))) .build(), ), ( "u64".into(), Variant::unnamed() .field(Field::new(DataType::Primitive(Primitive::u64))) .build(), ), ], attributes: Attributes::default(), }) } } struct SerdeYamlTaggedValue; impl Type for SerdeYamlTaggedValue { fn definition(types: &mut Types) -> DataType { Struct::named() .field("tag", Field::new(str::definition(types))) .field("value", Field::new(Value::definition(types))) .build() } } }; #[cfg(feature = "toml")] #[cfg_attr(docsrs, doc(cfg(feature = "toml")))] const _: () = { use toml::{Value, value}; impl_ndt!( toml::map::Map as PrimitiveMap = passthrough; toml::value::Datetime as TomlDatetime = inline; toml::Value as TomlValue = inline; ); struct TomlDatetime; impl Type for TomlDatetime { fn definition(types: &mut Types) -> DataType { Struct::named() .field("v", Field::new(str::definition(types))) .build() } } struct TomlValue; impl Type for TomlValue { fn definition(types: &mut Types) -> DataType { DataType::Enum(Enum { variants: vec![ ( "String".into(), Variant::unnamed() .field(Field::new(str::definition(types))) .build(), ), ( "Integer".into(), Variant::unnamed() .field(Field::new(i64::definition(types))) .build(), ), ( "Float".into(), Variant::unnamed() .field(Field::new(f64::definition(types))) .build(), ), ( "Boolean".into(), Variant::unnamed() .field(Field::new(bool::definition(types))) .build(), ), ( "Datetime".into(), Variant::unnamed() .field(Field::new(value::Datetime::definition(types))) .build(), ), ( "Array".into(), Variant::unnamed() .field(Field::new(Vec::::definition(types))) .build(), ), ( "Table".into(), Variant::unnamed() .field(Field::new(toml::map::Map::::definition( types, ))) .build(), ), ], attributes: Attributes::default(), }) } } }; #[cfg(feature = "ulid")] #[cfg_attr(docsrs, doc(cfg(feature = "ulid")))] impl_ndt!(ulid::Ulid as str = inline); #[cfg(feature = "uuid")] #[cfg_attr(docsrs, doc(cfg(feature = "uuid")))] impl_ndt!( uuid::Uuid as str = inline; uuid::fmt::Braced as str = inline; uuid::fmt::Hyphenated as str = inline; uuid::fmt::Simple as str = inline; uuid::fmt::Urn as str = inline; ); #[cfg(feature = "chrono")] #[cfg_attr(docsrs, doc(cfg(feature = "chrono")))] #[allow(deprecated)] const _: () = { impl_ndt!( chrono::NaiveDateTime as str = inline; chrono::NaiveDate as str = inline; chrono::NaiveTime as str = inline; chrono::Duration as str = inline; chrono::FixedOffset as str = inline; chrono::Utc as str = inline; chrono::Local as str = inline; chrono::Weekday as str = inline; chrono::Month as str = inline; chrono::Date where { T: Type + chrono::TimeZone } as str = inline; chrono::DateTime where { T: Type + chrono::TimeZone } as str = inline; ); }; #[cfg(feature = "time")] #[cfg_attr(docsrs, doc(cfg(feature = "time")))] impl_ndt!( time::PrimitiveDateTime as str = inline; time::OffsetDateTime as str = inline; time::Date as str = inline; time::UtcDateTime as str = inline; time::Time as str = inline; time::Duration as str = inline; time::UtcOffset as str = inline; time::Weekday as str = inline; time::Month as str = inline; ); #[cfg(feature = "jiff")] #[cfg_attr(docsrs, doc(cfg(feature = "jiff")))] impl_ndt!( jiff::Timestamp as str = inline; jiff::Zoned as str = inline; jiff::SignedDuration as str = inline; jiff::civil::Date as str = inline; jiff::civil::Time as str = inline; jiff::civil::DateTime as str = inline; jiff::civil::ISOWeekDate as str = inline; jiff::tz::TimeZone as str = inline; ); #[cfg(feature = "bigdecimal")] #[cfg_attr(docsrs, doc(cfg(feature = "bigdecimal")))] impl_ndt!(bigdecimal::BigDecimal as str = inline); // This assumes the `serde-with-str` feature is enabled. Check #26 for more info. #[cfg(feature = "rust_decimal")] #[cfg_attr(docsrs, doc(cfg(feature = "rust_decimal")))] impl_ndt!(rust_decimal::Decimal as str = inline); #[cfg(feature = "ipnetwork")] #[cfg_attr(docsrs, doc(cfg(feature = "ipnetwork")))] impl_ndt!( ipnetwork::IpNetwork as str = inline; ipnetwork::Ipv4Network as str = inline; ipnetwork::Ipv6Network as str = inline; ); #[cfg(feature = "mac_address")] #[cfg_attr(docsrs, doc(cfg(feature = "mac_address")))] impl_ndt!(mac_address::MacAddress as str = inline); #[cfg(feature = "bson")] #[cfg_attr(docsrs, doc(cfg(feature = "bson")))] const _: () = { impl_ndt!( bson::oid::ObjectId as BsonObjectId = inline; bson::Decimal128 as BsonDecimal128 = inline; bson::DateTime as BsonDateTime = inline; bson::Uuid as str = inline; bson::Timestamp as BsonTimestamp = inline; bson::Binary as BsonBinary = inline; bson::Regex as BsonRegex = inline; bson::JavaScriptCodeWithScope as BsonJavaScriptCodeWithScope = inline; bson::DbPointer as BsonDbPointer = inline; bson::Document as PrimitiveMap = inline; bson::Bson as Bson = inline; bson::Utf8Lossy as T = passthrough; bson::RawBsonRef<'a,> as Bson = inline; ); struct BsonObjectId; impl Type for BsonObjectId { fn definition(types: &mut Types) -> DataType { Struct::named() .field("$oid", Field::new(str::definition(types))) .build() } } struct BsonDecimal128; impl Type for BsonDecimal128 { fn definition(types: &mut Types) -> DataType { Struct::named() .field("$numberDecimal", Field::new(str::definition(types))) .build() } } struct BsonDateTime; impl Type for BsonDateTime { fn definition(types: &mut Types) -> DataType { Struct::named() .field("$date", Field::new(str::definition(types))) .build() } } struct BsonTimestamp; impl Type for BsonTimestamp { fn definition(types: &mut Types) -> DataType { Struct::named() .field( "$timestamp", Field::new( Struct::named() .field("t", Field::new(u32::definition(types))) .field("i", Field::new(u32::definition(types))) .build(), ), ) .build() } } struct BsonBinary; impl Type for BsonBinary { fn definition(types: &mut Types) -> DataType { Struct::named() .field( "$binary", Field::new( Struct::named() .field("base64", Field::new(str::definition(types))) .field("subType", Field::new(str::definition(types))) .build(), ), ) .build() } } struct BsonRegex; impl Type for BsonRegex { fn definition(types: &mut Types) -> DataType { Struct::named() .field("$regex", Field::new(str::definition(types))) .field("$options", Field::new(str::definition(types))) .build() } } struct BsonJavaScriptCode; impl Type for BsonJavaScriptCode { fn definition(types: &mut Types) -> DataType { Struct::named() .field("$code", Field::new(str::definition(types))) .build() } } struct BsonJavaScriptCodeWithScope; impl Type for BsonJavaScriptCodeWithScope { fn definition(types: &mut Types) -> DataType { Struct::named() .field("$code", Field::new(str::definition(types))) .field("$scope", Field::new(bson::Document::definition(types))) .build() } } struct BsonDbPointer; impl Type for BsonDbPointer { fn definition(types: &mut Types) -> DataType { Struct::named() .field( "$dbPointer", Field::new( Struct::named() .field("$ref", Field::new(str::definition(types))) .field("$id", Field::new(bson::oid::ObjectId::definition(types))) .build(), ), ) .build() } } struct Bson; impl Type for Bson { fn definition(types: &mut Types) -> DataType { DataType::Enum(Enum { variants: vec![ ( "Double".into(), Variant::unnamed() .field(Field::new(f64::definition(types))) .build(), ), ( "String".into(), Variant::unnamed() .field(Field::new(str::definition(types))) .build(), ), ( "Array".into(), Variant::unnamed() .field(Field::new(Vec::::definition(types))) .build(), ), ( "Document".into(), Variant::unnamed() .field(Field::new(bson::Document::definition(types))) .build(), ), ( "Boolean".into(), Variant::unnamed() .field(Field::new(bool::definition(types))) .build(), ), ("Null".into(), Variant::unit()), ( "RegularExpression".into(), Variant::unnamed() .field(Field::new(bson::Regex::definition(types))) .build(), ), ( "JavaScriptCode".into(), Variant::unnamed() .field(Field::new(BsonJavaScriptCode::definition(types))) .build(), ), ( "JavaScriptCodeWithScope".into(), Variant::unnamed() .field(Field::new(bson::JavaScriptCodeWithScope::definition(types))) .build(), ), ( "Int32".into(), Variant::unnamed() .field(Field::new(i32::definition(types))) .build(), ), ( "Int64".into(), Variant::unnamed() .field(Field::new(i64::definition(types))) .build(), ), ( "Timestamp".into(), Variant::unnamed() .field(Field::new(bson::Timestamp::definition(types))) .build(), ), ( "Binary".into(), Variant::unnamed() .field(Field::new(bson::Binary::definition(types))) .build(), ), ( "ObjectId".into(), Variant::unnamed() .field(Field::new(bson::oid::ObjectId::definition(types))) .build(), ), ( "DateTime".into(), Variant::unnamed() .field(Field::new(bson::DateTime::definition(types))) .build(), ), ( "Symbol".into(), Variant::unnamed() .field(Field::new( Struct::named() .field("$symbol", Field::new(str::definition(types))) .build(), )) .build(), ), ( "Decimal128".into(), Variant::unnamed() .field(Field::new(bson::Decimal128::definition(types))) .build(), ), ( "Undefined".into(), Variant::unnamed() .field(Field::new( Struct::named() .field("$undefined", Field::new(bool::definition(types))) .build(), )) .build(), ), ( "MaxKey".into(), Variant::unnamed() .field(Field::new( Struct::named() .field("$maxKey", Field::new(u8::definition(types))) .build(), )) .build(), ), ( "MinKey".into(), Variant::unnamed() .field(Field::new( Struct::named() .field("$minKey", Field::new(u8::definition(types))) .build(), )) .build(), ), ( "DbPointer".into(), Variant::unnamed() .field(Field::new(bson::DbPointer::definition(types))) .build(), ), ], attributes: Attributes::default(), }) } } }; // Technically this can be u64 for formats not marked as human readable in Serde. // but we have no way of inspecting that as it's runtime. This is the most common output. #[cfg(feature = "bytesize")] #[cfg_attr(docsrs, doc(cfg(feature = "bytesize")))] impl_ndt!(bytesize::ByteSize as String = inline); #[cfg(feature = "uhlc")] #[cfg_attr(docsrs, doc(cfg(feature = "uhlc")))] const _: () = { impl_ndt!( uhlc::NTP64 as u64 = inline; uhlc::ID as std::num::NonZeroU128 = inline; uhlc::Timestamp as UhlcTimestamp = inline; ); struct UhlcTimestamp; impl Type for UhlcTimestamp { fn definition(types: &mut Types) -> DataType { DataType::Struct(Struct { fields: Fields::Named(NamedFields { fields: vec![ ( "time".into(), Field { optional: false, deprecated: None, docs: Default::default(), ty: Some(uhlc::NTP64::definition(types)), attributes: Attributes::default(), }, ), ( "id".into(), Field { optional: false, deprecated: None, docs: Default::default(), ty: Some(uhlc::ID::definition(types)), attributes: Attributes::default(), }, ), ], }), attributes: Attributes::default(), }) } } }; #[cfg(feature = "glam")] #[cfg_attr(docsrs, doc(cfg(feature = "glam")))] impl_ndt!( // Affines glam::Affine2 as [f32; 6] = inline; glam::Affine3A as [f32; 12] = inline; glam::DAffine2 as [f64; 6] = inline; glam::DAffine3 as [f64; 12] = inline; // Matrices glam::Mat2 as [f32; 4] = inline; glam::Mat3 as [f32; 9] = inline; glam::Mat3A as [f32; 9] = inline; glam::Mat4 as [f32; 16] = inline; glam::DMat2 as [f64; 4] = inline; glam::DMat3 as [f64; 9] = inline; glam::DMat4 as [f64; 16] = inline; // Quaternions glam::Quat as [f32; 4] = inline; glam::DQuat as [f64; 4] = inline; // Vectors glam::Vec2 as [f32; 2] = inline; glam::Vec3 as [f32; 3] = inline; glam::Vec3A as [f32; 3] = inline; glam::Vec4 as [f32; 4] = inline; glam::DVec2 as [f64; 2] = inline; glam::DVec3 as [f64; 3] = inline; glam::DVec4 as [f64; 4] = inline; // Implementation for https://docs.rs/glam/latest/glam/bool/index.html glam::BVec2 as [bool; 2] = inline; glam::BVec3 as [bool; 3] = inline; glam::BVec3A as [bool; 3] = inline; glam::BVec4 as [bool; 4] = inline; glam::BVec4A as [bool; 4] = inline; // Implementations for https://docs.rs/glam/latest/glam/i8/index.html glam::I8Vec2 as [i8; 2] = inline; glam::I8Vec3 as [i8; 3] = inline; glam::I8Vec4 as [i8; 4] = inline; // Implementations for https://docs.rs/glam/latest/glam/u8/index.html glam::U8Vec2 as [u8; 2] = inline; glam::U8Vec3 as [u8; 3] = inline; glam::U8Vec4 as [u8; 4] = inline; // Implementations for https://docs.rs/glam/latest/glam/i16/index.html glam::I16Vec2 as [i16; 2] = inline; glam::I16Vec3 as [i16; 3] = inline; glam::I16Vec4 as [i16; 4] = inline; // Implementations for https://docs.rs/glam/latest/glam/u16/index.html glam::U16Vec2 as [u16; 2] = inline; glam::U16Vec3 as [u16; 3] = inline; glam::U16Vec4 as [u16; 4] = inline; // Implementations for https://docs.rs/glam/latest/glam/u32/index.html glam::UVec2 as [u32; 2] = inline; glam::UVec3 as [u32; 3] = inline; glam::UVec4 as [u32; 4] = inline; // Implementations for https://docs.rs/glam/latest/glam/i32/index.html glam::IVec2 as [i32; 2] = inline; glam::IVec3 as [i32; 3] = inline; glam::IVec4 as [i32; 4] = inline; // Implementation for https://docs.rs/glam/latest/glam/i64/index.html glam::I64Vec2 as [i64; 2] = inline; glam::I64Vec3 as [i64; 3] = inline; glam::I64Vec4 as [i64; 4] = inline; // Implementation for https://docs.rs/glam/latest/glam/u64/index.html glam::U64Vec2 as [u64; 2] = inline; glam::U64Vec3 as [u64; 3] = inline; glam::U64Vec4 as [u64; 4] = inline; // implementation for https://docs.rs/glam/latest/glam/usize/index.html glam::USizeVec2 as [usize; 2] = inline; glam::USizeVec3 as [usize; 3] = inline; glam::USizeVec4 as [usize; 4] = inline; // implementation for https://docs.rs/glam/latest/glam/isize/index.html glam::ISizeVec2 as [isize; 2] = inline; glam::ISizeVec3 as [isize; 3] = inline; glam::ISizeVec4 as [isize; 4] = inline; ); #[cfg(feature = "url")] #[cfg_attr(docsrs, doc(cfg(feature = "url")))] const _: () = { impl_ndt!( url::Url as str = inline; url::Host as UrlHost = inline; ); struct UrlHost; impl Type for UrlHost { fn definition(types: &mut Types) -> DataType { DataType::Enum(Enum { variants: vec![ ( "Domain".into(), Variant::unnamed() .field(Field::new(String::definition(types))) .build(), ), ( "Ipv4".into(), Variant::unnamed() .field(Field::new(std::net::Ipv4Addr::definition(types))) .build(), ), ( "Ipv6".into(), Variant::unnamed() .field(Field::new(std::net::Ipv6Addr::definition(types))) .build(), ), ], attributes: Attributes::default(), }) } } }; #[cfg(feature = "either")] #[cfg_attr(docsrs, doc(cfg(feature = "either")))] const _: () = { impl_ndt!(either::Either as Either = inline); struct Either(std::marker::PhantomData<(L, R)>); impl Type for Either { fn definition(types: &mut Types) -> DataType { DataType::Enum(Enum { variants: vec![ ( "Left".into(), Variant::unnamed() .field(Field::new(L::definition(types))) .build(), ), ( "Right".into(), Variant::unnamed() .field(Field::new(R::definition(types))) .build(), ), ], attributes: Attributes::default(), }) } } }; #[cfg(feature = "error-stack")] #[cfg_attr(docsrs, doc(cfg(feature = "error-stack")))] const _: () = { impl_ndt!( "error_stack" ErrorStackContext as ErrorStackContextInner = named; error_stack::Report<> where { C: std::error::Error + Send + Sync + 'static } as ReportInner = named; ); impl Type for error_stack::Report<[C]> { fn definition(types: &mut Types) -> DataType { error_stack::Report::::definition(types) } } struct ErrorStackContext; struct ErrorStackContextInner; impl Type for ErrorStackContextInner { fn definition(types: &mut Types) -> DataType { let attachments = DataType::List(List::new(String::definition(types))); let sources = DataType::List(List::new(ErrorStackContext::definition(types))); Struct::named() .field("context", Field::new(String::definition(types))) .field("attachments", Field::new(attachments)) .field("sources", Field::new(sources)) .build() } } struct ReportInner; impl Type for ReportInner { fn definition(types: &mut Types) -> DataType { DataType::List(List::new(ErrorStackContext::definition(types))) } } }; #[cfg(feature = "bevy_ecs")] #[cfg_attr(docsrs, doc(cfg(feature = "bevy_ecs")))] impl_ndt!( bevy_ecs::entity::Entity as u64 = named; bevy_ecs::name::Name as str = named; bevy_ecs::hierarchy::ChildOf as bevy_ecs::entity::Entity = named; bevy_ecs::entity::EntityHashMap where { V: Type } as PrimitiveMap = named; bevy_ecs::entity::EntityHashSet as PrimitiveSet = named; bevy_ecs::entity::EntityIndexMap where { V: Type } as PrimitiveMap = named; bevy_ecs::entity::EntityIndexSet as PrimitiveSet = named; ); #[cfg(feature = "bevy_input")] #[cfg_attr(docsrs, doc(cfg(feature = "bevy_input")))] const _: () = { impl_ndt!( bevy_input::ButtonState as BevyButtonState = named; bevy_input::keyboard::KeyboardInput as BevyKeyboardInput = named; bevy_input::keyboard::KeyboardFocusLost as BevyKeyboardFocusLost = named; bevy_input::keyboard::NativeKeyCode as str = named; bevy_input::keyboard::KeyCode as str = named; bevy_input::keyboard::NativeKey as str = named; bevy_input::keyboard::Key as str = named; bevy_input::mouse::MouseButtonInput as BevyMouseButtonInput = named; bevy_input::mouse::MouseButton as BevyMouseButton = named; bevy_input::mouse::MouseMotion as BevyMouseMotion = named; bevy_input::mouse::MouseScrollUnit as BevyMouseScrollUnit = named; bevy_input::mouse::MouseWheel as BevyMouseWheel = named; bevy_input::mouse::AccumulatedMouseMotion as BevyAccumulatedMouseMotion = named; bevy_input::mouse::AccumulatedMouseScroll as BevyAccumulatedMouseScroll = named; bevy_input::touch::TouchInput as BevyTouchInput = named; bevy_input::touch::ForceTouch as BevyForceTouch = named; bevy_input::touch::TouchPhase as BevyTouchPhase = named; bevy_input::gestures::PinchGesture as f32 = named; bevy_input::gestures::RotationGesture as f32 = named; bevy_input::gestures::DoubleTapGesture as BevyDoubleTapGesture = named; bevy_input::gestures::PanGesture as [f32; 2] = named; bevy_input::gamepad::GamepadEvent as BevyGamepadEvent = named; bevy_input::gamepad::RawGamepadEvent as BevyRawGamepadEvent = named; bevy_input::gamepad::RawGamepadButtonChangedEvent as BevyRawGamepadButtonChangedEvent = named; bevy_input::gamepad::RawGamepadAxisChangedEvent as BevyRawGamepadAxisChangedEvent = named; bevy_input::gamepad::GamepadConnectionEvent as BevyGamepadConnectionEvent = named; bevy_input::gamepad::GamepadButtonStateChangedEvent as BevyGamepadButtonStateChangedEvent = named; bevy_input::gamepad::GamepadButtonChangedEvent as BevyGamepadButtonChangedEvent = named; bevy_input::gamepad::GamepadAxisChangedEvent as BevyGamepadAxisChangedEvent = named; bevy_input::gamepad::GamepadButton as BevyGamepadButton = named; bevy_input::gamepad::GamepadAxis as BevyGamepadAxis = named; bevy_input::gamepad::GamepadConnection as BevyGamepadConnection = named; ); struct BevyButtonState; impl Type for BevyButtonState { fn definition(_: &mut Types) -> DataType { DataType::Enum(Enum { variants: vec![ ("Pressed".into(), Variant::unit()), ("Released".into(), Variant::unit()), ], attributes: Attributes::default(), }) } } struct BevyKeyboardFocusLost; impl Type for BevyKeyboardFocusLost { fn definition(_: &mut Types) -> DataType { DataType::Struct(Struct { fields: Fields::Unit, attributes: Attributes::default(), }) } } struct BevyKeyboardInput; impl Type for BevyKeyboardInput { fn definition(types: &mut Types) -> DataType { Struct::named() .field( "key_code", Field::new(bevy_input::keyboard::KeyCode::definition(types)), ) .field( "logical_key", Field::new(bevy_input::keyboard::Key::definition(types)), ) .field( "state", Field::new(bevy_input::ButtonState::definition(types)), ) .field( "text", Field::new(Option::::definition(types)), ) .field("repeat", Field::new(bool::definition(types))) .field( "window", Field::new(bevy_ecs::entity::Entity::definition(types)), ) .build() } } struct BevyMouseButtonInput; impl Type for BevyMouseButtonInput { fn definition(types: &mut Types) -> DataType { Struct::named() .field( "button", Field::new(bevy_input::mouse::MouseButton::definition(types)), ) .field( "state", Field::new(bevy_input::ButtonState::definition(types)), ) .field( "window", Field::new(bevy_ecs::entity::Entity::definition(types)), ) .build() } } struct BevyMouseButton; impl Type for BevyMouseButton { fn definition(types: &mut Types) -> DataType { DataType::Enum(Enum { variants: vec![ ("Left".into(), Variant::unit()), ("Right".into(), Variant::unit()), ("Middle".into(), Variant::unit()), ("Back".into(), Variant::unit()), ("Forward".into(), Variant::unit()), ( "Other".into(), Variant::unnamed() .field(Field::new(u16::definition(types))) .build(), ), ], attributes: Attributes::default(), }) } } struct BevyMouseMotion; impl Type for BevyMouseMotion { fn definition(types: &mut Types) -> DataType { Struct::named() .field("delta", Field::new(<[f32; 2]>::definition(types))) .build() } } struct BevyMouseScrollUnit; impl Type for BevyMouseScrollUnit { fn definition(_: &mut Types) -> DataType { DataType::Enum(Enum { variants: vec![ ("Line".into(), Variant::unit()), ("Pixel".into(), Variant::unit()), ], attributes: Attributes::default(), }) } } struct BevyMouseWheel; impl Type for BevyMouseWheel { fn definition(types: &mut Types) -> DataType { Struct::named() .field( "unit", Field::new(bevy_input::mouse::MouseScrollUnit::definition(types)), ) .field("x", Field::new(f32::definition(types))) .field("y", Field::new(f32::definition(types))) .field( "window", Field::new(bevy_ecs::entity::Entity::definition(types)), ) .field( "phase", Field::new(bevy_input::touch::TouchPhase::definition(types)), ) .build() } } struct BevyAccumulatedMouseMotion; impl Type for BevyAccumulatedMouseMotion { fn definition(types: &mut Types) -> DataType { Struct::named() .field("delta", Field::new(<[f32; 2]>::definition(types))) .build() } } struct BevyAccumulatedMouseScroll; impl Type for BevyAccumulatedMouseScroll { fn definition(types: &mut Types) -> DataType { Struct::named() .field( "unit", Field::new(bevy_input::mouse::MouseScrollUnit::definition(types)), ) .field("delta", Field::new(<[f32; 2]>::definition(types))) .build() } } struct BevyTouchInput; impl Type for BevyTouchInput { fn definition(types: &mut Types) -> DataType { Struct::named() .field( "phase", Field::new(bevy_input::touch::TouchPhase::definition(types)), ) .field("position", Field::new(<[f32; 2]>::definition(types))) .field( "window", Field::new(bevy_ecs::entity::Entity::definition(types)), ) .field( "force", Field::new(Option::::definition(types)), ) .field("id", Field::new(u64::definition(types))) .build() } } struct BevyForceTouch; impl Type for BevyForceTouch { fn definition(types: &mut Types) -> DataType { DataType::Enum(Enum { variants: vec![ ( "Calibrated".into(), Variant::named() .field("force", Field::new(f64::definition(types))) .field("max_possible_force", Field::new(f64::definition(types))) .field( "altitude_angle", Field::new(Option::::definition(types)), ) .build(), ), ( "Normalized".into(), Variant::unnamed() .field(Field::new(f64::definition(types))) .build(), ), ], attributes: Attributes::default(), }) } } struct BevyTouchPhase; impl Type for BevyTouchPhase { fn definition(_: &mut Types) -> DataType { DataType::Enum(Enum { variants: vec![ ("Started".into(), Variant::unit()), ("Moved".into(), Variant::unit()), ("Ended".into(), Variant::unit()), ("Canceled".into(), Variant::unit()), ], attributes: Attributes::default(), }) } } struct BevyDoubleTapGesture; impl Type for BevyDoubleTapGesture { fn definition(_: &mut Types) -> DataType { DataType::Struct(Struct { fields: Fields::Unit, attributes: Attributes::default(), }) } } struct BevyGamepadEvent; impl Type for BevyGamepadEvent { fn definition(types: &mut Types) -> DataType { DataType::Enum(Enum { variants: vec![ ( "Connection".into(), Variant::unnamed() .field(Field::new( bevy_input::gamepad::GamepadConnectionEvent::definition(types), )) .build(), ), ( "Button".into(), Variant::unnamed() .field(Field::new( bevy_input::gamepad::GamepadButtonChangedEvent::definition(types), )) .build(), ), ( "Axis".into(), Variant::unnamed() .field(Field::new( bevy_input::gamepad::GamepadAxisChangedEvent::definition(types), )) .build(), ), ], attributes: Attributes::default(), }) } } struct BevyRawGamepadEvent; impl Type for BevyRawGamepadEvent { fn definition(types: &mut Types) -> DataType { DataType::Enum(Enum { variants: vec![ ( "Connection".into(), Variant::unnamed() .field(Field::new( bevy_input::gamepad::GamepadConnectionEvent::definition(types), )) .build(), ), ( "Button".into(), Variant::unnamed() .field(Field::new( bevy_input::gamepad::RawGamepadButtonChangedEvent::definition( types, ), )) .build(), ), ( "Axis".into(), Variant::unnamed() .field(Field::new( bevy_input::gamepad::RawGamepadAxisChangedEvent::definition(types), )) .build(), ), ], attributes: Attributes::default(), }) } } struct BevyRawGamepadButtonChangedEvent; impl Type for BevyRawGamepadButtonChangedEvent { fn definition(types: &mut Types) -> DataType { Struct::named() .field( "gamepad", Field::new(bevy_ecs::entity::Entity::definition(types)), ) .field( "button", Field::new(bevy_input::gamepad::GamepadButton::definition(types)), ) .field("value", Field::new(f32::definition(types))) .build() } } struct BevyRawGamepadAxisChangedEvent; impl Type for BevyRawGamepadAxisChangedEvent { fn definition(types: &mut Types) -> DataType { Struct::named() .field( "gamepad", Field::new(bevy_ecs::entity::Entity::definition(types)), ) .field( "axis", Field::new(bevy_input::gamepad::GamepadAxis::definition(types)), ) .field("value", Field::new(f32::definition(types))) .build() } } struct BevyGamepadConnectionEvent; impl Type for BevyGamepadConnectionEvent { fn definition(types: &mut Types) -> DataType { Struct::named() .field( "gamepad", Field::new(bevy_ecs::entity::Entity::definition(types)), ) .field( "connection", Field::new(bevy_input::gamepad::GamepadConnection::definition(types)), ) .build() } } struct BevyGamepadButtonStateChangedEvent; impl Type for BevyGamepadButtonStateChangedEvent { fn definition(types: &mut Types) -> DataType { Struct::named() .field( "entity", Field::new(bevy_ecs::entity::Entity::definition(types)), ) .field( "button", Field::new(bevy_input::gamepad::GamepadButton::definition(types)), ) .field( "state", Field::new(bevy_input::ButtonState::definition(types)), ) .build() } } struct BevyGamepadButtonChangedEvent; impl Type for BevyGamepadButtonChangedEvent { fn definition(types: &mut Types) -> DataType { Struct::named() .field( "entity", Field::new(bevy_ecs::entity::Entity::definition(types)), ) .field( "button", Field::new(bevy_input::gamepad::GamepadButton::definition(types)), ) .field( "state", Field::new(bevy_input::ButtonState::definition(types)), ) .field("value", Field::new(f32::definition(types))) .build() } } struct BevyGamepadAxisChangedEvent; impl Type for BevyGamepadAxisChangedEvent { fn definition(types: &mut Types) -> DataType { Struct::named() .field( "entity", Field::new(bevy_ecs::entity::Entity::definition(types)), ) .field( "axis", Field::new(bevy_input::gamepad::GamepadAxis::definition(types)), ) .field("value", Field::new(f32::definition(types))) .build() } } struct BevyGamepadButton; impl Type for BevyGamepadButton { fn definition(types: &mut Types) -> DataType { DataType::Enum(Enum { variants: vec![ ("South".into(), Variant::unit()), ("East".into(), Variant::unit()), ("North".into(), Variant::unit()), ("West".into(), Variant::unit()), ("C".into(), Variant::unit()), ("Z".into(), Variant::unit()), ("LeftTrigger".into(), Variant::unit()), ("LeftTrigger2".into(), Variant::unit()), ("RightTrigger".into(), Variant::unit()), ("RightTrigger2".into(), Variant::unit()), ("Select".into(), Variant::unit()), ("Start".into(), Variant::unit()), ("Mode".into(), Variant::unit()), ("LeftThumb".into(), Variant::unit()), ("RightThumb".into(), Variant::unit()), ("DPadUp".into(), Variant::unit()), ("DPadDown".into(), Variant::unit()), ("DPadLeft".into(), Variant::unit()), ("DPadRight".into(), Variant::unit()), ( "Other".into(), Variant::unnamed() .field(Field::new(u8::definition(types))) .build(), ), ], attributes: Attributes::default(), }) } } struct BevyGamepadAxis; impl Type for BevyGamepadAxis { fn definition(types: &mut Types) -> DataType { DataType::Enum(Enum { variants: vec![ ("LeftStickX".into(), Variant::unit()), ("LeftStickY".into(), Variant::unit()), ("LeftZ".into(), Variant::unit()), ("RightStickX".into(), Variant::unit()), ("RightStickY".into(), Variant::unit()), ("RightZ".into(), Variant::unit()), ( "Other".into(), Variant::unnamed() .field(Field::new(u8::definition(types))) .build(), ), ], attributes: Attributes::default(), }) } } struct BevyGamepadConnection; impl Type for BevyGamepadConnection { fn definition(types: &mut Types) -> DataType { DataType::Enum(Enum { variants: vec![ ( "Connected".into(), Variant::named() .field("name", Field::new(String::definition(types))) .field("vendor_id", Field::new(Option::::definition(types))) .field("product_id", Field::new(Option::::definition(types))) .build(), ), ("Disconnected".into(), Variant::unit()), ], attributes: Attributes::default(), }) } } }; #[cfg(feature = "camino")] #[cfg_attr(docsrs, doc(cfg(feature = "camino")))] impl_ndt!( camino::Utf8Path as str = inline; camino::Utf8PathBuf as str = inline; ); #[cfg(feature = "geojson")] #[cfg_attr(docsrs, doc(cfg(feature = "geojson")))] const _: () = { impl_ndt!( geojson::Position as [f64] = inline; geojson::GeoJson as GeoJson = inline; geojson::GeometryValue as GeoJsonGeometryValue = inline; geojson::Geometry as GeoJsonGeometry = inline; geojson::Feature as GeoJsonFeature = inline; geojson::FeatureCollection as GeoJsonFeatureCollection = inline; geojson::feature::Id as GeoJsonFeatureId = inline; ); struct GeoJson; impl Type for GeoJson { fn definition(types: &mut Types) -> DataType { let mut attributes = Attributes::default(); attributes.insert("serde:container:untagged", true); DataType::Enum(Enum { variants: vec![ ( "Geometry".into(), Variant::unnamed() .field(Field::new(geojson::Geometry::definition(types))) .build(), ), ( "Feature".into(), Variant::unnamed() .field(Field::new(geojson::Feature::definition(types))) .build(), ), ( "FeatureCollection".into(), Variant::unnamed() .field(Field::new(geojson::FeatureCollection::definition(types))) .build(), ), ], attributes, }) } } struct GeoJsonGeometryValue; impl Type for GeoJsonGeometryValue { fn definition(types: &mut Types) -> DataType { let mut attributes = Attributes::default(); attributes.insert("serde:container:tag", std::string::String::from("type")); DataType::Enum(Enum { variants: vec![ ( "Point".into(), Variant::named() .field( "coordinates", Field::new(geojson::PointType::definition(types)), ) .build(), ), ( "MultiPoint".into(), Variant::named() .field( "coordinates", Field::new(Vec::::definition(types)), ) .build(), ), ( "LineString".into(), Variant::named() .field( "coordinates", Field::new(geojson::LineStringType::definition(types)), ) .build(), ), ( "MultiLineString".into(), Variant::named() .field( "coordinates", Field::new(Vec::::definition(types)), ) .build(), ), ( "Polygon".into(), Variant::named() .field( "coordinates", Field::new(geojson::PolygonType::definition(types)), ) .build(), ), ( "MultiPolygon".into(), Variant::named() .field( "coordinates", Field::new(Vec::::definition(types)), ) .build(), ), ( "GeometryCollection".into(), Variant::named() .field( "geometries", Field::new(Vec::::definition(types)), ) .build(), ), ], attributes, }) } } struct GeoJsonGeometry; impl Type for GeoJsonGeometry { fn definition(types: &mut Types) -> DataType { let mut value = Field::new(geojson::GeometryValue::definition(types)); value.attributes.insert("serde:field:flatten", true); let mut foreign_members = Field::new(Option::::definition(types)); foreign_members .attributes .insert("serde:field:flatten", true); Struct::named() .field( "bbox", Field::new(Option::::definition(types)), ) .field("value", value) .field("foreign_members", foreign_members) .build() } } struct GeoJsonFeature; impl Type for GeoJsonFeature { fn definition(types: &mut Types) -> DataType { let mut attributes = Attributes::default(); attributes.insert("serde:container:tag", std::string::String::from("type")); let mut foreign_members = Field::new(Option::::definition(types)); foreign_members .attributes .insert("serde:field:flatten", true); DataType::Struct(Struct { fields: Fields::Named(NamedFields { fields: vec![ ( "bbox".into(), Field::new(Option::::definition(types)), ), ( "geometry".into(), Field::new(Option::::definition(types)), ), ( "id".into(), Field::new(Option::::definition(types)), ), ( "properties".into(), Field::new(Option::::definition(types)), ), ("foreign_members".into(), foreign_members), ], }), attributes, }) } } struct GeoJsonFeatureCollection; impl Type for GeoJsonFeatureCollection { fn definition(types: &mut Types) -> DataType { let mut attributes = Attributes::default(); attributes.insert("serde:container:tag", std::string::String::from("type")); let mut foreign_members = Field::new(Option::::definition(types)); foreign_members .attributes .insert("serde:field:flatten", true); DataType::Struct(Struct { fields: Fields::Named(NamedFields { fields: vec![ ( "bbox".into(), Field::new(Option::::definition(types)), ), ( "features".into(), Field::new(Vec::::definition(types)), ), ("foreign_members".into(), foreign_members), ], }), attributes, }) } } struct GeoJsonFeatureId; impl Type for GeoJsonFeatureId { fn definition(types: &mut Types) -> DataType { let mut attributes = Attributes::default(); attributes.insert("serde:container:untagged", true); DataType::Enum(Enum { variants: vec![ ( "String".into(), Variant::unnamed() .field(Field::new(str::definition(types))) .build(), ), ( "Number".into(), Variant::unnamed() .field(Field::new(serde_json::Number::definition(types))) .build(), ), ], attributes, }) } } }; ================================================ FILE: specta/src/type/macros.rs ================================================ macro_rules! _impl_primitives { ($($i:ident)+) => {$( impl Type for $i { fn definition(_: &mut Types) -> DataType { DataType::Primitive(datatype::Primitive::$i) } } )+}; } macro_rules! _impl_tuple { ( impl $($i:ident),* ) => { #[allow(non_snake_case)] impl<$($i: Type),*> Type for ($($i,)*) { fn definition(_types: &mut Types) -> DataType { DataType::Tuple(datatype::Tuple { elements: vec![$(<$i as Type>::definition(_types)),*], }) } } }; ( $i2:ident $(, $i:ident)* ) => { impl_tuple!(impl $($i),* ); impl_tuple!($($i),*); }; () => {}; } macro_rules! _impl_ndt { () => {}; // Multiple types ( $module_path:literal $ty:ident $(< $( $lifetime:lifetime, )* $( $generic:ident ),* $(,)? >)? $( where { $($bounds:tt)* } )? as $as_ty:ty = $kind:ident; $($rest:tt)* ) => { impl_ndt!(@single $module_path $ty $(< $( $lifetime, )* $( $generic ),* >)? $( where { $($bounds)* } )? as $as_ty = $kind ); impl_ndt!($($rest)*); }; ( $head:ident :: $( $tail:ident )::+ < $( $specta_generic:ident ),* $(,)? > < $( $impl_generic:ident ),+ $(,)? > $( where { $($bounds:tt)* } )? as $as_ty:ty = $kind:ident; $($rest:tt)* ) => { impl_ndt!(@single $head :: $( $tail )::+ < $( $specta_generic ),* > < $( $impl_generic ),* > $( where { $($bounds)* } )? as $as_ty = $kind ); impl_ndt!($($rest)*); }; ( $head:ident :: $( $tail:ident )::+ < $( $specta_generic:ident ),* $(,)? > < $first_impl_generic:ident, $second_impl_generic:ident, $third_impl_generic:ident, $( const $const_generic:ident : $const_ty:ty ),+ $(,)? > $( where { $($bounds:tt)* } )? as $as_ty:ty = $kind:ident; $($rest:tt)* ) => { impl_ndt!(@single $head :: $( $tail )::+ < $( $specta_generic ),* > < $first_impl_generic, $second_impl_generic, $third_impl_generic, $( const $const_generic : $const_ty ),* > $( where { $($bounds)* } )? as $as_ty = $kind ); impl_ndt!($($rest)*); }; ( $head:ident :: $( $tail:ident )::+ < $( $specta_generic:ident ),* $(,)? > < $first_impl_generic:ident, $second_impl_generic:ident, $( const $const_generic:ident : $const_ty:ty ),+ $(,)? > $( where { $($bounds:tt)* } )? as $as_ty:ty = $kind:ident; $($rest:tt)* ) => { impl_ndt!(@single $head :: $( $tail )::+ < $( $specta_generic ),* > < $first_impl_generic, $second_impl_generic, $( const $const_generic : $const_ty ),* > $( where { $($bounds)* } )? as $as_ty = $kind ); impl_ndt!($($rest)*); }; ( $head:ident :: $( $tail:ident )::+ < $( $specta_generic:ident ),* $(,)? > < $first_impl_generic:ident, $( const $const_generic:ident : $const_ty:ty ),+, $( $rest_impl_generic:ident ),+ $(,)? > $( where { $($bounds:tt)* } )? as $as_ty:ty = $kind:ident; $($rest:tt)* ) => { impl_ndt!(@single $head :: $( $tail )::+ < $( $specta_generic ),* > < $first_impl_generic, $( const $const_generic : $const_ty, )* $( $rest_impl_generic ),* > $( where { $($bounds)* } )? as $as_ty = $kind ); impl_ndt!($($rest)*); }; ( $head:ident :: $( $tail:ident )::+ < $( $specta_generic:ident ),* $(,)? > < $impl_generic:ident, $( const $const_generic:ident : $const_ty:ty ),+ $(,)? > $( where { $($bounds:tt)* } )? as $as_ty:ty = $kind:ident; $($rest:tt)* ) => { impl_ndt!(@single $head :: $( $tail )::+ < $( $specta_generic ),* > < $impl_generic, $( const $const_generic : $const_ty ),* > $( where { $($bounds)* } )? as $as_ty = $kind ); impl_ndt!($($rest)*); }; ( $head:ident :: $( $tail:ident )::+ < $( const $const_generic:ident : $const_ty:ty ),+ $(,)? > $( where { $($bounds:tt)* } )? as $as_ty:ty = $kind:ident; $($rest:tt)* ) => { impl_ndt!(@single $head :: $( $tail )::+ < $( const $const_generic : $const_ty ),* > $( where { $($bounds)* } )? as $as_ty = $kind ); impl_ndt!($($rest)*); }; ( $head:ident :: $( $tail:ident )::+ < $( const $const_generic:ident : $const_ty:ty ),+, $( $rest_impl_generic:ident ),+ $(,)? > $( where { $($bounds:tt)* } )? as $as_ty:ty = $kind:ident; $($rest:tt)* ) => { impl_ndt!(@single $head :: $( $tail )::+ < $( const $const_generic : $const_ty, )* $( $rest_impl_generic ),* > $( where { $($bounds)* } )? as $as_ty = $kind ); impl_ndt!($($rest)*); }; ( $head:ident :: $( $tail:ident )::+ < $impl_generic:ident, $( const $const_generic:ident : $const_ty:ty ),+ $(,)? > $( where { $($bounds:tt)* } )? as $as_ty:ty = $kind:ident; $($rest:tt)* ) => { impl_ndt!(@single $head :: $( $tail )::+ < $impl_generic, $( const $const_generic : $const_ty ),* > $( where { $($bounds)* } )? as $as_ty = $kind ); impl_ndt!($($rest)*); }; ( $( $head:ident :: $( $tail:ident )::+ $(< $( $lifetime:lifetime, )* $( $generic:ident ),* $(,)? >)? $( where { $($bounds:tt)* } )? as $as_ty:ty = $kind:ident );+ $(;)? ) => { $( impl_ndt!(@single $head :: $( $tail )::+ $(< $( $lifetime, )* $( $generic ),* >)? $( where { $($bounds)* } )? as $as_ty = $kind ); )+ }; // Single type (@single $module_path:literal $ty:ident $(< $( $lifetime:lifetime, )* $( $generic:ident ),* $(,)? >)? $( where { $($bounds:tt)* } )? as $as_ty:ty = inline) => { impl_ndt!(@kind inline $module_path $ty $(< $( $lifetime, )* $( $generic ),* >)? $( where { $($bounds)* } )? as $as_ty); }; (@single $module_path:literal $ty:ident $(< $( $lifetime:lifetime, )* $( $generic:ident ),* $(,)? >)? $( where { $($bounds:tt)* } )? as $as_ty:ty = passthrough) => { impl_ndt!(@kind passthrough $module_path $ty $(< $( $lifetime, )* $( $generic ),* >)? $( where { $($bounds)* } )? as $as_ty); }; (@single $module_path:literal $ty:ident $(< $( $lifetime:lifetime, )* $( $generic:ident ),* $(,)? >)? $( where { $($bounds:tt)* } )? as $as_ty:ty = named) => { impl_ndt!(@kind named $module_path $ty $(< $( $lifetime, )* $( $generic ),* >)? $( where { $($bounds)* } )? as $as_ty); }; (@single $head:ident :: $( $tail:ident )::+ < $( $specta_generic:ident ),* $(,)? > < $( $impl_generic:ident ),+ $(,)? > $( where { $($bounds:tt)* } )? as $as_ty:ty = inline) => { impl_ndt!(true, false [$( $specta_generic ),*] [$( $impl_generic, )*] [$head :: $( $tail )::+] [< $( $specta_generic ),* >] [< $( $impl_generic ),* >] $( where { $($bounds)* } )? as $as_ty); }; (@single $head:ident :: $( $tail:ident )::+ < $( $specta_generic:ident ),* $(,)? > < $( $impl_generic:ident ),+ $(,)? > $( where { $($bounds:tt)* } )? as $as_ty:ty = passthrough) => { impl_ndt!(false, true [$( $specta_generic ),*] [$( $impl_generic, )*] [$head :: $( $tail )::+] [< $( $specta_generic ),* >] [< $( $impl_generic ),* >] $( where { $($bounds)* } )? as $as_ty); }; (@single $head:ident :: $( $tail:ident )::+ < $( $specta_generic:ident ),* $(,)? > < $( $impl_generic:ident ),+ $(,)? > $( where { $($bounds:tt)* } )? as $as_ty:ty = named) => { impl_ndt!(false, false [$( $specta_generic ),*] [$( $impl_generic, )*] [$head :: $( $tail )::+] [< $( $specta_generic ),* >] [< $( $impl_generic ),* >] $( where { $($bounds)* } )? as $as_ty); }; (@single $head:ident :: $( $tail:ident )::+ < $( $specta_generic:ident ),* $(,)? > < $first_impl_generic:ident, $second_impl_generic:ident, $third_impl_generic:ident, $( const $const_generic:ident : $const_ty:ty ),+ $(,)? > $( where { $($bounds:tt)* } )? as $as_ty:ty = inline) => { impl_ndt!(true, false [$( $specta_generic ),*] [$first_impl_generic, $second_impl_generic, $third_impl_generic, $( const $const_generic : $const_ty, )*] [$head :: $( $tail )::+] [< $( $specta_generic ),* >] [< $first_impl_generic, $second_impl_generic, $third_impl_generic, $( $const_generic ),* >] $( where { $($bounds)* } )? as $as_ty); }; (@single $head:ident :: $( $tail:ident )::+ < $( $specta_generic:ident ),* $(,)? > < $first_impl_generic:ident, $second_impl_generic:ident, $third_impl_generic:ident, $( const $const_generic:ident : $const_ty:ty ),+ $(,)? > $( where { $($bounds:tt)* } )? as $as_ty:ty = passthrough) => { impl_ndt!(false, true [$( $specta_generic ),*] [$first_impl_generic, $second_impl_generic, $third_impl_generic, $( const $const_generic : $const_ty, )*] [$head :: $( $tail )::+] [< $( $specta_generic ),* >] [< $first_impl_generic, $second_impl_generic, $third_impl_generic, $( $const_generic ),* >] $( where { $($bounds)* } )? as $as_ty); }; (@single $head:ident :: $( $tail:ident )::+ < $( $specta_generic:ident ),* $(,)? > < $first_impl_generic:ident, $second_impl_generic:ident, $( const $const_generic:ident : $const_ty:ty ),+ $(,)? > $( where { $($bounds:tt)* } )? as $as_ty:ty = inline) => { impl_ndt!(true, false [$( $specta_generic ),*] [$first_impl_generic, $second_impl_generic, $( const $const_generic : $const_ty, )*] [$head :: $( $tail )::+] [< $( $specta_generic ),* >] [< $first_impl_generic, $second_impl_generic, $( $const_generic ),* >] $( where { $($bounds)* } )? as $as_ty); }; (@single $head:ident :: $( $tail:ident )::+ < $( $specta_generic:ident ),* $(,)? > < $first_impl_generic:ident, $second_impl_generic:ident, $( const $const_generic:ident : $const_ty:ty ),+ $(,)? > $( where { $($bounds:tt)* } )? as $as_ty:ty = passthrough) => { impl_ndt!(false, true [$( $specta_generic ),*] [$first_impl_generic, $second_impl_generic, $( const $const_generic : $const_ty, )*] [$head :: $( $tail )::+] [< $( $specta_generic ),* >] [< $first_impl_generic, $second_impl_generic, $( $const_generic ),* >] $( where { $($bounds)* } )? as $as_ty); }; (@single $head:ident :: $( $tail:ident )::+ < $( $specta_generic:ident ),* $(,)? > < $first_impl_generic:ident, $( const $const_generic:ident : $const_ty:ty ),+, $( $rest_impl_generic:ident ),+ $(,)? > $( where { $($bounds:tt)* } )? as $as_ty:ty = inline) => { impl_ndt!(true, false [$( $specta_generic ),*] [$first_impl_generic, $( const $const_generic : $const_ty, )* $( $rest_impl_generic, )*] [$head :: $( $tail )::+] [< $( $specta_generic ),* >] [< $first_impl_generic, $( $const_generic, )* $( $rest_impl_generic ),* >] $( where { $($bounds)* } )? as $as_ty); }; (@single $head:ident :: $( $tail:ident )::+ < $( $specta_generic:ident ),* $(,)? > < $first_impl_generic:ident, $( const $const_generic:ident : $const_ty:ty ),+, $( $rest_impl_generic:ident ),+ $(,)? > $( where { $($bounds:tt)* } )? as $as_ty:ty = passthrough) => { impl_ndt!(false, true [$( $specta_generic ),*] [$first_impl_generic, $( const $const_generic : $const_ty, )* $( $rest_impl_generic, )*] [$head :: $( $tail )::+] [< $( $specta_generic ),* >] [< $first_impl_generic, $( $const_generic, )* $( $rest_impl_generic ),* >] $( where { $($bounds)* } )? as $as_ty); }; (@single $head:ident :: $( $tail:ident )::+ < $( $specta_generic:ident ),* $(,)? > < $impl_generic:ident, $( const $const_generic:ident : $const_ty:ty ),+ $(,)? > $( where { $($bounds:tt)* } )? as $as_ty:ty = inline) => { impl_ndt!(true, false [$( $specta_generic ),*] [$impl_generic, $( const $const_generic : $const_ty, )*] [$head :: $( $tail )::+] [< $( $specta_generic ),* >] [< $impl_generic, $( $const_generic ),* >] $( where { $($bounds)* } )? as $as_ty); }; (@single $head:ident :: $( $tail:ident )::+ < $( $specta_generic:ident ),* $(,)? > < $impl_generic:ident, $( const $const_generic:ident : $const_ty:ty ),+ $(,)? > $( where { $($bounds:tt)* } )? as $as_ty:ty = passthrough) => { impl_ndt!(false, true [$( $specta_generic ),*] [$impl_generic, $( const $const_generic : $const_ty, )*] [$head :: $( $tail )::+] [< $( $specta_generic ),* >] [< $impl_generic, $( $const_generic ),* >] $( where { $($bounds)* } )? as $as_ty); }; (@single $head:ident :: $( $tail:ident )::+ < $( const $const_generic:ident : $const_ty:ty ),+ $(,)? > $( where { $($bounds:tt)* } )? as $as_ty:ty = inline) => { impl_ndt!(true, false [] [$( const $const_generic : $const_ty, )*] [$head :: $( $tail )::+] [] [< $( $const_generic ),* >] $( where { $($bounds)* } )? as $as_ty); }; (@single $head:ident :: $( $tail:ident )::+ < $( const $const_generic:ident : $const_ty:ty ),+ $(,)? > $( where { $($bounds:tt)* } )? as $as_ty:ty = passthrough) => { impl_ndt!(false, true [] [$( const $const_generic : $const_ty, )*] [$head :: $( $tail )::+] [] [< $( $const_generic ),* >] $( where { $($bounds)* } )? as $as_ty); }; (@single $head:ident :: $( $tail:ident )::+ < $( const $const_generic:ident : $const_ty:ty ),+, $( $rest_impl_generic:ident ),+ $(,)? > $( where { $($bounds:tt)* } )? as $as_ty:ty = inline) => { impl_ndt!(true, false [] [$( const $const_generic : $const_ty, )* $( $rest_impl_generic, )*] [$head :: $( $tail )::+] [] [< $( $const_generic, )* $( $rest_impl_generic ),* >] $( where { $($bounds)* } )? as $as_ty); }; (@single $head:ident :: $( $tail:ident )::+ < $( const $const_generic:ident : $const_ty:ty ),+, $( $rest_impl_generic:ident ),+ $(,)? > $( where { $($bounds:tt)* } )? as $as_ty:ty = passthrough) => { impl_ndt!(false, true [] [$( const $const_generic : $const_ty, )* $( $rest_impl_generic, )*] [$head :: $( $tail )::+] [] [< $( $const_generic, )* $( $rest_impl_generic ),* >] $( where { $($bounds)* } )? as $as_ty); }; (@single $head:ident :: $( $tail:ident )::+ < $impl_generic:ident, $( const $const_generic:ident : $const_ty:ty ),+ $(,)? > $( where { $($bounds:tt)* } )? as $as_ty:ty = inline) => { impl_ndt!(true, false [$impl_generic] [$impl_generic, $( const $const_generic : $const_ty, )*] [$head :: $( $tail )::+] [< $impl_generic >] [< $impl_generic, $( $const_generic ),* >] $( where { $($bounds)* } )? as $as_ty); }; (@single $head:ident :: $( $tail:ident )::+ < $impl_generic:ident, $( const $const_generic:ident : $const_ty:ty ),+ $(,)? > $( where { $($bounds:tt)* } )? as $as_ty:ty = passthrough) => { impl_ndt!(false, true [$impl_generic] [$impl_generic, $( const $const_generic : $const_ty, )*] [$head :: $( $tail )::+] [< $impl_generic >] [< $impl_generic, $( $const_generic ),* >] $( where { $($bounds)* } )? as $as_ty); }; (@single $head:ident :: $( $tail:ident )::+ $(< $( $lifetime:lifetime, )* $( $generic:ident ),* $(,)? >)? $( where { $($bounds:tt)* } )? as $as_ty:ty = inline) => { impl_ndt!(@kind inline $head :: $( $tail )::+ $(< $( $lifetime, )* $( $generic ),* >)? $( where { $($bounds)* } )? as $as_ty); }; (@single $head:ident :: $( $tail:ident )::+ $(< $( $lifetime:lifetime, )* $( $generic:ident ),* $(,)? >)? $( where { $($bounds:tt)* } )? as $as_ty:ty = passthrough) => { impl_ndt!(@kind passthrough $head :: $( $tail )::+ $(< $( $lifetime, )* $( $generic ),* >)? $( where { $($bounds)* } )? as $as_ty); }; (@single $head:ident :: $( $tail:ident )::+ $(< $( $lifetime:lifetime, )* $( $generic:ident ),* $(,)? >)? $( where { $($bounds:tt)* } )? as $as_ty:ty = named) => { impl_ndt!(@kind named $head :: $( $tail )::+ $(< $( $lifetime, )* $( $generic ),* >)? $( where { $($bounds)* } )? as $as_ty); }; (@kind inline $($tokens:tt)*) => { impl_ndt!(true, false $($tokens)*); }; (@kind passthrough $($tokens:tt)*) => { impl_ndt!(false, true $($tokens)*); }; (@kind named $($tokens:tt)*) => { impl_ndt!(false, false $($tokens)*); }; // Base implementation. Providing a where clause opts out of automatic Type bounds so // callers can use non-Specta impl generics. ($inline:literal, $container:literal $module_path:literal $ty:ident $(< $( $lifetime:lifetime, )* $( $generic:ident ),* $(,)? >)? where { $($bounds:tt)* } as $as_ty:ty) => { impl<$( $( $lifetime, )* $( $generic ),* )?> Type for $ty $(< $( $lifetime, )* $( $generic ),* >)? where $($bounds)* { fn definition(types: &mut Types) -> DataType { use $crate::datatype; impl_ndt!(@definition_body false stringify!($ty $(< $( $generic ),* >)?), [$( $( $generic ),* )?], [$ty $(< $( $generic ),* >)?], $module_path, $inline, $container, $as_ty, types) } } }; ($inline:literal, $container:literal $module_path:literal $ty:ident $(< $( $lifetime:lifetime, )* $( $generic:ident ),* $(,)? >)? as $as_ty:ty) => { impl<$( $( $lifetime, )* $( $generic ),* )?> Type for $ty $(< $( $lifetime, )* $( $generic ),* >)? where $( $( $generic: Type, )* )? { fn definition(types: &mut Types) -> DataType { use $crate::datatype; impl_ndt!(@definition_body true stringify!($ty $(< $( $generic ),* >)?), [$( $( $generic ),* )?], [$ty $(< $( $generic ),* >)?], $module_path, $inline, $container, $as_ty, types) } } }; ($inline:literal, $container:literal $head:ident :: $( $tail:ident )::+ $(< $( $lifetime:lifetime, )* $( $generic:ident ),* $(,)? >)? where { $($bounds:tt)* } as $as_ty:ty) => { impl<$( $( $lifetime, )* $( $generic ),* )?> Type for $head :: $( $tail )::+ $(< $( $lifetime, )* $( $generic ),* >)? where $($bounds)* { fn definition(types: &mut Types) -> DataType { use $crate::datatype; impl_ndt!(@definition_body false stringify!($head::$( $tail )::+ $(< $( $generic ),* >)?), [$( $( $generic ),* )?], [$head :: $( $tail )::+ $(< $( $generic ),* >)?], impl_ndt!(@module_path $head :: $( $tail )::+), $inline, $container, $as_ty, types) } } }; ($inline:literal, $container:literal $head:ident :: $( $tail:ident )::+ $(< $( $lifetime:lifetime, )* $( $generic:ident ),* $(,)? >)? as $as_ty:ty) => { impl<$( $( $lifetime, )* $( $generic ),* )?> Type for $head :: $( $tail )::+ $(< $( $lifetime, )* $( $generic ),* >)? where $( $( $generic: Type, )* )? { fn definition(types: &mut Types) -> DataType { use $crate::datatype; impl_ndt!(@definition_body true stringify!($head::$( $tail )::+ $(< $( $generic ),* >)?), [$( $( $generic ),* )?], [$head :: $( $tail )::+ $(< $( $generic ),* >)?], impl_ndt!(@module_path $head :: $( $tail )::+), $inline, $container, $as_ty, types) } } }; // Base implementation for types with const generics. Const generics are part of the Rust // implementation but not Specta generic definitions. ($inline:literal, $container:literal [$($generic:ident),*] [$($impl_generics:tt)*] [$($ty:tt)*] [$($specta_generics:tt)*] [$($ty_generics:tt)*] where { $($bounds:tt)* } as $as_ty:ty) => { impl<$($impl_generics)*> Type for $($ty)* $($ty_generics)* where $($bounds)* { fn definition(types: &mut Types) -> DataType { use $crate::datatype; impl_ndt!(@definition_body_const false stringify!($($ty)* $($ty_generics)*), [$($generic),*], [$($ty)* $($specta_generics)*], impl_ndt!(@module_path $($ty)*), $inline, $container, $as_ty, types) } } }; ($inline:literal, $container:literal [$($generic:ident),*] [$($impl_generics:tt)*] [$($ty:tt)*] [$($specta_generics:tt)*] [$($ty_generics:tt)*] as $as_ty:ty) => { impl<$($impl_generics)*> Type for $($ty)* $($ty_generics)* where $($generic: Type,)* { fn definition(types: &mut Types) -> DataType { use $crate::datatype; impl_ndt!(@definition_body_const true stringify!($($ty)* $($ty_generics)*), [$($generic),*], [$($ty)* $($specta_generics)*], impl_ndt!(@module_path $($ty)*), $inline, $container, $as_ty, types) } } }; (@definition_body $typed_generics:tt $sentinel:expr, [$($generic:ident),*], [$($type_name:tt)*], $module_path:expr, $inline:literal, $container:literal, $as_ty:ty, $types:ident) => {{ impl_ndt!(@definition_body_inner false, $typed_generics $sentinel, [$($generic),*], [$($type_name)*], $module_path, $inline, $container, $as_ty, $types) }}; (@definition_body_const $typed_generics:tt $sentinel:expr, [$($generic:ident),*], [$($type_name:tt)*], $module_path:expr, $inline:literal, $container:literal, $as_ty:ty, $types:ident) => {{ impl_ndt!(@definition_body_inner true, $typed_generics $sentinel, [$($generic),*], [$($type_name)*], $module_path, $inline, $container, $as_ty, $types) }}; // Helpers for determining NDT name (@definition_body_inner $has_const_param:literal, $typed_generics:tt $sentinel:expr, [$($generic:ident),*], [$($type_name:tt)*], $module_path:expr, $inline:literal, $container:literal, $as_ty:ty, $types:ident) => {{ static SENTINEL: &str = $sentinel; static GENERICS: &[datatype::GenericDefinition] = &[ $( datatype::GenericDefinition::new( ::std::borrow::Cow::Borrowed(stringify!($generic)), None, ), )* ]; let definition = |types: &mut Types| { DataType::Reference(datatype::NamedDataType::init_with_sentinel( SENTINEL, &[ $( ( datatype::Generic::new(::std::borrow::Cow::Borrowed(stringify!($generic))), impl_ndt!(@generic_dt $typed_generics $generic types), ), )* ], $has_const_param, $container, types, |types, ndt| { ndt.name = ::std::borrow::Cow::Borrowed(impl_ndt!(@type_name $($type_name)*)); ndt.module_path = ::std::borrow::Cow::Borrowed($module_path); ndt.generics = ::std::borrow::Cow::Borrowed(GENERICS); if !$inline && !$container { $( #[allow(dead_code)] pub(crate) struct $generic; impl Type for $generic { fn definition(_: &mut Types) -> DataType { datatype::Generic::new( ::std::borrow::Cow::Borrowed(stringify!($generic)) ).into() } } )* ndt.ty = Some(<$as_ty as Type>::definition(types)); } }, |types| <$as_ty as Type>::definition(types), )) }; if $inline { datatype::inline($types, definition) } else { definition($types) } }}; (@generic_dt true $generic:ident $types:ident) => { <$generic as Type>::definition($types) }; (@generic_dt false $generic:ident $types:ident) => { datatype::Generic::new(::std::borrow::Cow::Borrowed(stringify!($generic))).into() }; // Helpers for determining NDT name (@type_name $head:ident :: $( $tail:ident )::+ $(< $( $lifetime:lifetime, )* $( $generic:ident ),* $(,)? >)?) => { impl_ndt!(@type_name $( $tail )::+ $(< $( $lifetime, )* $( $generic ),* >)?) }; (@type_name $name:ident $(< $( $lifetime:lifetime, )* $( $generic:ident ),* $(,)? >)?) => { stringify!($name) }; // Helpers for determining NDT module path (@module_path $head:ident :: $name:ident) => { stringify!($head) }; (@module_path $head:ident :: $next:ident :: $( $tail:ident )::+) => { concat!( stringify!($head), "::", impl_ndt!(@module_path $next :: $( $tail )::+) ) }; } #[allow(unused_imports)] pub(crate) use _impl_ndt as impl_ndt; pub(crate) use _impl_primitives as impl_primitives; pub(crate) use _impl_tuple as impl_tuple; ================================================ FILE: specta/src/type.rs ================================================ use crate::{Types, datatype::DataType}; mod impls; mod legacy_impls; mod macros; /// Provides runtime type information for a Rust type. /// /// Exporters call this trait to build a [`DataType`] graph and collect any /// referenced named types into [`Types`]. Prefer deriving this trait with /// [`#[derive(Type)]`](derive@crate::Type); hand-written implementations must /// preserve the same invariants as the derive macro. /// /// # Invariants /// /// Implementations should register every named dependency they reference in the /// provided [`Types`] collection. Generic placeholders should only be emitted /// inside the canonical [`NamedDataType`](crate::datatype::NamedDataType) /// definition for the declaring type, not as arbitrary top-level results. /// #[diagnostic::on_unimplemented( message = "the trait `specta::Type` is not implemented for `{Self}`", label = "`{Self}` must implement `Type`", note = "Depending on your use case, this can be fixed in multiple ways: - If your using an type defined in one of your own crates, ensure you have `#[derive(specta::Type)]` on it. - If your using a crate with official Specta support, enable the matching feature flag on the `specta` crate. - If your using an external crate without Specta support, you may need to wrap your type in a new-type wrapper. " )] pub trait Type { /// Returns a [`DataType`] that represents `Self`. /// /// This may mutate `types` by registering `Self` and any named datatypes /// needed by the returned definition. fn definition(types: &mut Types) -> DataType; } ================================================ FILE: specta/src/types.rs ================================================ use std::{ collections::{HashMap, hash_map}, fmt, }; use crate::{ Type, datatype::{NamedDataType, NamedId, NamedReference}, }; /// Collection of named datatypes that can be exported together. /// /// Resolving a [`Type`] adds every named type it depends on to this collection. /// Exporters usually receive a completed `Types` value and iterate over the /// collected [`NamedDataType`] entries. /// /// # Invariants /// /// Internally, entries may temporarily be placeholders while recursive types are /// resolving. Public iterators and [`Types::len`] expose only completed /// [`NamedDataType`] values. #[derive(Default, Clone)] pub struct Types { /// Registered named datatypes keyed by their stable identity. /// /// A `None` value is a placeholder for a datatype whose definition is /// currently being resolved. This lets recursive definitions refer to the /// in-progress type without re-entering resolution indefinitely. pub(crate) types: HashMap>, /// Cached count of completed entries in [`Self::types`]. /// /// Placeholders are excluded. Keeping this count avoids repeatedly walking /// the full map when exporters ask for iterator lengths which we need for `ExactSizeIterator`. pub(crate) len: usize, /// Stack of inline named-type expansions currently being resolved. /// /// Each entry is a hash of the named type sentinel and concrete generic /// arguments for that inline use site. Seeing the same entry twice means an /// inline definition has recursively reached itself, so resolution can emit /// a recursive reference instead of expanding forever. pub(crate) stack: Vec, /// Whether named types discovered in the current context should be inlined. /// /// This is set while resolving fields annotated with `#[specta(inline)]` and /// similar container/wrapper contexts. It is temporarily cleared when /// building canonical named definitions so top-level registrations are not /// accidentally affected by a use-site inline request. pub(crate) should_inline: bool, /// Whether the current named-type definition is being built with const parameters. /// /// This remains `false` unless Specta is exporting the canonical definition /// for a `#[derive(Type)]` type that declares one or more const-generic /// parameters. /// /// Consider a type like this: /// /// ```rs /// #[derive(Type)] /// struct Demo { /// data: [u32; N], /// } /// ``` /// /// If `impl Type for [T; N]` always exported the concrete array length, the /// first encountered value of `N` would be baked into the shared global /// definition for `Demo`, which is wrong. For example: /// /// ```rs /// pub struct A { /// a: Demo<1>, /// b: Demo<2>, /// } /// // becomes: /// // export type A = { a: Demo, b: Demo } /// // export type Demo = { [number] }; // This is invalid for the `b` field. /// /// // and if we encounter the fields in the opposite order it changes: /// /// pub struct B { /// // we flipped field definition /// b: Demo<2>, /// a: Demo<1>, /// } /// // becomes: /// // export type A = { a: Demo, b: Demo } /// // export type Demo = { [number, number] }; // This is invalid for the `a` field. /// ``` /// /// For a length to differ across two instantiations of the same type, the /// type must either have a const parameter or have a generic parameter whose /// type uses a trait associated constant. /// /// Specta does not support the trait-associated-constant case here because /// generic `T` parameters are shadowed by virtual structs that return generic /// references instead of flat datatypes. /// /// Therefore, including the fixed array length is safe as long as the /// current resolving context has no const parameters. This is tracked at /// runtime, avoiding brittle scans of the user's `TokenStream` in the derive /// macro. /// /// `specta_util::FixedArray` can be used to force Specta to export a /// fixed-length array instead of a generic `number[]` when the user knows /// the length is safe to include. This does not fix the core issue, but it /// gives the user a way to assert the specific use site is correct. pub(crate) has_const_params: bool, } impl fmt::Debug for Types { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("Types").field(&self.types).finish() } } impl Types { /// Registers `T` and its named dependencies with the collection. /// /// This consumes and returns `self`, making it convenient to chain multiple /// registrations. pub fn register(mut self) -> Self { T::definition(&mut self); self } /// Registers `T` and its named dependencies with the collection in-place. pub fn register_mut(&mut self) -> &mut Self { T::definition(self); self } /// Gets the named datatype targeted by a [`NamedReference`]. /// /// Returns `None` if the reference is unknown or currently only has an /// internal placeholder entry. pub fn get(&self, r: &NamedReference) -> Option<&NamedDataType> { self.types.get(&r.id)?.as_ref() } /// Returns the number of completed named datatypes in the collection. pub fn len(&self) -> usize { debug_assert_eq!( self.len, self.types .iter() .filter_map(|(_, ndt)| ndt.as_ref()) .count(), "Types count logic mismatch" ); self.len } /// Returns `true` when the typemap has no entries at all. pub fn is_empty(&self) -> bool { debug_assert_eq!( self.len, self.types .iter() .filter_map(|(_, ndt)| ndt.as_ref()) .count(), "Types count logic mismatch" ); self.len == 0 } /// Merges types from another collection into this one. /// /// Existing completed entries in `self` are kept. A placeholder in `self` is /// replaced by a completed entry from `other` when available. pub fn extend(&mut self, other: &Self) { for (id, other) in &other.types { match self.types.get(id) { // Key doesn't exist - insert from other None => { if other.is_some() { self.len += 1; } self.types.insert(id.clone(), other.clone()); } // Key exists with Some - keep self (prefer self over other) Some(Some(_)) => {} // Key exists with None, but other has Some - use other (prefer Some over None) Some(None) if other.is_some() => { self.len += 1; self.types.insert(id.clone(), other.clone()); } // Key exists with None, other also None - do nothing Some(None) => {} } } } /// Sorts completed named datatypes into a consistent order and returns an iterator. /// /// The sort order is not guaranteed to remain identical between releases but is designed to stay stable, /// so that between multiple runs of the exporter you get the same type in the same order in the file. /// /// This method allocates a temporary vector to sort the collection. Prefer /// [`Types::into_unsorted_iter`] if the order does not matter. pub fn into_sorted_iter(&self) -> impl ExactSizeIterator { let mut v = self .types .iter() .filter_map(|(_, ndt)| ndt.as_ref()) .collect::>(); assert_eq!(v.len(), self.len, "Types count logic mismatch"); v.sort_by(|a, b| { a.name .cmp(&b.name) .then(a.module_path.cmp(&b.module_path)) .then(a.location.cmp(&b.location)) }); v.into_iter() } /// Returns an unsorted iterator over completed named datatypes. pub fn into_unsorted_iter(&self) -> impl ExactSizeIterator { UnsortedIter { iter: self.types.iter(), count: self.len, } } /// Mutably modifies each [`NamedDataType`] in the collection. pub fn iter_mut(&mut self, mut f: F) where F: FnMut(&mut NamedDataType), { for (_, ndt) in self.types.iter_mut() { if let Some(ndt) = ndt { f(ndt); } } } /// Transforms each [`NamedDataType`] in the collection. pub fn map(mut self, mut f: F) -> Self where F: FnMut(NamedDataType) -> NamedDataType, { for (_, slot) in self.types.iter_mut() { if let Some(ndt) = slot.take() { *slot = Some(f(ndt)); } } self } } struct UnsortedIter<'a> { iter: hash_map::Iter<'a, NamedId, Option>, count: usize, } impl<'a> Iterator for UnsortedIter<'a> { type Item = &'a NamedDataType; fn next(&mut self) -> Option { self.iter.find_map(|(_, ndt)| ndt.as_ref()) } fn size_hint(&self) -> (usize, Option) { (self.count, Some(self.count)) } } impl ExactSizeIterator for UnsortedIter<'_> {} ================================================ FILE: specta-go/Cargo.toml ================================================ [package] name = "specta-go" description = "Export your Rust types to Go" version = "0.0.2" authors = ["Oscar Beaumont "] edition = "2024" license = "MIT" repository = "https://github.com/specta-rs/specta" documentation = "https://docs.rs/specta-go/latest/specta-go" keywords = ["async", "specta", "rspc", "go", "typesafe"] categories = ["web-programming", "asynchronous"] readme = "../README.md" # /bin/sh RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features [package.metadata."docs.rs"] all-features = true rustdoc-args = ["--cfg", "docsrs"] [lints] workspace = true [dependencies] specta = { version = "=2.0.0-rc.24", path = "../specta" } [dev-dependencies] specta_serde = { package = "specta-serde", version = "=0.0.11", path = "../specta-serde" } ================================================ FILE: specta-go/bindings.go ================================================ package bindings type MyType struct { Field String `json:"field"` } ================================================ FILE: specta-go/src/error.rs ================================================ use std::{error, fmt, io}; use crate::Layout; #[derive(Debug)] /// Errors that can occur during Go code generation. pub enum Error { /// IO error during file operations. Io(io::Error), /// Formatting error while writing generated code. Fmt(fmt::Error), /// Custom format callback failed. Format { /// Context describing which format callback failed. message: &'static str, /// The underlying format error. source: specta::FormatError, }, /// A generated Go identifier used a forbidden name. ForbiddenName { /// Path to the type or field containing the forbidden name. path: String, /// The forbidden Go identifier. name: String, }, /// A BigInt value was encountered but cannot be represented in Go. BigIntForbidden { /// Path to the unsupported BigInt value. path: String, }, /// The configured layout cannot be exported by this operation. UnableToExport(Layout), } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Error::Io(e) => write!(f, "IO error: {e}"), Error::Fmt(e) => write!(f, "Fmt error: {e}"), Error::Format { message, source } => write!(f, "Format error: {message}: {source}"), Error::ForbiddenName { path, name } => { write!(f, "Forbidden name: {name} in {path}") } Error::BigIntForbidden { path } => { write!(f, "BigInt forbidden in {path}") } Error::UnableToExport(layout) => { write!(f, "Unable to export layout: {layout:?}") } } } } impl error::Error for Error {} impl From for Error { fn from(e: io::Error) -> Self { Self::Io(e) } } impl From for Error { fn from(e: fmt::Error) -> Self { Self::Fmt(e) } } impl Error { pub(crate) fn format(message: &'static str, source: specta::FormatError) -> Self { Self::Format { message, source } } } ================================================ FILE: specta-go/src/go.rs ================================================ use std::{borrow::Cow, path::Path}; use specta::{ Format, Types, datatype::{DataType, Fields, Reference}, }; use crate::{ Error, primitives::{self, GoContext}, }; /// Allows configuring the format of the final file. #[derive(Debug, Clone, Copy, Default, PartialEq, Eq)] pub enum Layout { /// Flatten all types into a single file. (Idiomatic for Go packages) #[default] FlatFile, /// Produce a dedicated file for each type (Not recommended for Go) Files, } /// Go language exporter. #[derive(Debug, Clone)] #[non_exhaustive] pub struct Go { /// Content written before the generated Go package declaration. pub header: Cow<'static, str>, /// The output file layout. pub layout: Layout, package_name: String, } impl Default for Go { fn default() -> Self { Self { header: Cow::Borrowed(""), layout: Layout::FlatFile, package_name: "bindings".into(), } } } impl Go { /// Creates a Go exporter using the default configuration. pub fn new() -> Self { Default::default() } /// Sets the generated Go package name. pub fn package_name(mut self, name: impl Into) -> Self { self.package_name = name.into(); self } /// Sets content written before the generated Go package declaration. pub fn header(mut self, header: impl Into>) -> Self { self.header = header.into(); self } /// Exports the provided types into a Go source file string. pub fn export(&self, types: &Types, format: impl Format) -> Result { let mut ctx = GoContext::default(); let mut body = String::new(); let exporter = self.clone(); let formatted_types = format_types(&exporter, types, &format)?; let types = formatted_types.as_ref(); for ndt in types.into_sorted_iter() { let type_def = primitives::export(&exporter, types, ndt, &mut ctx)?; body.push_str(&type_def); body.push('\n'); } let mut out = String::new(); if !exporter.header.is_empty() { out.push_str(&exporter.header); out.push('\n'); } out.push_str("package "); out.push_str(&exporter.package_name); out.push_str("\n\n"); if !ctx.imports.is_empty() { out.push_str("import (\n"); let mut sorted: Vec<_> = ctx.imports.iter().collect(); sorted.sort(); for imp in sorted { out.push_str(&format!("\t\"{}\"\n", imp)); } out.push_str(")\n\n"); } out.push_str(&body); Ok(out) } /// Exports the provided types to a Go source file at the given path. pub fn export_to( &self, path: impl AsRef, types: &Types, format: impl Format, ) -> Result<(), Error> { if self.layout == Layout::Files { return Err(Error::UnableToExport(Layout::Files)); } let content = self.export(types, format)?; if let Some(parent) = path.as_ref().parent() { std::fs::create_dir_all(parent)?; } std::fs::write(path, content)?; Ok(()) } } fn format_types<'a>( exporter: &Go, types: &'a Types, format: &dyn Format, ) -> Result, Error> { let mapped_types = format .map_types(types) .map_err(|err| Error::format("type graph formatter failed", err))?; Ok(Cow::Owned( map_types_for_datatype_format(exporter, mapped_types.as_ref(), Some(format))?.into_owned(), )) } fn map_datatype_format( exporter: &Go, format: Option<&dyn Format>, types: &Types, dt: &DataType, ) -> Result { let Some(format) = format else { return Ok(dt.clone()); }; let mapped = format .map_type(types, dt) .map_err(|err| Error::format("datatype formatter failed", err))?; match mapped { Cow::Borrowed(dt) => { map_datatype_format_children(exporter, Some(format), types, dt.clone()) } Cow::Owned(dt) => map_datatype_format_children(exporter, Some(format), types, dt), } } fn map_datatype_format_children( exporter: &Go, format: Option<&dyn Format>, types: &Types, mut dt: DataType, ) -> Result { match &mut dt { DataType::Primitive(_) => {} DataType::List(list) => { *list.ty = map_datatype_format(exporter, format, types, &list.ty)?; } DataType::Map(map) => { let key = map_datatype_format(exporter, format, types, map.key_ty())?; let value = map_datatype_format(exporter, format, types, map.value_ty())?; map.set_key_ty(key); map.set_value_ty(value); } DataType::Nullable(inner) => { **inner = map_datatype_format(exporter, format, types, inner)?; } DataType::Struct(strct) => map_datatype_fields(exporter, format, types, &mut strct.fields)?, DataType::Enum(enm) => { for (_, variant) in &mut enm.variants { map_datatype_fields(exporter, format, types, &mut variant.fields)?; } } DataType::Tuple(tuple) => { for element in &mut tuple.elements { *element = map_datatype_format(exporter, format, types, element)?; } } DataType::Intersection(intersection) => { for element in intersection { *element = map_datatype_format(exporter, format, types, element)?; } } DataType::Reference(Reference::Named(reference)) => { if let specta::datatype::NamedReferenceType::Reference { generics, .. } = &mut reference.inner { for (_, generic) in generics { *generic = map_datatype_format(exporter, format, types, generic)?; } } } DataType::Reference(Reference::Opaque(_)) | DataType::Generic(_) => {} } Ok(dt) } fn map_datatype_fields( exporter: &Go, format: Option<&dyn Format>, types: &Types, fields: &mut Fields, ) -> Result<(), Error> { match fields { Fields::Unit => {} Fields::Unnamed(unnamed) => { for field in &mut unnamed.fields { if let Some(ty) = field.ty.as_mut() { *ty = map_datatype_format(exporter, format, types, ty)?; } } } Fields::Named(named) => { for (_, field) in &mut named.fields { if let Some(ty) = field.ty.as_mut() { *ty = map_datatype_format(exporter, format, types, ty)?; } } } } Ok(()) } fn map_types_for_datatype_format<'a>( exporter: &Go, types: &'a Types, format: Option<&dyn Format>, ) -> Result, Error> { if format.is_none() { return Ok(Cow::Borrowed(types)); } let mut mapped_types = types.clone(); let mut map_err = None; mapped_types.iter_mut(|ndt| { if map_err.is_some() { return; } let Some(ty) = &ndt.ty else { return; }; match map_datatype_format(exporter, format, types, ty) { Ok(mapped) => ndt.ty = Some(mapped), Err(err) => map_err = Some(err), } }); if let Some(err) = map_err { return Err(err); } Ok(Cow::Owned(mapped_types)) } ================================================ FILE: specta-go/src/lib.rs ================================================ //! [Go](https://go.dev) language exporter for [Specta](specta). //! //!
//! This crate is still in active development and is not yet ready for general purpose use! //!
//! //! # Usage //! //! ```rust //! use specta::Types; //! use specta_go::Go; //! //! #[derive(specta::Type)] //! pub struct MyType { //! pub field: String, //! } //! //! let types = Types::default().register::(); //! //! Go::default() //! .export_to("./bindings.go", &types, specta_serde::Format) //! .unwrap(); //! ``` #![cfg_attr(docsrs, feature(doc_cfg))] #![doc( html_logo_url = "https://github.com/specta-rs/specta/raw/main/.github/logo-128.png", html_favicon_url = "https://github.com/specta-rs/specta/raw/main/.github/logo-128.png" )] mod error; mod go; mod primitives; mod reserved_names; pub use error::Error; pub use go::{Go, Layout}; ================================================ FILE: specta-go/src/primitives.rs ================================================ use std::collections::HashSet; use specta::{ Types, datatype::{ DataType, Enum, Fields, Generic, NamedDataType, NamedReferenceType, Primitive, Reference, Struct, }, }; use crate::{Error, Go, reserved_names::RESERVED_GO_NAMES}; /// Tracks necessary Go imports (e.g. "time", "encoding/json") #[derive(Default)] pub struct GoContext { pub imports: HashSet, } impl GoContext { pub fn add_import(&mut self, import: &str) { self.imports.insert(import.to_string()); } } pub fn export( exporter: &Go, types: &Types, ndt: &NamedDataType, ctx: &mut GoContext, ) -> Result { let mut s = String::new(); let docs = &ndt.docs; if !docs.is_empty() { for line in docs.lines() { s.push_str("// "); s.push_str(line); s.push('\n'); } } let name = to_pascal_case(&ndt.name); if RESERVED_GO_NAMES.contains(&name.as_str()) { return Err(Error::ForbiddenName { path: ndt.name.to_string(), name: ndt.name.to_string(), }); } s.push_str("type "); s.push_str(&name); if !ndt.generics.is_empty() { s.push('['); for (i, g) in ndt.generics.iter().enumerate() { if i != 0 { s.push_str(", "); } s.push_str(g.name.as_ref()); s.push_str(" any"); } s.push(']'); } s.push(' '); let generic_names = ndt .generics .iter() .map(|generic| generic.reference()) .collect::>(); let Some(ty) = &ndt.ty else { return Ok(String::new()); }; match ty { DataType::Struct(st) => { s.push_str("struct {\n"); struct_fields( &mut s, exporter, types, &generic_names, st, vec![ndt.name.to_string()], ctx, )?; s.push('}'); } DataType::Enum(e) => { s.push_str("struct {\n"); enum_variants( &mut s, exporter, types, &generic_names, e, vec![ndt.name.to_string()], ctx, )?; s.push('}'); } DataType::Tuple(t) => { if t.elements.len() == 1 { datatype( &mut s, exporter, types, &generic_names, &t.elements[0], vec![ndt.name.to_string(), "0".into()], ctx, )?; } else { s.push_str("[]any"); } } _ => { datatype( &mut s, exporter, types, &generic_names, ty, vec![ndt.name.to_string()], ctx, )?; } } s.push('\n'); Ok(s) } fn struct_fields( s: &mut String, exporter: &Go, types: &Types, generic_names: &[Generic], st: &Struct, location: Vec, ctx: &mut GoContext, ) -> Result<(), Error> { match &st.fields { Fields::Unit => {} Fields::Unnamed(fields) => { for (i, field) in fields.fields.iter().enumerate() { s.push('\t'); s.push_str(&format!("Field{}", i)); s.push(' '); if field.optional { s.push('*'); } if let Some(ty) = field.ty.as_ref() { let mut location = location.clone(); location.push(i.to_string()); datatype(s, exporter, types, generic_names, ty, location, ctx)?; } else { s.push_str("any"); } s.push('\n'); } } Fields::Named(fields) => { for (name, field) in &fields.fields { let docs = &field.docs; if !docs.is_empty() { s.push_str("\t// "); s.push_str(docs.replace('\n', "\n\t// ").trim()); s.push('\n'); } s.push('\t'); s.push_str(&to_pascal_case(name)); s.push(' '); if field.optional { s.push('*'); } if let Some(ty) = field.ty.as_ref() { let mut location = location.clone(); location.push(name.to_string()); datatype(s, exporter, types, generic_names, ty, location, ctx)?; } else { s.push_str("any"); } if field.optional { s.push_str(&format!(" `json:\"{},omitempty\"`\n", name)); } else { s.push_str(&format!(" `json:\"{}\"`\n", name)); } } } } Ok(()) } fn enum_variants( s: &mut String, exporter: &Go, types: &Types, generic_names: &[Generic], e: &Enum, location: Vec, ctx: &mut GoContext, ) -> Result<(), Error> { for (name, variant) in &e.variants { let docs = &variant.docs; if !docs.is_empty() { s.push_str("\t// "); s.push_str(docs); s.push('\n'); } s.push('\t'); s.push_str(&to_pascal_case(name)); s.push(' '); s.push('*'); match &variant.fields { Fields::Unit => s.push_str("bool"), Fields::Unnamed(f) => { s.push_str("struct {\n"); for (i, field) in f.fields.iter().enumerate() { s.push_str("\t\tValue"); s.push_str(&i.to_string()); s.push(' '); if let Some(ty) = field.ty.as_ref() { let mut location = location.clone(); location.push(name.to_string()); location.push(i.to_string()); datatype(s, exporter, types, generic_names, ty, location, ctx)?; } else { s.push_str("any"); } s.push_str(&format!(" `json:\"{}\"`\n", i)); } s.push('\t'); s.push('}'); } Fields::Named(f) => { s.push_str("struct {\n\t"); let mut fill_in = Struct::unit(); fill_in.fields = Fields::Named(f.clone()); let mut location = location.clone(); location.push(name.to_string()); struct_fields(s, exporter, types, generic_names, &fill_in, location, ctx)?; s.push('\t'); s.push('}'); } } s.push_str(&format!(" `json:\"{},omitempty\"`\n", name)); } Ok(()) } fn datatype( s: &mut String, exporter: &Go, types: &Types, generic_names: &[Generic], dt: &DataType, location: Vec, ctx: &mut GoContext, ) -> Result<(), Error> { match dt { DataType::Primitive(p) => match p { Primitive::i8 => s.push_str("int8"), Primitive::i16 => s.push_str("int16"), Primitive::i32 => s.push_str("int32"), Primitive::i64 | Primitive::isize => s.push_str("int64"), Primitive::u8 => s.push_str("uint8"), Primitive::u16 => s.push_str("uint16"), Primitive::u32 => s.push_str("uint32"), Primitive::u64 | Primitive::usize => s.push_str("uint64"), Primitive::f16 | Primitive::f32 => s.push_str("float32"), Primitive::f64 | Primitive::f128 => s.push_str("float64"), Primitive::bool => s.push_str("bool"), Primitive::str | Primitive::char => s.push_str("string"), Primitive::i128 | Primitive::u128 => { return Err(Error::BigIntForbidden { path: location.join("."), }); } }, DataType::Nullable(t) => { s.push('*'); datatype(s, exporter, types, generic_names, t, location, ctx)?; } DataType::Map(m) => { s.push_str("map["); datatype( s, exporter, types, generic_names, m.key_ty(), location.clone(), ctx, )?; s.push(']'); datatype( s, exporter, types, generic_names, m.value_ty(), location, ctx, )?; } DataType::List(l) => { s.push_str("[]"); datatype(s, exporter, types, generic_names, &l.ty, location, ctx)?; } DataType::Tuple(t) => { if t.elements.is_empty() { s.push_str("struct{}"); } else { s.push_str("[]any"); } } DataType::Struct(st) => { s.push_str("struct {\n"); struct_fields(s, exporter, types, generic_names, st, location, ctx)?; s.push('}'); } DataType::Enum(e) => { s.push_str("struct {\n"); enum_variants(s, exporter, types, generic_names, e, location, ctx)?; s.push('}'); } DataType::Reference(r) => match r { Reference::Named(r) => { let ndt = types.get(r).ok_or_else(|| Error::ForbiddenName { path: "lookup".into(), name: "missing_reference_in_collection".into(), })?; s.push_str(&to_pascal_case(&ndt.name)); let generics = match &r.inner { NamedReferenceType::Reference { generics, .. } => generics.as_slice(), NamedReferenceType::Inline { .. } | NamedReferenceType::Recursive => &[], }; if !generics.is_empty() { s.push('['); for (i, (_, g)) in generics.iter().enumerate() { if i != 0 { s.push_str(", "); } let mut location = location.clone(); location.push(format!("generic{}", i)); datatype(s, exporter, types, generic_names, g, location, ctx)?; } s.push(']'); } } Reference::Opaque(o) => match o.type_name() { "String" | "char" => s.push_str("string"), "bool" => s.push_str("bool"), "i8" | "i16" | "i32" | "isize" => s.push_str("int"), "u8" | "u16" | "u32" | "usize" => s.push_str("uint"), "i64" => s.push_str("int64"), "u64" => s.push_str("uint64"), "f32" => s.push_str("float32"), "f64" => s.push_str("float64"), "SystemTime" | "DateTime" => { ctx.add_import("time"); s.push_str("time.Time"); } "Duration" => { ctx.add_import("time"); s.push_str("time.Duration"); } _ => s.push_str("any"), }, }, DataType::Generic(g) => { let name = generic_names .iter() .find(|candidate| candidate.reference() == *g) .map(|generic| generic.name().as_ref()) .unwrap_or("any"); s.push_str(name); } DataType::Intersection(_) => s.push_str("any"), } Ok(()) } fn to_pascal_case(s: &str) -> String { let mut result = String::with_capacity(s.len()); let mut next_upper = true; for c in s.chars() { if c == '_' { next_upper = true; } else if next_upper { result.push(c.to_ascii_uppercase()); next_upper = false; } else { result.push(c); } } result } ================================================ FILE: specta-go/src/reserved_names.rs ================================================ /// Reserved keywords and common types in the Go programming language. pub(crate) const RESERVED_GO_NAMES: &[&str] = &[ // Keywords "break", "default", "func", "interface", "select", "case", "defer", "go", "map", "struct", "chan", "else", "goto", "package", "switch", "const", "fallthrough", "if", "range", "type", "continue", "for", "import", "return", "var", // Built-in Types "bool", "byte", "complex64", "complex128", "error", "float32", "float64", "int", "int8", "int16", "int32", "int64", "rune", "string", "uint", "uint8", "uint16", "uint32", "uint64", "uintptr", "any", "comparable", // Built-in Constants "true", "false", "iota", "nil", // Built-in Functions "append", "cap", "close", "complex", "copy", "delete", "imag", "len", "make", "new", "panic", "print", "println", "real", "recover", ]; ================================================ FILE: specta-jsonschema/Cargo.toml ================================================ [package] name = "specta-jsonschema" description = "Export your Rust types to a JSON Schema" version = "0.0.2" authors = ["Oscar Beaumont "] edition = "2024" license = "MIT" repository = "https://github.com/specta-rs/specta" documentation = "https://docs.rs/specta-jsonschema/latest/specta-jsonschema" keywords = ["async", "specta", "rspc", "jsonschema", "typesafe"] categories = ["web-programming", "asynchronous"] readme = "../README.md" # /bin/sh RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features [package.metadata."docs.rs"] all-features = true rustdoc-args = ["--cfg", "docsrs"] [lints] workspace = true [features] default = [] [dependencies] specta = { version = "=2.0.0-rc.24", path = "../specta" } schemars = { version = "1.2", default-features = false } serde = { version = "1", features = ["derive"] } serde_json = "1" thiserror = "2" [dev-dependencies] specta = { version = "=2.0.0-rc.24", path = "../specta", features = ["derive", "collect"] } specta-serde = { path = "../specta-serde" } specta-util = { path = "../specta-util", features = ["serde"] } insta = { version = "1", features = ["json"] } ================================================ FILE: specta-jsonschema/examples/jsonschema.rs ================================================ #![allow(missing_docs)] use serde::{Deserialize, Serialize}; use specta::{Type, Types}; use specta_jsonschema::{JsonSchema, SchemaVersion}; #[derive(Serialize, Deserialize, Type)] #[serde(rename_all = "camelCase")] pub struct User { pub id: u32, pub name: String, pub email: Option, pub role: Role, } #[derive(Serialize, Deserialize, Type)] pub enum Role { Admin, User, Guest, } #[derive(Serialize, Deserialize, Type)] #[serde(rename_all = "camelCase")] pub struct Post { pub id: u32, pub title: String, pub content: String, pub author_id: u32, pub tags: Vec, } fn main() { // Create a type collection with all the types we want to export let types = Types::default() .register::() .register::() .register::(); // Export to JSON Schema (Draft 7) let schema = JsonSchema::default() .schema_version(SchemaVersion::Draft7) .title("My API Types") .description("JSON Schema for my API types") .export(&types, specta_serde::Format) .unwrap(); println!("{}", schema); } ================================================ FILE: specta-jsonschema/src/error.rs ================================================ use std::io; #[derive(Debug, thiserror::Error)] pub enum Error { #[error("IO error: {0}")] Io(#[from] io::Error), #[error("JSON serialization error: {0}")] Json(#[from] serde_json::Error), #[error("Invalid schema version: {0}")] InvalidSchemaVersion(String), #[error("Duplicate type name '{name}' at {location1} and {location2}")] DuplicateTypeName { name: String, location1: String, location2: String, }, #[error("Invalid type name '{name}' at {path}")] InvalidTypeName { name: String, path: String }, #[error("Unable to convert schema: {0}")] ConversionError(String), #[error("Format error: {message}: {source}")] Format { message: &'static str, source: specta::FormatError, }, #[error("Unsupported DataType: {0}")] UnsupportedDataType(String), #[error("Invalid reference: {0}")] InvalidReference(String), } impl Error { pub(crate) fn format(message: &'static str, source: specta::FormatError) -> Self { Self::Format { message, source } } } ================================================ FILE: specta-jsonschema/src/import.rs ================================================ use crate::Error; use schemars::Schema; use serde_json::{Map as JsonMap, Value}; use specta::datatype::*; use std::borrow::Cow; /// Convert a schemars Schema to a Specta DataType pub fn from_schema(schema: &Schema) -> Result { match schema.as_bool() { Some(true) => { // True schema = any // We use an empty struct as a placeholder for "any" Ok(Struct::named().build()) } Some(false) => { // False schema = never type (nothing validates) Err(Error::ConversionError( "false schema (never type) not supported".into(), )) } None => schema .as_object() .ok_or_else(|| Error::ConversionError("schema must be object or bool".into())) .and_then(schema_object_to_datatype), } } fn value_to_datatype(value: &Value) -> Result { let schema: &Schema = value.try_into()?; from_schema(schema) } fn schema_object_to_datatype(obj: &JsonMap) -> Result { // Handle $ref if let Some(reference) = obj.get("$ref").and_then(Value::as_str) { // We use an opaque reference since we do not have a Types context here. return Ok(DataType::Reference(Reference::opaque(reference.to_owned()))); } // Handle const values (literals) if obj.get("const").is_some() { // Specta does not currently expose a direct literal DataType variant. return Ok(DataType::Primitive(Primitive::str)); } // Handle enum values (for string enums) if let Some(enum_values) = obj.get("enum").and_then(Value::as_array) && enum_values.iter().all(|v| v.is_string()) { let mut e = Enum::default(); for value in enum_values { if let Some(s) = value.as_str() { let variant = Variant::unit(); e.variants.push((Cow::Owned(s.to_string()), variant)); } } return Ok(DataType::Enum(e)); } // Handle anyOf / oneOf (union types) if let Some(any_of) = obj.get("anyOf").and_then(Value::as_array) { return handle_any_of(any_of); } if let Some(one_of) = obj.get("oneOf").and_then(Value::as_array) { return handle_any_of(one_of); } // Handle type-based schemas if let Some(instance_type) = obj.get("type") { return instance_type_to_datatype(instance_type, obj); } // No type specified - return empty struct (acts like "any") Ok(Struct::named().build()) } fn instance_type_to_datatype( instance_type: &Value, obj: &JsonMap, ) -> Result { match instance_type { Value::String(t) => instance_type_name_to_datatype(t, obj), Value::Array(types) => { // Multiple types - create a union (enum with unnamed variants) let mut e = Enum::default(); for (i, item) in types.iter().enumerate() { if let Value::String(t) = item { let dt = instance_type_name_to_datatype(t, obj)?; let variant = Variant::unnamed().field(Field::new(dt)).build(); e.variants .push((Cow::Owned(format!("Variant{}", i)), variant)); } } Ok(DataType::Enum(e)) } _ => Err(Error::ConversionError( "schema `type` must be a string or array".into(), )), } } fn instance_type_name_to_datatype( instance_type: &str, obj: &JsonMap, ) -> Result { match instance_type { "null" => { // Null type - use empty tuple Ok(DataType::Tuple(Tuple::new(vec![]))) } "boolean" => Ok(DataType::Primitive(Primitive::bool)), "string" => Ok(DataType::Primitive(Primitive::str)), "number" => { if let Some(format) = obj.get("format").and_then(Value::as_str) { match format { "float" => Ok(DataType::Primitive(Primitive::f32)), "double" => Ok(DataType::Primitive(Primitive::f64)), _ => Ok(DataType::Primitive(Primitive::f64)), } } else { Ok(DataType::Primitive(Primitive::f64)) } } "integer" => { if let Some(format) = obj.get("format").and_then(Value::as_str) { match format { "int32" => Ok(DataType::Primitive(Primitive::i32)), "int64" => Ok(DataType::Primitive(Primitive::i64)), "uint32" => Ok(DataType::Primitive(Primitive::u32)), "uint64" => Ok(DataType::Primitive(Primitive::u64)), _ => Ok(DataType::Primitive(Primitive::i32)), } } else { Ok(DataType::Primitive(Primitive::i32)) } } "array" => { if let Some(items) = obj.get("items") { match items { Value::Object(_) | Value::Bool(_) => { let item_dt = value_to_datatype(items)?; Ok(DataType::List(List::new(item_dt))) } Value::Array(schemas) => { // Tuple with specific items let elements: Result, _> = schemas.iter().map(value_to_datatype).collect(); Ok(DataType::Tuple(Tuple::new(elements?))) } _ => Err(Error::ConversionError( "array `items` must be a schema or list of schemas".into(), )), } } else { // Array without items = array of empty struct (any) Ok(DataType::List(List::new(Struct::named().build()))) } } "object" => { if let Some(properties) = obj.get("properties").and_then(Value::as_object) && !properties.is_empty() { // Build struct from properties let mut builder = Struct::named(); let required: Vec<&str> = obj .get("required") .and_then(Value::as_array) .map(|values| values.iter().filter_map(Value::as_str).collect()) .unwrap_or_default(); for (name, schema) in properties { let dt = value_to_datatype(schema)?; let is_optional = !required.contains(&name.as_str()); let mut field = Field::new(dt); field.optional = is_optional; builder.field_mut(Cow::Owned(name.clone()), field); } return Ok(builder.build()); } if let Some(additional) = obj.get("additionalProperties") { match additional { Value::Object(_) => { let value_dt = value_to_datatype(additional)?; return Ok(DataType::Map(Map::new( DataType::Primitive(Primitive::str), value_dt, ))); } Value::Bool(true) => { return Ok(DataType::Map(Map::new( DataType::Primitive(Primitive::str), Struct::named().build(), ))); } Value::Bool(false) => {} _ => { return Err(Error::ConversionError( "`additionalProperties` must be a boolean or schema".into(), )); } } } Ok(Struct::named().build()) } _ => Ok(Struct::named().build()), } } fn handle_any_of(schemas: &[Value]) -> Result { // Check if it's a nullable pattern (type | null) if schemas.len() == 2 { let is_null = |s: &Value| { s.as_object() .and_then(|obj| obj.get("type")) .is_some_and(|ty| matches!(ty, Value::String(t) if t == "null")) }; if is_null(&schemas[0]) { return Ok(DataType::Nullable(Box::new(value_to_datatype( &schemas[1], )?))); } if is_null(&schemas[1]) { return Ok(DataType::Nullable(Box::new(value_to_datatype( &schemas[0], )?))); } } // General anyOf - create enum with unnamed variants let mut e = Enum::default(); for (i, schema) in schemas.iter().enumerate() { let dt = value_to_datatype(schema)?; let variant = Variant::unnamed().field(Field::new(dt)).build(); e.variants .push((Cow::Owned(format!("Variant{}", i)), variant)); } Ok(DataType::Enum(e)) } ================================================ FILE: specta-jsonschema/src/json_schema.rs ================================================ use crate::{Error, Layout, SchemaVersion, primitives}; use serde_json::Value; use specta::{Format, Types, datatype::NamedDataType}; use std::{borrow::Cow, collections::BTreeMap, path::Path}; /// JSON Schema exporter configuration #[derive(Debug, Clone)] pub struct JsonSchema { /// JSON Schema version to use pub schema_version: SchemaVersion, /// Layout for output organization pub layout: Layout, /// Optional title for the root schema pub title: Option, /// Optional description for the root schema pub description: Option, } impl Default for JsonSchema { fn default() -> Self { Self { schema_version: SchemaVersion::default(), layout: Layout::default(), title: None, description: None, } } } impl JsonSchema { /// Create a new JsonSchema exporter with default settings pub fn new() -> Self { Self::default() } /// Set JSON Schema version pub fn schema_version(mut self, version: SchemaVersion) -> Self { self.schema_version = version; self } /// Set output layout pub fn layout(mut self, layout: Layout) -> Self { self.layout = layout; self } /// Set root schema title pub fn title(mut self, title: impl Into) -> Self { self.title = Some(title.into()); self } /// Set root schema description pub fn description(mut self, description: impl Into) -> Self { self.description = Some(description.into()); self } /// Export types to JSON Schema as a JSON string pub fn export(&self, types: &Types, format: impl Format) -> Result { let value = self.export_as_value(types, format)?; Ok(serde_json::to_string_pretty(&value)?) } /// Export types to JSON Schema as serde_json::Value pub fn export_as_value(&self, types: &Types, format: impl Format) -> Result { let exporter = self.clone(); let formatted_types = format_types(&exporter, types, &format)?; let types = formatted_types.as_ref(); match exporter.layout { Layout::SingleFile => exporter.export_single_file(types), Layout::Files => Err(Error::ConversionError( "Use export_to() for Files layout".to_string(), )), } } /// Export to file or directory pub fn export_to( &self, path: impl AsRef, types: &Types, format: impl Format, ) -> Result<(), Error> { let exporter = self.clone(); let formatted_types = format_types(&exporter, types, &format)?; let types = formatted_types.as_ref(); let path = path.as_ref(); match exporter.layout { Layout::SingleFile => { let json = exporter.export_single_file(types)?; if let Some(parent) = path.parent() { std::fs::create_dir_all(parent)?; } std::fs::write(path, serde_json::to_string_pretty(&json)?)?; Ok(()) } Layout::Files => exporter.export_files(path, types), } } fn export_single_file(&self, types: &Types) -> Result { let mut definitions = BTreeMap::new(); // Convert each type to a schema for ndt in types.into_sorted_iter() { let schema = primitives::export(self, types, &ndt)?; let name = ndt.name.to_string(); definitions.insert(name, schema); } // Build root schema let defs_key = self.schema_version.definitions_key(); let mut root = serde_json::json!({ "$schema": self.schema_version.uri(), defs_key: definitions, }); if let Some(title) = &self.title { root.as_object_mut() .unwrap() .insert("title".to_string(), Value::String(title.clone())); } if let Some(description) = &self.description { root.as_object_mut().unwrap().insert( "description".to_string(), Value::String(description.clone()), ); } Ok(root) } fn export_files(&self, base_path: &Path, types: &Types) -> Result<(), Error> { // Create base directory std::fs::create_dir_all(base_path)?; // Group types by module path let mut by_module: BTreeMap> = BTreeMap::new(); for ndt in types.into_sorted_iter() { // module_path returns &Cow<'static, str> which is like &String // We need to convert path segments to a string let module = ndt.module_path.to_string().replace("::", "/"); by_module.entry(module).or_default().push(ndt.clone()); } // Write each type to its own file for (module, ndts) in by_module { let module_dir = if module.is_empty() { base_path.to_path_buf() } else { base_path.join(&module) }; std::fs::create_dir_all(&module_dir)?; for ndt in &ndts { let schema = primitives::export(self, types, ndt)?; let filename = format!("{}.schema.json", ndt.name); let file_path = module_dir.join(filename); // Create a root schema for this type let mut root = serde_json::json!({ "$schema": self.schema_version.uri(), }); // Merge in the type's schema properties if let Some(obj) = schema.as_object() { for (k, v) in obj { root.as_object_mut().unwrap().insert(k.clone(), v.clone()); } } std::fs::write(file_path, serde_json::to_string_pretty(&root)?)?; } } Ok(()) } } fn format_types<'a>( exporter: &JsonSchema, types: &'a Types, format: &dyn Format, ) -> Result, Error> { let mapped_types = format .map_types(types) .map_err(|err| Error::format("type graph formatter failed", err))?; Ok(Cow::Owned(mapped_types.into_owned())) } ================================================ FILE: specta-jsonschema/src/layout.rs ================================================ /// Controls how JSON schemas are organized in output #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Layout { /// Single file with all types in $defs section (default) /// All type definitions are placed in a single JSON file under the /// definitions/$defs key. SingleFile, /// Separate .json file per type, organized by module path /// Each type gets its own file like: `my_module/MyType.schema.json` Files, } impl Default for Layout { fn default() -> Self { Self::SingleFile } } ================================================ FILE: specta-jsonschema/src/lib.rs ================================================ //! [JSON Schema](https://json-schema.org) exporter and importer for [Specta](specta). //! //! This crate provides bidirectional conversion between Specta types and JSON Schema: //! - Export Specta types to JSON Schema (Draft 7, 2019-09, or 2020-12) //! - Import JSON Schema definitions as Specta DataTypes //! //! # Features //! //! - **Bidirectional conversion**: Export to JSON Schema and import from JSON Schema //! - **Multiple schema versions**: Support for Draft 7 (default), Draft 2019-09, and Draft 2020-12 //! - **Serde integration**: Use `specta-serde` in userspace before export //! - **Flexible layouts**: Single file with `$defs` or separate files per type //! - **schemars ecosystem**: Compatible with the schemars crate for interoperability //! //! # Usage //! //! ## Exporting to JSON Schema //! //! ```ignore //! use serde::{Deserialize, Serialize}; //! use specta::{Type, Types}; //! use specta_jsonschema::{JsonSchema, SchemaVersion}; //! //! #[derive(Serialize, Deserialize, Type)] //! #[serde(rename_all = "camelCase")] //! pub struct User { //! pub id: u32, //! pub name: String, //! pub email: Option, //! } //! //! fn main() { //! let types = Types::default() //! .register::(); //! //! // Export to JSON Schema //! let schema = JsonSchema::default() //! .schema_version(SchemaVersion::Draft7) //! .export(&types, specta_serde::Format) //! .unwrap(); //! //! println!("{}", schema); //! } //! ``` //! //! ## With Serde Integration //! //! ```ignore //! use serde::{Deserialize, Serialize}; //! use specta::{Type, Types}; //! use specta_jsonschema::JsonSchema; //! //! #[derive(Serialize, Deserialize, Type)] //! #[serde(rename_all = "camelCase")] //! pub struct User { //! pub user_id: u32, //! #[serde(rename = "fullName")] //! pub name: String, //! } //! //! fn main() { //! let types = Types::default().register::(); //! //! JsonSchema::default() //! .export_to("./schema.json", &types, specta_serde::Format) //! .unwrap(); //! } //! ``` //! //! ## Importing from JSON Schema //! //! ```ignore //! use schemars::Schema; //! use specta_jsonschema::import::from_schema; //! //! let schema: Schema = serde_json::from_str(r#"{ //! "type": "object", //! "properties": { //! "name": { "type": "string" }, //! "age": { "type": "integer" } //! }, //! "required": ["name"] //! }"#).unwrap(); //! //! let datatype = from_schema(&schema).unwrap(); //! ``` //! //! ## Multiple Output Layouts //! //! ```ignore //! use specta_jsonschema::{JsonSchema, Layout}; //! //! // Single file with all types in $defs //! JsonSchema::default() //! .layout(Layout::SingleFile) //! .export_to( //! "./schema.json", //! &types, //! specta_serde::Format, //! ) //! .unwrap(); //! //! // Separate file per type, organized by module //! JsonSchema::default() //! .layout(Layout::Files) //! .export_to( //! "./schemas/", //! &types, //! specta_serde::Format, //! ) //! .unwrap(); //! ``` #![cfg_attr(docsrs, feature(doc_cfg))] #![doc( html_logo_url = "https://github.com/specta-rs/specta/raw/main/.github/logo-128.png", html_favicon_url = "https://github.com/specta-rs/specta/raw/main/.github/logo-128.png" )] #![allow(warnings)] // TODO: leaving this until it's implemented to avoid unnecessary warnings. mod error; pub mod import; mod json_schema; mod layout; mod primitives; mod schema_version; pub use error::Error; pub use json_schema::JsonSchema; pub use layout::Layout; pub use schema_version::SchemaVersion; // Legacy function - kept for backward compatibility #[deprecated(note = "Use import::from_schema instead")] pub fn to_ast(schema: &schemars::Schema) -> Result { import::from_schema(schema) } ================================================ FILE: specta-jsonschema/src/primitives.rs ================================================ use crate::{Error, JsonSchema}; use serde_json::{Map, Value, json}; use specta::{ Types, datatype::{NamedDataType, *}, }; /// Convert a NamedDataType to a JSON Schema definition pub fn export(js: &JsonSchema, types: &Types, ndt: &NamedDataType) -> Result { let Some(ty) = &ndt.ty else { return Ok(json!({})); }; datatype_to_schema(js, types, ty, true) } /// Convert a DataType to a JSON Schema, optionally as a reference pub fn datatype_to_schema( js: &JsonSchema, types: &Types, dt: &DataType, is_definition: bool, ) -> Result { match dt { // Primitives DataType::Primitive(p) => Ok(primitive_to_schema(p)), // Nullable DataType::Nullable(inner) => { let inner_schema = datatype_to_schema(js, types, inner, false)?; Ok(json!({ "anyOf": [ inner_schema, {"type": "null"} ] })) } // List/Array DataType::List(list) => { let items = datatype_to_schema(js, types, &list.ty, false)?; if let Some(len) = list.length { // Fixed-length array (tuple-like) Ok(json!({ "type": "array", "items": items, "minItems": len, "maxItems": len })) } else { // Variable-length array Ok(json!({ "type": "array", "items": items })) } } // Map DataType::Map(map) => { let value_schema = datatype_to_schema(js, types, map.value_ty(), false)?; // JSON Schema uses additionalProperties for maps Ok(json!({ "type": "object", "additionalProperties": value_schema })) } // Struct DataType::Struct(s) => struct_to_schema(js, types, s), // Enum DataType::Enum(e) => enum_to_schema(js, types, e), // Tuple DataType::Tuple(t) => tuple_to_schema(js, types, t), // Reference DataType::Reference(r) => { match r { Reference::Named(r) => { if is_definition { // When exporting a definition, inline it if let Some(referenced_ndt) = types.get(r) { let Some(ty) = &referenced_ndt.ty else { return Ok(json!({})); }; datatype_to_schema(js, types, ty, true) } else { Err(Error::InvalidReference( "Reference not found in Types".to_string(), )) } } else { // Use $ref for references let defs_key = js.schema_version.definitions_key(); if let Some(referenced_ndt) = types.get(r) { Ok(json!({ "$ref": format!("#/{}/{}", defs_key, referenced_ndt.name) })) } else { Err(Error::InvalidReference( "Reference not found in Types".to_string(), )) } } } Reference::Opaque(_) => Err(Error::UnsupportedDataType( "Opaque references are not supported by JSON Schema exporter".to_string(), )), } } DataType::Generic(_) => Ok(json!({})), // Empty schema accepts anything DataType::Intersection(intersection) => Ok(json!({ "allOf": intersection .iter() .map(|ty| datatype_to_schema(js, types, ty, false)) .collect::, _>>()? })), } } fn primitive_to_schema(p: &Primitive) -> Value { match p { Primitive::bool => json!({"type": "boolean"}), Primitive::str => json!({"type": "string"}), Primitive::char => json!({"type": "string", "minLength": 1, "maxLength": 1}), // Integers Primitive::i8 => json!({"type": "integer", "minimum": i8::MIN, "maximum": i8::MAX}), Primitive::i16 => json!({"type": "integer", "minimum": i16::MIN, "maximum": i16::MAX}), Primitive::i32 => json!({"type": "integer", "format": "int32"}), Primitive::i64 => json!({"type": "integer", "format": "int64"}), Primitive::i128 => json!({"type": "integer"}), Primitive::isize => json!({"type": "integer"}), Primitive::u8 => json!({"type": "integer", "minimum": 0, "maximum": u8::MAX}), Primitive::u16 => json!({"type": "integer", "minimum": 0, "maximum": u16::MAX}), Primitive::u32 => json!({"type": "integer", "minimum": 0, "format": "uint32"}), Primitive::u64 => json!({"type": "integer", "minimum": 0, "format": "uint64"}), Primitive::u128 => json!({"type": "integer", "minimum": 0}), Primitive::usize => json!({"type": "integer", "minimum": 0}), // Floats Primitive::f16 => json!({"type": "number", "format": "float16"}), Primitive::f32 => json!({"type": "number", "format": "float"}), Primitive::f64 => json!({"type": "number", "format": "double"}), Primitive::f128 => json!({"type": "number", "format": "float128"}), } } fn struct_to_schema(js: &JsonSchema, types: &Types, s: &Struct) -> Result { match &s.fields { Fields::Unit => { // Unit struct = null Ok(json!({"type": "null"})) } Fields::Unnamed(fields) => { // Tuple struct - represent as array let items: Result, _> = fields .fields .iter() .filter_map(|field| field.ty.as_ref().map(|ty| (field, ty))) .map(|(_, ty)| datatype_to_schema(js, types, ty, false)) .collect(); let items = items?; Ok(json!({ "type": "array", "prefixItems": items, "items": false, "minItems": items.len(), "maxItems": items.len() })) } Fields::Named(fields) => { // Named fields = object let mut properties = Map::new(); let mut required = Vec::new(); for (name, (field, ty)) in fields .fields .iter() .filter_map(|(name, field)| field.ty.as_ref().map(|ty| (name, (field, ty)))) { let schema = datatype_to_schema(js, types, ty, false)?; properties.insert(name.clone().into_owned(), schema); if !field.optional { required.push(Value::String(name.clone().into_owned())); } } let mut obj = json!({ "type": "object", "properties": properties }); if !required.is_empty() { obj.as_object_mut() .unwrap() .insert("required".to_string(), Value::Array(required)); } Ok(obj) } } } fn enum_to_schema(js: &JsonSchema, types: &Types, e: &Enum) -> Result { let variants: Result, _> = e .variants .iter() .filter(|(_, variant)| !variant.skip) .map(|(name, variant)| variant_to_schema(js, types, name, variant)) .collect(); let variants = variants?; if variants.is_empty() { return Err(Error::ConversionError( "Enum has no non-skipped variants".to_string(), )); } if variants.len() == 1 { Ok(variants.into_iter().next().unwrap()) } else { Ok(json!({ "anyOf": variants })) } } fn variant_to_schema( js: &JsonSchema, types: &Types, name: &str, variant: &Variant, ) -> Result { // Get enum representation from attributes // For now, default to external tagging match &variant.fields { Fields::Unit => { // Unit variant = string literal Ok(json!({"const": name})) } Fields::Unnamed(fields) => { // Tuple variant with external tagging: { "VariantName": [...] } let items: Result, _> = fields .fields .iter() .filter_map(|field| field.ty.as_ref().map(|ty| (field, ty))) .map(|(_, ty)| datatype_to_schema(js, types, ty, false)) .collect(); let items = items?; if items.len() == 1 { // Single item - unwrap the array Ok(json!({ "type": "object", "required": [name], "properties": { name: items[0].clone() }, "additionalProperties": false })) } else { Ok(json!({ "type": "object", "required": [name], "properties": { name: { "type": "array", "prefixItems": items.clone(), "items": false, "minItems": items.len(), "maxItems": items.len() } }, "additionalProperties": false })) } } Fields::Named(fields) => { // Named variant with external tagging: { "VariantName": {...} } let mut properties = Map::new(); let mut required = Vec::new(); for (field_name, (field, ty)) in fields .fields .iter() .filter_map(|(name, field)| field.ty.as_ref().map(|ty| (name, (field, ty)))) { let schema = datatype_to_schema(js, types, ty, false)?; properties.insert(field_name.clone().into_owned(), schema); if !field.optional { required.push(Value::String(field_name.clone().into_owned())); } } let mut inner_obj = json!({ "type": "object", "properties": properties }); if !required.is_empty() { inner_obj .as_object_mut() .unwrap() .insert("required".to_string(), Value::Array(required)); } Ok(json!({ "type": "object", "required": [name], "properties": { name: inner_obj }, "additionalProperties": false })) } } } fn tuple_to_schema(js: &JsonSchema, types: &Types, t: &Tuple) -> Result { if t.elements.is_empty() { // Empty tuple = null return Ok(json!({"type": "null"})); } let items: Result, _> = t .elements .iter() .map(|ty| datatype_to_schema(js, types, ty, false)) .collect(); let items = items?; Ok(json!({ "type": "array", "prefixItems": items.clone(), "items": false, "minItems": items.len(), "maxItems": items.len() })) } ================================================ FILE: specta-jsonschema/src/schema_version.rs ================================================ use serde::{Deserialize, Serialize}; /// JSON Schema version specification #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] pub enum SchemaVersion { /// JSON Schema Draft 7 (2018) - Most widely supported Draft7, /// JSON Schema Draft 2019-09 Draft2019_09, /// JSON Schema Draft 2020-12 (latest) Draft2020_12, } impl SchemaVersion { /// Returns the $schema URI for this version pub fn uri(&self) -> &'static str { match self { Self::Draft7 => "http://json-schema.org/draft-07/schema#", Self::Draft2019_09 => "https://json-schema.org/draft/2019-09/schema", Self::Draft2020_12 => "https://json-schema.org/draft/2020-12/schema", } } /// Returns the key used for definitions in this version /// Draft 7 uses "definitions", newer versions use "$defs" pub fn definitions_key(&self) -> &'static str { match self { Self::Draft7 => "definitions", Self::Draft2019_09 | Self::Draft2020_12 => "$defs", } } } impl Default for SchemaVersion { fn default() -> Self { Self::Draft7 } } ================================================ FILE: specta-jsonschema/tests/basic.rs ================================================ #![allow(missing_docs)] use std::fs; use serde::{Deserialize, Serialize}; use specta::{Type, Types}; use specta_jsonschema::{JsonSchema, SchemaVersion}; #[derive(Serialize, Deserialize, Type)] struct User { id: u32, name: String, email: Option, } #[derive(Serialize, Deserialize, Type)] enum Status { Active, Inactive, Pending, } #[test] fn test_basic_export() { let types = Types::default().register::().register::(); let result = JsonSchema::default().export(&types, specta_serde::Format); assert!(result.is_ok(), "Export should succeed: {:?}", result.err()); let schema_str = result.unwrap(); assert!(schema_str.contains("\"$schema\"")); assert!(schema_str.contains("\"User\"")); assert!(schema_str.contains("\"Status\"")); } #[test] fn test_schema_version() { let types = Types::default().register::(); let result = JsonSchema::default() .schema_version(SchemaVersion::Draft7) .export(&types, specta_serde::Format); assert!(result.is_ok()); let schema = result.unwrap(); assert!(schema.contains("http://json-schema.org/draft-07/schema#")); } #[test] fn test_primitives() { #[derive(Serialize, Deserialize, Type)] struct Primitives { string_field: String, int_field: i32, float_field: f64, bool_field: bool, } let types = Types::default().register::(); let result = JsonSchema::default().export(&types, specta_serde::Format); assert!(result.is_ok()); let schema = result.unwrap(); assert!(schema.contains("Primitives")); } #[test] fn test_nullable() { let types = Types::default().register::(); let result = JsonSchema::default().export(&types, specta_serde::Format); assert!(result.is_ok()); let schema = result.unwrap(); // email is Option so should have anyOf with null assert!(schema.contains("anyOf") || schema.contains("null")); } #[test] fn test_enum() { let types = Types::default().register::(); let result = JsonSchema::default().export(&types, specta_serde::Format); assert!(result.is_ok()); let schema = result.unwrap(); assert!(schema.contains("\"Active\"")); assert!(schema.contains("\"Inactive\"")); assert!(schema.contains("\"Pending\"")); } #[test] fn test_export_uses_format() { #[derive(Type, serde::Serialize)] #[serde(rename_all = "camelCase")] struct SerdeUser { user_id: u32, } let types = Types::default().register::(); let schema = JsonSchema::default() .export(&types, specta_serde::Format) .unwrap(); assert!(schema.contains("userId")); assert!(!schema.contains("user_id")); } #[test] fn test_export_to_uses_format() { #[derive(Type, serde::Serialize)] #[serde(rename_all = "camelCase")] struct SerdeUser { user_id: u32, } let types = Types::default().register::(); let path = std::path::Path::new(env!("CARGO_MANIFEST_DIR")) .join("target") .join(format!("jsonschema-test-{}.json", std::process::id())); JsonSchema::default() .export_to(&path, &types, specta_serde::Format) .unwrap(); let schema = fs::read_to_string(&path).unwrap(); fs::remove_file(&path).unwrap(); assert!(schema.contains("userId")); assert!(!schema.contains("user_id")); } ================================================ FILE: specta-kotlin/Cargo.toml ================================================ [package] name = "specta-kotlin" description = "Export your Rust types to Kotlin" version = "0.0.2" authors = ["Oscar Beaumont "] edition = "2024" license = "MIT" repository = "https://github.com/specta-rs/specta" documentation = "https://docs.rs/specta-kotlin/latest/specta-kotlin" keywords = ["async", "specta", "rspc", "kotlin", "typesafe"] categories = ["web-programming", "asynchronous"] readme = "../README.md" # /bin/sh RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features [package.metadata."docs.rs"] all-features = true rustdoc-args = ["--cfg", "docsrs"] [lints] workspace = true [dependencies] specta = { version = "=2.0.0-rc.24", path = "../specta" } ================================================ FILE: specta-kotlin/src/lib.rs ================================================ //! [Kotlin](https://kotlinlang.org) language exporter for [Specta](specta). //! //!
//! This crate is still in active development and is not yet ready for general purpose use! //!
//! #![cfg_attr(docsrs, feature(doc_cfg))] #![doc( html_logo_url = "https://github.com/specta-rs/specta/raw/main/.github/logo-128.png", html_favicon_url = "https://github.com/specta-rs/specta/raw/main/.github/logo-128.png" )] // use specta::{ // datatype::{DataType, Primitive}, // Type, Types, // }; // /// TODO // pub fn export() -> Result { // datatype(&T::definition( // &mut Types::default(), // Generics::Definition, // )) // } // fn datatype(t: &DataType) -> Result { // Ok(match t { // DataType::Primitive(p) => match p { // Primitive::str => "String", // Primitive::char => "Char", // Primitive::i8 => "Byte", // Primitive::i16 => "Short", // Primitive::isize | Primitive::i32 => "Int", // Primitive::i64 => "Long", // Primitive::u8 => "UByte", // Primitive::u16 => "UShort", // Primitive::usize | Primitive::u32 => "UInt", // Primitive::u64 => "ULong", // Primitive::bool => "Boolean", // Primitive::f32 => "Float", // Primitive::f64 => "Double", // Primitive::i128 | Primitive::u128 => { // return Err("Swift does not support 128 numbers!".to_owned()) // } // } // .to_string(), // DataType::List(t) => format!("List<{}>", datatype(t.ty())?), // DataType::Tuple(_) => return Err("Kotlin does not support tuple types".to_owned()), // DataType::Map(t) => format!( // "HashMap<{}, {}>", // datatype(&t.key_ty())?, // datatype(&t.value_ty())? // ), // DataType::Generic(t) => t.to_string(), // DataType::Reference(reference) => { // // let name = reference.name(); // let generics = reference.generics(); // // match &generics[..] { // // [] => name.to_string(), // // generics => { // // let generics = generics // // .iter() // // .map(|(_, t)| datatype(t)) // // .collect::, _>>()? // // .join(", "); // // format!("{name}<{generics}>") // // } // // } // todo!(); // } // DataType::Nullable(t) => format!("{}?", datatype(&t)?), // DataType::Struct(s) => { // let name = s.name(); // let generics = s.generics(); // let fields = s.fields(); // let tag = s.tag(); // // let decl = match &fields[..] { // // [] => "class {name}".to_string(), // // fields => { // // let generics = (!generics.is_empty()) // // .then(|| format!("<{}>", generics.join(", "))) // // .unwrap_or_default(); // // let fields = fields // // .iter() // // .map(|f| { // // let name = &f.name; // // let typ = datatype(&f.ty)?; // // let optional = matches!(f.ty, DataType::Nullable(_)) // // .then(|| "= null") // // .unwrap_or_default(); // // Ok(format!("\tvar {name}: {typ}{optional}")) // // }) // // .collect::, String>>()? // // .join(", "); // // let tag = tag // // .clone() // // .map(|t| format!("var {t}: String")) // // .unwrap_or_default(); // // format!("data class {name}{generics} ({fields}{tag})") // // } // // }; // // format!("@Serializable\n{decl}\n") // todo!(); // } // DataType::Literal(_) => return Err("Kotlin does not support literal types!".to_owned()), // _ => todo!(), // }) // } ================================================ FILE: specta-macros/Cargo.toml ================================================ [package] name = "specta-macros" description = "Macros for specta. Don't use directly!" version = "2.0.0-rc.24" authors = ["Oscar Beaumont "] edition = "2024" license = "MIT" repository = "https://github.com/specta-rs/specta" documentation = "https://docs.rs/specta/latest/specta" keywords = ["async", "specta", "rspc", "typescript", "typesafe"] categories = ["web-programming", "asynchronous"] [lib] proc-macro = true [features] default = [] serde = [] # These will be enabled by `specta` or `specta-util` automatically as required. They depend on certain exports of it so enabling them manually is not useful. DO_NOT_USE_collect = [] DO_NOT_USE_function = ["syn/full"] [lints] workspace = true [dependencies] proc-macro2 = "1" quote = "1" syn = { version = "2", default-features = false, features = [ "clone-impls", "derive", "parsing", "printing", "proc-macro", "visit", "visit-mut", ] } Inflector = { version = "0.11", default-features = false } ================================================ FILE: specta-macros/README.md ================================================ # Specta Macros The macros for [Specta](https://crates.io/crates/specta). Do not use this crate directly! It is reexported by the Specta crate. ================================================ FILE: specta-macros/src/lib.rs ================================================ //! Easily export your Rust types to other languages //! //! This crate contains the macro which are reexported by the `specta` crate. //! You shouldn't need to use this crate directly. //! Checkout [Specta](https://docs.rs/specta). #![doc( html_logo_url = "https://github.com/specta-rs/specta/raw/main/.github/logo-128.png", html_favicon_url = "https://github.com/specta-rs/specta/raw/main/.github/logo-128.png" )] #[cfg(feature = "DO_NOT_USE_function")] mod specta; mod r#type; mod utils; use quote::quote; use syn::{Error, LitStr, Type, parse_macro_input}; /// Implements `specta::Type` for a given struct or enum. /// /// # Attributes /// /// `Type` supports `#[specta(...)]` attributes on containers, variants, and fields. /// It also understands selected Rust and Serde attributes. /// /// ## `#[specta(...)]` container attributes /// /// These can be used on the struct or enum deriving `Type`. /// /// - `#[specta(type = T)]` overrides the generated type definition with `T`. /// `T` may be a path or Rust type, such as `String`, `Vec`, or `(String, i32)`. /// - `#[specta(crate = path::to::specta)]` uses a custom path to the `specta` crate. /// - `#[specta(inline)]` or `#[specta(inline = true)]` inlines this type where it is referenced. /// Use `#[specta(inline = false)]` to disable it. /// - `#[specta(remote = path::ToType)]` implements `Type` for a remote type instead of the /// local derive input name. /// - `#[specta(collect)]` or `#[specta(collect = true)]` enables collection for this type when /// the `collect` feature is used. Use `#[specta(collect = false)]` to prevent collection. /// - `#[specta(skip_attr = "attr_name")]` ignores attributes named `attr_name` while parsing and /// while collecting runtime attributes. This may be repeated. /// - `#[specta(transparent)]` or `#[specta(transparent = true)]` treats a struct as its single /// non-skipped field. Use `#[specta(transparent = false)]` to disable it. /// - `#[specta(bound = "T: Type")]` replaces the automatically inferred `Type` bounds. /// Use `#[specta(bound = "")]` to emit no inferred bounds. /// /// `#[specta(type = ...)]` cannot be combined with `#[specta(transparent)]`. /// `#[specta(transparent)]` is only valid on structs with exactly one non-skipped field. /// /// ## `#[specta(...)]` variant attributes /// /// These can be used on enum variants. /// /// - `#[specta(type = T)]` or `#[specta(r#type = T)]` overrides the generated variant payload /// type with `T`. /// - `#[specta(skip)]` or `#[specta(skip = true)]` marks the variant as skipped. /// Use `#[specta(skip = false)]` to disable it. /// - `#[specta(inline)]` or `#[specta(inline = true)]` inlines the first unnamed field of the /// variant. Use `#[specta(inline = false)]` to disable it. /// /// ## `#[specta(...)]` field attributes /// /// These can be used on struct fields and enum variant fields. /// /// - `#[specta(type = T)]` overrides the generated field type with `T`. /// - `#[specta(inline)]` or `#[specta(inline = true)]` inlines the field type. /// Use `#[specta(inline = false)]` to disable it. /// - `#[specta(skip)]` or `#[specta(skip = true)]` skips generating the field type. /// Use `#[specta(skip = false)]` to disable it. /// - `#[specta(optional)]` or `#[specta(optional = true)]` marks the field as optional. /// This is commonly used with `Option` to export `{ a?: T | null }` instead of /// `{ a: T | null }`. /// - `#[specta(default)]` or `#[specta(default = true)]` is an alias for `optional`. /// /// ## Rust attributes /// /// These are read on containers, variants, and fields. /// /// - `#[doc = "..."]` is exported as documentation. /// - `#[deprecated]` marks the item as deprecated. /// - `#[deprecated = "..."]` marks the item as deprecated with a note. /// - `#[deprecated(note = "...")]` marks the item as deprecated with a note. /// - `#[deprecated(since = "...", note = "...")]` marks the item as deprecated with a version /// and note. /// /// `#[repr(transparent)]` is also accepted on containers as an alias for /// `#[specta(transparent)]`. /// /// ## Serde attributes /// /// Specta can read selected `#[serde(...)]` attributes. Prefer Serde attributes when the same /// behavior should apply to Serde and Specta. /// /// These are always understood by the derive macro: /// /// - Container: `#[serde(transparent)]` acts like `#[specta(transparent)]`. /// - Field: `#[serde(skip)]` acts like `#[specta(skip)]`. /// - Variant: `#[serde(skip)]` acts like `#[specta(skip)]`. /// /// With the `serde` feature enabled, the following Serde attributes are also preserved as /// runtime attributes. /// To apply these attributes during export, use /// [`specta_serde::Format`](https://docs.rs/specta-serde/latest/specta_serde/struct.Format.html) /// or /// [`specta_serde::FormatPhases`](https://docs.rs/specta-serde/latest/specta_serde/struct.FormatPhases.html). /// See the [`specta-serde` docs](https://docs.rs/specta-serde) for details. /// /// Container attributes: /// /// - `#[serde(rename = "...")]` /// - `#[serde(rename(serialize = "..."))]` /// - `#[serde(rename(deserialize = "..."))]` /// - `#[serde(rename_all = "...")]` /// - `#[serde(rename_all(serialize = "..."))]` /// - `#[serde(rename_all(deserialize = "..."))]` /// - `#[serde(rename_all_fields = "...")]` /// - `#[serde(rename_all_fields(serialize = "..."))]` /// - `#[serde(rename_all_fields(deserialize = "..."))]` /// - `#[serde(tag = "...")]` /// - `#[serde(content = "...")]` /// - `#[serde(untagged)]` /// - `#[serde(default)]` or `#[serde(default = "...")]` /// - `#[serde(transparent)]` /// - `#[serde(from = "T")]` /// - `#[serde(try_from = "T")]` /// - `#[serde(into = "T")]` /// - `#[serde(variant_identifier)]` /// - `#[serde(field_identifier)]` /// /// Variant attributes: /// /// - `#[serde(rename = "...")]` /// - `#[serde(rename(serialize = "..."))]` /// - `#[serde(rename(deserialize = "..."))]` /// - `#[serde(alias = "...")]` /// - `#[serde(rename_all = "...")]` /// - `#[serde(rename_all(serialize = "..."))]` /// - `#[serde(rename_all(deserialize = "..."))]` /// - `#[serde(skip)]` /// - `#[serde(skip_serializing)]` /// - `#[serde(skip_deserializing)]` /// - `#[serde(serialize_with = "...")]` /// - `#[serde(deserialize_with = "...")]` /// - `#[serde(with = "...")]` /// - `#[serde(other)]` /// - `#[serde(untagged)]` /// /// Field attributes: /// /// - `#[serde(rename = "...")]` /// - `#[serde(rename(serialize = "..."))]` /// - `#[serde(rename(deserialize = "..."))]` /// - `#[serde(alias = "...")]` /// - `#[serde(default)]` or `#[serde(default = "...")]` /// - `#[serde(flatten)]` /// - `#[serde(skip)]` /// - `#[serde(skip_serializing)]` /// - `#[serde(skip_deserializing)]` /// - `#[serde(skip_serializing_if = "...")]` /// - `#[serde(serialize_with = "...")]` /// - `#[serde(deserialize_with = "...")]` /// - `#[serde(with = "...")]` /// /// Supported rename casing values are: /// /// - `"lowercase"` /// - `"UPPERCASE"` /// - `"PascalCase"` /// - `"camelCase"` /// - `"snake_case"` /// - `"SCREAMING_SNAKE_CASE"` /// - `"kebab-case"` /// - `"SCREAMING-KEBAB-CASE"` /// /// ## Example /// /// ```ignore /// use specta::Type; /// /// // Use it on structs /// #[derive(Type)] /// pub struct MyCustomStruct { /// pub name: String, /// } /// /// #[derive(Type)] /// pub struct MyCustomStruct2(String, i32, bool); /// /// // Use it on enums /// #[derive(Type)] /// pub enum MyCustomType { /// VariantOne, /// VariantTwo(String, i32), /// VariantThree { name: String, age: i32 }, /// } /// ``` /// /// ## Known limitations /// /// - Const generics will not be exported within user-defined types which define const generics /// - Associated constants or types can't be used /// #[proc_macro_derive(Type, attributes(specta))] pub fn derive_type(input: proc_macro::TokenStream) -> proc_macro::TokenStream { r#type::derive(input).unwrap_or_else(|err| err.into_compile_error().into()) } /// Parses a string literal into a Rust type token stream. /// /// This is an internal helper proc macro used by Specta macros to turn a /// literal like `"Option"` into a Rust type at compile time. #[proc_macro] pub fn parse_type_from_lit(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let lit = parse_macro_input!(input as LitStr); match syn::parse_str::(&lit.value()) { Ok(ty) => quote!(#ty).into(), Err(err) => Error::new_spanned(lit, format!("invalid type literal: {err}")) .to_compile_error() .into(), } } /// Prepares a function to have its types extracted using `specta::function::fn_datatype!` /// /// ## Example /// /// ```ignore /// #[specta::specta] /// fn my_function(arg1: i32, arg2: bool) -> &'static str { /// "Hello World" /// } /// ``` #[proc_macro_attribute] #[cfg(feature = "DO_NOT_USE_function")] pub fn specta( attr: proc_macro::TokenStream, item: proc_macro::TokenStream, ) -> proc_macro::TokenStream { specta::attribute(attr, item).unwrap_or_else(|err| err.into_compile_error().into()) } ================================================ FILE: specta-macros/src/specta.rs ================================================ // inspired by https://github.com/tauri-apps/tauri/blob/2901145c497299f033ba7120af5f2e7ead16c75a/core/tauri-macros/src/command/handler.rs use std::str::FromStr; use inflector::Inflector; use proc_macro2::TokenStream; use quote::{ToTokens, quote}; use syn::{FnArg, ItemFn, Pat, Visibility, parse}; use crate::{ r#type::attr::deprecated_as_tokens, utils::{AttrExtract, format_fn_wrapper, parse_attrs}, }; fn unraw(s: &str) -> &str { if s.starts_with("r#") { s.split_at(2).1 } else { s } } #[derive(Clone, Copy)] enum RenameAllRule { Lowercase, Uppercase, PascalCase, CamelCase, SnakeCase, ScreamingSnakeCase, KebabCase, ScreamingKebabCase, } impl RenameAllRule { fn parse(value: &str, span: proc_macro2::Span) -> syn::Result { match value { "lowercase" => Ok(Self::Lowercase), "UPPERCASE" => Ok(Self::Uppercase), "PascalCase" => Ok(Self::PascalCase), "camelCase" => Ok(Self::CamelCase), "snake_case" => Ok(Self::SnakeCase), "SCREAMING_SNAKE_CASE" => Ok(Self::ScreamingSnakeCase), "kebab-case" => Ok(Self::KebabCase), "SCREAMING-KEBAB-CASE" => Ok(Self::ScreamingKebabCase), _ => Err(syn::Error::new( span, "specta: unsupported rename rule. Expected one of lowercase, UPPERCASE, PascalCase, camelCase, snake_case, SCREAMING_SNAKE_CASE, kebab-case, SCREAMING-KEBAB-CASE", )), } } fn apply(self, input: &str) -> String { match self { Self::Lowercase => input.to_lowercase(), Self::Uppercase => input.to_uppercase(), Self::PascalCase => input.to_pascal_case(), Self::CamelCase => input.to_camel_case(), Self::SnakeCase => input.to_snake_case(), Self::ScreamingSnakeCase => input.to_screaming_snake_case(), Self::KebabCase => input.to_kebab_case(), Self::ScreamingKebabCase => input.to_kebab_case().to_uppercase(), } } } struct FunctionNameAttrs { rename: Option, rename_all: Option, } fn parse_name_attrs( attr: proc_macro::TokenStream, function: &ItemFn, ) -> syn::Result { let mut attrs = function.attrs.clone(); let attr = proc_macro2::TokenStream::from(attr); if !attr.is_empty() { let specta_attr: syn::Attribute = syn::parse_quote!(#[specta(#attr)]); attrs.push(specta_attr); } let mut attrs = parse_attrs(&attrs)?; let rename = attrs .extract("specta", "rename") .map(|attr| attr.parse_string()) .transpose()?; let rename_all = attrs .extract("specta", "rename_all") .or_else(|| attrs.extract("command", "rename_all")) .map(|attr| RenameAllRule::parse(&attr.parse_string()?, attr.value_span())) .transpose()?; Ok(FunctionNameAttrs { rename, rename_all }) } pub fn attribute( attr: proc_macro::TokenStream, item: proc_macro::TokenStream, ) -> syn::Result { let crate_ref = quote!(specta); let function = parse::(item)?; let name_attrs = parse_name_attrs(attr, &function)?; let wrapper = format_fn_wrapper(&function.sig.ident); // While using wasm_bindgen and Specta is rare, this should make the DX nicer. if function.sig.unsafety.is_some() && function .sig .ident .to_string() .starts_with("__wasm_bindgen_generated") { return Err(syn::Error::new_spanned( function.sig.ident, "specta: You must apply the #[specta] macro before the #[wasm_bindgen] macro", )); } let visibility = &function.vis; let maybe_macro_export = match &visibility { Visibility::Public(_) => { quote!(#[macro_export]) } _ => Default::default(), }; let function_name = &function.sig.ident; let mut function_name_str = unraw(&function_name.to_string()).to_string(); if let Some(rule) = name_attrs.rename_all { function_name_str = rule.apply(&function_name_str); } if let Some(rename) = name_attrs.rename { function_name_str = rename; } let function_asyncness = function.sig.asyncness.is_some(); let mut arg_names = Vec::new(); for input in function.sig.inputs.iter() { let arg = match input { FnArg::Receiver(_) => { return Err(syn::Error::new_spanned( input, "functions with `#[specta]` cannot take 'self'", )); } FnArg::Typed(arg) => match &*arg.pat { Pat::Ident(ident) => ident.ident.to_token_stream(), Pat::Macro(m) => m.mac.tokens.to_token_stream(), Pat::Struct(s) => s.path.to_token_stream(), Pat::Slice(s) => s.attrs[0].to_token_stream(), Pat::Tuple(s) => s.elems[0].to_token_stream(), _ => { return Err(syn::Error::new_spanned( input, "functions with `#[specta]` must take named arguments", )); } }, }; let mut s = arg.to_string(); let s = if s.starts_with("r#") { s.split_off(2) } else { s }; let arg_name = TokenStream::from_str(&s).map_err(|err| { syn::Error::new_spanned(input, format!("invalid token stream for argument: {err}")) })?; let mut arg_name_str = arg_name.to_string(); if let Some(rule) = name_attrs.rename_all { arg_name_str = rule.apply(&arg_name_str); } arg_names.push(arg_name_str); } let arg_signatures = function.sig.inputs.iter().map(|_| quote!(_)); let mut attrs = parse_attrs(&function.attrs)?; let common = crate::r#type::attr::RustCAttr::from_attrs(&mut attrs)?; let deprecated = if let Some(deprecated) = common.deprecated { let tokens = deprecated_as_tokens(deprecated); quote!(#tokens) } else { quote!(None) }; let docs = common.doc; let no_return_type = match function.sig.output { syn::ReturnType::Default => true, syn::ReturnType::Type(_, _) => false, }; Ok(quote! { #function #maybe_macro_export #[doc(hidden)] macro_rules! #wrapper { // We take in `$function` from the invocation so we have `fn_name::` (@export_fn; $function:path) => {{ use #crate_ref::datatype; fn export(types: &mut #crate_ref::Types) -> datatype::Function { #crate_ref::internal::get_fn_datatype( $function as fn(#(#arg_signatures),*) -> _, #function_asyncness, #function_name_str.into(), types, &[#(#arg_names.into()),* ], std::borrow::Cow::Borrowed(#docs), #deprecated, #no_return_type, ) } export }} } // allow the macro to be resolved with the same path as the function #[allow(unused_imports)] #visibility use #wrapper; } .into()) } ================================================ FILE: specta-macros/src/type/attr/container.rs ================================================ use proc_macro2::TokenStream; use quote::ToTokens; use syn::Result; use syn::Type; use crate::utils::{AttrExtract, Attribute}; use super::RustCAttr; #[derive(Default)] pub struct ContainerAttr { pub r#type: Option, pub crate_name: Option, pub inline: bool, pub remote: Option, pub collect: Option, pub skip_attrs: Vec, pub common: RustCAttr, // Struct only (we pass it anyway so enums get nice errors) pub transparent: bool, // Custom where clause bounds (None = automatic, Some(vec) = custom) pub bound: Option>, } impl ContainerAttr { pub fn from_attrs(attrs: &mut Vec) -> Result { let mut result = Self { common: RustCAttr::from_attrs(attrs)?, ..Default::default() }; if let Some(attr) = attrs.extract("specta", "crate") { result.crate_name = result .crate_name .take() .or(Some(attr.parse_path()?.to_token_stream())); } if let Some(attr) = attrs.extract("specta", "type") { result.r#type = result.r#type.take().or(Some(attr.parse_type()?)); } if let Some(attr) = attrs.extract("specta", "inline") { result.inline = attr.parse_bool().unwrap_or(true); } if let Some(attr) = attrs.extract("specta", "remote") { result.remote = result .remote .take() .or(Some(attr.parse_path()?.to_token_stream())); } if let Some(attr) = attrs.extract("specta", "collect") { result.collect = result .collect .take() .or(Some(attr.parse_bool().unwrap_or(true))); } for attr in attrs.extract_all("specta", "skip_attr") { result.skip_attrs.push(attr.parse_string()?); } if let Some(attr) = attrs.extract("specta", "transparent") { result.transparent = attr.parse_bool().unwrap_or(true); } else if let Some(attr) = attrs.extract("repr", "transparent") { result.transparent = attr.parse_bool().unwrap_or(true); } else if let Some(attr) = attrs.extract("serde", "transparent") { // We generally want `#[serde(...)]` attributes to only be handled by the runtime but, // we make an exception for `#[serde(transparent)]`. result.transparent = attr.parse_bool().unwrap_or(true); } if let Some(attr) = attrs.extract("specta", "bound") { let bound_str = attr.parse_string()?; if bound_str.is_empty() { // Empty string means explicitly no automatic bounds result.bound = Some(Vec::new()); } else { // Parse where predicates from string let where_clause_str = format!("where {}", bound_str); match syn::parse_str::(&where_clause_str) { Ok(where_clause) => { result.bound = Some(where_clause.predicates.into_iter().collect()); } Err(e) => { return Err(syn::Error::new( attr.value_span(), format!("Failed to parse bound attribute: {}", e), )); } } } } Ok(result) } } ================================================ FILE: specta-macros/src/type/attr/field.rs ================================================ use syn::{Result, Type}; use crate::utils::{AttrExtract, Attribute}; use super::RustCAttr; #[derive(Default)] pub struct FieldAttr { pub r#type: Option, pub inline: bool, pub skip: bool, pub optional: bool, pub common: RustCAttr, } impl FieldAttr { pub fn from_attrs(attrs: &mut Vec) -> Result { let mut result = Self { common: RustCAttr::from_attrs(attrs)?, ..Default::default() }; if let Some(attr) = attrs.extract("specta", "type") { result.r#type = result.r#type.take().or(Some(attr.parse_type()?)); } if let Some(attr) = attrs.extract("specta", "inline") { result.inline = attr.parse_bool().unwrap_or(true); } if let Some(attr) = attrs.extract("specta", "skip") { result.skip = attr.parse_bool().unwrap_or(true); } else if let Some(attr) = attrs.extract("serde", "skip") { // We generally want `#[serde(...)]` attributes to only be handled by the runtime but, // we make an exception for `#[serde(skip)]` because it's usually used on fields // that would fail a `T: Type` so handling it at runtime would prevent your code from compiling. result.skip = attr.parse_bool().unwrap_or(true); } if let Some(attr) = attrs.extract("specta", "optional") { result.optional = attr.parse_bool().unwrap_or(true); } if let Some(attr) = attrs.extract("specta", "default") { result.optional = attr.parse_bool().unwrap_or(true); } Ok(result) } } ================================================ FILE: specta-macros/src/type/attr/legacy.rs ================================================ #[derive(Clone, Copy)] pub enum Scope { Container, Field, Variant, } impl Scope { fn as_str(self) -> &'static str { match self { Scope::Container => "container", Scope::Field => "field", Scope::Variant => "variant", } } } pub fn migration_hint(scope: Scope, key: &str) -> Option { let replacement = match (scope, key) { (Scope::Container, "rename") | (Scope::Field, "rename") | (Scope::Variant, "rename") => { Some("#[serde(rename = \"...\")]") } (Scope::Container, "rename_all") | (Scope::Variant, "rename_all") => { Some("#[serde(rename_all = \"...\")]") } (Scope::Container, "tag") => Some("#[serde(tag = \"...\")]"), (Scope::Container, "content") => Some("#[serde(content = \"...\")]"), (Scope::Container, "untagged") => Some("#[serde(untagged)]"), (Scope::Field, "flatten") => Some("#[serde(flatten)]"), (Scope::Field, "skip_serializing") | (Scope::Variant, "skip_serializing") => { Some("#[serde(skip_serializing)]") } (Scope::Field, "skip_deserializing") | (Scope::Variant, "skip_deserializing") => { Some("#[serde(skip_deserializing)]") } (Scope::Field, "skip_serializing_if") => Some("#[serde(skip_serializing_if = \"...\")]"), _ => None, }?; Some(format!( "specta: `#[specta({key} ...)]` is no longer supported on {scope}s. Use `{replacement}` instead.", scope = scope.as_str() )) } ================================================ FILE: specta-macros/src/type/attr/mod.rs ================================================ pub use container::*; pub use field::*; pub use legacy::*; pub use rustc::*; pub use variant::*; mod container; mod field; mod legacy; mod rustc; mod variant; ================================================ FILE: specta-macros/src/type/attr/rustc.rs ================================================ use std::borrow::Cow; use proc_macro2::TokenStream; use quote::quote; use syn::{Lit, Result}; use crate::utils::{Attribute, AttributeValue}; // Copy of `specta/src/datatype/named.rs` pub struct Deprecated { note: Option>, since: Option>, } impl Deprecated { pub const fn new() -> Self { Self { note: None, since: None, } } pub fn with_note(note: Cow<'static, str>) -> Self { Self { note: Some(note), since: None, } } pub fn with_since_note(since: Option>, note: Cow<'static, str>) -> Self { Self { note: Some(note), since, } } } #[derive(Default)] pub struct RustCAttr { pub doc: String, pub deprecated: Option, } impl RustCAttr { pub fn from_attrs(attrs: &mut Vec) -> Result { let doc = attrs.extract_if(.., |attr| attr.key == "doc").try_fold( String::new(), |mut s, doc| { let doc = doc.parse_string()?; if !s.is_empty() { s.push('\n'); } s.push_str(&doc); Ok(s) as syn::Result<_> }, )?; let mut deprecated = None; if let Some(pos) = attrs.iter().position(|attr| attr.key == "deprecated") { let attr_value = attrs[pos].clone(); match &attr_value.value { Some(AttributeValue::Lit(lit)) => { deprecated = Some(Deprecated::with_note(match lit { Lit::Str(s) => s.value().into(), _ => return Err(syn::Error::new_spanned(lit, "expected string")), })); } Some(AttributeValue::Path(_)) => { unreachable!("deprecated attribute can't be a path!") } Some(AttributeValue::Expr(_)) => { unreachable!("deprecated attribute can't be an expression!") } Some(AttributeValue::Attribute { attr, .. }) => { let since = attr .iter() .find(|attr| attr.key == "since") .and_then(|v| v.value.as_ref()) .and_then(|v| match v { AttributeValue::Lit(lit) => Some(lit), _ => None, // TODO: This should probs be an error }) .and_then(|lit| match lit { syn::Lit::Str(s) => Some(s.value()), _ => None, // TODO: This should probs be an error }); let note = attr .iter() .find(|attr| attr.key == "note") .and_then(|v| match v.value.as_ref() { Some(AttributeValue::Lit(lit)) => Some(lit), _ => None, // TODO: This should probs be an error }) .and_then(|lit| match lit { syn::Lit::Str(s) => Some(s.value()), _ => None, // TODO: This should probs be an error }) .unwrap_or_default(); deprecated = Some(Deprecated::with_since_note( // TODO: Use Cow's earlier rather than later since.map(Into::into), note.into(), )); } None => deprecated = Some(Deprecated::new()), } attrs.swap_remove(pos); }; Ok(RustCAttr { doc, deprecated }) } } pub(crate) fn deprecated_as_tokens(Deprecated { note, since }: Deprecated) -> TokenStream { let since = since.map(|v| quote!(#v.into())).unwrap_or(quote!(None)); let note = match note { Some(note) => quote!(Some(#note.into())), None => quote!(None), }; quote!(Some(datatype::Deprecated::with_since_note(#since, #note.unwrap_or_default()))) } ================================================ FILE: specta-macros/src/type/attr/variant.rs ================================================ use syn::{Result, Type}; use crate::utils::{AttrExtract, Attribute}; use super::RustCAttr; #[derive(Default)] pub struct VariantAttr { pub r#type: Option, pub skip: bool, pub inline: bool, pub common: RustCAttr, } impl VariantAttr { pub fn from_attrs(attrs: &mut Vec) -> Result { let mut result = Self { common: RustCAttr::from_attrs(attrs)?, ..Default::default() }; if let Some(attr) = attrs.extract("specta", "skip") { result.skip = attr.parse_bool().unwrap_or(true); } else if let Some(attr) = attrs.extract("serde", "skip") { // We generally want `#[serde(...)]` attributes to only be handled by the runtime but, // we make an exception for `#[serde(skip)]` because it's usually used on fields // that would fail a `T: Type` so handling it at runtime would prevent your code from compiling. result.skip = attr.parse_bool().unwrap_or(true); } if let Some(attr) = attrs.extract("specta", "inline") { result.inline = attr.parse_bool().unwrap_or(true); } if let Some(attr) = attrs .extract("specta", "type") .or_else(|| attrs.extract("specta", "r#type")) { result.r#type = result.r#type.take().or(Some(attr.parse_type()?)); } Ok(result) } } ================================================ FILE: specta-macros/src/type/enum.rs ================================================ use super::{ AttributeScope, attr::*, build_runtime_attributes, generics::type_with_inferred_lifetimes, r#struct::decode_field_attrs, }; use crate::{r#type::field::construct_field_with_variant_skip, utils::*}; use proc_macro2::TokenStream; use quote::{ToTokens, quote}; use syn::{DataEnum, Fields, Type, spanned::Spanned}; pub fn parse_enum( crate_ref: &TokenStream, container_attrs: &ContainerAttr, data: &DataEnum, ) -> syn::Result { if container_attrs.transparent { return Err(syn::Error::new( data.enum_token.span(), "#[specta(transparent)] is not allowed on an enum", )); } let variant_types = data .variants .iter() .map(|v| { // We pass all the attributes at the start and when decoding them pop them off the list. // This means at the end we can check for any that weren't consumed and throw an error. let mut attrs = parse_attrs_with_filter(&v.attrs, &container_attrs.skip_attrs)?; let mut variant_attrs = VariantAttr::from_attrs(&mut attrs)?; if variant_attrs.r#type.is_none() { variant_attrs.r#type = parse_variant_type_override(&v.attrs)?; let _ = attrs.extract("specta", "type"); let _ = attrs.extract("specta", "r#type"); } // The expectation is that when an attribute is processed it will be removed so if any are left over we know they are invalid // but we only throw errors for Specta-specific attributes so we don't continually break other attributes. if let Some(attr) = attrs.iter().find(|attr| attr.source == "specta") { match &attr.value { None | Some(AttributeValue::Lit(_)) | Some(AttributeValue::Path(_)) | Some(AttributeValue::Expr(_)) => { return Err(syn::Error::new( attr.key.span(), "specta: invalid formatted attribute", )); } Some(AttributeValue::Attribute { attr: inner_attrs, .. }) => { if let Some(inner_attr) = inner_attrs.first() { if let Some(message) = migration_hint(Scope::Variant, &inner_attr.key.to_string()) { return Err(syn::Error::new(inner_attr.key.span(), message)); } return Err(syn::Error::new( inner_attr.key.span(), format!( "specta: Found unsupported variant attribute '{}'", inner_attr.key ), )); } return Err(syn::Error::new( attr.key.span(), "specta: invalid formatted attribute", )); } } } let runtime_attrs = build_runtime_attributes( crate_ref, AttributeScope::Variant, quote!(v.attributes), &v.attrs, &container_attrs.skip_attrs, )?; Ok((v, variant_attrs, runtime_attrs)) }) .collect::>>()? .into_iter() .map(|(variant, attrs, runtime_attrs)| { let variant_ident_str = unraw_raw_ident(&variant.ident); let variant_name_str = variant_ident_str.to_token_stream(); let variant_value = if let Some(ref variant_ty) = attrs.r#type { let variant_ty = type_with_inferred_lifetimes(variant_ty); quote!(datatype::Variant::unnamed().field({ datatype::Field::new(<#variant_ty as #crate_ref::Type>::definition(types)) }).build()) } else { match &variant.fields { Fields::Unit => quote!(datatype::Variant::unit()), Fields::Unnamed(fields) => { let fields = fields .unnamed .iter() .enumerate() .map(|(idx, field)| { let (mut field_attrs, raw_attrs) = decode_field_attrs(field, &container_attrs.skip_attrs)?; if attrs.inline && idx == 0 { field_attrs.inline = true; } construct_field_with_variant_skip( crate_ref, container_attrs, field_attrs, &field.ty, raw_attrs, attrs.skip, ) }) .collect::>>()?; quote!(datatype::Variant::unnamed() #(.field(#fields))* .build()) } Fields::Named(fields) => { let field_calls = fields .named .iter() .map(|field| { let (field_attrs, raw_attrs) = decode_field_attrs(field, &container_attrs.skip_attrs)?; let field_ident_str = unraw_raw_ident(field.ident.as_ref().ok_or_else(|| { syn::Error::new( field.span(), "specta: named field must have an identifier", ) })?); let field_name = field_ident_str; let inner = construct_field_with_variant_skip( crate_ref, container_attrs, field_attrs, &field.ty, raw_attrs, attrs.skip, )?; Ok(quote!(.field(#field_name, #inner))) }) .collect::>>()?; quote!(datatype::Variant::named() #(#field_calls)* .build()) } } }; let variant_skip = attrs.skip.then(|| quote!( v.skip = true;)); let variant_docs = (!attrs.common.doc.is_empty()).then(|| { let docs = &container_attrs.common.doc; quote! { v.docs = Cow::Borrowed(#docs); } }); let field_deprecated = attrs.common.deprecated.map(|deprecated| { let tokens = deprecated_as_tokens(deprecated); quote!(v.deprecated = #tokens;) }); let type_overridden_attribute = attrs .r#type .as_ref() .map(|_| quote!(v.attributes.insert("specta:type_override", true);)); Ok(quote!((#variant_name_str.into(), { let mut v = #variant_value; #variant_skip #field_deprecated #variant_docs #runtime_attrs #type_overridden_attribute v }))) }) .collect::>>()?; Ok(quote!({ let mut e = datatype::Enum::default(); e.variants = vec![#(#variant_types),*]; e.into() })) } fn parse_variant_type_override(attrs: &[syn::Attribute]) -> syn::Result> { let mut result = None; for attr in attrs { if !attr.path().is_ident("specta") { continue; } let syn::Meta::List(list) = &attr.meta else { continue; }; list.parse_nested_meta(|meta| { if meta.path.is_ident("type") || meta.path.is_ident("r#type") { let value = meta.value()?; result = Some(value.parse()?); } Ok(()) })?; } Ok(result) } ================================================ FILE: specta-macros/src/type/field.rs ================================================ use proc_macro2::TokenStream; use quote::quote; use syn::Type; use crate::r#type::attr::deprecated_as_tokens; use super::{ AttributeScope, ContainerAttr, FieldAttr, build_runtime_attributes, generics::type_with_inferred_lifetimes, }; pub fn construct_field( crate_ref: &TokenStream, container_attrs: &ContainerAttr, attrs: FieldAttr, field_ty: &Type, raw_attrs: &[syn::Attribute], ) -> syn::Result { construct_field_with_variant_skip( crate_ref, container_attrs, attrs, field_ty, raw_attrs, false, ) } pub fn construct_field_with_variant_skip( crate_ref: &TokenStream, container_attrs: &ContainerAttr, attrs: FieldAttr, field_ty: &Type, raw_attrs: &[syn::Attribute], variant_skip: bool, ) -> syn::Result { let field_ty = type_with_inferred_lifetimes(attrs.r#type.as_ref().unwrap_or(field_ty)); let runtime_attrs = build_runtime_attributes( crate_ref, AttributeScope::Field, quote!(field.attributes), raw_attrs, &container_attrs.skip_attrs, )?; let field_optional = attrs.optional.then(|| quote!(field.optional = true;)); let field_deprecated = attrs.common.deprecated.map(|deprecated| { let tokens = deprecated_as_tokens(deprecated); quote!(field.deprecated = #tokens;) }); let field_docs = (!attrs.common.doc.is_empty()).then(|| { let docs = &container_attrs.common.doc; quote! { field.docs = Cow::Borrowed(#docs); } }); let type_overridden_attribute = attrs .r#type .as_ref() .map(|_| quote!(field.attributes.insert("specta:type_override", true);)); let field_ty = if attrs.skip || variant_skip { quote!() } else if attrs.inline { quote!(field.ty = Some(datatype::inline(types, |types| <#field_ty as #crate_ref::Type>::definition(types)));) } else { quote!(field.ty = Some(<#field_ty as #crate_ref::Type>::definition(types));) }; Ok(quote!({ let mut field = datatype::Field::default(); #field_optional #field_deprecated #field_docs #runtime_attrs #type_overridden_attribute #field_ty field })) } ================================================ FILE: specta-macros/src/type/generics.rs ================================================ use proc_macro2::TokenStream; use quote::quote; use std::collections::{HashSet, hash_map::Entry}; use syn::{ ConstParam, Data, GenericParam, Generics, LifetimeParam, Type, TypeParam, TypePath, WhereClause, parse_quote, visit::{self, Visit}, visit_mut::VisitMut, }; use crate::utils::parse_attrs; use super::{FieldAttr, VariantAttr}; #[derive(Default)] pub struct UsedTypeParams { pub direct: Vec, pub associated: Vec, pub conservative: bool, } pub fn generics_with_ident_and_bounds_only(generics: &Generics) -> Option { (!generics.params.is_empty()) .then(|| { use GenericParam::*; generics.params.iter().map(|param| match param { Type(TypeParam { ident, colon_token, bounds, .. }) => quote!(#ident #colon_token #bounds), Lifetime(LifetimeParam { lifetime, colon_token, bounds, .. }) => quote!(#lifetime #colon_token #bounds), Const(ConstParam { const_token, ident, colon_token, ty, .. }) => quote!(#const_token #ident #colon_token #ty), }) }) .map(|gs| quote!(<#(#gs),*>)) } pub fn generics_with_ident_only_and_const_ty( generics: &Generics, include_type_bounds: bool, ) -> Option { generics .params .iter() .any(|param| matches!(param, GenericParam::Type(_) | GenericParam::Const(_))) .then(|| { use GenericParam::*; generics.params.iter().filter_map(|param| match param { Type(TypeParam { ident, colon_token, bounds, .. }) if include_type_bounds => Some(quote!(#ident #colon_token #bounds)), Type(TypeParam { ident, .. }) => Some(quote!(#ident)), Lifetime(_) => None, Const(ConstParam { const_token, ident, colon_token, ty, .. }) => Some(quote!(#const_token #ident #colon_token #ty)), }) }) .map(|gs| quote!(<#(#gs),*>)) } pub fn type_where_clause( ty: &TokenStream, used_generic_types: &[syn::Ident], associated_type_usage: &[TypePath], ) -> Option { if used_generic_types.is_empty() && associated_type_usage.is_empty() { return None; } let generic_preds = used_generic_types .iter() .map(|ident| parse_quote!(#ident : #ty)); let associated_preds = associated_type_usage .iter() .map(|path| parse_quote!(#path : #ty)); let preds = generic_preds .chain(associated_preds) .collect::>(); Some(parse_quote! { where #(#preds),* }) } pub fn generics_with_ident_only(generics: &Generics) -> Option { (!generics.params.is_empty()) .then(|| { use GenericParam::*; generics.params.iter().map(|param| match param { Type(TypeParam { ident, .. }) | Const(ConstParam { ident, .. }) => quote!(#ident), Lifetime(LifetimeParam { lifetime, .. }) => quote!(#lifetime), }) }) .map(|gs| quote!(<#(#gs),*>)) } pub fn type_with_inferred_lifetimes(ty: &Type) -> Type { let mut ty = ty.clone(); InferredLifetimeVisitor.visit_type_mut(&mut ty); ty } struct InferredLifetimeVisitor; impl VisitMut for InferredLifetimeVisitor { fn visit_lifetime_mut(&mut self, lifetime: &mut syn::Lifetime) { *lifetime = syn::Lifetime::new("'_", lifetime.apostrophe); } } pub fn all_type_param_idents(generics: &Generics) -> Vec { generics .params .iter() .filter_map(|gp| match gp { GenericParam::Type(ty) => Some(ty.ident.clone()), _ => None, }) .collect() } // Code adopted from ts-rs. Thanks to it's original author! // Additional associated-type handling inspired by Serde's derive bound collection. pub fn used_type_params( generics: &Generics, data: &Data, container_type: Option<&Type>, ) -> syn::Result { let all_generic_type_idents = all_type_param_idents(generics); if all_generic_type_idents.is_empty() { return Ok(UsedTypeParams::default()); } let known_generics = all_generic_type_idents .iter() .map(ToString::to_string) .collect::>(); let mut visitor = GenericTypeUseVisitor { known_generics: &known_generics, used_generics: HashSet::new(), associated_type_usage: Vec::new(), conservative: false, }; if let Some(container_type) = container_type { visitor.visit_type(container_type); } else { match data { Data::Struct(data) => { for field in &data.fields { if field_is_skipped(field)? { continue; } visitor.visit_type(&field.ty); } } Data::Enum(data) => { for variant in &data.variants { if variant_is_skipped(variant)? { continue; } for field in &variant.fields { if field_is_skipped(field)? { continue; } visitor.visit_type(&field.ty); } } } Data::Union(_) => {} } } if visitor.conservative { return Ok(UsedTypeParams { direct: all_generic_type_idents, associated: Vec::new(), conservative: true, }); } let direct = all_generic_type_idents .iter() .filter(|ident| visitor.used_generics.contains(&ident.to_string())) .cloned() .collect(); let mut associated = Vec::new(); let mut seen = std::collections::HashMap::::new(); for path in visitor.associated_type_usage { let key = quote!(#path).to_string(); match seen.entry(key) { Entry::Vacant(v) => { v.insert(()); associated.push(path); } Entry::Occupied(_) => {} } } Ok(UsedTypeParams { direct, associated, conservative: false, }) } fn field_is_skipped(field: &syn::Field) -> syn::Result { let mut attrs = parse_attrs(&field.attrs)?; Ok(FieldAttr::from_attrs(&mut attrs)?.skip) } fn variant_is_skipped(variant: &syn::Variant) -> syn::Result { let mut attrs = parse_attrs(&variant.attrs)?; Ok(VariantAttr::from_attrs(&mut attrs)?.skip) } pub fn has_associated_type_usage(used_generic_types: &UsedTypeParams) -> bool { !used_generic_types.associated.is_empty() } pub fn used_direct_type_params<'a>( used_generic_types: &'a UsedTypeParams, all_generic_type_idents: &'a [syn::Ident], ) -> &'a [syn::Ident] { if used_generic_types.conservative { all_generic_type_idents } else { &used_generic_types.direct } } pub fn used_associated_type_paths(used_generic_types: &UsedTypeParams) -> &[TypePath] { if used_generic_types.conservative { &[] } else { &used_generic_types.associated } } pub fn add_type_to_where_clause( ty: &TokenStream, generics: &Generics, custom_bounds: Option<&[syn::WherePredicate]>, used_generic_types: &[syn::Ident], associated_type_usage: &[TypePath], ) -> Option { if let Some(where_clause) = merge_custom_bounds(generics, custom_bounds) { return Some(where_clause); } if used_generic_types.is_empty() && associated_type_usage.is_empty() { return generics.where_clause.clone(); } let generic_preds = used_generic_types .iter() .map(|ident| parse_quote!(#ident : #ty)); let associated_preds = associated_type_usage .iter() .map(|path| parse_quote!(#path : #ty)); let preds = generic_preds .chain(associated_preds) .collect::>(); match &generics.where_clause { None => Some(parse_quote! { where #(#preds),* }), Some(w) => { let bounds = w.predicates.iter(); Some(parse_quote! { where #(#bounds,)* #(#preds),* }) } } } fn merge_custom_bounds( generics: &Generics, custom_bounds: Option<&[syn::WherePredicate]>, ) -> Option { if let Some(predicates) = custom_bounds { if predicates.is_empty() { return generics.where_clause.clone(); } return match &generics.where_clause { None => Some(parse_quote! { where #(#predicates),* }), Some(w) => { let existing = w.predicates.iter(); Some(parse_quote! { where #(#existing,)* #(#predicates),* }) } }; } None } struct GenericTypeUseVisitor<'a> { known_generics: &'a HashSet, used_generics: HashSet, associated_type_usage: Vec, conservative: bool, } impl Visit<'_> for GenericTypeUseVisitor<'_> { fn visit_type_path(&mut self, node: &syn::TypePath) { if let Some(first) = node.path.segments.first() && self.known_generics.contains(&first.ident.to_string()) && node.path.segments.len() > 1 { self.associated_type_usage.push(node.clone()); } if let Some(qself) = &node.qself && let syn::Type::Path(syn::TypePath { qself: None, path }) = qself.ty.as_ref() && let Some(first) = path.segments.first() && self.known_generics.contains(&first.ident.to_string()) { self.associated_type_usage.push(node.clone()); } if node.qself.is_none() && node.path.leading_colon.is_none() && node.path.segments.len() == 1 && let Some(segment) = node.path.segments.first() { let segment_name = segment.ident.to_string(); if self.known_generics.contains(&segment_name) { self.used_generics.insert(segment_name); } } visit::visit_type_path(self, node); } fn visit_type(&mut self, node: &syn::Type) { match node { syn::Type::Macro(_) | syn::Type::Verbatim(_) => { self.conservative = true; } _ => visit::visit_type(self, node), } } } ================================================ FILE: specta-macros/src/type/mod.rs ================================================ use attr::*; use r#enum::parse_enum; use proc_macro2::TokenStream; use quote::{ToTokens, format_ident, quote}; use r#struct::parse_struct; use syn::{Data, DeriveInput, GenericParam, parse}; use crate::utils::{AttrExtract, parse_attrs, unraw_raw_ident}; use self::generics::{ add_type_to_where_clause, all_type_param_idents, generics_with_ident_and_bounds_only, generics_with_ident_only, generics_with_ident_only_and_const_ty, has_associated_type_usage, type_where_clause, type_with_inferred_lifetimes, used_associated_type_paths, used_direct_type_params, used_type_params, }; pub(crate) mod attr; mod r#enum; mod field; mod generics; #[cfg(feature = "serde")] mod serde; mod r#struct; #[derive(Copy, Clone)] pub(super) enum AttributeScope { Container, Variant, Field, } pub(super) fn build_runtime_attributes( crate_ref: &TokenStream, scope: AttributeScope, attrs: TokenStream, raw_attrs: &[syn::Attribute], skip_attrs: &[String], ) -> syn::Result> { let metas = raw_attrs .iter() .filter(|attr| { let path = attr.path().to_token_stream().to_string(); !skip_attrs.contains(&path) && path != "specta" }) .map(|attr| attr.meta.to_token_stream()) .collect::>(); #[cfg(feature = "serde")] let serde_insert = serde::lower_runtime_attributes(crate_ref, scope, raw_attrs)?; #[cfg(not(feature = "serde"))] let serde_insert: Option = { let _ = crate_ref; let _ = scope; None }; if metas.is_empty() && serde_insert.is_none() { return Ok(None); } Ok(Some(quote!({ let attrs = &mut #attrs; #serde_insert }))) } pub fn derive(input: proc_macro::TokenStream) -> syn::Result { let DeriveInput { ident: raw_ident, generics, data, attrs, .. } = &parse::(input)?; // We pass all the attributes at the start and when decoding them pop them off the list. // This means at the end we can check for any that weren't consumed and throw an error. let raw_attrs = attrs; // Preserve raw attrs before parse_attrs shadows the variable let mut attrs = parse_attrs(attrs)?; let container_attrs = ContainerAttr::from_attrs(&mut attrs)?; let crate_ref = container_attrs.crate_name.clone().unwrap_or(quote!(specta)); if container_attrs.r#type.is_some() && container_attrs.transparent { return Err(syn::Error::new( raw_ident.span(), "specta: `#[specta(type = ...)]` cannot be combined with `#[specta(transparent)]`", )); } let ident = container_attrs .remote .clone() .unwrap_or_else(|| raw_ident.to_token_stream()); let name = unraw_raw_ident(&format_ident!("{}", raw_ident.to_string())).to_token_stream(); // Check for unknown specta attributes after all parsing is done // Since extract() removes consumed attributes, any remaining ones are unknown if let Some(attr) = attrs.iter().find(|attr| attr.source == "specta") { // Check if it's an invalid formatted attribute (like #[specta] or #[specta = "..."]) match &attr.value { None | Some(crate::utils::AttributeValue::Lit(_)) | Some(crate::utils::AttributeValue::Path(_)) => { return Err(syn::Error::new( attr.key.span(), "specta: invalid formatted attribute", )); } Some(crate::utils::AttributeValue::Expr(_)) => { return Err(syn::Error::new( attr.key.span(), "specta: invalid formatted attribute", )); } Some(crate::utils::AttributeValue::Attribute { attr: inner_attrs, .. }) => { // If there are nested attributes remaining, report the first one if let Some(inner_attr) = inner_attrs.first() { if let Some(message) = migration_hint(Scope::Container, &inner_attr.key.to_string()) { return Err(syn::Error::new(inner_attr.key.span(), message)); } return Err(syn::Error::new( inner_attr.key.span(), format!( "specta: Found unsupported container attribute '{}'", inner_attr.key ), )); } // If the nested list is empty, it's an invalid format return Err(syn::Error::new( attr.key.span(), "specta: invalid formatted attribute", )); } } } let container_runtime_attrs = build_runtime_attributes( &crate_ref, AttributeScope::Container, quote!(s.attributes), raw_attrs, &container_attrs.skip_attrs, )?; let enum_runtime_attrs = build_runtime_attributes( &crate_ref, AttributeScope::Container, quote!(en.attributes), raw_attrs, &container_attrs.skip_attrs, )?; let container_runtime_attrs = if container_runtime_attrs.is_some() || enum_runtime_attrs.is_some() { quote! { match &mut e { datatype::DataType::Struct(s) => { #container_runtime_attrs } datatype::DataType::Enum(en) => { #enum_runtime_attrs } _ => unreachable!("specta derive generated non-container datatype"), } } } else { quote!() }; let dt_expr = if let Some(container_ty) = &container_attrs.r#type { let container_ty = type_with_inferred_lifetimes(container_ty); quote!(datatype::inline(types, |types| <#container_ty as #crate_ref::Type>::definition(types))) } else { let dt_expr = match data { Data::Struct(data) => parse_struct(&crate_ref, &container_attrs, data), Data::Enum(data) => parse_enum(&crate_ref, &container_attrs, data), Data::Union(data) => Err(syn::Error::new_spanned( data.union_token, "specta: Union types are not supported by Specta yet!", )), }?; quote! { let mut e = #dt_expr; #container_runtime_attrs e } }; let bounds = generics_with_ident_and_bounds_only(generics); let type_args = generics_with_ident_only(generics); let has_const_param = generics .params .iter() .any(|param| matches!(param, GenericParam::Const(_))); let used_generic_types = used_type_params(generics, data, container_attrs.r#type.as_ref())?; let all_generic_type_idents = all_type_param_idents(generics); let used_direct_generics = used_direct_type_params(&used_generic_types, &all_generic_type_idents); let used_associated_paths = used_associated_type_paths(&used_generic_types); let where_bound = add_type_to_where_clause( "e!(#crate_ref::Type), generics, container_attrs.bound.as_deref(), used_direct_generics, used_associated_paths, ); let build_ty_where_bound = type_where_clause( "e!(#crate_ref::Type), used_direct_generics, used_associated_paths, ); let build_ty_bounds = generics_with_ident_only_and_const_ty( generics, has_associated_type_usage(&used_generic_types), ); let build_ty_placeholder_args = generics .params .iter() .any(|param| matches!(param, GenericParam::Type(_) | GenericParam::Const(_))) .then(|| { let args = generics.params.iter().filter_map(|param| match param { GenericParam::Lifetime(_) => None, GenericParam::Const(t) => Some(t.ident.to_token_stream()), GenericParam::Type(t) => { Some(format_ident!("PLACEHOLDER_{}", t.ident).to_token_stream()) } }); quote!(::<#(#args),*>) }); let build_ty_passthrough_args = generics .params .iter() .any(|param| matches!(param, GenericParam::Type(_) | GenericParam::Const(_))) .then(|| { let args = generics.params.iter().filter_map(|param| match param { GenericParam::Lifetime(_) => None, GenericParam::Const(t) => Some(t.ident.to_token_stream()), GenericParam::Type(t) => Some(t.ident.to_token_stream()), }); quote!(::<#(#args),*>) }); let (generic_placeholders, shadow_generics): (Vec<_>, Vec<_>) = generics .params .iter() .filter_map(|param| match param { GenericParam::Lifetime(_) | GenericParam::Const(_) => None, GenericParam::Type(t) => { let ident = &t.ident; let ident_str = ident.to_string(); let placeholder_ident = format_ident!("PLACEHOLDER_{ident}"); Some(( quote!( pub struct #placeholder_ident; impl #crate_ref::Type for #placeholder_ident { fn definition(_: &mut #crate_ref::Types) -> datatype::DataType { datatype::Generic::new(Cow::Borrowed(#ident_str)).into() } } ), quote!(type #ident = #placeholder_ident;), )) } }) .unzip(); let (generics_for_ndt, instantiation_generics) = generics .params .iter() .map(|param| match param { GenericParam::Lifetime(_) | GenericParam::Const(_) => Ok(None), GenericParam::Type(t) => { let i = &t.ident; let skip_default = parse_attrs(&t.attrs)? .extract("specta", "skip_default_generic") .map(|attr| attr.parse_bool().unwrap_or(true)) .unwrap_or(false); if !used_direct_generics.iter().any(|used| used == i) && !skip_default { return Ok(None); } let i_str = i.to_string(); let default = match (&t.default, skip_default) { (_, true) | (None, false) => quote!(None), (Some(default), false) => { quote!(Some(<#default as #crate_ref::Type>::definition(types))) } }; let reference = used_direct_generics.iter().any(|used| used == i).then(|| { quote!(( #crate_ref::datatype::Generic::new(Cow::Borrowed(#i_str)), <#i as #crate_ref::Type>::definition(types), )) }); Ok(Some(( quote!(#crate_ref::datatype::GenericDefinition::new( Cow::Borrowed(#i_str), #default, )), reference, ))) } }) .collect::>>()? .into_iter() .flatten() .collect::<(Vec<_>, Vec<_>)>(); let collect = (cfg!(feature = "DO_NOT_USE_collect") && !container_attrs.inline && container_attrs.collect.unwrap_or(true)) .then(|| { let export_fn_name = format_ident!("__push_specta_type_{}", raw_ident); let generic_params = generics .params .iter() .filter(|param| matches!(param, syn::GenericParam::Type(_))) .map(|_| quote! { () }); quote! { #[doc(hidden)] #[allow(unsafe_code, non_snake_case)] #[#crate_ref::collect::internal::small_ctor::ctor] unsafe fn #export_fn_name() { #crate_ref::collect::internal::register::<#ident<#(#generic_params),*>>(); } } }); let shadow_generic_aliases = if has_associated_type_usage(&used_generic_types) { quote!() } else { quote!(#(#shadow_generics)*) }; let ndt_build_ty_args = if has_associated_type_usage(&used_generic_types) { &build_ty_passthrough_args } else { &build_ty_placeholder_args }; let has_generic_default = generics .params .iter() .any(|param| matches!(param, GenericParam::Type(ty) if ty.default.is_some())); let generics = (!generics_for_ndt.is_empty()).then(|| { if has_generic_default { quote! { ndt.generics = Cow::Owned(vec![#(#generics_for_ndt),*]); } } else { quote! { static GENERICS: &[datatype::GenericDefinition] = &[#(#generics_for_ndt),*]; ndt.generics = Cow::Borrowed(GENERICS); } } }); let docs = (!container_attrs.common.doc.is_empty()).then(|| { let docs = &container_attrs.common.doc; quote! { ndt.docs = Cow::Borrowed(#docs); } }); let deprecated = container_attrs.common.deprecated.map(|deprecated| { let tokens = deprecated_as_tokens(deprecated); quote!(ndt.deprecated = #tokens;) }); let ndt_ty = (!container_attrs.inline).then(|| { quote! { #(#generic_placeholders)* #shadow_generic_aliases ndt.ty = Some(build #ndt_build_ty_args (types)); } }); let definition = quote! { datatype::DataType::Reference( datatype::NamedDataType::init_with_sentinel( SENTINEL, &[#(#instantiation_generics),*], #has_const_param, false, types, |types, ndt| { ndt.name = Cow::Borrowed(#name); ndt.module_path = Cow::Borrowed(module_path!()); #generics #docs #deprecated; #ndt_ty }, build #build_ty_passthrough_args ) ) }; let definition = if container_attrs.inline { quote!(datatype::inline(types, |types| #definition)) } else { definition }; Ok(quote! { #[automatically_derived] impl #bounds #crate_ref::Type for #ident #type_args #where_bound { fn definition(types: &mut #crate_ref::Types) -> #crate_ref::datatype::DataType { use std::borrow::Cow; use #crate_ref::datatype; static SENTINEL: &str = concat!(module_path!(), "::", stringify!(#raw_ident)); fn build #build_ty_bounds (types: &mut #crate_ref::Types) -> datatype::DataType #build_ty_where_bound { #dt_expr } #definition } } #collect } .into()) } ================================================ FILE: specta-macros/src/type/serde.rs ================================================ use proc_macro2::TokenStream; use quote::quote; use syn::{Attribute, LitStr, Meta, Result, Type, meta::ParseNestedMeta}; use super::AttributeScope; #[derive(Clone)] struct ConversionType { type_src: String, ty: Type, } #[derive(Copy, Clone)] enum RenameRule { Lower, Upper, Pascal, Camel, Snake, ScreamingSnake, Kebab, ScreamingKebab, } impl RenameRule { fn parse(lit: &LitStr) -> Result { Ok(match lit.value().as_str() { "lowercase" => Self::Lower, "UPPERCASE" => Self::Upper, "PascalCase" => Self::Pascal, "camelCase" => Self::Camel, "snake_case" => Self::Snake, "SCREAMING_SNAKE_CASE" => Self::ScreamingSnake, "kebab-case" => Self::Kebab, "SCREAMING-KEBAB-CASE" => Self::ScreamingKebab, _ => { return Err(syn::Error::new( lit.span(), format!("unsupported serde casing: `{}`", lit.value()), )); } }) } fn as_str(self) -> &'static str { match self { Self::Lower => "lowercase", Self::Upper => "UPPERCASE", Self::Pascal => "PascalCase", Self::Camel => "camelCase", Self::Snake => "snake_case", Self::ScreamingSnake => "SCREAMING_SNAKE_CASE", Self::Kebab => "kebab-case", Self::ScreamingKebab => "SCREAMING-KEBAB-CASE", } } } #[derive(Default)] struct ContainerAttrs { rename_serialize: Option, rename_deserialize: Option, rename_all_serialize: Option, rename_all_deserialize: Option, rename_all_fields_serialize: Option, rename_all_fields_deserialize: Option, tag: Option, content: Option, untagged: bool, default: bool, transparent: bool, from: Option, try_from: Option, into: Option, variant_identifier: bool, field_identifier: bool, } #[derive(Default)] struct VariantAttrs { rename_serialize: Option, rename_deserialize: Option, aliases: Vec, rename_all_serialize: Option, rename_all_deserialize: Option, skip_serializing: bool, skip_deserializing: bool, has_serialize_with: bool, has_deserialize_with: bool, has_with: bool, other: bool, untagged: bool, } #[derive(Default)] struct FieldAttrs { rename_serialize: Option, rename_deserialize: Option, aliases: Vec, default: bool, flatten: bool, skip_serializing: bool, skip_deserializing: bool, skip_serializing_if: Option, has_serialize_with: bool, has_deserialize_with: bool, has_with: bool, } pub(super) fn lower_runtime_attributes( crate_ref: &TokenStream, scope: AttributeScope, raw_attrs: &[Attribute], ) -> Result> { match scope { AttributeScope::Container => parse_container_attrs(raw_attrs) .map(|attrs| attrs.map(|attrs| lower_container_attrs(crate_ref, attrs))), AttributeScope::Variant => parse_variant_attrs(raw_attrs) .map(|attrs| attrs.map(|attrs| lower_variant_attrs(crate_ref, attrs))), AttributeScope::Field => parse_field_attrs(raw_attrs) .map(|attrs| attrs.map(|attrs| lower_field_attrs(crate_ref, attrs))), } } fn parse_container_attrs(attrs: &[Attribute]) -> Result> { let mut parsed = ContainerAttrs::default(); let mut found = false; for attr in attrs.iter().filter(|attr| attr.path().is_ident("serde")) { let Meta::List(list) = &attr.meta else { continue; }; found = true; list.parse_nested_meta(|meta| parse_container_meta(&mut parsed, meta))?; } Ok(found.then_some(parsed)) } fn parse_variant_attrs(attrs: &[Attribute]) -> Result> { let mut parsed = VariantAttrs::default(); let mut found = false; for attr in attrs.iter().filter(|attr| attr.path().is_ident("serde")) { let Meta::List(list) = &attr.meta else { continue; }; found = true; list.parse_nested_meta(|meta| parse_variant_meta(&mut parsed, meta))?; } Ok(found.then_some(parsed)) } fn parse_field_attrs(attrs: &[Attribute]) -> Result> { let mut parsed = FieldAttrs::default(); let mut found = false; for attr in attrs.iter().filter(|attr| attr.path().is_ident("serde")) { let Meta::List(list) = &attr.meta else { continue; }; found = true; list.parse_nested_meta(|meta| parse_field_meta(&mut parsed, meta))?; } Ok(found.then_some(parsed)) } fn parse_container_meta(target: &mut ContainerAttrs, meta: ParseNestedMeta<'_>) -> Result<()> { if meta.path.is_ident("rename") { parse_rename( &meta, &mut target.rename_serialize, &mut target.rename_deserialize, )?; } else if meta.path.is_ident("rename_all") { parse_rename_all( &meta, &mut target.rename_all_serialize, &mut target.rename_all_deserialize, )?; } else if meta.path.is_ident("rename_all_fields") { parse_rename_all( &meta, &mut target.rename_all_fields_serialize, &mut target.rename_all_fields_deserialize, )?; } else if meta.path.is_ident("tag") { target.tag = Some(parse_string_assignment(&meta)?); } else if meta.path.is_ident("content") { target.content = Some(parse_string_assignment(&meta)?); } else if meta.path.is_ident("untagged") { target.untagged = true; } else if meta.path.is_ident("default") { parse_default_assignment(&meta)?; target.default = true; } else if meta.path.is_ident("transparent") { target.transparent = true; } else if meta.path.is_ident("from") { target.from = Some(parse_conversion_assignment(&meta)?); } else if meta.path.is_ident("try_from") { target.try_from = Some(parse_conversion_assignment(&meta)?); } else if meta.path.is_ident("into") { target.into = Some(parse_conversion_assignment(&meta)?); } else if meta.path.is_ident("variant_identifier") { target.variant_identifier = true; } else if meta.path.is_ident("field_identifier") { target.field_identifier = true; } Ok(()) } fn parse_variant_meta(target: &mut VariantAttrs, meta: ParseNestedMeta<'_>) -> Result<()> { if meta.path.is_ident("rename") { parse_rename( &meta, &mut target.rename_serialize, &mut target.rename_deserialize, )?; } else if meta.path.is_ident("alias") { target.aliases.push(parse_string_assignment(&meta)?); } else if meta.path.is_ident("rename_all") { parse_rename_all( &meta, &mut target.rename_all_serialize, &mut target.rename_all_deserialize, )?; } else if meta.path.is_ident("skip") { target.skip_serializing = true; target.skip_deserializing = true; } else if meta.path.is_ident("skip_serializing") { target.skip_serializing = true; } else if meta.path.is_ident("skip_deserializing") { target.skip_deserializing = true; } else if meta.path.is_ident("serialize_with") { target.has_serialize_with = true; parse_string_assignment(&meta)?; } else if meta.path.is_ident("deserialize_with") { target.has_deserialize_with = true; parse_string_assignment(&meta)?; } else if meta.path.is_ident("with") { target.has_with = true; parse_string_assignment(&meta)?; } else if meta.path.is_ident("other") { target.other = true; } else if meta.path.is_ident("untagged") { target.untagged = true; } Ok(()) } fn parse_field_meta(target: &mut FieldAttrs, meta: ParseNestedMeta<'_>) -> Result<()> { if meta.path.is_ident("rename") { parse_rename( &meta, &mut target.rename_serialize, &mut target.rename_deserialize, )?; } else if meta.path.is_ident("alias") { target.aliases.push(parse_string_assignment(&meta)?); } else if meta.path.is_ident("default") { parse_default_assignment(&meta)?; target.default = true; } else if meta.path.is_ident("flatten") { target.flatten = true; } else if meta.path.is_ident("skip") { target.skip_serializing = true; target.skip_deserializing = true; } else if meta.path.is_ident("skip_serializing") { target.skip_serializing = true; } else if meta.path.is_ident("skip_deserializing") { target.skip_deserializing = true; } else if meta.path.is_ident("skip_serializing_if") { target.skip_serializing_if = Some(parse_string_assignment(&meta)?); } else if meta.path.is_ident("serialize_with") { target.has_serialize_with = true; parse_string_assignment(&meta)?; } else if meta.path.is_ident("deserialize_with") { target.has_deserialize_with = true; parse_string_assignment(&meta)?; } else if meta.path.is_ident("with") { target.has_with = true; parse_string_assignment(&meta)?; } Ok(()) } fn parse_rename( meta: &ParseNestedMeta<'_>, rename_serialize: &mut Option, rename_deserialize: &mut Option, ) -> Result<()> { if meta.input.peek(syn::Token![=]) { let value = parse_string_assignment(meta)?; *rename_serialize = Some(value.clone()); *rename_deserialize = Some(value); return Ok(()); } meta.parse_nested_meta(|meta| { if meta.path.is_ident("serialize") { *rename_serialize = Some(parse_string_assignment(&meta)?); } else if meta.path.is_ident("deserialize") { *rename_deserialize = Some(parse_string_assignment(&meta)?); } Ok(()) }) } fn parse_rename_all( meta: &ParseNestedMeta<'_>, rename_serialize: &mut Option, rename_deserialize: &mut Option, ) -> Result<()> { if meta.input.peek(syn::Token![=]) { let lit = parse_lit_str(meta)?; let rule = RenameRule::parse(&lit)?; *rename_serialize = Some(rule); *rename_deserialize = Some(rule); return Ok(()); } meta.parse_nested_meta(|meta| { if meta.path.is_ident("serialize") { *rename_serialize = Some(RenameRule::parse(&parse_lit_str(&meta)?)?); } else if meta.path.is_ident("deserialize") { *rename_deserialize = Some(RenameRule::parse(&parse_lit_str(&meta)?)?); } Ok(()) }) } fn parse_default_assignment(meta: &ParseNestedMeta<'_>) -> Result { if meta.input.peek(syn::Token![=]) { parse_string_assignment(meta) } else { Ok("__default__".to_owned()) } } fn parse_conversion_assignment(meta: &ParseNestedMeta<'_>) -> Result { let lit = parse_lit_str(meta)?; let type_src = lit.value(); let ty = syn::parse_str::(&type_src) .map_err(|err| syn::Error::new(lit.span(), format!("invalid type literal: {err}")))?; Ok(ConversionType { type_src, ty }) } fn parse_string_assignment(meta: &ParseNestedMeta<'_>) -> Result { parse_lit_str(meta).map(|lit| lit.value()) } fn parse_lit_str(meta: &ParseNestedMeta<'_>) -> Result { meta.value()?.parse() } fn lower_container_attrs(crate_ref: &TokenStream, attrs: ContainerAttrs) -> TokenStream { let mut inserts = Vec::new(); push_opt_string( &mut inserts, "serde:container:rename_serialize", &attrs.rename_serialize, ); push_opt_string( &mut inserts, "serde:container:rename_deserialize", &attrs.rename_deserialize, ); push_opt_rename_rule( &mut inserts, "serde:container:rename_all_serialize", attrs.rename_all_serialize, ); push_opt_rename_rule( &mut inserts, "serde:container:rename_all_deserialize", attrs.rename_all_deserialize, ); push_opt_rename_rule( &mut inserts, "serde:container:rename_all_fields_serialize", attrs.rename_all_fields_serialize, ); push_opt_rename_rule( &mut inserts, "serde:container:rename_all_fields_deserialize", attrs.rename_all_fields_deserialize, ); push_opt_string(&mut inserts, "serde:container:tag", &attrs.tag); push_opt_string(&mut inserts, "serde:container:content", &attrs.content); push_bool(&mut inserts, "serde:container:untagged", attrs.untagged); push_bool(&mut inserts, "serde:container:default", attrs.default); push_bool( &mut inserts, "serde:container:transparent", attrs.transparent, ); push_opt_conversion(&mut inserts, crate_ref, "from", &attrs.from); push_opt_conversion(&mut inserts, crate_ref, "try_from", &attrs.try_from); push_opt_conversion(&mut inserts, crate_ref, "into", &attrs.into); push_bool( &mut inserts, "serde:container:variant_identifier", attrs.variant_identifier, ); push_bool( &mut inserts, "serde:container:field_identifier", attrs.field_identifier, ); quote!(#(#inserts)*) } fn lower_variant_attrs(_crate_ref: &TokenStream, attrs: VariantAttrs) -> TokenStream { let mut inserts = Vec::new(); push_opt_string( &mut inserts, "serde:variant:rename_serialize", &attrs.rename_serialize, ); push_opt_string( &mut inserts, "serde:variant:rename_deserialize", &attrs.rename_deserialize, ); push_vec_string(&mut inserts, "serde:variant:aliases", &attrs.aliases); push_opt_rename_rule( &mut inserts, "serde:variant:rename_all_serialize", attrs.rename_all_serialize, ); push_opt_rename_rule( &mut inserts, "serde:variant:rename_all_deserialize", attrs.rename_all_deserialize, ); push_bool( &mut inserts, "serde:variant:skip_serializing", attrs.skip_serializing, ); push_bool( &mut inserts, "serde:variant:skip_deserializing", attrs.skip_deserializing, ); push_bool( &mut inserts, "serde:variant:has_serialize_with", attrs.has_serialize_with, ); push_bool( &mut inserts, "serde:variant:has_deserialize_with", attrs.has_deserialize_with, ); push_bool(&mut inserts, "serde:variant:has_with", attrs.has_with); push_bool(&mut inserts, "serde:variant:other", attrs.other); push_bool(&mut inserts, "serde:variant:untagged", attrs.untagged); quote!(#(#inserts)*) } fn lower_field_attrs(_crate_ref: &TokenStream, attrs: FieldAttrs) -> TokenStream { let mut inserts = Vec::new(); push_opt_string( &mut inserts, "serde:field:rename_serialize", &attrs.rename_serialize, ); push_opt_string( &mut inserts, "serde:field:rename_deserialize", &attrs.rename_deserialize, ); push_vec_string(&mut inserts, "serde:field:aliases", &attrs.aliases); push_bool(&mut inserts, "serde:field:default", attrs.default); push_bool(&mut inserts, "serde:field:flatten", attrs.flatten); push_bool( &mut inserts, "serde:field:skip_serializing", attrs.skip_serializing, ); push_bool( &mut inserts, "serde:field:skip_deserializing", attrs.skip_deserializing, ); push_opt_string( &mut inserts, "serde:field:skip_serializing_if", &attrs.skip_serializing_if, ); push_bool( &mut inserts, "serde:field:has_serialize_with", attrs.has_serialize_with, ); push_bool( &mut inserts, "serde:field:has_deserialize_with", attrs.has_deserialize_with, ); push_bool(&mut inserts, "serde:field:has_with", attrs.has_with); quote!(#(#inserts)*) } fn push_opt_string(inserts: &mut Vec, key: &str, value: &Option) { if let Some(value) = value { inserts.push(quote!(attrs.insert(#key, ::std::string::String::from(#value));)); } } fn push_vec_string(inserts: &mut Vec, key: &str, value: &[String]) { if value.is_empty() { return; } let value = value .iter() .map(|value| quote!(::std::string::String::from(#value))); inserts.push(quote!(attrs.insert(#key, vec![#(#value),*]);)); } fn push_bool(inserts: &mut Vec, key: &str, value: bool) { if value { inserts.push(quote!(attrs.insert(#key, true);)); } } fn push_opt_rename_rule(inserts: &mut Vec, key: &str, value: Option) { if let Some(value) = value { let value = value.as_str(); inserts.push(quote!(attrs.insert(#key, ::std::string::String::from(#value));)); } } fn push_opt_conversion( inserts: &mut Vec, crate_ref: &TokenStream, key: &str, value: &Option, ) { if let Some(value) = value { let type_src = &value.type_src; let ty = &value.ty; let src_key = format!("serde:container:{key}_type_src"); let resolved_key = format!("serde:container:{key}_resolved"); inserts.push(quote!(attrs.insert(#src_key, ::std::string::String::from(#type_src));)); inserts.push( quote!(attrs.insert(#resolved_key, <#ty as #crate_ref::Type>::definition(types));), ); } } ================================================ FILE: specta-macros/src/type/struct.rs ================================================ use crate::{ r#type::field::construct_field, utils::{parse_attrs_with_filter, unraw_raw_ident}, }; use proc_macro2::TokenStream; use quote::{ToTokens, quote}; use syn::{DataStruct, Field, Fields, Type, spanned::Spanned}; use super::attr::*; pub fn decode_field_attrs<'a>( field: &'a Field, skip_attrs: &[String], ) -> syn::Result<(FieldAttr, &'a [syn::Attribute])> { // We pass all the attributes at the start and when decoding them pop them off the list. // This means at the end we can check for any that weren't consumed and throw an error. let raw_attrs = parse_attrs_with_filter(&field.attrs, skip_attrs)?; let mut attrs = raw_attrs.clone(); let field_attrs = FieldAttr::from_attrs(&mut attrs)?; // The expectation is that when an attribute is processed it will be removed so if any are left over we know they are invalid // but we only throw errors for Specta-specific attributes so we don't continually break other attributes. if let Some(attr) = attrs.iter().find(|attr| attr.source == "specta") { match &attr.value { None | Some(crate::utils::AttributeValue::Lit(_)) | Some(crate::utils::AttributeValue::Path(_)) => { return Err(syn::Error::new( attr.key.span(), "specta: invalid formatted attribute", )); } Some(crate::utils::AttributeValue::Expr(_)) => { return Err(syn::Error::new( attr.key.span(), "specta: invalid formatted attribute", )); } Some(crate::utils::AttributeValue::Attribute { attr: inner_attrs, .. }) => { if let Some(inner_attr) = inner_attrs.first() { if let Some(message) = migration_hint(Scope::Field, &inner_attr.key.to_string()) { return Err(syn::Error::new(inner_attr.key.span(), message)); } return Err(syn::Error::new( inner_attr.key.span(), format!( "specta: Found unsupported field attribute '{}'", inner_attr.key ), )); } return Err(syn::Error::new( attr.key.span(), "specta: invalid formatted attribute", )); } } } Ok((field_attrs, &field.attrs)) } pub fn parse_struct( crate_ref: &TokenStream, container_attrs: &ContainerAttr, data: &DataStruct, ) -> syn::Result { if container_attrs.transparent { if let Fields::Unit = data.fields { return Err(syn::Error::new( data.fields.span(), "specta: unit structs cannot be transparent", )); } let fields = data .fields .iter() .map(|field| { decode_field_attrs(field, &container_attrs.skip_attrs) .map(|(attrs, raw)| (field.ty.clone(), attrs, raw)) }) .collect::>>()? .into_iter() .filter(|(_, attrs, _)| !attrs.skip) .collect::>(); if fields.len() != 1 { return Err(syn::Error::new( data.fields.span(), "specta: transparent structs must have exactly one field", )); } let (field_ty, field_attrs, raw_attrs) = fields.into_iter().next().expect("fields.len() != 1"); let field = construct_field( crate_ref, container_attrs, field_attrs, &field_ty, raw_attrs, )?; return Ok(quote!(datatype::Struct::unnamed().field(#field).build())); } let fields = match &data.fields { Fields::Named(_) => { let fields = data .fields .iter() .map(|field| { let (field_attrs, raw_attrs) = decode_field_attrs(field, &container_attrs.skip_attrs)?; let field_ident_str = unraw_raw_ident(field.ident.as_ref().ok_or_else(|| { syn::Error::new( field.span(), "specta: named field must have an identifier", ) })?); let field_name = field_ident_str.to_token_stream(); let inner = construct_field( crate_ref, container_attrs, field_attrs, &field.ty, raw_attrs, )?; Ok(quote!(builder.field_mut(#field_name, #inner);)) }) .collect::>>()?; quote!({ let mut builder = datatype::Struct::named(); #(#fields)* builder.build() }) } Fields::Unnamed(_) => { let fields = data .fields .iter() .map(|field| { let (field_attrs, raw_attrs) = decode_field_attrs(field, &container_attrs.skip_attrs)?; construct_field( crate_ref, container_attrs, field_attrs, &field.ty, raw_attrs, ) .map(|inner| quote!(builder.field_mut(#inner);)) }) .collect::>>()?; quote!({ let mut builder = datatype::Struct::unnamed(); #(#fields)* builder.build() }) } Fields::Unit => quote!(datatype::Struct::unit().into()), }; Ok(fields) } ================================================ FILE: specta-macros/src/utils.rs ================================================ use proc_macro2::Span; use quote::ToTokens; use syn::{ Expr, Ident, Lit, Meta, Path, Result, Token, Type, TypePath, ext::IdentExt, parse::{Parse, ParseStream}, spanned::Spanned, token::Paren, }; #[derive(Clone)] pub enum AttributeValue { /// Literal value. Eg. `#[specta(name = "hello")]` or `#[specta(name = u32)]` Lit(Lit), /// Path value. Eg. `#[specta(type = String)]` or `#[specta(type = ::std::string::String)]` /// Path doesn't follow the Rust spec hence the need for this custom parser. We are doing this anyway for backwards compatibility. Path(Path), /// Expression value for values that are not valid paths. /// This allows us to later parse richer forms such as tuple/array/reference types. Expr(Expr), /// A nested attribute. Eg. the `deprecated(note = "some note") in `#[specta(deprecated(note = "some note"))]` Attribute { span: Span, attr: Vec }, } impl AttributeValue { fn span(&self) -> Span { match self { Self::Lit(lit) => lit.span(), Self::Path(path) => path.span(), Self::Expr(expr) => expr.span(), Self::Attribute { span, .. } => *span, } } } impl Parse for AttributeValue { fn parse(input: ParseStream) -> Result { Ok(match input.peek(Lit) { true => Self::Lit(input.parse()?), false => { if input.fork().parse::().is_ok() { Self::Path(input.parse()?) } else { Self::Expr(input.parse()?) } } }) } } #[derive(Clone)] pub struct Attribute { /// Source of the attribute. Eg. `specta`, `serde`, `repr`, `deprecated`, etc. pub source: String, /// Key of the current item. Eg. `specta` or `type`in `#[specta(type = String)]` pub key: Ident, /// Value of the item. Eg. `String` in `#[specta(type = String)]` pub value: Option, } impl Attribute { /// Span of they value. Eg. `String` in `#[specta(type = String)]` /// Will fallback to the key span if no value is present. pub fn value_span(&self) -> Span { match &self.value { Some(v) => v.span(), None => self.key.span(), } } pub fn parse_string(&self) -> Result { match &self.value { Some(AttributeValue::Lit(Lit::Str(string))) => Ok(string.value()), _ => Err(syn::Error::new( self.value_span(), "specta: expected string literal. Eg. `\"somestring\"`", )), } } pub fn parse_bool(&self) -> Result { match &self.value { Some(AttributeValue::Lit(Lit::Bool(b))) => Ok(b.value()), _ => Err(syn::Error::new( self.value_span(), "specta: expected boolean literal. Eg. `true` or `false`", )), } } pub fn parse_path(&self) -> Result { match &self.value { Some(AttributeValue::Path(path)) => Ok(path.clone()), Some(AttributeValue::Expr(Expr::Path(path))) => Ok(path.path.clone()), _ => Err(syn::Error::new( self.value_span(), "specta: expected path. Eg. `String` or `std::string::String`", )), } } pub fn parse_type(&self) -> Result { match &self.value { Some(AttributeValue::Path(path)) => Ok(Type::Path(TypePath { qself: None, path: path.clone(), })), Some(AttributeValue::Expr(expr)) => syn::parse2(expr.to_token_stream()).map_err(|_| { syn::Error::new( self.value_span(), "specta: expected type. Eg. `String`, `(String, i32)` or `Vec`", ) }), _ => Err(syn::Error::new( self.value_span(), "specta: expected type. Eg. `String`, `(String, i32)` or `Vec`", )), } } } pub trait AttrExtract { fn extract(&mut self, source: &str, key: &str) -> Option; fn extract_all(&mut self, source: &str, key: &str) -> Vec; } impl AttrExtract for Vec { fn extract(&mut self, source: &str, key: &str) -> Option { // 1. Check for top-level match (e.g., #[deprecated]) if let Some(pos) = self .iter() .position(|attr| attr.source == source && attr.key == key) { return Some(self.swap_remove(pos)); } // 2. Check nested attributes within parent matching source // e.g., extract("specta", "inline") from #[specta(inline)] // Structure: Attribute { source: "specta", key: "specta", value: Attribute { key: "inline" } } for i in 0..self.len() { if self[i].source == source && self[i].key == source && let Some(AttributeValue::Attribute { attr: nested_attrs, .. }) = &mut self[i].value && let Some(nested_pos) = nested_attrs.iter().position(|a| a.key == key) { let result = nested_attrs.swap_remove(nested_pos); // If parent attribute is now empty, remove it too if nested_attrs.is_empty() { self.swap_remove(i); } return Some(result); } } None } fn extract_all(&mut self, source: &str, key: &str) -> Vec { let mut result = Vec::new(); // 1. Extract all top-level matches let mut i = 0; while i < self.len() { if self[i].source == source && self[i].key == key { result.push(self.swap_remove(i)); // Don't increment i, as swap_remove moved a new element to position i } else { i += 1; } } // 2. Extract all nested matches let mut i = 0; while i < self.len() { let mut should_remove_parent = false; if self[i].source == source && self[i].key == source && let Some(AttributeValue::Attribute { attr: nested_attrs, .. }) = &mut self[i].value { let mut j = 0; while j < nested_attrs.len() { if nested_attrs[j].key == key { result.push(nested_attrs.swap_remove(j)); } else { j += 1; } } should_remove_parent = nested_attrs.is_empty(); } if should_remove_parent { self.swap_remove(i); } else { i += 1; } } result } } struct NestedAttributeList { attrs: Vec, } impl Parse for NestedAttributeList { fn parse(input: ParseStream) -> Result { let mut attrs = Vec::new(); while !input.is_empty() { if input.peek(Ident::peek_any) { let fork = input.fork(); let _ = fork.call(Ident::parse_any)?; if fork.peek(Token![::]) { let _ignored: syn::Expr = input.parse()?; } else { let key = input.call(Ident::parse_any)?; let key_span = key.span(); attrs.push(Attribute { source: String::new(), key, value: match false { _ if input.peek(Paren) => { let content; syn::parenthesized!(content in input); Some(AttributeValue::Attribute { span: key_span, attr: content.parse::()?.attrs, }) } _ if input.peek(Token![=]) => { input.parse::()?; Some(input.parse()?) } _ => None, }, }); } } else { let _ignored: syn::Expr = input.parse()?; } if input.peek(Token![,]) { input.parse::()?; } } Ok(NestedAttributeList { attrs }) } } /// pass all of the attributes into a single structure. /// We can then remove them from the struct while passing an any left over must be invalid and an error can be thrown. pub fn parse_attrs(attrs: &[syn::Attribute]) -> syn::Result> { parse_attrs_with_filter(attrs, &[]) } /// Same as `parse_attrs` but allows skipping attributes by name. /// This is useful for skipping attributes that may have non-standard syntax that we can't parse. pub fn parse_attrs_with_filter( attrs: &[syn::Attribute], skip_attrs: &[String], ) -> syn::Result> { let mut result = Vec::new(); for attr in attrs { let ident = attr .path() .segments .last() .expect("Attribute path must have at least one segment") .clone() .ident; // Skip attributes that are in the skip list let attr_name = ident.to_string(); if skip_attrs.contains(&attr_name) { continue; } result.append(&mut match &attr.meta { Meta::Path(_) => vec![Attribute { source: attr_name.clone(), key: ident.clone(), value: None, }], Meta::List(meta) => { let source = attr_name.clone(); let mut parsed: Vec = syn::parse2::(meta.tokens.clone())?.attrs; for a in &mut parsed { a.source = source.clone(); } vec![Attribute { source, key: ident.clone(), value: Some(AttributeValue::Attribute { span: ident.span(), attr: parsed, }), }] } Meta::NameValue(meta) => { let source = attr_name.clone(); let mut parsed: Vec = syn::parse2::(meta.to_token_stream().clone())?.attrs; for a in &mut parsed { a.source = source.clone(); } parsed } }); } Ok(result) } pub fn unraw_raw_ident(ident: &Ident) -> String { let ident = ident.to_string(); if ident.starts_with("r#") { ident.trim_start_matches("r#").to_owned() } else { ident } } #[cfg(feature = "DO_NOT_USE_function")] pub fn format_fn_wrapper(function: &Ident) -> Ident { quote::format_ident!("__specta__fn__{}", function) } ================================================ FILE: specta-openapi/Cargo.toml ================================================ [package] name = "specta-openapi" description = "Export your Rust types to OpenAPI" version = "0.0.2" authors = ["Oscar Beaumont "] edition = "2024" license = "MIT" repository = "https://github.com/specta-rs/specta" documentation = "https://docs.rs/specta-openapi/latest/specta-openapi" keywords = ["async", "specta", "rspc", "openapi", "typesafe"] categories = ["web-programming", "asynchronous"] readme = "../README.md" # /bin/sh RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features [package.metadata."docs.rs"] all-features = true rustdoc-args = ["--cfg", "docsrs"] [lints] workspace = true [dependencies] specta = { version = "=2.0.0-rc.24", path = "../specta" } openapiv3 = { version = "2", default-features = false, features = [] } ================================================ FILE: specta-openapi/src/lib.rs ================================================ //! [OpenAPI](https://www.openapis.org) language exporter for [Specta](specta). //! //!
//! This crate is still in active development and is not yet ready for general purpose use! //!
//! #![cfg_attr(docsrs, feature(doc_cfg))] #![doc( html_logo_url = "https://github.com/specta-rs/specta/raw/main/.github/logo-128.png", html_favicon_url = "https://github.com/specta-rs/specta/raw/main/.github/logo-128.png" )] #![allow(warnings)] // TODO: This crate is still in development use openapiv3::{ ArrayType, BooleanType, NumberType, ReferenceOr, Schema, SchemaData, SchemaKind, StringType, Type, }; use specta::datatype::{DataType, Primitive}; // pub fn to_openapi_export(def: &DataType) -> Result { // Ok(match &def { // // Named struct // // DataType::Struct(StructType { // // name, // // generics, // // fields, // // .. // // }) => match fields.len() { // // 0 => format!("export type {name} = {inline_ts}"), // // _ => { // // let generics = match generics.len() { // // 0 => "".into(), // // _ => format!("<{}>", generics.to_vec().join(", ")), // // }; // // format!("export interface {name}{generics} {inline_ts}") // // } // // }, // // // Enum // // DataType::Enum(EnumType { name, generics, .. }) => { // // let generics = match generics.len() { // // 0 => "".into(), // // _ => format!("<{}>", generics.to_vec().join(", ")), // // }; // // format!("export type {name}{generics} = {inline_ts}") // // } // // // Unnamed struct // // DataType::Tuple(TupleType { name, .. }) => { // // format!("export type {name} = {inline_ts}") // // } // _ => todo!(), // return Err(format!("Type cannot be exported: {:?}", def)), // }) // } macro_rules! primitive_def { ($($t:ident)+) => { $(DataType::Primitive(Primitive::$t))|+ } } pub fn to_openapi(typ: &DataType) -> ReferenceOr { let mut schema_data = SchemaData { nullable: false, deprecated: false, // TODO example: None, // TODO title: None, // TODO description: None, // TODO default: None, // TODO ..Default::default() }; match &typ { // DataType::Any => ReferenceOr::Item(Schema { // schema_data, // schema_kind: SchemaKind::Type(Type::Object(openapiv3::ObjectType::default())), // TODO: Use official "Any Type" // }), primitive_def!(i8 i16 i32 isize u8 u16 u32 usize f16 f32 f64 f128) => { ReferenceOr::Item(Schema { schema_data, schema_kind: SchemaKind::Type(Type::Number(NumberType::default())), // TODO: Configure number type. Ts: `number` }) } primitive_def!(i64 u64 i128 u128) => ReferenceOr::Item(Schema { schema_data, schema_kind: SchemaKind::Type(Type::Number(NumberType::default())), // TODO: Configure number type. Ts: `bigint` }), primitive_def!(str char) => ReferenceOr::Item(Schema { schema_data, schema_kind: SchemaKind::Type(Type::String(StringType::default())), // TODO: Configure string type. Ts: `string` }), primitive_def!(bool) => ReferenceOr::Item(Schema { schema_data, schema_kind: SchemaKind::Type(Type::Boolean(BooleanType::default())), }), // primitive_def!(Never) => "never".into(), DataType::Nullable(def) => { to_openapi(def) // schema.schema_data.nullable = true; // TODO } // DataType::Map(def) => { // format!("Record<{}, {}>", to_openapi(&def.0), to_openapi(&def.1)) // } DataType::List(def) => ReferenceOr::Item(Schema { schema_data, schema_kind: SchemaKind::Type(Type::Array(ArrayType { items: Some(match to_openapi(&def.ty) { ReferenceOr::Item(schema) => ReferenceOr::Item(Box::new(schema)), ReferenceOr::Reference { reference } => ReferenceOr::Reference { reference }, }), // TODO: This type is missing `Default` min_items: None, max_items: None, unique_items: false, })), }), DataType::Tuple(tuple) => match tuple.elements.as_slice() { [] => { schema_data.nullable = true; ReferenceOr::Item(Schema { schema_data, schema_kind: SchemaKind::Type(Type::Object(openapiv3::ObjectType::default())), // TODO: This should be `null` type }) } [ty] => to_openapi(ty), _tys => todo!(), }, DataType::Struct(s) => { let _fields = &s.fields; // match &fields[..] { // [] => todo!(), // "null".to_string(), // fields => { // // let mut out = match tag { // // Some(tag) => vec![format!("{tag}: \"{name}\"")], // // None => vec![], // // }; // // let field_defs = object_fields(fields); // // out.extend(field_defs); // // format!("{{ {} }}", out.join(", ")) // ReferenceOr::Item(Schema { // schema_data, // schema_kind: SchemaKind::Type(Type::Object(openapiv3::ObjectType { // properties: fields // .iter() // .map( // |ObjectField { // name, ty, optional, .. // }| { // ( // name.clone(), // match to_openapi(ty) { // ReferenceOr::Item(v) => { // ReferenceOr::Item(Box::new(v)) // } // ReferenceOr::Reference { reference } => { // ReferenceOr::Reference { reference } // } // }, // ) // }, // ) // .collect(), // ..Default::default() // })), // }) // } // } todo!(); } DataType::Enum(_e) => { // let variants = e.variants(); // match &variants[..] { // [] => todo!(), // "never".to_string(), // variants => { // // variants // // .iter() // // .map(|variant| { // // let sanitised_name = sanitise_name(variant.name()); // // match (repr, variant) { // // (EnumRepr::Internal { tag }, Variant::Unit(_)) => { // // format!("{{ {tag}: \"{sanitised_name}\" }}") // // } // // (EnumRepr::Internal { tag }, Variant::Unnamed(tuple)) => { // // let typ = to_openapi(&DataType::Tuple(tuple.clone())); // // format!("{{ {tag}: \"{sanitised_name}\" }} & {typ}") // // } // // (EnumRepr::Internal { tag }, Variant::Named(obj)) => { // // let mut fields = vec![format!("{tag}: \"{sanitised_name}\"")]; // // fields.extend(object_fields(&obj.fields)); // // format!("{{ {} }}", fields.join(", ")) // // } // // (EnumRepr::External, Variant::Unit(_)) => { // // format!("\"{sanitised_name}\"") // // } // // (EnumRepr::External, v) => { // // let ts_values = to_openapi(&v.data_type()); // // format!("{{ {sanitised_name}: {ts_values} }}") // // } // // (EnumRepr::Untagged, Variant::Unit(_)) => "null".to_string(), // // (EnumRepr::Untagged, v) => to_openapi(&v.data_type()), // // (EnumRepr::Adjacent { tag, .. }, Variant::Unit(_)) => { // // format!("{{ {tag}: \"{sanitised_name}\" }}") // // } // // (EnumRepr::Adjacent { tag, content }, v) => { // // let ts_values = to_openapi(&v.data_type()); // // format!("{{ {tag}: \"{sanitised_name}\", {content}: {ts_values} }}") // // } // // } // // }) // // .collect::>() // // .join(" | "); // ReferenceOr::Item(Schema { // schema_data, // schema_kind: SchemaKind::AnyOf { // any_of: variants // .iter() // .map(|variant| match variant { // EnumVariants::Unit(_) => ReferenceOr::Item(Schema { // schema_data: Default::default(), // schema_kind: SchemaKind::Type(Type::Object( // openapiv3::ObjectType::default(), // TODO: Is this correct? // )), // }), // EnumVariants::Unnamed(tuple) => { // to_openapi(&DataType::Tuple(tuple.clone())) // } // Variant::Named(obj) => { // to_openapi(&DataType::Struct(obj.clone())) // } // }) // .collect(), // }, // }) // } // } todo!(); } DataType::Reference(_reference) => { todo!(); // match &reference.generics()[..] { // [] => { // todo!(); // // ReferenceOr::Item(Schema { // // schema_data, // // schema_kind: SchemaKind::OneOf { // // one_of: vec![ReferenceOr::Reference { // // reference: format!("#/components/schemas/{}", reference.name()), // // }], // // }, // // }) // } // generics => { // // let generics = generics // // .iter() // // .map(to_openapi) // // .collect::>() // // .join(", "); // // format!("{name}<{generics}>") // todo!(); // } // } } // DataType::Generic(ident) => ident.to_string(), x => { println!("{:?} {:?}", x, typ); todo!(); } } } ================================================ FILE: specta-serde/Cargo.toml ================================================ [package] name = "specta-serde" description = "Serde support for Specta" version = "0.0.11" authors = ["Oscar Beaumont "] edition = "2024" license = "MIT" repository = "https://github.com/specta-rs/specta" documentation = "https://docs.rs/specta-zod/latest/specta-zod" keywords = ["async", "specta", "rspc", "typescript", "typesafe"] categories = ["web-programming", "asynchronous"] # /bin/sh RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features [package.metadata."docs.rs"] all-features = true rustdoc-args = ["--cfg", "docsrs"] [lints] workspace = true [dependencies] specta = { version = "=2.0.0-rc.24", path = "../specta" } specta-macros = { version = "=2.0.0-rc.24", path = "../specta-macros", features = ["serde"] } [dev-dependencies] specta = { version = "=2.0.0-rc.24", path = "../specta", features = ["derive"] } serde = { version = "1", features = ["derive"] } ================================================ FILE: specta-serde/README.md ================================================ # Specta Serde [Serde](https://serde.rs) support for [Specta](https://github.com/specta-rs/specta). This allows for apply Serde macro attributes on your types to the Specta generated types! ## Using with Specta TypeScript `specta-serde` exposes two format implementation for usage with any of the exporter crates (like `specta-typescript`): - `specta_serde::format`: unified shape for both serialize and deserialize. - `specta_serde::format_phases`: split serialize/deserialize shapes. ## `format` (unified shape) Use `format` when serde behavior is symmetric and only a single TypeScript type is produced. Note: This will error with certain Serde attributes like `#[serde(rename(serialize = "a", deserialize = "b"))]` as it's unclear what is correct. ```rust use specta::Types; use specta_typescript::Typescript; #[derive(specta::Type, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "camelCase")] struct User { user_id: u32, } let types = Types::default().register::(); let output = Typescript::default() .export(&types, specta_serde::format) .unwrap(); assert!(output.contains("export type User")); assert!(output.contains("userId: number")); ``` You should always prefer `format_phases` where possible as it will generate a more accurate type. ## `format_phases` (split by direction) Use `format_phases` when the wire format could between serialization and deserialization. This may product two different types `TypeName_Serialize` and `TypeName_Deserialize` to accurately represent both phases. It will produce `TypeName` which is `TypeName_Serialize | TypeName_Deserialize` so the type can be used in a general format when needed. This is common with directional serde metadata (`serialize_with`, `deserialize_with`, `from`, `into`, `try_from`) or explicit `#[specta(type = specta_serde::Phased)]` overrides. ```rust use serde::{Deserialize, Serialize}; use serde_with::{OneOrMany, serde_as}; use specta::{Type, Types}; use specta_typescript::Typescript; #[derive(Type, Serialize, Deserialize)] #[serde(untagged)] enum OneOrManyString { One(String), Many(Vec), } #[serde_as] #[derive(Type, Serialize, Deserialize)] struct Filters { #[serde_as(as = "OneOrMany<_>")] #[specta(type = specta_serde::Phased, OneOrManyString>)] tags: Vec, } let types = Types::default().register::(); let output = Typescript::default() .export(&types, specta_serde::format_phases) .unwrap(); assert!(output.contains("Filters_Serialize")); assert!(output.contains("Filters_Deserialize")); assert!(output.contains("OneOrManyString")); ``` ================================================ FILE: specta-serde/src/error.rs ================================================ use std::{borrow::Cow, error, fmt}; /// Error type for serde transformation and validation failures. #[non_exhaustive] pub struct Error { kind: ErrorKind, } #[derive(Debug)] enum ErrorKind { InvalidUsageOfSkip { path: String, reason: Cow<'static, str>, }, InvalidInternallyTaggedEnum { path: String, variant: String, reason: Cow<'static, str>, }, InvalidEnumRepresentation { reason: Cow<'static, str>, }, InvalidExternalTaggedVariant { variant: String, }, InvalidAdjacentTaggedVariant { variant: String, }, InvalidInternallyTaggedVariant { variant: String, reason: Cow<'static, str>, }, IncompatibleRename { context: Cow<'static, str>, name: String, serialize: Option, deserialize: Option, }, IncompatibleConversion { context: Cow<'static, str>, name: String, serialize: Option, deserialize: Option, }, InvalidConversionUsage { path: String, reason: Cow<'static, str>, }, UnsupportedSerdeCustomCodec { path: String, attribute: Cow<'static, str>, }, InvalidPhasedTypeUsage { path: String, reason: Cow<'static, str>, }, InvalidRenameRule { attribute: Cow<'static, str>, value: String, }, } impl Error { pub(crate) fn invalid_usage_of_skip( path: impl Into, reason: impl Into>, ) -> Self { Self { kind: ErrorKind::InvalidUsageOfSkip { path: path.into(), reason: reason.into(), }, } } pub(crate) fn invalid_internally_tagged_enum( path: impl Into, variant: impl Into, reason: impl Into>, ) -> Self { Self { kind: ErrorKind::InvalidInternallyTaggedEnum { path: path.into(), variant: variant.into(), reason: reason.into(), }, } } pub(crate) fn invalid_enum_representation(reason: impl Into>) -> Self { Self { kind: ErrorKind::InvalidEnumRepresentation { reason: reason.into(), }, } } pub(crate) fn invalid_external_tagged_variant(variant: impl Into) -> Self { Self { kind: ErrorKind::InvalidExternalTaggedVariant { variant: variant.into(), }, } } pub(crate) fn invalid_adjacent_tagged_variant(variant: impl Into) -> Self { Self { kind: ErrorKind::InvalidAdjacentTaggedVariant { variant: variant.into(), }, } } pub(crate) fn invalid_internally_tagged_variant( variant: impl Into, reason: impl Into>, ) -> Self { Self { kind: ErrorKind::InvalidInternallyTaggedVariant { variant: variant.into(), reason: reason.into(), }, } } pub(crate) fn incompatible_rename( context: impl Into>, name: impl Into, serialize: Option, deserialize: Option, ) -> Self { Self { kind: ErrorKind::IncompatibleRename { context: context.into(), name: name.into(), serialize, deserialize, }, } } pub(crate) fn incompatible_conversion( context: impl Into>, name: impl Into, serialize: Option, deserialize: Option, ) -> Self { Self { kind: ErrorKind::IncompatibleConversion { context: context.into(), name: name.into(), serialize, deserialize, }, } } pub(crate) fn invalid_conversion_usage( path: impl Into, reason: impl Into>, ) -> Self { Self { kind: ErrorKind::InvalidConversionUsage { path: path.into(), reason: reason.into(), }, } } pub(crate) fn unsupported_serde_custom_codec( path: impl Into, attribute: impl Into>, ) -> Self { Self { kind: ErrorKind::UnsupportedSerdeCustomCodec { path: path.into(), attribute: attribute.into(), }, } } pub(crate) fn invalid_phased_type_usage( path: impl Into, reason: impl Into>, ) -> Self { Self { kind: ErrorKind::InvalidPhasedTypeUsage { path: path.into(), reason: reason.into(), }, } } pub(crate) fn invalid_rename_rule( attribute: impl Into>, value: impl Into, ) -> Self { Self { kind: ErrorKind::InvalidRenameRule { attribute: attribute.into(), value: value.into(), }, } } } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.kind { ErrorKind::InvalidUsageOfSkip { path, reason } => { write!(f, "Invalid usage of #[serde(skip)] at '{path}': {reason}") } ErrorKind::InvalidInternallyTaggedEnum { path, variant, reason, } => write!( f, "Invalid internally tagged enum at '{path}', variant '{variant}': {reason}" ), ErrorKind::InvalidEnumRepresentation { reason } => { write!(f, "Invalid serde enum representation: {reason}") } ErrorKind::InvalidExternalTaggedVariant { variant } => write!( f, "Invalid externally tagged enum variant '{variant}': variant payload is fully skipped" ), ErrorKind::InvalidAdjacentTaggedVariant { variant } => write!( f, "Invalid adjacently tagged enum variant '{variant}': variant payload is fully skipped" ), ErrorKind::InvalidInternallyTaggedVariant { variant, reason } => write!( f, "Invalid internally tagged enum variant '{variant}': {reason}" ), ErrorKind::IncompatibleRename { context, name, serialize, deserialize, } => write!( f, "Incompatible {context} for '{name}' in unified mode: serialize={serialize:?}, deserialize={deserialize:?}" ), ErrorKind::IncompatibleConversion { context, name, serialize, deserialize, } => write!( f, "Incompatible {context} for '{name}' in unified mode: serialize={serialize:?}, deserialize={deserialize:?}. Use PhasesFormat for asymmetric serde conversions" ), ErrorKind::InvalidConversionUsage { path, reason } => { write!( f, "Invalid usage of serde conversion attributes at '{path}': {reason}" ) } ErrorKind::UnsupportedSerdeCustomCodec { path, attribute } => write!( f, "Unsupported serde attribute at '{path}': #[serde({attribute})] changes the wire type. Add #[specta(type = ...)] (or #[specta(type = specta_serde::Phased)])" ), ErrorKind::InvalidPhasedTypeUsage { path, reason } => { write!(f, "Invalid phased type usage at '{path}': {reason}") } ErrorKind::InvalidRenameRule { attribute, value } => { write!(f, "Invalid serde rename rule for '{attribute}': {value:?}") } } } } impl fmt::Debug for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(self, f) } } impl error::Error for Error {} ================================================ FILE: specta-serde/src/inflection.rs ================================================ //! This file has been directed copied from Serde (). //! All code is licensed under the MIT & Apache license by it's original authors. //! //! We use this to ensure we maintain the exact same result as Serde in regards to renames. use self::RenameRule::*; use std::fmt::{self, Debug, Display}; /// The different possible ways to change case of fields in a struct, or variants in an enum. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub enum RenameRule { /// Don't apply a default rename rule. #[allow(dead_code)] None, /// Rename direct children to "lowercase" style. LowerCase, /// Rename direct children to "UPPERCASE" style. UpperCase, /// Rename direct children to "PascalCase" style, as typically used for /// enum variants. PascalCase, /// Rename direct children to "camelCase" style. CamelCase, /// Rename direct children to "snake_case" style, as commonly used for /// fields. SnakeCase, /// Rename direct children to "SCREAMING_SNAKE_CASE" style, as commonly /// used for constants. ScreamingSnakeCase, /// Rename direct children to "kebab-case" style. KebabCase, /// Rename direct children to "SCREAMING-KEBAB-CASE" style. ScreamingKebabCase, } static RENAME_RULES: &[(&str, RenameRule)] = &[ ("lowercase", LowerCase), ("UPPERCASE", UpperCase), ("PascalCase", PascalCase), ("camelCase", CamelCase), ("snake_case", SnakeCase), ("SCREAMING_SNAKE_CASE", ScreamingSnakeCase), ("kebab-case", KebabCase), ("SCREAMING-KEBAB-CASE", ScreamingKebabCase), ]; impl RenameRule { /// Parse serde's `rename_all` / `rename_all_fields` rule string. #[allow(clippy::should_implement_trait)] pub fn from_str(rename_all_str: &str) -> Result> { for (name, rule) in RENAME_RULES { if rename_all_str == *name { return Ok(*rule); } } Err(ParseError { unknown: rename_all_str, }) } /// Apply a renaming rule to an enum variant, returning the version expected in the source. pub fn apply_to_variant(self, variant: &str) -> String { match self { None | PascalCase => variant.to_owned(), LowerCase => variant.to_ascii_lowercase(), UpperCase => variant.to_ascii_uppercase(), CamelCase => variant[..1].to_ascii_lowercase() + &variant[1..], SnakeCase => { let mut snake = String::new(); for (i, ch) in variant.char_indices() { if i > 0 && ch.is_uppercase() { snake.push('_'); } snake.push(ch.to_ascii_lowercase()); } snake } ScreamingSnakeCase => SnakeCase.apply_to_variant(variant).to_ascii_uppercase(), KebabCase => SnakeCase.apply_to_variant(variant).replace('_', "-"), ScreamingKebabCase => ScreamingSnakeCase .apply_to_variant(variant) .replace('_', "-"), } } /// Apply a renaming rule to a struct field, returning the version expected in the source. pub fn apply_to_field(self, field: &str) -> String { match self { None | LowerCase | SnakeCase => field.to_owned(), UpperCase => field.to_ascii_uppercase(), PascalCase => { let mut pascal = String::new(); let mut capitalize = true; for ch in field.chars() { if ch == '_' { capitalize = true; } else if capitalize { pascal.push(ch.to_ascii_uppercase()); capitalize = false; } else { pascal.push(ch); } } pascal } CamelCase => { let pascal = PascalCase.apply_to_field(field); pascal[..1].to_ascii_lowercase() + &pascal[1..] } ScreamingSnakeCase => field.to_ascii_uppercase(), KebabCase => field.replace('_', "-"), ScreamingKebabCase => ScreamingSnakeCase.apply_to_field(field).replace('_', "-"), } } /// Returns the `RenameRule` if it is not `None`, `rule_b` otherwise. #[allow(dead_code)] pub fn or(self, rule_b: Self) -> Self { match self { None => rule_b, _ => self, } } } pub struct ParseError<'a> { unknown: &'a str, } impl Display for ParseError<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("unknown rename rule `rename_all = ")?; Debug::fmt(self.unknown, f)?; f.write_str("`, expected one of ")?; for (i, (name, _rule)) in RENAME_RULES.iter().enumerate() { if i > 0 { f.write_str(", ")?; } Debug::fmt(name, f)?; } Ok(()) } } ================================================ FILE: specta-serde/src/lib.rs ================================================ //! [Serde](https://serde.rs) support for Specta. //! //! # Choosing a mode //! //! - Use [`Format`] when serde behavior is symmetric and a single exported shape //! should work for both serialization and deserialization. //! - Use [`PhasesFormat`] when serde behavior differs by direction (for example //! deserialize-widening enums, asymmetric conversion attributes, or explicit //! [`Phased`] overrides). //! //! # `serde_with` and `#[serde(with = ...)]` //! //! `serde_with` is supported through the same mechanism as raw serde codec //! attributes because it expands to serde metadata (`with`, `serialize_with`, //! `deserialize_with`). //! //! When codecs change the wire type, add an explicit Specta override: //! //! ```rust,ignore //! use serde::{Deserialize, Serialize}; //! use specta::Type; //! //! #[derive(Type, Serialize, Deserialize)] //! struct Digest { //! #[serde(with = "hex_bytes")] //! #[specta(type = String)] //! value: Vec, //! } //! ``` //! //! If serialize and deserialize shapes are different, use [`Phased`] and //! [`PhasesFormat`]. //! //! This is required because a single unified type graph cannot represent two //! different directional wire shapes at once. //! //! ```rust,ignore //! use serde::{Deserialize, Serialize}; //! use serde_with::{OneOrMany, serde_as}; //! use specta::{Type, Types}; //! //! #[derive(Type, Serialize, Deserialize)] //! #[serde(untagged)] //! enum OneOrManyString { //! One(String), //! Many(Vec), //! } //! //! #[serde_as] //! #[derive(Type, Serialize, Deserialize)] //! struct Filters { //! #[serde_as(as = "OneOrMany<_>")] //! #[specta(type = specta_serde::Phased, OneOrManyString>)] //! tags: Vec, //! } //! //! let types = Types::default().register::(); //! let phased_types = specta_typescript::Typescript::default() //! .export(&types, specta_serde::PhasesFormat)?; //! ``` //! //! As an alternative to codec attributes, `#[serde(into = ...)]`, //! `#[serde(from = ...)]`, and `#[serde(try_from = ...)]` often produce better //! type inference because the wire type is modeled as an explicit Rust type: //! //! ```rust,ignore //! use serde::{Deserialize, Serialize}; //! use specta::Type; //! //! #[derive(Type, Serialize, Deserialize)] //! struct UserWire { //! id: String, //! } //! //! #[derive(Type, Clone, Serialize, Deserialize)] //! #[serde(into = "UserWire")] //! struct UserInto { //! id: String, //! } //! //! #[derive(Type, Clone, Serialize, Deserialize)] //! #[serde(from = "UserWire")] //! struct UserFrom { //! id: String, //! } //! //! #[derive(Type, Clone, Serialize, Deserialize)] //! #[serde(try_from = "UserWire")] //! struct UserTryFrom { //! id: String, //! } //! ``` //! //! See `examples/basic-ts/src/main.rs` for a complete exporter example using //! [`Format`] and [`PhasesFormat`]. #![cfg_attr(docsrs, feature(doc_cfg))] #![doc( html_logo_url = "https://github.com/specta-rs/specta/raw/main/.github/logo-128.png", html_favicon_url = "https://github.com/specta-rs/specta/raw/main/.github/logo-128.png" )] use std::{ borrow::Cow, collections::{HashMap, HashSet, VecDeque}, }; use specta::{ FormatError, Types, datatype::{ DataType, Enum, Field, Fields, NamedDataType, NamedReference, NamedReferenceType, Primitive, Reference, Struct, Tuple, UnnamedFields, Variant, }, }; mod error; mod inflection; mod parser; mod phased; mod repr; mod validate; use inflection::RenameRule; use parser::{SerdeContainerAttrs, SerdeFieldAttrs, SerdeVariantAttrs}; use phased::PhasedTy; use repr::EnumRepr; pub use error::Error; pub use phased::{Phased, phased}; /// Selects which directional type shape to use with [`PhasesFormat`]. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Phase { /// The shape used when Rust serializes data to the wire. Serialize, /// The shape used when Rust deserializes data from the wire. Deserialize, } /// Applies serde-aware rewrites to a single shared type graph. /// /// Use this when the serialized and deserialized wire shape can be represented /// by the same exported schema. Exporters should pass this formatter to Specta's /// formatting hook, for example /// `specta_typescript::Typescript::default().export(&types, specta_serde::Format)`. /// /// This formatter validates the graph for unified export and applies serde /// container, variant, and field behavior that affects the exported shape, such /// as renames, tagging, defaults, flattening, and compatible conversion attrs. /// /// If serde metadata produces different serialize and deserialize shapes, this /// formatter returns an error instead of guessing. In that case, use /// [`PhasesFormat`]. pub struct Format; impl specta::Format for Format { fn map_types(&'_ self, types: &Types) -> Result, FormatError> { validate::validate_for_mode(types, validate::ApplyMode::Unified)?; let mut out = types.clone(); let generated = HashMap::::new(); let split_types = HashSet::::new(); let mut rewrite_err = None; out.iter_mut(|ndt| { if rewrite_err.is_some() { return; } let ndt_name = ndt.name.to_string(); if let Some(ty) = ndt.ty.as_mut() { if rewrite_err.is_some() { return; } if let Err(err) = rewrite_datatype_for_phase( ty, PhaseRewrite::Unified, types, &generated, &split_types, Some(ndt_name.as_str()), ) { rewrite_err = Some(err); } } if rewrite_err.is_some() { return; } if let Err(err) = rewrite_named_type_for_phase(ndt, PhaseRewrite::Unified) { rewrite_err = Some(err); } }); if let Some(err) = rewrite_err { return Err(Box::new(err)); } Ok(Cow::Owned(out)) } fn map_type(&'_ self, types: &Types, dt: &DataType) -> Result, FormatError> { if datatype_is_registered_definition(types, dt) { return Ok(Cow::Owned(dt.clone())); } validate::validate_datatype_for_mode(dt, types, validate::ApplyMode::Unified)?; let mut dt = dt.clone(); rewrite_datatype_for_phase( &mut dt, PhaseRewrite::Unified, types, &HashMap::new(), &HashSet::new(), None, )?; Ok(Cow::Owned(dt)) } } /// Applies serde-aware rewrites while preserving separate serialize and /// deserialize shapes. /// /// Use this when serde metadata makes the wire format directional, such as /// asymmetric renames, directional skips, `#[serde(with = ...)]`-style codecs, /// `#[serde(into = ...)]`/`#[serde(from = ...)]`, or explicit [`Phased`] /// overrides. /// /// Exporters should pass this formatter to Specta's formatting hook, for /// example /// `specta_typescript::Typescript::default().export(&types, specta_serde::PhasesFormat)`. /// /// The transformed type graph includes `*_Serialize` and `*_Deserialize` named /// types for definitions that need to diverge, while unchanged definitions stay /// shared. Inline datatype rendering uses the serialize-facing shape; use /// [`select_phase_datatype`] to inspect either direction explicitly. pub struct PhasesFormat; impl specta::Format for PhasesFormat { fn map_types(&'_ self, types: &Types) -> Result, FormatError> { validate::validate_for_mode(types, validate::ApplyMode::Phases)?; let originals = types.into_unsorted_iter().collect::>(); let mut dependencies = HashMap::>::new(); let mut reverse_dependencies = HashMap::>::new(); for original in &originals { let key = TypeIdentity::from_ndt(original); let mut deps = HashSet::new(); if let Some(ty) = &original.ty { collect_dependencies(ty, types, &mut deps)?; } for dep in &deps { reverse_dependencies .entry(dep.clone()) .or_default() .insert(key.clone()); } dependencies.insert(key, deps); } let mut split_types = HashSet::new(); for ndt in &originals { if ndt .ty .as_ref() .is_some_and(|ty| has_local_phase_difference(ty).unwrap_or(false)) { split_types.insert(TypeIdentity::from_ndt(ndt)); } } let mut queue = VecDeque::from_iter(split_types.iter().cloned()); while let Some(key) = queue.pop_front() { if let Some(dependents) = reverse_dependencies.get(&key) { for dependent in dependents { if split_types.insert(dependent.clone()) { queue.push_back(dependent.clone()); } } } } let mut out = types.clone(); let mut generated = HashMap::::new(); let mut generated_types = HashSet::::new(); for original in &originals { let key = TypeIdentity::from_ndt(original); if split_types.contains(&key) { let serialize_ndt = build_from_original(original, PhaseRewrite::Serialize)?; let deserialize_ndt = build_from_original(original, PhaseRewrite::Deserialize)?; generated.insert( key, SplitGeneratedTypes { serialize: serialize_ndt, deserialize: Box::new(deserialize_ndt), }, ); } } for original in &originals { let key = TypeIdentity::from_ndt(original); if !split_types.contains(&key) { continue; } let Some(mut generated_types_for_phase) = generated.get(&key).cloned() else { continue; }; let mut rewrite_err = None; if let Some(ty) = generated_types_for_phase.serialize.ty.as_mut() && let Err(err) = rewrite_datatype_for_phase( ty, PhaseRewrite::Serialize, types, &generated, &split_types, Some(original.name.as_ref()), ) { rewrite_err = Some(err); } if let Some(err) = rewrite_err.take() { return Err(Box::new(err)); } rewrite_named_type_for_phase( &mut generated_types_for_phase.serialize, PhaseRewrite::Serialize, )?; if let Some(ty) = generated_types_for_phase.deserialize.ty.as_mut() && let Err(err) = rewrite_datatype_for_phase( ty, PhaseRewrite::Deserialize, types, &generated, &split_types, Some(original.name.as_ref()), ) { rewrite_err = Some(err); } if let Some(err) = rewrite_err { return Err(Box::new(err)); } rewrite_named_type_for_phase( &mut generated_types_for_phase.deserialize, PhaseRewrite::Deserialize, )?; generated.insert(key, generated_types_for_phase); } for generated_types_for_phase in generated.values_mut() { let serialize = register_generated_type(&mut out, generated_types_for_phase.serialize.clone()); let deserialize = Box::new(register_generated_type( &mut out, (*generated_types_for_phase.deserialize).clone(), )); generated_types.insert(TypeIdentity::from_ndt(&serialize)); generated_types.insert(TypeIdentity::from_ndt(&deserialize)); generated_types_for_phase.serialize = serialize; generated_types_for_phase.deserialize = deserialize; } let registered_generated = generated.clone(); for generated_types_for_phase in generated.values_mut() { if let Some(ty) = generated_types_for_phase.serialize.ty.as_mut() { rewrite_datatype_for_phase( ty, PhaseRewrite::Serialize, types, ®istered_generated, &split_types, Some(generated_types_for_phase.serialize.name.as_ref()), )?; } if let Some(ty) = generated_types_for_phase.deserialize.ty.as_mut() { rewrite_datatype_for_phase( ty, PhaseRewrite::Deserialize, types, ®istered_generated, &split_types, Some(generated_types_for_phase.deserialize.name.as_ref()), )?; } } out.iter_mut(|ndt| { for generated_types_for_phase in generated.values() { if ndt.name == generated_types_for_phase.serialize.name { ndt.ty = generated_types_for_phase.serialize.ty.clone(); return; } if ndt.name == generated_types_for_phase.deserialize.name { ndt.ty = generated_types_for_phase.deserialize.ty.clone(); return; } } }); let mut rewrite_err = None; out.iter_mut(|ndt| { if rewrite_err.is_some() { return; } let ndt_name = ndt.name.to_string(); let key = TypeIdentity::from_ndt(ndt); if split_types.contains(&key) || generated_types.contains(&key) { return; } if let Some(ty) = ndt.ty.as_mut() && let Err(err) = rewrite_datatype_for_phase( ty, PhaseRewrite::Unified, types, &generated, &split_types, Some(ndt_name.as_str()), ) { rewrite_err = Some(err); return; } if let Err(err) = rewrite_named_type_for_phase(ndt, PhaseRewrite::Unified) { rewrite_err = Some(err); } }); if let Some(err) = rewrite_err { return Err(Box::new(err)); } out.iter_mut(|ndt| { let key = TypeIdentity::from_ndt(ndt); if !split_types.contains(&key) { return; } let Some(SplitGeneratedTypes { serialize, deserialize, }) = generated.get(&key) else { return; }; let generic_args = ndt .generics .iter() .map(|generic| { let generic = specta::datatype::Generic::new(generic.name.clone()); (generic.clone(), generic.into()) }) .collect::>(); let mut serialize_variant = Variant::unnamed().build(); if let Fields::Unnamed(fields) = &mut serialize_variant.fields { fields .fields .push(Field::new(serialize.reference(generic_args.clone()).into())); } let mut deserialize_variant = Variant::unnamed().build(); if let Fields::Unnamed(fields) = &mut deserialize_variant.fields { fields .fields .push(Field::new(deserialize.reference(generic_args).into())); } let mut wrapper = Enum::default(); wrapper .variants .push((Cow::Borrowed("Serialize"), serialize_variant)); wrapper .variants .push((Cow::Borrowed("Deserialize"), deserialize_variant)); ndt.ty = Some(DataType::Enum(wrapper)); }); Ok(Cow::Owned(out)) } fn map_type(&'_ self, types: &Types, dt: &DataType) -> Result, FormatError> { if datatype_is_registered_definition(types, dt) { return Ok(Cow::Owned(dt.clone())); } let mut selected = select_phase_datatype(dt, types, Phase::Serialize); validate::validate_datatype_for_mode_shallow( &selected, types, validate::ApplyMode::Phases, )?; rewrite_datatype_for_phase( &mut selected, PhaseRewrite::Serialize, types, &HashMap::new(), &HashSet::new(), None, )?; Ok(Cow::Owned(selected)) } } fn datatype_is_registered_definition(types: &Types, dt: &DataType) -> bool { types .into_unsorted_iter() .any(|ndt| ndt.ty.as_ref() == Some(dt)) } /// Rewrites a [`DataType`] to the requested directional shape for [`PhasesFormat`]. /// /// This is useful for exporter integrations that need deserialize-specific input /// types and serialize-specific output types while still exporting against the /// resolved type graph produced by the `map_types` callback from /// [`PhasesFormat`]. /// /// # Examples /// /// ```rust /// use serde::{Deserialize, Serialize}; /// use specta::{Format as _, Type, Types, datatype::{DataType, Reference}}; /// use specta_serde::{Phase, Phased, PhasesFormat, select_phase_datatype}; /// /// #[derive(Type, Serialize, Deserialize)] /// #[serde(untagged)] /// enum OneOrManyString { /// One(String), /// Many(Vec), /// } /// /// #[derive(Type, Serialize, Deserialize)] /// struct Filters { /// #[specta(type = Phased, OneOrManyString>)] /// tags: Vec, /// } /// /// let mut types = Types::default(); /// let dt = Filters::definition(&mut types); /// let format = PhasesFormat; /// let resolved = format.map_types(&types) /// .expect("PhasesFormat should succeed") /// .into_owned(); /// /// let serialize = select_phase_datatype(&dt, &resolved, Phase::Serialize); /// let deserialize = select_phase_datatype(&dt, &resolved, Phase::Deserialize); /// /// let DataType::Reference(Reference::Named(serialize_reference)) = &serialize else { /// panic!("expected named serialize reference"); /// }; /// let DataType::Reference(Reference::Named(deserialize_reference)) = &deserialize else { /// panic!("expected named deserialize reference"); /// }; /// /// assert_eq!( /// resolved.get(serialize_reference).unwrap().name, /// "Filters_Serialize" /// ); /// assert_eq!( /// resolved.get(deserialize_reference).unwrap().name, /// "Filters_Deserialize" /// ); /// # Ok::<(), specta_serde::Error>(()) /// ``` pub fn select_phase_datatype(dt: &DataType, types: &Types, phase: Phase) -> DataType { let mut dt = dt.clone(); select_phase_datatype_inner(&mut dt, types, phase); dt } #[derive(Debug, Clone, Copy, PartialEq, Eq)] enum PhaseRewrite { Unified, Serialize, Deserialize, } fn select_phase_datatype_inner(ty: &mut DataType, types: &Types, phase: Phase) { if let Some(resolved) = select_split_wrapper_variant(ty, phase) { *ty = resolved; select_phase_datatype_inner(ty, types, phase); return; } if let Some(resolved) = select_explicit_phased_type(ty, phase) { *ty = resolved; select_phase_datatype_inner(ty, types, phase); return; } match ty { DataType::Struct(s) => select_phase_fields(&mut s.fields, types, phase), DataType::Enum(e) => { for (_, variant) in &mut e.variants { select_phase_fields(&mut variant.fields, types, phase); } } DataType::Tuple(tuple) => { for ty in &mut tuple.elements { select_phase_datatype_inner(ty, types, phase); } } DataType::List(list) => select_phase_datatype_inner(&mut list.ty, types, phase), DataType::Map(map) => { select_phase_datatype_inner(map.key_ty_mut(), types, phase); select_phase_datatype_inner(map.value_ty_mut(), types, phase); } DataType::Intersection(types_) => { for ty in types_ { select_phase_datatype_inner(ty, types, phase); } } DataType::Nullable(inner) => select_phase_datatype_inner(inner, types, phase), DataType::Reference(Reference::Named(reference)) => { if let NamedReferenceType::Inline { dt, .. } = &mut reference.inner { select_phase_datatype_inner(dt, types, phase); return; } let Some(referenced_ndt) = types.get(reference) else { return; }; for (_, dt) in named_reference_generics_mut(reference) { select_phase_datatype_inner(dt, types, phase); } if let Some(mut selected) = referenced_ndt .ty .as_ref() .and_then(|ty| select_split_wrapper_variant(ty, phase)) { select_phase_datatype_inner(&mut selected, types, phase); *ty = selected; return; } let target_ndt = select_split_type_variant(referenced_ndt, types, phase).unwrap_or(referenced_ndt); let Reference::Named(new_reference) = target_ndt.reference(named_reference_generics(reference).to_vec()) else { unreachable!("named types always produce named references") }; *reference = new_reference; } DataType::Reference(Reference::Opaque(_)) | DataType::Generic(_) | DataType::Primitive(_) => {} } } fn select_phase_fields(fields: &mut Fields, types: &Types, phase: Phase) { match fields { Fields::Unit => {} Fields::Unnamed(fields) => { for field in &mut fields.fields { if let Some(ty) = field.ty.as_mut() { select_phase_datatype_inner(ty, types, phase); } } } Fields::Named(fields) => { for (_, field) in &mut fields.fields { if let Some(ty) = field.ty.as_mut() { select_phase_datatype_inner(ty, types, phase); } } } } } fn select_explicit_phased_type(ty: &DataType, phase: Phase) -> Option { let DataType::Reference(Reference::Opaque(reference)) = ty else { return None; }; let phased = reference.downcast_ref::()?; Some(match phase { Phase::Serialize => phased.serialize.clone(), Phase::Deserialize => phased.deserialize.clone(), }) } fn select_split_wrapper_variant(ty: &DataType, phase: Phase) -> Option { let DataType::Enum(wrapper) = ty else { return None; }; if wrapper.variants.len() != 2 { return None; } let variant_name = match phase { Phase::Serialize => "Serialize", Phase::Deserialize => "Deserialize", }; let (_, variant) = wrapper .variants .iter() .find(|(name, _)| name == variant_name)?; let Fields::Unnamed(fields) = &variant.fields else { return None; }; let [field] = &fields.fields[..] else { return None; }; field.ty.clone() } fn select_split_type_variant<'a>( ndt: &'a NamedDataType, types: &'a Types, phase: Phase, ) -> Option<&'a NamedDataType> { let Some(DataType::Enum(wrapper)) = &ndt.ty else { return None; }; if wrapper.variants.len() != 2 { return None; } let variant_name = match phase { Phase::Serialize => "Serialize", Phase::Deserialize => "Deserialize", }; let (_, variant) = wrapper .variants .iter() .find(|(name, _)| name == variant_name)?; let Fields::Unnamed(fields) = &variant.fields else { return None; }; let [field] = &fields.fields[..] else { return None; }; let Some(DataType::Reference(Reference::Named(reference))) = field.ty.as_ref() else { return None; }; types.get(reference) } fn named_reference_generics( reference: &NamedReference, ) -> &[(specta::datatype::Generic, DataType)] { match &reference.inner { NamedReferenceType::Reference { generics, .. } => generics, NamedReferenceType::Inline { .. } | NamedReferenceType::Recursive => &[], } } fn named_reference_generics_mut( reference: &mut NamedReference, ) -> &mut [(specta::datatype::Generic, DataType)] { match &mut reference.inner { NamedReferenceType::Reference { generics, .. } => generics, NamedReferenceType::Inline { .. } | NamedReferenceType::Recursive => &mut [], } } #[derive(Debug, Clone)] struct SplitGeneratedTypes { serialize: NamedDataType, deserialize: Box, } #[derive(Debug, Clone, PartialEq, Eq, Hash)] struct TypeIdentity { name: String, module_path: String, file: &'static str, line: u32, column: u32, } impl TypeIdentity { fn from_ndt(ty: &specta::datatype::NamedDataType) -> Self { let location = ty.location; Self { name: ty.name.to_string(), module_path: ty.module_path.to_string(), file: location.file(), line: location.line(), column: location.column(), } } } fn rewrite_datatype_for_phase( ty: &mut DataType, mode: PhaseRewrite, original_types: &Types, generated: &HashMap, split_types: &HashSet, container_name: Option<&str>, ) -> Result<(), Error> { if let Some(resolved) = resolve_phased_type(ty, mode, "type")? { *ty = resolved; } if let Some(converted) = conversion_datatype_for_mode(ty, mode)? && converted != *ty { *ty = converted; return rewrite_datatype_for_phase( ty, mode, original_types, generated, split_types, container_name, ); } match ty { DataType::Struct(s) => { let container_default = SerdeContainerAttrs::from_attributes(&s.attributes)? .is_some_and(|attrs| attrs.default); let container_rename_all = container_rename_all_rule( &s.attributes, mode, "struct rename_all", container_name.unwrap_or(""), )?; rewrite_fields_for_phase( &mut s.fields, mode, original_types, generated, split_types, container_rename_all, container_default, false, )?; rewrite_struct_repr_for_phase(s, mode, container_name)?; if let Some(intersection) = lower_flattened_struct(s)? { *ty = intersection; } } DataType::Enum(e) => { filter_enum_variants_for_phase(e, mode)?; let container_attrs = SerdeContainerAttrs::from_attributes(&e.attributes)?; for (variant_name, variant) in &mut e.variants { let rename_rule = enum_variant_field_rename_rule(&container_attrs, variant, mode, variant_name)?; rewrite_fields_for_phase( &mut variant.fields, mode, original_types, generated, split_types, rename_rule, false, true, )?; } if rewrite_identifier_enum_for_phase(e, mode, original_types, generated, split_types)? { return Ok(()); } rewrite_enum_repr_for_phase(e, mode, original_types)?; } DataType::Tuple(tuple) => { for ty in &mut tuple.elements { rewrite_datatype_for_phase(ty, mode, original_types, generated, split_types, None)?; } } DataType::List(list) => rewrite_datatype_for_phase( &mut list.ty, mode, original_types, generated, split_types, None, )?, DataType::Map(map) => { rewrite_datatype_for_phase( map.key_ty_mut(), mode, original_types, generated, split_types, None, )?; rewrite_datatype_for_phase( map.value_ty_mut(), mode, original_types, generated, split_types, None, )?; } DataType::Intersection(types_) => { for ty in types_ { rewrite_datatype_for_phase(ty, mode, original_types, generated, split_types, None)?; } } DataType::Nullable(inner) => { rewrite_datatype_for_phase(inner, mode, original_types, generated, split_types, None)? } DataType::Reference(Reference::Named(reference)) => { if let NamedReferenceType::Inline { dt, .. } = &mut reference.inner { rewrite_datatype_for_phase(dt, mode, original_types, generated, split_types, None)?; } let Some(referenced_ndt) = original_types.get(reference) else { return Ok(()); }; let key = TypeIdentity::from_ndt(referenced_ndt); for (_, dt) in named_reference_generics_mut(reference) { rewrite_datatype_for_phase(dt, mode, original_types, generated, split_types, None)?; } if !split_types.contains(&key) { return Ok(()); } let Some(target) = generated.get(&key) else { return Ok(()); }; let Reference::Named(reference_from_target) = (match mode { PhaseRewrite::Unified => { unreachable!("unified mode should not reference split types") } PhaseRewrite::Serialize => target .serialize .reference(named_reference_generics(reference).to_vec()), PhaseRewrite::Deserialize => target .deserialize .reference(named_reference_generics(reference).to_vec()), }) else { unreachable!("named types always produce named references") }; *reference = reference_from_target; } DataType::Reference(Reference::Opaque(_)) | DataType::Generic(_) | DataType::Primitive(_) => {} } Ok(()) } fn lower_flattened_struct(strct: &mut Struct) -> Result, Error> { let Fields::Named(named) = &mut strct.fields else { return Ok(None); }; let has_flattened = named .fields .iter() .any(|(_, field)| field_is_flattened(field)); if !has_flattened { return Ok(None); } let fields = std::mem::take(&mut named.fields); let mut base = Struct::named(); let mut parts = Vec::new(); for (name, field) in fields { if field_is_flattened(&field) { if let Some(ty) = field.ty { parts.push(ty); } } else { base.field_mut(name, field); } } let mut base = match base.build() { DataType::Struct(base) => base, _ => unreachable!("Struct::named always builds a struct"), }; if matches!(&base.fields, Fields::Named(named) if !named.fields.is_empty()) { base.attributes = strct.attributes.clone(); parts.insert(0, DataType::Struct(base)); } Ok(Some(DataType::Intersection(parts))) } fn field_is_flattened(field: &Field) -> bool { SerdeFieldAttrs::from_attributes(&field.attributes) .ok() .flatten() .is_some_and(|attrs| attrs.flatten) } fn rewrite_fields_for_phase( fields: &mut Fields, mode: PhaseRewrite, original_types: &Types, generated: &HashMap, split_types: &HashSet, rename_all_rule: Option, container_default: bool, preserve_skipped_unnamed_fields: bool, ) -> Result<(), Error> { match fields { Fields::Unit => {} Fields::Unnamed(unnamed) => { for field in &mut unnamed.fields { if should_skip_field_for_mode(field, mode)? { if preserve_skipped_unnamed_fields { *field = skipped_field_marker(field); } continue; } apply_field_attrs(field, mode, container_default)?; rewrite_field_for_phase(field, mode, original_types, generated, split_types)?; } if !preserve_skipped_unnamed_fields { unnamed.fields.retain(|field| field.ty.as_ref().is_some()); } } Fields::Named(named) => { let mut skip_err = None; named .fields .retain(|(_, field)| match should_skip_field_for_mode(field, mode) { Ok(skip) => !skip, Err(err) => { skip_err = Some(err); true } }); if let Some(err) = skip_err { return Err(err); } for (name, field) in &mut named.fields { apply_field_attrs(field, mode, container_default)?; if let Some(serde_attrs) = SerdeFieldAttrs::from_attributes(&field.attributes)? { let rename = select_phase_string( mode, serde_attrs.rename_serialize.as_deref(), serde_attrs.rename_deserialize.as_deref(), "field rename", name.as_ref(), )?; if let Some(rename) = rename { *name = Cow::Owned(rename.to_string()); } else if let Some(rule) = rename_all_rule { *name = Cow::Owned(rule.apply_to_field(name.as_ref())); } } else if let Some(rule) = rename_all_rule { *name = Cow::Owned(rule.apply_to_field(name.as_ref())); } rewrite_field_for_phase(field, mode, original_types, generated, split_types)?; } } } Ok(()) } fn rewrite_field_for_phase( field: &mut Field, mode: PhaseRewrite, original_types: &Types, generated: &HashMap, split_types: &HashSet, ) -> Result<(), Error> { if let Some(attrs) = SerdeFieldAttrs::from_attributes(&field.attributes)? && attrs.skip_serializing_if.is_some() { if let PhaseRewrite::Serialize = mode { field.optional = true; } // The attribute is meaningless on phase-split fields: the _Serialize // variant already has `optional = true`, and the _Deserialize variant // treats the field as present-or-default. Leaving it attached makes // `validate_datatype_for_mode(_, _, ApplyMode::Unified)` reject the // already-split variant — a footgun for downstream callers (e.g. // tauri-specta's `validate_exported_command`) that run unified // validation on the post-`apply_phases` graph. field.attributes.remove(parser::FIELD_SKIP_SERIALIZING_IF); } if let Some(ty) = field.ty.clone() && let Some(resolved) = resolve_phased_type(&ty, mode, "field")? { field.ty = Some(resolved); } if let Some(ty) = field.ty.as_mut() { rewrite_datatype_for_phase(ty, mode, original_types, generated, split_types, None)?; } Ok(()) } fn rewrite_struct_repr_for_phase( strct: &mut Struct, mode: PhaseRewrite, container_name: Option<&str>, ) -> Result<(), Error> { let Some((tag, rename_serialize, rename_deserialize)) = SerdeContainerAttrs::from_attributes(&strct.attributes)?.map(|attrs| { ( attrs.tag.clone(), attrs.rename_serialize.clone(), attrs.rename_deserialize.clone(), ) }) else { return Ok(()); }; let Some(tag) = tag.as_deref() else { return Ok(()); }; let Fields::Named(named) = &mut strct.fields else { return Ok(()); }; if named.fields.iter().any(|(name, field)| { name.as_ref() == tag && field .ty .as_ref() .is_some_and(is_generated_string_literal_datatype) }) { return Ok(()); } let serialized_name = match select_phase_string( mode, rename_serialize.as_deref(), rename_deserialize.as_deref(), "struct rename", container_name.unwrap_or(""), )? { Some(rename) => rename.to_string(), None => container_name .map(str::to_owned) .ok_or_else(|| { Error::invalid_phased_type_usage( "", "`#[serde(tag = ...)]` on structs requires either a named type or `#[serde(rename = ...)]`", ) })?, }; named.fields.insert( 0, ( Cow::Owned(tag.to_string()), Field::new(string_literal_datatype(serialized_name)), ), ); Ok(()) } fn should_skip_field_for_mode(field: &Field, mode: PhaseRewrite) -> Result { let Some(attrs) = SerdeFieldAttrs::from_attributes(&field.attributes)? else { return Ok(false); }; Ok(match mode { PhaseRewrite::Serialize => attrs.skip_serializing, PhaseRewrite::Deserialize => attrs.skip_deserializing, PhaseRewrite::Unified => attrs.skip_serializing || attrs.skip_deserializing, }) } fn skipped_field_marker(field: &Field) -> Field { let mut skipped = Field::default(); skipped.optional = field.optional; skipped.deprecated = field.deprecated.clone(); skipped.docs = field.docs.clone(); skipped.attributes = field.attributes.clone(); skipped } fn unnamed_live_fields(unnamed: &UnnamedFields) -> impl Iterator { unnamed.fields.iter().filter(|field| field.ty.is_some()) } fn unnamed_live_field_count(unnamed: &UnnamedFields) -> usize { unnamed_live_fields(unnamed).count() } fn unnamed_has_effective_payload(unnamed: &UnnamedFields) -> bool { unnamed_live_field_count(unnamed) != 0 } fn unnamed_fields_all_skipped(unnamed: &UnnamedFields) -> bool { !unnamed.fields.is_empty() && !unnamed_has_effective_payload(unnamed) } fn rewrite_enum_repr_for_phase( e: &mut Enum, mode: PhaseRewrite, original_types: &Types, ) -> Result<(), Error> { if enum_repr_already_rewritten(e) { return Ok(()); } let repr = EnumRepr::from_attrs(&e.attributes)?; if matches!(repr, EnumRepr::Untagged) { return Ok(()); } let container_attrs = SerdeContainerAttrs::from_attributes(&e.attributes)?; let variants = std::mem::take(&mut e.variants); let mut transformed = Vec::with_capacity(variants.len()); for (variant_name, variant) in variants { if variant.skip { continue; } let variant_attrs = SerdeVariantAttrs::from_attributes(&variant.attributes)?; if variant_attrs .as_ref() .is_some_and(|attrs| variant_is_skipped_for_mode(attrs, mode)) { continue; } if variant_attrs.as_ref().is_some_and(|attrs| attrs.untagged) { transformed.push(( Cow::Owned(variant_name.into_owned()), transform_untagged_variant(&variant)?, )); continue; } let serialized_name = serialized_variant_name(&variant_name, &variant, &container_attrs, mode)?; let widen_tag = mode == PhaseRewrite::Deserialize && variant_attrs.is_some_and(|attrs| attrs.other); let mut transformed_variant = match &repr { EnumRepr::External => transform_external_variant(serialized_name.clone(), &variant)?, EnumRepr::Internal { tag } => transform_internal_variant( serialized_name.clone(), tag.as_ref(), &variant, original_types, widen_tag, )?, EnumRepr::Adjacent { tag, content } => { if tag == content { return Err(Error::invalid_enum_representation( "serde adjacent tagging requires distinct `tag` and `content` field names", )); } transform_adjacent_variant( serialized_name.clone(), tag.as_ref(), content.as_ref(), &variant, widen_tag, )? } EnumRepr::Untagged => unreachable!(), }; transformed_variant.attributes = Default::default(); transformed.push((Cow::Owned(serialized_name), transformed_variant)); } e.variants = transformed; e.attributes = Default::default(); Ok(()) } fn enum_repr_already_rewritten(e: &Enum) -> bool { e.attributes.is_empty() && !e.variants.is_empty() && e.variants.iter().all(|(name, variant)| { variant.attributes.is_empty() && variant_repr_already_rewritten(name, variant) }) } fn variant_repr_already_rewritten(name: &str, variant: &Variant) -> bool { match &variant.fields { Fields::Unit => false, Fields::Unnamed(fields) if name.is_empty() => unnamed_live_field_count(fields) == 1, Fields::Unnamed(fields) if fields.fields.len() == 1 => fields .fields .first() .and_then(|field| field.ty.as_ref()) .is_some_and(is_generated_string_literal_datatype), Fields::Named(fields) => fields.fields.iter().any(|(field_name, field)| { field_name == name || field .ty .as_ref() .is_some_and(is_generated_string_literal_datatype) }), _ => false, } } fn rewrite_identifier_enum_for_phase( e: &mut Enum, mode: PhaseRewrite, original_types: &Types, generated: &HashMap, split_types: &HashSet, ) -> Result { let Some(attrs) = SerdeContainerAttrs::from_attributes(&e.attributes)? else { return Ok(false); }; if !attrs.variant_identifier && !attrs.field_identifier { return Ok(false); } if mode != PhaseRewrite::Deserialize { return Ok(false); } let container_attrs = SerdeContainerAttrs::from_attributes(&e.attributes)?; let mut variants = Vec::new(); let mut seen = HashSet::new(); for (variant_name, variant) in e.variants.iter() { let serialized_name = serialized_variant_name( variant_name, variant, &container_attrs, PhaseRewrite::Deserialize, )?; if seen.insert(serialized_name.clone()) { variants.push(( Cow::Owned(serialized_name.clone()), identifier_union_variant(string_literal_datatype(serialized_name)), )); } if let Some(variant_attrs) = SerdeVariantAttrs::from_attributes(&variant.attributes)? { for alias in &variant_attrs.aliases { if seen.insert(alias.clone()) { variants.push(( Cow::Owned(alias.clone()), identifier_union_variant(string_literal_datatype(alias.clone())), )); } } } } variants.push(( Cow::Borrowed(""), identifier_union_variant(DataType::Primitive(specta::datatype::Primitive::u32)), )); if attrs.field_identifier && let Some((_, fallback)) = &e.variants.last() && let Fields::Unnamed(unnamed) = &fallback.fields && let Some(field) = unnamed.fields.first() && let Some(ty) = field.ty.as_ref() { let mut fallback_ty = ty.clone(); rewrite_datatype_for_phase( &mut fallback_ty, mode, original_types, generated, split_types, None, )?; variants.push((Cow::Borrowed(""), identifier_union_variant(fallback_ty))); } e.attributes = Default::default(); e.variants = variants; Ok(true) } fn container_rename_all_rule( attrs: &specta::datatype::Attributes, mode: PhaseRewrite, context: &str, container_name: &str, ) -> Result, Error> { let attrs = SerdeContainerAttrs::from_attributes(attrs)?; select_phase_rule( mode, attrs.as_ref().and_then(|attrs| attrs.rename_all_serialize), attrs .as_ref() .and_then(|attrs| attrs.rename_all_deserialize), context, container_name, ) } fn enum_variant_field_rename_rule( container_attrs: &Option, variant: &Variant, mode: PhaseRewrite, variant_name: &str, ) -> Result, Error> { let variant_attrs = SerdeVariantAttrs::from_attributes(&variant.attributes)?; let variant_rule = select_phase_rule( mode, variant_attrs .as_ref() .and_then(|attrs| attrs.rename_all_serialize), variant_attrs .as_ref() .and_then(|attrs| attrs.rename_all_deserialize), "enum variant rename_all", variant_name, )?; if variant_rule.is_some() { return Ok(variant_rule); } select_phase_rule( mode, container_attrs .as_ref() .and_then(|attrs| attrs.rename_all_fields_serialize), container_attrs .as_ref() .and_then(|attrs| attrs.rename_all_fields_deserialize), "enum rename_all_fields", variant_name, ) } fn identifier_union_variant(ty: DataType) -> Variant { let mut variant = Variant::unnamed().build(); if let Fields::Unnamed(fields) = &mut variant.fields { fields.fields.push(Field::new(ty)); } variant } fn transform_untagged_variant(variant: &Variant) -> Result { let payload = variant_payload_field(variant) .ok_or_else(|| Error::invalid_external_tagged_variant(""))?; Ok(clone_variant_with_unnamed_fields(variant, vec![payload])) } fn filter_enum_variants_for_phase(e: &mut Enum, mode: PhaseRewrite) -> Result<(), Error> { let mut filter_err = None; e.variants.retain(|(_, variant)| { if variant.skip { return false; } match SerdeVariantAttrs::from_attributes(&variant.attributes) { Ok(Some(attrs)) => !variant_is_skipped_for_mode(&attrs, mode), Ok(None) => true, Err(err) => { filter_err = Some(err); true } } }); if let Some(err) = filter_err { return Err(err); } Ok(()) } fn variant_is_skipped_for_mode(attrs: &SerdeVariantAttrs, mode: PhaseRewrite) -> bool { match mode { PhaseRewrite::Serialize => attrs.skip_serializing, PhaseRewrite::Deserialize => attrs.skip_deserializing, PhaseRewrite::Unified => attrs.skip_serializing || attrs.skip_deserializing, } } fn serialized_variant_name( variant_name: &str, variant: &Variant, container_attrs: &Option, mode: PhaseRewrite, ) -> Result { let variant_attrs = SerdeVariantAttrs::from_attributes(&variant.attributes)?; if let Some(rename) = select_phase_string( mode, variant_attrs .as_ref() .and_then(|attrs| attrs.rename_serialize.as_deref()), variant_attrs .as_ref() .and_then(|attrs| attrs.rename_deserialize.as_deref()), "enum variant rename", variant_name, )? { return Ok(rename.to_string()); } Ok(select_phase_rule( mode, container_attrs .as_ref() .and_then(|attrs| attrs.rename_all_serialize), container_attrs .as_ref() .and_then(|attrs| attrs.rename_all_deserialize), "enum rename_all", variant_name, )? .map_or_else( || variant_name.to_string(), |rule| rule.apply_to_variant(variant_name), )) } fn select_phase_string<'a>( mode: PhaseRewrite, serialize: Option<&'a str>, deserialize: Option<&'a str>, context: &str, name: &str, ) -> Result, Error> { Ok(match mode { PhaseRewrite::Serialize => serialize, PhaseRewrite::Deserialize => deserialize, PhaseRewrite::Unified => match (serialize, deserialize) { (Some(serialize), Some(deserialize)) if serialize != deserialize => { return Err(Error::incompatible_rename( context.to_string(), name, Some(serialize.to_string()), Some(deserialize.to_string()), )); } (serialize, deserialize) => serialize.or(deserialize), }, }) } fn select_phase_rule( mode: PhaseRewrite, serialize: Option, deserialize: Option, context: &str, name: &str, ) -> Result, Error> { Ok(match mode { PhaseRewrite::Serialize => serialize, PhaseRewrite::Deserialize => deserialize, PhaseRewrite::Unified => match (serialize, deserialize) { (Some(serialize), Some(deserialize)) if serialize != deserialize => { return Err(Error::incompatible_rename( context.to_string(), name, Some(format!("{serialize:?}")), Some(format!("{deserialize:?}")), )); } (serialize, deserialize) => serialize.or(deserialize), }, }) } fn resolve_phased_type( ty: &DataType, mode: PhaseRewrite, path: &str, ) -> Result, Error> { let DataType::Reference(Reference::Opaque(reference)) = ty else { return Ok(None); }; let Some(phased) = reference.downcast_ref::() else { return Ok(None); }; Ok(match mode { // Note that we won't hit this if `TSerialize == TDeserialize` because it will just return `T` directly in the `impl Type for Phased<...>` PhaseRewrite::Unified => { return Err(Error::invalid_phased_type_usage( path, "`specta_serde::Phased` requires `PhasesFormat`", )); } PhaseRewrite::Serialize => Some(phased.serialize.clone()), PhaseRewrite::Deserialize => Some(phased.deserialize.clone()), }) } fn conversion_datatype_for_mode( ty: &DataType, mode: PhaseRewrite, ) -> Result, Error> { let attrs = match ty { DataType::Struct(s) => &s.attributes, DataType::Enum(e) => &e.attributes, _ => return Ok(None), }; select_conversion_target(attrs, mode) } fn select_conversion_target( attrs: &specta::datatype::Attributes, mode: PhaseRewrite, ) -> Result, Error> { let parsed = SerdeContainerAttrs::from_attributes(attrs)?; let resolved = parsed.as_ref(); let serialize_target = resolved.and_then(|v| v.resolved_into.as_ref()); let deserialize_target = resolved.and_then(|v| v.resolved_from.as_ref().or(v.resolved_try_from.as_ref())); match mode { PhaseRewrite::Serialize => Ok(serialize_target.cloned()), PhaseRewrite::Deserialize => Ok(deserialize_target.cloned()), PhaseRewrite::Unified => match (serialize_target, deserialize_target) { (None, None) => Ok(None), (Some(serialize), Some(deserialize)) if serialize == deserialize => { Ok(Some(serialize.clone())) } _ => Err(Error::incompatible_conversion( "container conversion", resolved .and_then(|attrs| { attrs .into .as_ref() .map(|v| format!("into({})", v.type_src)) .or_else(|| { attrs.from.as_ref().map(|v| format!("from({})", v.type_src)) }) .or_else(|| { attrs .try_from .as_ref() .map(|v| format!("try_from({})", v.type_src)) }) }) .unwrap_or_else(|| "".to_string()), resolved.and_then(|attrs| attrs.into.as_ref().map(|v| v.type_src.clone())), resolved.and_then(|attrs| { attrs.from.as_ref().map(|v| v.type_src.clone()).or_else(|| { attrs .try_from .as_ref() .map(|v| format!("try_from({})", v.type_src)) }) }), )), }, } } fn transform_external_variant( serialized_name: String, variant: &Variant, ) -> Result { let skipped_only_unnamed = match &variant.fields { Fields::Unnamed(unnamed) => unnamed_fields_all_skipped(unnamed), Fields::Unit | Fields::Named(_) => false, }; Ok(match &variant.fields { Fields::Unit => clone_variant_with_unnamed_fields( variant, vec![Field::new(string_literal_datatype(serialized_name))], ), _ if skipped_only_unnamed => clone_variant_with_unnamed_fields( variant, vec![Field::new(string_literal_datatype(serialized_name))], ), _ => { let payload = variant_payload_field(variant) .ok_or_else(|| Error::invalid_external_tagged_variant(serialized_name.clone()))?; clone_variant_with_named_fields(variant, vec![(Cow::Owned(serialized_name), payload)]) } }) } fn transform_adjacent_variant( serialized_name: String, tag: &str, content: &str, variant: &Variant, widen_tag: bool, ) -> Result { let mut fields = vec![( Cow::Owned(tag.to_string()), Field::new(if widen_tag { DataType::Primitive(Primitive::str) } else { string_literal_datatype(serialized_name.clone()) }), )]; if variant_has_effective_payload(variant) { let payload = variant_payload_field(variant) .ok_or_else(|| Error::invalid_adjacent_tagged_variant(serialized_name.clone()))?; fields.push((Cow::Owned(content.to_string()), payload)); } Ok(clone_variant_with_named_fields(variant, fields)) } fn transform_internal_variant( serialized_name: String, tag: &str, variant: &Variant, original_types: &Types, widen_tag: bool, ) -> Result { let mut fields = vec![( Cow::Owned(tag.to_string()), Field::new(if widen_tag { DataType::Primitive(Primitive::str) } else { string_literal_datatype(serialized_name.clone()) }), )]; match &variant.fields { Fields::Unit => {} Fields::Named(named) => { fields.extend(named.fields.iter().cloned()); } Fields::Unnamed(unnamed) => { let live_field_count = unnamed_live_field_count(unnamed); if live_field_count == 0 { return Ok(clone_variant_with_named_fields(variant, fields)); } let non_skipped = unnamed_live_fields(unnamed).collect::>(); if live_field_count != 1 { return Err(Error::invalid_internally_tagged_variant( serialized_name, "tuple variant must have exactly one non-skipped field", )); } let payload_field = non_skipped .into_iter() .next() .expect("checked above") .clone(); let payload_ty = payload_field.ty.clone().expect("checked above"); let Some(payload_is_effectively_empty) = internal_tag_payload_compatibility( &payload_ty, original_types, &mut HashSet::new(), )? else { return Err(Error::invalid_internally_tagged_variant( serialized_name, "payload cannot be merged with a tag", )); }; if !payload_is_effectively_empty { return Ok(clone_variant_with_unnamed_fields( variant, vec![Field::new(DataType::Intersection(vec![ named_fields_datatype(fields), payload_ty, ]))], )); } } } Ok(clone_variant_with_named_fields(variant, fields)) } fn named_fields_datatype(fields: Vec<(Cow<'static, str>, Field)>) -> DataType { let mut builder = Struct::named(); for (name, field) in fields { builder = builder.field(name, field); } builder.build() } fn string_literal_datatype(value: String) -> DataType { let mut value_enum = Enum::default(); value_enum .variants .push((Cow::Owned(value), Variant::unit())); DataType::Enum(value_enum) } fn is_generated_string_literal_datatype(ty: &DataType) -> bool { let DataType::Enum(e) = ty else { return false; }; let Some((_, variant)) = e.variants.first() else { return false; }; if e.variants.len() != 1 { return false; } match &variant.fields { Fields::Unit => true, Fields::Unnamed(fields) if fields.fields.len() == 1 => fields .fields .first() .and_then(|field| field.ty.as_ref()) .is_some_and(is_generated_string_literal_datatype), _ => false, } } fn variant_has_effective_payload(variant: &Variant) -> bool { match &variant.fields { Fields::Unit => false, Fields::Named(named) => !&named.fields.is_empty(), Fields::Unnamed(unnamed) => unnamed_has_effective_payload(unnamed), } } fn variant_payload_field(variant: &Variant) -> Option { match &variant.fields { Fields::Unit => Some(Field::new(DataType::Tuple(Tuple::new(vec![])))), Fields::Named(named) => { let mut out = Struct::named(); for (name, field) in named.fields.iter().cloned() { out.field_mut(name, field); } Some(Field::new(out.build())) } Fields::Unnamed(unnamed) => { let original_unnamed_len = unnamed.fields.len(); let non_skipped = unnamed_live_fields(unnamed).collect::>(); match non_skipped.as_slice() { [] => Some(Field::new(DataType::Tuple(Tuple::new(vec![])))), [single] if original_unnamed_len == 1 => Some((*single).clone()), _ => Some(Field::new(DataType::Tuple(Tuple::new( non_skipped .iter() .filter_map(|field| field.ty.clone()) .collect(), )))), } } } } fn clone_variant_with_named_fields( original: &Variant, fields: Vec<(Cow<'static, str>, Field)>, ) -> Variant { let mut builder = Variant::named(); for (name, field) in fields { builder = builder.field(name, field); } let mut transformed = builder.build(); transformed.skip = original.skip; transformed.docs = original.docs.clone(); transformed.deprecated = original.deprecated.clone(); transformed.attributes = original.attributes.clone(); transformed } fn clone_variant_with_unnamed_fields(original: &Variant, fields: Vec) -> Variant { let mut builder = Variant::unnamed(); for field in fields { builder = builder.field(field); } let mut transformed = builder.build(); transformed.skip = original.skip; transformed.docs = original.docs.clone(); transformed.deprecated = original.deprecated.clone(); transformed.attributes = original.attributes.clone(); transformed } fn internal_tag_payload_compatibility( ty: &DataType, original_types: &Types, seen: &mut HashSet, ) -> Result, Error> { match ty { DataType::Map(_) => Ok(Some(false)), DataType::Struct(strct) => { if SerdeContainerAttrs::from_attributes(&strct.attributes)? .is_some_and(|attrs| attrs.transparent) { let payload_fields = match &strct.fields { Fields::Unit => return Ok(Some(true)), Fields::Unnamed(unnamed) => unnamed .fields .iter() .filter_map(|field| field.ty.as_ref()) .collect::>(), Fields::Named(named) => named .fields .iter() .filter_map(|(_, field)| field.ty.as_ref()) .collect::>(), }; let [inner_ty] = payload_fields.as_slice() else { if payload_fields.is_empty() { return Ok(Some(true)); } return Ok(None); }; return internal_tag_payload_compatibility(inner_ty, original_types, seen); } Ok(match &strct.fields { Fields::Named(named) => Some( named .fields .iter() .all(|(_, field)| field.ty.as_ref().is_none()), ), Fields::Unit | Fields::Unnamed(_) => None, }) } DataType::Tuple(tuple) => Ok(tuple.elements.is_empty().then_some(true)), DataType::Intersection(types) => { let mut is_effectively_empty = true; for ty in types { let Some(part_empty) = internal_tag_payload_compatibility(ty, original_types, seen)? else { return Ok(None); }; is_effectively_empty &= part_empty; } Ok(Some(is_effectively_empty)) } DataType::Reference(Reference::Named(reference)) => { if let NamedReferenceType::Inline { dt, .. } = &reference.inner { return internal_tag_payload_compatibility(dt, original_types, seen); } let Some(referenced) = original_types.get(reference) else { return Ok(None); }; let Some(referenced_ty) = referenced.ty.as_ref() else { return Ok(None); }; let key = TypeIdentity::from_ndt(referenced); if !seen.insert(key.clone()) { return Ok(Some(false)); } let compatible = internal_tag_payload_compatibility(referenced_ty, original_types, seen); seen.remove(&key); compatible } DataType::Enum(enm) => match EnumRepr::from_attrs(&enm.attributes) { Ok(EnumRepr::Untagged) => { let mut is_effectively_empty = true; for (_, variant) in &enm.variants { let Some(variant_empty) = internal_tag_variant_payload_compatibility(variant, original_types, seen)? else { return Ok(None); }; is_effectively_empty &= variant_empty; } Ok(Some(is_effectively_empty)) } Ok(EnumRepr::External | EnumRepr::Internal { .. } | EnumRepr::Adjacent { .. }) => { Ok(Some(false)) } Err(_) => Ok(None), }, DataType::Primitive(_) | DataType::List(_) | DataType::Nullable(_) | DataType::Reference(Reference::Opaque(_)) | DataType::Generic(_) => Ok(None), } } fn internal_tag_variant_payload_compatibility( variant: &Variant, original_types: &Types, seen: &mut HashSet, ) -> Result, Error> { match &variant.fields { Fields::Unit => Ok(Some(true)), Fields::Named(named) => Ok(Some( named .fields .iter() .all(|(_, field)| field.ty.as_ref().is_none()), )), Fields::Unnamed(unnamed) => { if unnamed.fields.len() != 1 { return Ok(None); } unnamed .fields .iter() .find_map(|field| field.ty.as_ref()) .map_or(Ok(None), |ty| { internal_tag_payload_compatibility(ty, original_types, seen) }) } } } fn has_local_phase_difference(dt: &DataType) -> Result { match dt { DataType::Struct(s) => Ok(container_has_local_difference(&s.attributes)? || fields_have_local_difference(&s.fields)?), DataType::Enum(e) => Ok(container_has_local_difference(&e.attributes)? || e.variants .iter() .try_fold(false, |has_difference, (_, variant)| { if has_difference { return Ok(true); } Ok(variant_has_local_difference(variant)? || fields_have_local_difference(&variant.fields)?) })?), DataType::Tuple(tuple) => tuple.elements.iter().try_fold(false, |has_difference, ty| { if has_difference { return Ok(true); } has_local_phase_difference(ty) }), DataType::List(list) => has_local_phase_difference(&list.ty), DataType::Map(map) => Ok(has_local_phase_difference(map.key_ty())? || has_local_phase_difference(map.value_ty())?), DataType::Intersection(types_) => types_.iter().try_fold(false, |has_difference, ty| { if has_difference { return Ok(true); } has_local_phase_difference(ty) }), DataType::Nullable(inner) => has_local_phase_difference(inner), DataType::Reference(Reference::Opaque(reference)) => { Ok(reference.downcast_ref::().is_some()) } DataType::Primitive(_) | DataType::Reference(Reference::Named(_)) | DataType::Generic(_) => Ok(false), } } fn container_has_local_difference(attrs: &specta::datatype::Attributes) -> Result { let Some(conversions) = SerdeContainerAttrs::from_attributes(attrs)? else { return Ok(false); }; Ok(conversions.resolved_into.as_ref() != conversions .resolved_from .as_ref() .or(conversions.resolved_try_from.as_ref()) || conversions.rename_serialize != conversions.rename_deserialize || conversions.rename_all_serialize != conversions.rename_all_deserialize || conversions.rename_all_fields_serialize != conversions.rename_all_fields_deserialize || conversions.variant_identifier || conversions.field_identifier) } fn fields_have_local_difference(fields: &Fields) -> Result { match fields { Fields::Unit => Ok(false), Fields::Unnamed(unnamed) => { unnamed .fields .iter() .try_fold(false, |has_difference, field| { if has_difference { return Ok(true); } field .ty .as_ref() .map_or(Ok(false), has_local_phase_difference) }) } Fields::Named(named) => { named .fields .iter() .try_fold(false, |has_difference, (_, field)| { if has_difference { return Ok(true); } Ok(field_has_local_difference(field)? || field .ty .as_ref() .map_or(Ok(false), has_local_phase_difference)?) }) } } } fn field_has_local_difference(field: &Field) -> Result { Ok(SerdeFieldAttrs::from_attributes(&field.attributes)? .map(|attrs| { attrs.rename_serialize.as_deref() != attrs.rename_deserialize.as_deref() || attrs.skip_serializing != attrs.skip_deserializing || attrs.skip_serializing_if.is_some() || attrs.has_serialize_with || attrs.has_deserialize_with || attrs.has_with }) .unwrap_or_default()) } fn variant_has_local_difference(variant: &Variant) -> Result { Ok(SerdeVariantAttrs::from_attributes(&variant.attributes)? .map(|attrs| { attrs.rename_serialize.as_deref() != attrs.rename_deserialize.as_deref() || attrs.rename_all_serialize != attrs.rename_all_deserialize || attrs.skip_serializing != attrs.skip_deserializing || attrs.has_serialize_with || attrs.has_deserialize_with || attrs.has_with || attrs.other }) .unwrap_or_default()) } fn collect_dependencies( dt: &DataType, types: &Types, deps: &mut HashSet, ) -> Result<(), Error> { match dt { DataType::Struct(s) => { collect_conversion_dependencies(&s.attributes, types, deps)?; collect_fields_dependencies(&s.fields, types, deps)?; } DataType::Enum(e) => { collect_conversion_dependencies(&e.attributes, types, deps)?; for (_, variant) in &e.variants { collect_fields_dependencies(&variant.fields, types, deps)?; } } DataType::Tuple(tuple) => { for ty in &tuple.elements { collect_dependencies(ty, types, deps)?; } } DataType::List(list) => collect_dependencies(&list.ty, types, deps)?, DataType::Map(map) => { collect_dependencies(map.key_ty(), types, deps)?; collect_dependencies(map.value_ty(), types, deps)?; } DataType::Intersection(types_) => { for ty in types_ { collect_dependencies(ty, types, deps)?; } } DataType::Nullable(inner) => collect_dependencies(inner, types, deps)?, DataType::Reference(Reference::Named(reference)) => { if let NamedReferenceType::Inline { dt, .. } = &reference.inner { collect_dependencies(dt, types, deps)?; } if let Some(referenced) = types.get(reference) { deps.insert(TypeIdentity::from_ndt(referenced)); } for (_, generic) in named_reference_generics(reference) { collect_dependencies(generic, types, deps)?; } } DataType::Reference(Reference::Opaque(_)) => { if let DataType::Reference(Reference::Opaque(reference)) = dt && let Some(phased) = reference.downcast_ref::() { collect_dependencies(&phased.serialize, types, deps)?; collect_dependencies(&phased.deserialize, types, deps)?; } } DataType::Primitive(_) | DataType::Generic(_) => {} } Ok(()) } fn collect_conversion_dependencies( attrs: &specta::datatype::Attributes, types: &Types, deps: &mut HashSet, ) -> Result<(), Error> { let Some(conversions) = SerdeContainerAttrs::from_attributes(attrs)? else { return Ok(()); }; for conversion in [ conversions.resolved_into.as_ref(), conversions.resolved_from.as_ref(), conversions.resolved_try_from.as_ref(), ] .into_iter() .flatten() { collect_dependencies(conversion, types, deps)?; } Ok(()) } fn collect_fields_dependencies( fields: &Fields, types: &Types, deps: &mut HashSet, ) -> Result<(), Error> { match fields { Fields::Unit => {} Fields::Unnamed(unnamed) => { for field in &unnamed.fields { if let Some(ty) = field.ty.as_ref() { collect_dependencies(ty, types, deps)?; } } } Fields::Named(named) => { for (_, field) in &named.fields { if let Some(ty) = field.ty.as_ref() { collect_dependencies(ty, types, deps)?; } } } } Ok(()) } fn build_from_original( original: &NamedDataType, mode: PhaseRewrite, ) -> Result { let mut ndt = original.clone(); ndt.name = Cow::Owned(split_type_name(original, mode)?); Ok(ndt) } fn register_generated_type(types: &mut Types, generated: NamedDataType) -> NamedDataType { NamedDataType::new(generated.name.clone(), types, move |_, ndt| { ndt.docs = generated.docs; ndt.deprecated = generated.deprecated; ndt.module_path = generated.module_path; ndt.location = generated.location; ndt.generics = generated.generics; ndt.ty = generated.ty; }) } fn rewrite_named_type_for_phase(ndt: &mut NamedDataType, mode: PhaseRewrite) -> Result<(), Error> { if let Some(ty) = &ndt.ty && let Some(rename) = renamed_type_name_for_phase(ty, mode, ndt.name.as_ref())? { ndt.name = Cow::Owned(rename); } Ok(()) } fn split_type_name(original: &NamedDataType, mode: PhaseRewrite) -> Result { let suffix = match mode { PhaseRewrite::Serialize => "Serialize", PhaseRewrite::Deserialize => "Deserialize", PhaseRewrite::Unified => return Ok(original.name.to_string()), }; let base_name = original .ty .as_ref() .map(|ty| renamed_type_name_for_phase(ty, mode, original.name.as_ref())) .transpose()? .flatten() .unwrap_or_else(|| original.name.to_string()); Ok(format!("{base_name}_{suffix}")) } fn renamed_type_name_for_phase( ty: &DataType, mode: PhaseRewrite, current_name: &str, ) -> Result, Error> { let DataType::Struct(strct) = ty else { return Ok(None); }; let Some(attrs) = SerdeContainerAttrs::from_attributes(&strct.attributes)? else { return Ok(None); }; Ok(select_phase_string( mode, attrs.rename_serialize.as_deref(), attrs.rename_deserialize.as_deref(), "container rename", current_name, )? .map(str::to_string)) } fn apply_field_attrs( field: &mut Field, mode: PhaseRewrite, container_default: bool, ) -> Result<(), Error> { let mut optional = field.optional; if let Some(attrs) = SerdeFieldAttrs::from_attributes(&field.attributes)? { if field_is_optional_for_mode(Some(&attrs), container_default, mode) { optional = true; } } else if field_is_optional_for_mode(None, container_default, mode) { optional = true; } field.optional = optional; Ok(()) } fn field_is_optional_for_mode( attrs: Option<&SerdeFieldAttrs>, container_default: bool, mode: PhaseRewrite, ) -> bool { match mode { PhaseRewrite::Serialize => false, PhaseRewrite::Deserialize | PhaseRewrite::Unified => { container_default || attrs.is_some_and(|attrs| attrs.default || attrs.skip_deserializing) } } } #[cfg(test)] mod tests { use serde::{Deserialize, Serialize}; use specta::{Format as _, Type, Types, datatype::DataType}; use super::{ Phase, Phased, PhasesFormat, parser, select_phase_datatype, validate::{ApplyMode, validate_datatype_for_mode}, }; #[derive(Type, Serialize, Deserialize)] #[serde(untagged)] enum OneOrManyString { One(String), Many(Vec), } #[derive(Type, Serialize, Deserialize)] struct Filters { #[specta(type = Phased, OneOrManyString>)] tags: Vec, } #[derive(Type, Serialize, Deserialize)] struct FilterList { items: Vec, } #[derive(Type, Serialize, Deserialize)] struct Plain { name: String, } #[derive(Type, Serialize, Deserialize)] struct WithSkipIf { #[serde(default, skip_serializing_if = "Option::is_none")] nickname: Option, } #[test] fn selects_split_named_reference_for_each_phase() { let mut types = specta::Types::default(); let dt = Filters::definition(&mut types); let resolved = formatted_phases(types); let serialize = select_phase_datatype(&dt, &resolved, Phase::Serialize); let deserialize = select_phase_datatype(&dt, &resolved, Phase::Deserialize); assert_named_reference(&serialize, &resolved, "Filters_Serialize"); assert_named_reference(&deserialize, &resolved, "Filters_Deserialize"); } #[test] fn rewrites_nested_generics_for_each_phase() { let mut types = specta::Types::default(); let dt = FilterList::definition(&mut types); let resolved = formatted_phases(types); let serialize = select_phase_datatype(&dt, &resolved, Phase::Serialize); let deserialize = select_phase_datatype(&dt, &resolved, Phase::Deserialize); assert_named_reference(&serialize, &resolved, "FilterList_Serialize"); assert_named_reference(&deserialize, &resolved, "FilterList_Deserialize"); let serialize_inner = named_field_type(&serialize, &resolved, "items"); let deserialize_inner = named_field_type(&deserialize, &resolved, "items"); assert_named_reference( list_item_type(serialize_inner), &resolved, "Filters_Serialize", ); assert_named_reference( list_item_type(deserialize_inner), &resolved, "Filters_Deserialize", ); } #[test] fn preserves_unsplit_types() { let mut types = specta::Types::default(); let dt = Plain::definition(&mut types); let resolved = formatted_phases(types); let serialize = select_phase_datatype(&dt, &resolved, Phase::Serialize); let deserialize = select_phase_datatype(&dt, &resolved, Phase::Deserialize); assert_named_reference(&serialize, &resolved, "Plain"); assert_named_reference(&deserialize, &resolved, "Plain"); } #[test] fn clears_skip_serializing_if_attribute_after_phase_split() { let mut types = specta::Types::default(); let dt = WithSkipIf::definition(&mut types); let resolved = formatted_phases(types); let serialize = select_phase_datatype(&dt, &resolved, Phase::Serialize); let deserialize = select_phase_datatype(&dt, &resolved, Phase::Deserialize); assert!(!field_has_skip_serializing_if( &serialize, &resolved, "nickname" )); assert!(!field_has_skip_serializing_if( &deserialize, &resolved, "nickname" )); } #[test] fn phase_split_field_passes_unified_mode_validation() { // Regression test for the interaction with downstream callers (e.g. // tauri-specta's `validate_exported_command`) that run unified-mode // validation on the post-`apply_phases` graph. Before clearing the // attribute on phase-split fields, this would error with // "skip_serializing_if requires format_phases because unified mode // cannot represent conditional omission". let mut types = specta::Types::default(); let dt = WithSkipIf::definition(&mut types); let resolved = formatted_phases(types); let serialize = select_phase_datatype(&dt, &resolved, Phase::Serialize); let deserialize = select_phase_datatype(&dt, &resolved, Phase::Deserialize); validate_datatype_for_mode(&serialize, &resolved, ApplyMode::Unified) .expect("Unified validation should accept phase-split _Serialize variant"); validate_datatype_for_mode(&deserialize, &resolved, ApplyMode::Unified) .expect("Unified validation should accept phase-split _Deserialize variant"); } #[test] fn resolves_explicit_phased_datatypes_without_named_types() { let mut types = specta::Types::default(); let dt = >>::definition(&mut types); let resolved = formatted_phases(types); let serialize = select_phase_datatype(&dt, &resolved, Phase::Serialize); let deserialize = select_phase_datatype(&dt, &resolved, Phase::Deserialize); assert_named_reference(&serialize, &resolved, "String"); assert_named_reference(&deserialize, &resolved, "Vec"); } fn assert_named_reference(dt: &DataType, types: &Types, expected_name: &str) { let DataType::Reference(specta::datatype::Reference::Named(reference)) = dt else { panic!("expected named reference"); }; let actual = types .get(reference) .expect("reference should resolve") .name .as_ref(); assert_eq!(actual, expected_name); } fn named_field_type<'a>(dt: &'a DataType, types: &'a Types, field_name: &str) -> &'a DataType { let DataType::Reference(specta::datatype::Reference::Named(reference)) = dt else { panic!("expected named reference"); }; let named = types.get(reference).expect("reference should resolve"); let Some(DataType::Struct(strct)) = &named.ty else { panic!("expected struct type"); }; let specta::datatype::Fields::Named(fields) = &strct.fields else { panic!("expected named fields"); }; fields .fields .iter() .find_map(|(name, field)| (name == field_name).then(|| field.ty.as_ref()).flatten()) .expect("field should exist") } fn field_has_skip_serializing_if(dt: &DataType, types: &Types, field_name: &str) -> bool { let DataType::Reference(specta::datatype::Reference::Named(reference)) = dt else { panic!("expected named reference"); }; let named = types.get(reference).expect("reference should resolve"); let Some(DataType::Struct(strct)) = &named.ty else { panic!("expected struct type"); }; let specta::datatype::Fields::Named(fields) = &strct.fields else { panic!("expected named fields"); }; fields .fields .iter() .find(|(name, _)| name == field_name) .map(|(_, field)| { field .attributes .contains_key(parser::FIELD_SKIP_SERIALIZING_IF) }) .expect("field should exist") } fn first_generic_type(dt: &DataType) -> &DataType { let DataType::Reference(specta::datatype::Reference::Named(reference)) = dt else { panic!("expected named reference with generics"); }; let specta::datatype::NamedReferenceType::Reference { generics, .. } = &reference.inner else { panic!("expected named reference with generics"); }; generics .first() .map(|(_, dt)| dt) .expect("expected first generic type") } fn list_item_type(dt: &DataType) -> &DataType { let DataType::Reference(specta::datatype::Reference::Named(reference)) = dt else { panic!("expected inline list reference"); }; let specta::datatype::NamedReferenceType::Inline { dt, .. } = &reference.inner else { return first_generic_type(dt); }; let DataType::List(list) = dt.as_ref() else { panic!("expected inline list"); }; &list.ty } fn formatted_phases(types: Types) -> Types { let format = PhasesFormat; format .map_types(&types) .expect("PhasesFormat should succeed") .into_owned() } } ================================================ FILE: specta-serde/src/parser.rs ================================================ #![allow(missing_docs)] use crate::{Error, inflection::RenameRule}; use specta::datatype::{Attributes, DataType}; const CONTAINER_RENAME_SERIALIZE: &str = "serde:container:rename_serialize"; const CONTAINER_RENAME_DESERIALIZE: &str = "serde:container:rename_deserialize"; const CONTAINER_RENAME_ALL_SERIALIZE: &str = "serde:container:rename_all_serialize"; const CONTAINER_RENAME_ALL_DESERIALIZE: &str = "serde:container:rename_all_deserialize"; const CONTAINER_RENAME_ALL_FIELDS_SERIALIZE: &str = "serde:container:rename_all_fields_serialize"; const CONTAINER_RENAME_ALL_FIELDS_DESERIALIZE: &str = "serde:container:rename_all_fields_deserialize"; const CONTAINER_TAG: &str = "serde:container:tag"; const CONTAINER_CONTENT: &str = "serde:container:content"; const CONTAINER_UNTAGGED: &str = "serde:container:untagged"; const CONTAINER_DEFAULT: &str = "serde:container:default"; const CONTAINER_TRANSPARENT: &str = "serde:container:transparent"; const CONTAINER_FROM_TYPE_SRC: &str = "serde:container:from_type_src"; const CONTAINER_FROM_RESOLVED: &str = "serde:container:from_resolved"; const CONTAINER_TRY_FROM_TYPE_SRC: &str = "serde:container:try_from_type_src"; const CONTAINER_TRY_FROM_RESOLVED: &str = "serde:container:try_from_resolved"; const CONTAINER_INTO_TYPE_SRC: &str = "serde:container:into_type_src"; const CONTAINER_INTO_RESOLVED: &str = "serde:container:into_resolved"; const CONTAINER_VARIANT_IDENTIFIER: &str = "serde:container:variant_identifier"; const CONTAINER_FIELD_IDENTIFIER: &str = "serde:container:field_identifier"; const VARIANT_RENAME_SERIALIZE: &str = "serde:variant:rename_serialize"; const VARIANT_RENAME_DESERIALIZE: &str = "serde:variant:rename_deserialize"; const VARIANT_ALIASES: &str = "serde:variant:aliases"; const VARIANT_RENAME_ALL_SERIALIZE: &str = "serde:variant:rename_all_serialize"; const VARIANT_RENAME_ALL_DESERIALIZE: &str = "serde:variant:rename_all_deserialize"; const VARIANT_SKIP_SERIALIZING: &str = "serde:variant:skip_serializing"; const VARIANT_SKIP_DESERIALIZING: &str = "serde:variant:skip_deserializing"; const VARIANT_HAS_SERIALIZE_WITH: &str = "serde:variant:has_serialize_with"; const VARIANT_HAS_DESERIALIZE_WITH: &str = "serde:variant:has_deserialize_with"; const VARIANT_HAS_WITH: &str = "serde:variant:has_with"; const VARIANT_OTHER: &str = "serde:variant:other"; const VARIANT_UNTAGGED: &str = "serde:variant:untagged"; const FIELD_RENAME_SERIALIZE: &str = "serde:field:rename_serialize"; const FIELD_RENAME_DESERIALIZE: &str = "serde:field:rename_deserialize"; const FIELD_ALIASES: &str = "serde:field:aliases"; const FIELD_DEFAULT: &str = "serde:field:default"; const FIELD_FLATTEN: &str = "serde:field:flatten"; const FIELD_SKIP_SERIALIZING: &str = "serde:field:skip_serializing"; const FIELD_SKIP_DESERIALIZING: &str = "serde:field:skip_deserializing"; pub(crate) const FIELD_SKIP_SERIALIZING_IF: &str = "serde:field:skip_serializing_if"; const FIELD_HAS_SERIALIZE_WITH: &str = "serde:field:has_serialize_with"; const FIELD_HAS_DESERIALIZE_WITH: &str = "serde:field:has_deserialize_with"; const FIELD_HAS_WITH: &str = "serde:field:has_with"; const CONTAINER_ATTR_KEYS: &[&str] = &[ CONTAINER_RENAME_SERIALIZE, CONTAINER_RENAME_DESERIALIZE, CONTAINER_RENAME_ALL_SERIALIZE, CONTAINER_RENAME_ALL_DESERIALIZE, CONTAINER_RENAME_ALL_FIELDS_SERIALIZE, CONTAINER_RENAME_ALL_FIELDS_DESERIALIZE, CONTAINER_TAG, CONTAINER_CONTENT, CONTAINER_UNTAGGED, CONTAINER_DEFAULT, CONTAINER_TRANSPARENT, CONTAINER_FROM_TYPE_SRC, CONTAINER_FROM_RESOLVED, CONTAINER_TRY_FROM_TYPE_SRC, CONTAINER_TRY_FROM_RESOLVED, CONTAINER_INTO_TYPE_SRC, CONTAINER_INTO_RESOLVED, CONTAINER_VARIANT_IDENTIFIER, CONTAINER_FIELD_IDENTIFIER, ]; const VARIANT_ATTR_KEYS: &[&str] = &[ VARIANT_RENAME_SERIALIZE, VARIANT_RENAME_DESERIALIZE, VARIANT_ALIASES, VARIANT_RENAME_ALL_SERIALIZE, VARIANT_RENAME_ALL_DESERIALIZE, VARIANT_SKIP_SERIALIZING, VARIANT_SKIP_DESERIALIZING, VARIANT_HAS_SERIALIZE_WITH, VARIANT_HAS_DESERIALIZE_WITH, VARIANT_HAS_WITH, VARIANT_OTHER, VARIANT_UNTAGGED, ]; const FIELD_ATTR_KEYS: &[&str] = &[ FIELD_RENAME_SERIALIZE, FIELD_RENAME_DESERIALIZE, FIELD_ALIASES, FIELD_DEFAULT, FIELD_FLATTEN, FIELD_SKIP_SERIALIZING, FIELD_SKIP_DESERIALIZING, FIELD_SKIP_SERIALIZING_IF, FIELD_HAS_SERIALIZE_WITH, FIELD_HAS_DESERIALIZE_WITH, FIELD_HAS_WITH, ]; #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct ConversionType { pub type_src: String, } #[derive(Debug, Clone, Default, PartialEq, Eq, Hash)] pub struct SerdeContainerAttrs { pub rename_serialize: Option, pub rename_deserialize: Option, pub rename_all_serialize: Option, pub rename_all_deserialize: Option, pub rename_all_fields_serialize: Option, pub rename_all_fields_deserialize: Option, pub tag: Option, pub content: Option, pub untagged: bool, pub default: bool, pub transparent: bool, pub from: Option, pub try_from: Option, pub into: Option, pub resolved_from: Option, pub resolved_try_from: Option, pub resolved_into: Option, pub variant_identifier: bool, pub field_identifier: bool, } impl SerdeContainerAttrs { pub fn from_attributes(attributes: &Attributes) -> Result, Error> { has_any_attr(attributes, CONTAINER_ATTR_KEYS) .then(|| { Ok(Self { rename_serialize: get_string(attributes, CONTAINER_RENAME_SERIALIZE), rename_deserialize: get_string(attributes, CONTAINER_RENAME_DESERIALIZE), rename_all_serialize: get_rename_rule( attributes, CONTAINER_RENAME_ALL_SERIALIZE, )?, rename_all_deserialize: get_rename_rule( attributes, CONTAINER_RENAME_ALL_DESERIALIZE, )?, rename_all_fields_serialize: get_rename_rule( attributes, CONTAINER_RENAME_ALL_FIELDS_SERIALIZE, )?, rename_all_fields_deserialize: get_rename_rule( attributes, CONTAINER_RENAME_ALL_FIELDS_DESERIALIZE, )?, tag: get_string(attributes, CONTAINER_TAG), content: get_string(attributes, CONTAINER_CONTENT), untagged: has_attr(attributes, CONTAINER_UNTAGGED), default: has_attr(attributes, CONTAINER_DEFAULT), transparent: has_attr(attributes, CONTAINER_TRANSPARENT), from: get_string(attributes, CONTAINER_FROM_TYPE_SRC) .map(|type_src| ConversionType { type_src }), try_from: get_string(attributes, CONTAINER_TRY_FROM_TYPE_SRC) .map(|type_src| ConversionType { type_src }), into: get_string(attributes, CONTAINER_INTO_TYPE_SRC) .map(|type_src| ConversionType { type_src }), resolved_from: get_datatype(attributes, CONTAINER_FROM_RESOLVED), resolved_try_from: get_datatype(attributes, CONTAINER_TRY_FROM_RESOLVED), resolved_into: get_datatype(attributes, CONTAINER_INTO_RESOLVED), variant_identifier: has_attr(attributes, CONTAINER_VARIANT_IDENTIFIER), field_identifier: has_attr(attributes, CONTAINER_FIELD_IDENTIFIER), }) }) .transpose() } } #[derive(Debug, Clone, Default, PartialEq, Eq, Hash)] pub struct SerdeVariantAttrs { pub rename_serialize: Option, pub rename_deserialize: Option, pub aliases: Vec, pub rename_all_serialize: Option, pub rename_all_deserialize: Option, pub skip_serializing: bool, pub skip_deserializing: bool, pub has_serialize_with: bool, pub has_deserialize_with: bool, pub has_with: bool, pub other: bool, pub untagged: bool, } impl SerdeVariantAttrs { pub fn from_attributes(attributes: &Attributes) -> Result, Error> { has_any_attr(attributes, VARIANT_ATTR_KEYS) .then(|| { Ok(Self { rename_serialize: get_string(attributes, VARIANT_RENAME_SERIALIZE), rename_deserialize: get_string(attributes, VARIANT_RENAME_DESERIALIZE), aliases: get_strings(attributes, VARIANT_ALIASES), rename_all_serialize: get_rename_rule( attributes, VARIANT_RENAME_ALL_SERIALIZE, )?, rename_all_deserialize: get_rename_rule( attributes, VARIANT_RENAME_ALL_DESERIALIZE, )?, skip_serializing: has_attr(attributes, VARIANT_SKIP_SERIALIZING), skip_deserializing: has_attr(attributes, VARIANT_SKIP_DESERIALIZING), has_serialize_with: has_attr(attributes, VARIANT_HAS_SERIALIZE_WITH), has_deserialize_with: has_attr(attributes, VARIANT_HAS_DESERIALIZE_WITH), has_with: has_attr(attributes, VARIANT_HAS_WITH), other: has_attr(attributes, VARIANT_OTHER), untagged: has_attr(attributes, VARIANT_UNTAGGED), }) }) .transpose() } } #[derive(Debug, Clone, Default, PartialEq, Eq, Hash)] pub struct SerdeFieldAttrs { pub rename_serialize: Option, pub rename_deserialize: Option, pub aliases: Vec, pub default: bool, pub flatten: bool, pub skip_serializing: bool, pub skip_deserializing: bool, pub skip_serializing_if: Option, pub has_serialize_with: bool, pub has_deserialize_with: bool, pub has_with: bool, } impl SerdeFieldAttrs { pub fn from_attributes(attributes: &Attributes) -> Result, Error> { has_any_attr(attributes, FIELD_ATTR_KEYS) .then(|| { Ok(Self { rename_serialize: get_string(attributes, FIELD_RENAME_SERIALIZE), rename_deserialize: get_string(attributes, FIELD_RENAME_DESERIALIZE), aliases: get_strings(attributes, FIELD_ALIASES), default: has_attr(attributes, FIELD_DEFAULT), flatten: has_attr(attributes, FIELD_FLATTEN), skip_serializing: has_attr(attributes, FIELD_SKIP_SERIALIZING), skip_deserializing: has_attr(attributes, FIELD_SKIP_DESERIALIZING), skip_serializing_if: get_string(attributes, FIELD_SKIP_SERIALIZING_IF), has_serialize_with: has_attr(attributes, FIELD_HAS_SERIALIZE_WITH), has_deserialize_with: has_attr(attributes, FIELD_HAS_DESERIALIZE_WITH), has_with: has_attr(attributes, FIELD_HAS_WITH), }) }) .transpose() } } fn get_string(attributes: &Attributes, key: &str) -> Option { attributes.get_named_as::(key).cloned() } fn get_strings(attributes: &Attributes, key: &str) -> Vec { attributes .get_named_as::>(key) .cloned() .unwrap_or_default() } fn has_attr(attributes: &Attributes, key: &str) -> bool { attributes.contains_key(key) } fn get_datatype(attributes: &Attributes, key: &str) -> Option { attributes.get_named_as::(key).cloned() } fn get_rename_rule(attributes: &Attributes, key: &str) -> Result, Error> { match get_string(attributes, key) { Some(value) => RenameRule::from_str(&value) .map(Some) .map_err(|_| Error::invalid_rename_rule(key.to_string(), value.clone())), None => Ok(None), } } fn has_any_attr(attributes: &Attributes, keys: &[&str]) -> bool { keys.iter().copied().any(|key| attributes.contains_key(key)) } ================================================ FILE: specta-serde/src/phased.rs ================================================ use std::marker::PhantomData; use specta::{ Type, Types, datatype::{DataType, Reference}, }; /// Declares an explicit serialize/deserialize type pair for Specta output. /// /// This is primarily used with `#[specta(type = ...)]` when serde attributes /// cause the wire shape to differ by direction. /// /// - `Serialize` is the type used for serialization output. /// - `Deserialize` is the type accepted for deserialization input. /// /// When both phases resolve to the same Specta datatype, this collapses to that /// single type. When they differ, `PhasesFormat` can split the graph into /// `*_Serialize` and `*_Deserialize` variants. /// /// ```rust /// # use specta::Type; /// #[derive(Type)] /// struct OneOrMany { /// #[specta(type = specta_serde::Phased, String>)] /// value: Vec, /// } /// ``` pub struct Phased(PhantomData<(Serialize, Deserialize)>); #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub(crate) struct PhasedTy { pub(crate) serialize: DataType, pub(crate) deserialize: DataType, } /// Builds an explicit phased [`DataType`] from precomputed serialize and deserialize shapes. pub fn phased(serialize: DataType, deserialize: DataType) -> DataType { if serialize == deserialize { serialize } else { DataType::Reference(Reference::opaque(PhasedTy { serialize, deserialize, })) } } impl Type for Phased { fn definition(types: &mut Types) -> DataType { let serialize = Serialize::definition(types); let deserialize = Deserialize::definition(types); phased(serialize, deserialize) } } ================================================ FILE: specta-serde/src/repr.rs ================================================ use std::borrow::Cow; use specta::datatype::Attributes; use crate::{Error, parser::SerdeContainerAttrs}; /// Serde representation of an enum. /// Refer to the [Serde documentation](https://serde.rs/enum-representations.html) for more information. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum EnumRepr { /// Untagged enum representation. Untagged, /// Externally tagged enum representation. External, /// Internally tagged enum representation. Internal { /// Field name used as the tag discriminator. tag: Cow<'static, str>, }, /// Adjacently tagged enum representation. Adjacent { /// Field name used as the tag discriminator. tag: Cow<'static, str>, /// Field name used to hold the variant content. content: Cow<'static, str>, }, } impl EnumRepr { pub(crate) fn from_attrs(attrs: &Attributes) -> Result { let Some(container_attrs) = SerdeContainerAttrs::from_attributes(attrs)? else { return Ok(Self::External); }; if container_attrs.untagged { return Ok(Self::Untagged); } match ( container_attrs.tag.as_deref(), container_attrs.content.as_deref(), ) { (Some(tag), Some(content)) => Ok(Self::Adjacent { tag: Cow::Owned(tag.to_string()), content: Cow::Owned(content.to_string()), }), (Some(tag), None) => Ok(Self::Internal { tag: Cow::Owned(tag.to_string()), }), (None, Some(_)) => Err(Error::invalid_enum_representation( "`content` is set without `tag`", )), (None, None) => Ok(Self::External), } } } ================================================ FILE: specta-serde/src/validate.rs ================================================ use std::collections::HashSet; use specta::{ Types, datatype::{DataType, Enum, Field, Fields, NamedReferenceType, Reference, Variant}, }; use crate::{ Error, parser::{SerdeContainerAttrs, SerdeFieldAttrs, SerdeVariantAttrs}, phased::PhasedTy, repr::EnumRepr, }; #[derive(Clone, Copy, PartialEq, Eq)] pub enum ApplyMode { Unified, Phases, } pub fn validate_for_mode(types: &Types, mode: ApplyMode) -> Result<(), Error> { for ndt in types.into_unsorted_iter() { let Some(ty) = &ndt.ty else { continue; }; inner( ty, types, &mut HashSet::new(), ndt.name.to_string(), mode, true, )?; } Ok(()) } pub(crate) fn validate_datatype_for_mode( dt: &DataType, types: &Types, mode: ApplyMode, ) -> Result<(), Error> { inner( dt, types, &mut HashSet::new(), "".to_string(), mode, true, ) } pub(crate) fn validate_datatype_for_mode_shallow( dt: &DataType, types: &Types, mode: ApplyMode, ) -> Result<(), Error> { inner( dt, types, &mut HashSet::new(), "".to_string(), mode, false, ) } fn inner( dt: &DataType, types: &Types, checked_references: &mut HashSet, path: String, mode: ApplyMode, follow_named_references: bool, ) -> Result<(), Error> { match dt { DataType::Nullable(ty) => inner( ty, types, checked_references, path, mode, follow_named_references, )?, DataType::Map(map) => { inner( map.key_ty(), types, checked_references, format!("{path}."), mode, follow_named_references, )?; inner( map.value_ty(), types, checked_references, format!("{path}."), mode, follow_named_references, )?; } DataType::List(list) => { inner( &list.ty, types, checked_references, format!("{path}."), mode, follow_named_references, )?; } DataType::Struct(strct) => { validate_container_attributes( &strct.attributes, types, checked_references, &path, mode, )?; if let Some(attrs) = SerdeContainerAttrs::from_attributes(&strct.attributes)? { if attrs.variant_identifier || attrs.field_identifier { return Err(Error::invalid_phased_type_usage( path, "`#[serde(variant_identifier)]` and `#[serde(field_identifier)]` are only valid on enums", )); } if attrs.untagged { return Err(Error::invalid_phased_type_usage( path, "`#[serde(untagged)]` is only valid on enums", )); } if attrs.content.is_some() { return Err(Error::invalid_phased_type_usage( path, "`#[serde(content = ...)]` is only valid on enums", )); } if attrs.tag.is_some() && !matches!(&strct.fields, Fields::Named(_)) { return Err(Error::invalid_phased_type_usage( path, "`#[serde(tag = ...)]` on structs requires named fields", )); } } match &strct.fields { Fields::Unit => {} Fields::Unnamed(unnamed) => { for (idx, (_, ty)) in unnamed .fields .iter() .filter_map(|field| field.ty.as_ref().map(|ty| (field, ty))) .enumerate() { inner( ty, types, checked_references, format!("{path}[{idx}]"), mode, follow_named_references, )?; } } Fields::Named(named) => { for (name, (field, _)) in named .fields .iter() .filter_map(|(name, field)| field.ty.as_ref().map(|ty| (name, (field, ty)))) { validate_field_attributes(field, format!("{path}.{name}"), mode)?; } for (name, (_, ty)) in named .fields .iter() .filter_map(|(name, field)| field.ty.as_ref().map(|ty| (name, (field, ty)))) { inner( ty, types, checked_references, format!("{path}.{name}"), mode, follow_named_references, )?; } } } } DataType::Enum(enm) => { validate_container_attributes(&enm.attributes, types, checked_references, &path, mode)?; if SerdeContainerAttrs::from_attributes(&enm.attributes)? .is_some_and(|attrs| attrs.default) { return Err(Error::invalid_phased_type_usage( path, "`#[serde(default)]` is only valid on structs", )); } validate_identifier_enum(enm, &path, mode)?; validate_enum(enm, types, path.clone(), mode)?; for (variant_name, variant) in &enm.variants { validate_variant_attributes(variant, format!("{path}::{variant_name}"), mode)?; match &variant.fields { Fields::Unit => {} Fields::Named(named) => { for (name, (field, _)) in named.fields.iter().filter_map(|(name, field)| { field.ty.as_ref().map(|ty| (name, (field, ty))) }) { validate_field_attributes( field, format!("{path}::{variant_name}.{name}"), mode, )?; } for (name, (_, ty)) in named.fields.iter().filter_map(|(name, field)| { field.ty.as_ref().map(|ty| (name, (field, ty))) }) { inner( ty, types, checked_references, format!("{path}::{variant_name}.{name}"), mode, follow_named_references, )?; } } Fields::Unnamed(unnamed) => { for (idx, (field, _)) in unnamed .fields .iter() .filter_map(|field| field.ty.as_ref().map(|ty| (field, ty))) .enumerate() { validate_field_attributes( field, format!("{path}::{variant_name}[{idx}]"), mode, )?; } for (idx, (_, ty)) in unnamed .fields .iter() .filter_map(|field| field.ty.as_ref().map(|ty| (field, ty))) .enumerate() { inner( ty, types, checked_references, format!("{path}::{variant_name}[{idx}]"), mode, follow_named_references, )?; } } } } } DataType::Tuple(tuple) => { for (idx, ty) in tuple.elements.iter().enumerate() { inner( ty, types, checked_references, format!("{path}[{idx}]"), mode, follow_named_references, )?; } } DataType::Intersection(types_) => { for (idx, ty) in types_.iter().enumerate() { inner( ty, types, checked_references, format!("{path}."), mode, follow_named_references, )?; } } DataType::Reference(reference) => match reference { Reference::Named(reference) => { if let NamedReferenceType::Reference { generics: reference_generics, .. } = &reference.inner { for (_, dt) in reference_generics { inner( dt, types, checked_references, format!("{path}."), mode, follow_named_references, )?; } } if follow_named_references && !checked_references.contains(&Reference::Named(reference.clone())) { let reference_key = Reference::Named(reference.clone()); checked_references.insert(reference_key); if let Some(ty) = named_reference_ty(reference, types) { let name = types .get(reference) .map(|ndt| ndt.name.to_string()) .unwrap_or_else(|| path.clone()); inner( ty, types, checked_references, name, mode, follow_named_references, )?; } } } Reference::Opaque(reference) => { if let Some(phased) = reference.downcast_ref::() { if mode == ApplyMode::Unified { return Err(Error::invalid_phased_type_usage( path, "`specta_serde::Phased` requires `PhasesFormat`", )); } inner( &phased.serialize, types, checked_references, format!("{path}."), mode, follow_named_references, )?; inner( &phased.deserialize, types, checked_references, format!("{path}."), mode, follow_named_references, )?; } } }, DataType::Generic(_) | DataType::Primitive(_) => {} } Ok(()) } fn validate_identifier_enum(enm: &Enum, path: &str, mode: ApplyMode) -> Result<(), Error> { let Some(attrs) = SerdeContainerAttrs::from_attributes(&enm.attributes)? else { return Ok(()); }; if !attrs.variant_identifier && !attrs.field_identifier { return Ok(()); } if attrs.variant_identifier && attrs.field_identifier { return Err(Error::invalid_phased_type_usage( path, "`variant_identifier` and `field_identifier` cannot be used together", )); } if mode == ApplyMode::Unified { return Err(Error::invalid_phased_type_usage( path, "identifier enums require `PhasesFormat` because they widen deserialize-only input shape", )); } if attrs.variant_identifier && let Some((name, _)) = enm .variants .iter() .find(|(_, variant)| !matches!(&variant.fields, Fields::Unit)) { return Err(Error::invalid_phased_type_usage( path, format!( "`variant_identifier` requires all unit variants, but variant `{name}` is not unit" ), )); } if attrs.field_identifier { let variants = &enm.variants; for (idx, (name, variant)) in variants.iter().enumerate() { let is_last = idx + 1 == variants.len(); match &variant.fields { Fields::Unit => {} Fields::Unnamed(unnamed) if is_last && unnamed.fields.len() == 1 => {} _ => { return Err(Error::invalid_phased_type_usage( path, format!( "`field_identifier` requires unit variants and an optional final newtype fallback; invalid variant `{name}`" ), )); } } } } Ok(()) } fn validate_container_attributes( attrs: &specta::datatype::Attributes, types: &Types, checked_references: &mut HashSet, path: &str, mode: ApplyMode, ) -> Result<(), Error> { if let Some(parsed) = SerdeContainerAttrs::from_attributes(attrs)? && parsed.from.is_some() && parsed.try_from.is_some() { return Err(Error::invalid_conversion_usage( path, "`from` and `try_from` cannot be used together", )); } if let Some(conversions) = SerdeContainerAttrs::from_attributes(attrs)? { for (suffix, target) in [ ("", conversions.resolved_into.as_ref()), ("", conversions.resolved_from.as_ref()), ("", conversions.resolved_try_from.as_ref()), ] { if let Some(target) = target { inner( target, types, checked_references, format!("{path}.{suffix}"), mode, true, )?; } } } Ok(()) } fn validate_variant_attributes( variant: &Variant, path: String, mode: ApplyMode, ) -> Result<(), Error> { let Some(serde_attrs) = SerdeVariantAttrs::from_attributes(&variant.attributes)? else { return Ok(()); }; let has_type_override = has_type_override(&variant.attributes); if serde_attrs.has_serialize_with { ensure_codec_override(has_type_override, &path, "serialize_with")?; } if serde_attrs.has_deserialize_with { ensure_codec_override(has_type_override, &path, "deserialize_with")?; } if serde_attrs.has_with { ensure_codec_override(has_type_override, &path, "with")?; } if mode == ApplyMode::Unified && serde_attrs.untagged && serde_attrs.skip_serializing != serde_attrs.skip_deserializing { return Err(Error::invalid_phased_type_usage( path, "phase-specific `#[serde(untagged)]` variants require `PhasesFormat` because unified mode would drop one branch", )); } Ok(()) } fn validate_field_attributes(field: &Field, path: String, mode: ApplyMode) -> Result<(), Error> { let Some(serde_attrs) = SerdeFieldAttrs::from_attributes(&field.attributes)? else { return Ok(()); }; if mode == ApplyMode::Unified && let (Some(serialize), Some(deserialize)) = ( serde_attrs.rename_serialize.as_deref(), serde_attrs.rename_deserialize.as_deref(), ) && serialize != deserialize { return Err(Error::incompatible_rename( "field rename", path, Some(serialize.to_string()), Some(deserialize.to_string()), )); } let has_type_override = has_type_override(&field.attributes); if serde_attrs.has_serialize_with { ensure_codec_override(has_type_override, &path, "serialize_with")?; } if serde_attrs.has_deserialize_with { ensure_codec_override(has_type_override, &path, "deserialize_with")?; } if serde_attrs.has_with { ensure_codec_override(has_type_override, &path, "with")?; } if mode == ApplyMode::Unified && serde_attrs.skip_serializing_if.is_some() { return Err(Error::invalid_phased_type_usage( path, "`skip_serializing_if` requires `PhasesFormat` because unified mode cannot represent conditional omission", )); } Ok(()) } fn ensure_codec_override( has_type_override: bool, path: &str, attr: &'static str, ) -> Result<(), Error> { if has_type_override { return Ok(()); } Err(Error::unsupported_serde_custom_codec( path.to_string(), attr, )) } fn has_type_override(attributes: &specta::datatype::Attributes) -> bool { attributes .get_named_as::("specta:type_override") .copied() .unwrap_or(false) } fn validate_enum(enm: &Enum, types: &Types, path: String, mode: ApplyMode) -> Result<(), Error> { let valid_variants = enm .variants .iter() .filter(|(_, variant)| !variant.skip) .count(); if valid_variants == 0 && !&enm.variants.is_empty() { return Err(Error::invalid_usage_of_skip( path, "all variants are skipped, resulting in an invalid non-empty enum", )); } let repr = EnumRepr::from_attrs(&enm.attributes)?; validate_untagged_variants(enm, &path)?; validate_other_variant(enm, &path, &repr, mode)?; if matches!(repr, EnumRepr::Internal { .. }) { validate_internally_tag_enum(enm, types, path)?; } Ok(()) } fn validate_untagged_variants(enm: &Enum, path: &str) -> Result<(), Error> { let mut seen_untagged = false; for (name, variant) in &enm.variants { let is_untagged = SerdeVariantAttrs::from_attributes(&variant.attributes)? .is_some_and(|attrs| attrs.untagged); if is_untagged { seen_untagged = true; continue; } if seen_untagged && !variant.skip { return Err(Error::invalid_phased_type_usage( path, format!( "`#[serde(untagged)]` variants must be ordered last, but variant `{name}` appears after an untagged variant" ), )); } } Ok(()) } fn validate_other_variant( enm: &Enum, path: &str, repr: &EnumRepr, mode: ApplyMode, ) -> Result<(), Error> { let mut other_variants = Vec::new(); for (name, variant) in &enm.variants { if SerdeVariantAttrs::from_attributes(&variant.attributes)?.is_some_and(|attrs| attrs.other) { other_variants.push((name, variant)); } } if other_variants.is_empty() { return Ok(()); } if mode == ApplyMode::Unified { return Err(Error::invalid_phased_type_usage( path, "`#[serde(other)]` requires `PhasesFormat` because it widens deserialize-only input shape", )); } if !matches!(repr, EnumRepr::Internal { .. } | EnumRepr::Adjacent { .. }) { return Err(Error::invalid_phased_type_usage( path, "`#[serde(other)]` requires a tagged enum representation (`tag` with optional `content`)", )); } if other_variants.len() > 1 { return Err(Error::invalid_phased_type_usage( path, "`#[serde(other)]` can only be used on a single enum variant", )); } let (name, variant) = other_variants[0]; if !matches!(&variant.fields, Fields::Unit) { return Err(Error::invalid_phased_type_usage( path, format!("`#[serde(other)]` variant `{name}` must be a unit variant"), )); } Ok(()) } fn validate_internally_tag_enum(enm: &Enum, types: &Types, path: String) -> Result<(), Error> { for (variant_name, variant) in &enm.variants { validate_internally_tag_variant(enm, variant_name, variant, types, &path)?; } Ok(()) } fn validate_internally_tag_variant( enm: &Enum, variant_name: &str, variant: &Variant, types: &Types, path: &str, ) -> Result<(), Error> { let _ = enm; if SerdeVariantAttrs::from_attributes(&variant.attributes)?.is_some_and(|attrs| attrs.untagged) { return Ok(()); } match &variant.fields { Fields::Unit | Fields::Named(_) => Ok(()), Fields::Unnamed(unnamed) => { let mut fields = unnamed .fields .iter() .filter_map(|field| field.ty.as_ref().map(|ty| (field, ty))); let Some((_, first_field)) = fields.next() else { return Ok(()); }; if fields.next().is_some() { return Err(Error::invalid_internally_tagged_enum( path, variant_name, "tuple variant must have at most one non-skipped field", )); } validate_internally_tag_enum_datatype(first_field, types, path, variant_name) } } } fn validate_internally_tag_enum_datatype( ty: &DataType, types: &Types, path: &str, variant_name: &str, ) -> Result<(), Error> { match ty { DataType::Map(_) => Ok(()), DataType::Struct(_) => Ok(()), DataType::Reference(Reference::Named(reference)) if matches!(reference.inner, NamedReferenceType::Inline { .. }) => { if let Some(ty) = named_reference_ty(reference, types) { validate_internally_tag_enum_datatype(ty, types, path, variant_name)?; } Ok(()) } DataType::Enum(enm) => match EnumRepr::from_attrs(&enm.attributes)? { EnumRepr::Untagged => validate_internally_tag_enum(enm, types, path.to_string()), EnumRepr::External | EnumRepr::Internal { .. } | EnumRepr::Adjacent { .. } => Ok(()), }, DataType::Tuple(tuple) if tuple.elements.is_empty() => Ok(()), DataType::Reference(Reference::Named(reference)) => { if let Some(ty) = named_reference_ty(reference, types) { validate_internally_tag_enum_datatype(ty, types, path, variant_name)?; } Ok(()) } DataType::Reference(Reference::Opaque(_)) | DataType::Generic(_) | DataType::Intersection(_) | DataType::Tuple(_) | DataType::Primitive(_) | DataType::List(_) | DataType::Nullable(_) => Err(Error::invalid_internally_tagged_enum( path, variant_name, "payload cannot be merged with an internal tag", )), } } fn named_reference_ty<'a>( reference: &'a specta::datatype::NamedReference, types: &'a Types, ) -> Option<&'a DataType> { match &reference.inner { NamedReferenceType::Inline { dt, .. } => Some(dt), NamedReferenceType::Reference { .. } => types.get(reference)?.ty.as_ref(), NamedReferenceType::Recursive => None, } } ================================================ FILE: specta-swift/Cargo.toml ================================================ [package] name = "specta-swift" description = "Export your Rust types to Swift" version = "0.0.2" authors = ["Jamie Pine ", "Oscar Beaumont "] edition = "2024" license = "MIT" repository = "https://github.com/specta-rs/specta" documentation = "https://docs.rs/specta-swift/latest/specta-swift" keywords = ["async", "specta", "rspc", "swift", "typesafe"] categories = ["web-programming", "asynchronous"] # /bin/sh RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features [package.metadata."docs.rs"] all-features = true rustdoc-args = ["--cfg", "docsrs"] [lints] workspace = true [dependencies] specta = { version = "=2.0.0-rc.24", path = "../specta", features = ["derive", "uuid", "chrono"] } thiserror = "2.0" serde = { version = "1.0", features = ["derive"] } [dev-dependencies] insta = "1.47" trybuild = "1.0" specta-serde = { version = "=0.0.11", path = "../specta-serde" } uuid = "1.23.1" chrono = { version = "0.4.44", features = ["clock"] } [[example]] name = "basic_types" path = "examples/basic_types.rs" [[example]] name = "advanced_unions" path = "examples/advanced_unions.rs" [[example]] name = "configuration_options" path = "examples/configuration_options.rs" [[example]] name = "special_types" path = "examples/special_types.rs" [[example]] name = "string_enums" path = "examples/string_enums.rs" [[example]] name = "comprehensive_demo" path = "examples/comprehensive_demo.rs" ================================================ FILE: specta-swift/README.md ================================================ # Specta Swift [![Crates.io](https://img.shields.io/crates/v/specta-swift.svg)](https://crates.io/crates/specta-swift) [![Documentation](https://docs.rs/specta-swift/badge.svg)](https://docs.rs/specta-swift) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) A Rust crate for exporting Rust types to Swift, built on top of [Specta](https://github.com/specta-rs/specta). Generate idiomatic Swift code from your Rust type definitions with support for complex unions, generics, and nested structures. ## Features - 🚀 **Zero Runtime Cost** - Compile-time type generation - 🎯 **Idiomatic Swift** - Generates clean, Swift-idiomatic code - 🔄 **Complex Unions** - Full support for Rust enums with all variant types - 🧬 **Generics** - Single and multiple generic type parameters - 🔗 **Recursive Types** - Self-referencing and circular type definitions - ⚙️ **Highly Configurable** - Naming conventions, indentation styles, optional syntax - 📦 **Type Safety** - Leverages Specta's robust type introspection - 🧪 **Well Tested** - Comprehensive test suite with snapshot testing - 🕒 **Special Types** - Built-in support for Duration with helper structs - 📝 **Documentation** - Preserves and formats Rust doc comments in Swift - 🔧 **Custom Codable** - Automatic generation of custom Codable implementations - 🎨 **Protocol Conformance** - Support for additional Swift protocols - 📁 **File Export** - Direct export to Swift files with custom headers ## Quick Start Add `specta-swift` and `specta-serde` to your `Cargo.toml`: ```toml [dependencies] specta = { version = "2.0", features = ["derive"] } specta-serde = "0.0.11" specta-swift = "0.1" ``` Define your Rust types: ```rust use specta::{Type, Types}; use specta_swift::Swift; #[derive(Type)] struct User { id: u32, name: String, email: Option, role: UserRole, } #[derive(Type)] enum UserRole { Guest, User { permissions: Vec }, Admin { level: u8, department: String }, } #[derive(Type)] enum ApiResult { Success { data: T, status: u16 }, Error { message: String, code: u32 }, Loading { progress: f32 }, } ``` Generate Swift code: ```rust fn main() { let types = Types::default() .register::() .register::() .register::>(); let swift = Swift::default(); swift .export_to("./Types.swift", &types, specta_serde::format) .unwrap(); } ``` This generates: ```swift // This file has been generated by Specta. DO NOT EDIT. import Foundation enum ApiResult: Codable { case success(data: T, status: UInt16) case error(message: String, code: UInt32) case loading(progress: Float) } struct User: Codable { let id: UInt32 let name: String let email: String? let role: UserRole } enum UserRole: Codable { case guest case user(permissions: [String]) case admin(level: UInt8, department: String) } ``` ## Advanced Features ### Complex Union Types Specta Swift supports all Rust enum variant types: ```rust #[derive(Type)] enum ComplexUnion { // Unit variant None, // Tuple variant Tuple(String, u32, bool), // Named fields variant NamedFields { id: u32, name: String, active: bool, }, // Nested struct variant UserStruct(User), // Nested enum variant UserType(UserType), // Complex nested structure Complex { user: User, metadata: Vec, settings: Option, }, } ``` Generates: ```swift enum ComplexUnion: Codable { case none case tuple(String, UInt32, Bool) case namedfields(id: UInt32, name: String, active: Bool) case userstruct(User) case usertype(UserType) case complex(user: User, metadata: [String], settings: Admin?) } ``` ### Generic Types Full support for generic types with multiple parameters: ```rust #[derive(Type)] enum DatabaseResult { Ok { data: T, affected_rows: u64 }, Err { error: E, query: String }, ConnectionError { host: String, port: u16 }, } ``` ### Recursive Types Self-referencing types are fully supported: ```rust #[derive(Type)] enum Shape { None, Point(f64, f64), Circle { center: Point, radius: f64 }, Complex { shapes: Vec, metadata: Option }, } ``` ## Configuration ### Naming Conventions ```rust use specta_swift::{Swift, NamingConvention}; // PascalCase (default) let swift = Swift::default(); // camelCase let swift = Swift::new().naming(NamingConvention::CamelCase); // snake_case let swift = Swift::new().naming(NamingConvention::SnakeCase); ``` ### Optional Styles ```rust use specta_swift::{Swift, OptionalStyle}; // T? syntax (default) let swift = Swift::default(); // Optional syntax let swift = Swift::new().optionals(OptionalStyle::Optional); ``` ### Indentation Styles ```rust use specta_swift::{Swift, IndentStyle}; // 4 spaces (default) let swift = Swift::default(); // 2 spaces let swift = Swift::new().indent(IndentStyle::Spaces(2)); // Tabs let swift = Swift::new().indent(IndentStyle::Tabs); ``` ### Custom Headers ```rust let swift = Swift::new() .header("// Generated by MyApp v2.0\n// Custom header with app info\n// DO NOT EDIT MANUALLY") .naming(NamingConvention::SnakeCase); ``` ### Additional Protocols ```rust let swift = Swift::new() .add_protocol("Equatable") .add_protocol("Hashable") .add_protocol("CustomStringConvertible"); ``` ### Serde Integration ```rust let swift = Swift::new() .add_protocol("CustomDebugStringConvertible"); let output = swift.export(&types, specta_serde::format).unwrap(); ``` ## Type Mapping | Rust Type | Swift Type | Notes | | ------------------------- | ------------------------------------- | ------------------------------ | | `i8`, `i16`, `i32`, `i64` | `Int8`, `Int16`, `Int32`, `Int64` | Signed integers | | `u8`, `u16`, `u32`, `u64` | `UInt8`, `UInt16`, `UInt32`, `UInt64` | Unsigned integers | | `f32`, `f64` | `Float`, `Double` | Floating point numbers | | `bool` | `Bool` | Boolean values | | `char` | `Character` | Single Unicode character | | `String` | `String` | UTF-8 strings | | `Option` | `T?` or `Optional` | Optional values (configurable) | | `Vec` | `[T]` | Arrays | | `Vec>` | `[[T]]` | Nested arrays | | `HashMap` | `[K: V]` | Dictionaries | | `(T, U)` | `(T, U)` | Tuples | | `std::time::Duration` | `RustDuration` + helper | With automatic helper struct | | `struct` | `struct` | Structures | | `enum` | `enum` | Enums with custom Codable | ## Special Features ### Duration Support `std::time::Duration` types are automatically converted to a `RustDuration` helper struct: ```rust #[derive(Type)] struct Metrics { processing_time: Duration, timeout: Duration, } ``` Generates: ```swift // MARK: - Duration Helper public struct RustDuration: Codable { public let secs: UInt64 public let nanos: UInt32 public var timeInterval: TimeInterval { return Double(secs) + Double(nanos) / 1_000_000_000.0 } } public struct Metrics: Codable { public let processingTime: RustDuration public let timeout: RustDuration } ``` ### Documentation Support Rust doc comments are preserved and formatted for Swift: ```rust /// A comprehensive user account /// /// This struct represents a complete user account with all necessary /// information for authentication and personalization. /// /// # Security Notes /// - The password field should never be logged /// - All timestamps are in UTC #[derive(Type)] struct User { /// Unique identifier id: u32, /// User's display name name: String, } ``` Generates: ```swift /// A comprehensive user account /// /// This struct represents a complete user account with all necessary /// information for authentication and personalization. /// /// # Security Notes /// - The password field should never be logged /// - All timestamps are in UTC public struct User: Codable { /// Unique identifier public let id: UInt32 /// User's display name public let name: String } ``` ## Examples Check out the `examples/` directory for comprehensive examples: - `basic_types.rs` - Basic primitive types and their Swift equivalents - `advanced_unions.rs` - Complex enum scenarios and custom Codable implementations - `configuration_options.rs` - All Swift exporter configuration settings - `special_types.rs` - Duration types and special type handling - `string_enums.rs` - String enums and custom Codable patterns - `comprehensive_demo.rs` - Complete feature showcase (28 types!) - `simple_usage.rs` - Quick start example - `comments_example.rs` - Documentation and comment support Run any example: ```bash cargo run --example basic_types cargo run --example comprehensive_demo ``` Generated Swift files are saved to `examples/generated/` for inspection. ## Testing Run the test suite: ```bash cargo test ``` The test suite includes: - Basic type generation tests - Comprehensive union type tests - Advanced recursive type tests - Duration type mapping tests - Custom Codable implementation tests - Configuration option tests - Snapshot testing for generated code - String enum handling tests - Generic type parameter tests ## Contributing Contributions are welcome! Please see the main [Specta repository](https://github.com/specta-rs/specta) for contribution guidelines. ## License This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. ## Related Projects - [Specta](https://github.com/specta-rs/specta) - Core type introspection library - [Specta TypeScript](https://github.com/specta-rs/specta/tree/main/specta-typescript) - TypeScript exporter - [Specta Go](https://github.com/specta-rs/specta/tree/main/specta-go) - Go exporter ================================================ FILE: specta-swift/Types.swift ================================================ // This file has been generated by Specta. DO NOT EDIT. import Foundation public struct MyOtherType: Codable { public let otherField: String private enum CodingKeys: String, CodingKey { case otherField = "other_field" } } public struct MyType: Codable { public let field: MyOtherType } ================================================ FILE: specta-swift/examples/README.md ================================================ # specta-swift Examples This directory contains comprehensive examples demonstrating ALL the functionality of the `specta-swift` library. Each example focuses on different aspects of the Swift code generation capabilities. ## 📚 Available Examples ### 1. **`basic_types.rs`** - Fundamental Type Mappings Demonstrates basic Rust to Swift type conversions: - ✅ Primitive types (i8, u32, f64, bool, char, String) - ✅ Optional types (Option → T?) - ✅ Collections (Vec → [T]) - ✅ Nested collections (Vec> → [[T]]) - ✅ Tuple types ((String, String) → (String, String)) - ✅ Simple enums with different variant types - ✅ Generic structs with type parameters - ✅ Complex nested struct relationships **Run:** `cargo run --example basic_types` **Output:** `examples/generated/BasicTypes.swift` ### 2. **`advanced_unions.rs`** - Complex Enum Scenarios Showcases advanced enum patterns and custom Codable implementations: - ✅ Complex enums with mixed variant types - ✅ Generic enums with type parameters - ✅ Recursive type definitions (Tree) - ✅ Nested struct references in enum variants - ✅ String enums with automatic Codable - ✅ Mixed enums (both simple and complex variants) - ✅ Custom Codable implementations for complex enums - ✅ Struct generation for named field variants **Run:** `cargo run --example advanced_unions` **Output:** `examples/generated/AdvancedUnions.swift` ### 3. **`configuration_options.rs`** - All Swift Exporter Settings Comprehensive demonstration of every configuration option: - ✅ Custom headers and documentation - ✅ Naming conventions (PascalCase, camelCase, snake_case) - ✅ Indentation styles (spaces, tabs, different widths) - ✅ Generic type styles (protocol constraints vs typealias) - ✅ Optional type styles (question mark vs Optional) - ✅ Additional protocol conformance - ✅ Serde validation settings - ✅ Combined custom configurations **Run:** `cargo run --example configuration_options` **Output:** `examples/generated/` (multiple configuration files) ### 4. **`special_types.rs`** - Duration and Special Type Handling Demonstrates special type conversions and helper generation: - ✅ Duration type mapping to RustDuration helper - ✅ Automatic helper struct generation - ✅ timeInterval property for Swift integration - ✅ Duration fields in structs and enum variants - ✅ Optional Duration fields - ✅ Performance metrics with timing information - ✅ Complex timing-related data structures **Run:** `cargo run --example special_types` **Output:** `examples/generated/SpecialTypes.swift` ### 5. **`string_enums.rs`** - String Enums and Custom Codable Focuses on enum patterns and Codable implementations: - ✅ Pure string enums (String, Codable) - ✅ Mixed enums with both simple and complex variants - ✅ Custom Codable implementations for complex enums - ✅ Struct generation for named field variants - ✅ Generic enum support - ✅ Proper Swift enum case naming - ✅ Automatic protocol conformance **Run:** `cargo run --example string_enums` **Output:** `examples/generated/StringEnums.swift` ### 6. **`comprehensive_demo.rs`** - Complete Feature Showcase The ultimate example demonstrating EVERY feature in a realistic application: - ✅ All basic and advanced type patterns - ✅ Complex nested relationships - ✅ User management with permissions - ✅ Task management with status tracking - ✅ File attachment handling - ✅ Comment and review systems - ✅ API response patterns - ✅ System monitoring types - ✅ Health monitoring and metrics - ✅ Pagination and metadata **Run:** `cargo run --example comprehensive_demo` **Output:** `examples/generated/ComprehensiveDemo.swift` ### 7. **`simple_usage.rs`** - Quick Start Example A simple, focused example for getting started quickly: - ✅ Basic struct and enum definitions - ✅ Default Swift configuration - ✅ Custom configuration demonstration - ✅ File export functionality **Run:** `cargo run --example simple_usage` **Output:** `examples/generated/SimpleTypes.swift`, `examples/generated/CustomTypes.swift` ### 8. **`comments_example.rs`** - Documentation and Comments Demonstrates comprehensive documentation support: - ✅ Multi-line type documentation - ✅ Field-level documentation - ✅ Complex technical descriptions - ✅ Swift-compatible doc comments - ✅ Bullet points and formatting **Run:** `cargo run --example comments_example` **Output:** `examples/generated/CommentsExample.swift` ## 🚀 Quick Start To run any example: ```bash cd specta-swift cargo run --example ``` For example: ```bash cargo run --example basic_types cargo run --example comprehensive_demo ``` ## 📁 Generated Files Each example generates Swift files in the `examples/generated/` directory that you can inspect: - `examples/generated/BasicTypes.swift` - From basic_types example - `examples/generated/AdvancedUnions.swift` - From advanced_unions example - `examples/generated/SpecialTypes.swift` - From special_types example - `examples/generated/StringEnums.swift` - From string_enums example - `examples/generated/ComprehensiveDemo.swift` - From comprehensive_demo example - `examples/generated/CommentsExample.swift` - From comments_example - `examples/generated/SimpleTypes.swift` & `examples/generated/CustomTypes.swift` - From simple_usage - Multiple configuration files from the configuration_options example ## 🔍 Key Features Demonstrated ### Type System Support - ✅ All Rust primitive types - ✅ Optional types with proper Swift syntax - ✅ Collections and nested collections - ✅ Tuple types - ✅ Generic types with constraints - ✅ Complex nested relationships ### Enum Handling - ✅ Unit variants - ✅ Tuple variants - ✅ Named field variants - ✅ String enums with automatic Codable - ✅ Mixed enums with custom implementations - ✅ Generic enums - ✅ Recursive enum definitions ### Special Types - ✅ Duration → RustDuration helper - ✅ Automatic helper struct generation - ✅ timeInterval property for Swift integration - ✅ Proper Codable implementations ### Configuration Options - ✅ All naming conventions - ✅ All indentation styles - ✅ Generic type styles - ✅ Optional type styles - ✅ Additional protocols - ✅ Custom headers and documentation ### Code Generation Quality - ✅ Proper Swift naming conventions - ✅ Comprehensive Codable implementations - ✅ Error handling in custom Codable - ✅ Documentation preservation - ✅ Clean, readable Swift code ## 💡 Usage Tips 1. **Start with `basic_types`** to understand fundamental mappings 2. **Use `comprehensive_demo`** to see everything in action 3. **Check `configuration_options`** to customize your output 4. **Examine generated `.swift` files** to see the actual output 5. **Use `special_types`** if you work with Duration types 6. **Reference `string_enums`** for enum patterns ## 🎯 Real-World Applications These examples demonstrate patterns commonly used in: - 📱 iOS/macOS app development - 🔄 API client generation - 📊 Data serialization/deserialization - 🏗️ Cross-platform type sharing - 📈 Performance monitoring - 👥 User management systems - 📋 Task management applications --- **Happy coding! 🎉** These examples should give you everything you need to leverage the full power of `specta-swift` in your projects. ================================================ FILE: specta-swift/examples/advanced_unions.rs ================================================ #![allow(dead_code, missing_docs)] use specta::{Type, Types}; use specta_swift::Swift; /// Advanced example showcasing complex enum unions and their Swift representations /// /// This example demonstrates how specta-swift handles complex enum scenarios /// including nested types, generic enums, and custom Codable implementations. /// Complex enum with mixed variant types #[derive(Type)] enum ApiResult { /// Success with data and metadata Ok { data: T, status: u16, headers: Option>, timestamp: String, }, /// Error with detailed information Err { error: E, code: u32, message: String, retry_after: Option, }, /// Loading state with progress Loading { progress: f32, estimated_completion: Option, }, } /// Enum demonstrating different field patterns #[derive(Type)] enum Shape { /// Unit variant None, /// Tuple variant Point(f64, f64), /// Named fields variant Circle { center: Point, radius: f64 }, /// Referencing another struct Rectangle(Rectangle), /// Complex nested variant Line { start: Point, end: Point, style: LineStyle, }, /// Very complex variant with multiple fields Complex { vertices: Vec, fill_color: Color, stroke_color: Option, stroke_width: f64, is_closed: bool, }, } /// Supporting structs for the Shape enum #[derive(Type)] struct Point { x: f64, y: f64, } #[derive(Type)] struct Rectangle { top_left: Point, bottom_right: Point, } #[derive(Type)] struct LineStyle { dash_pattern: Option>, cap_style: String, join_style: String, } #[derive(Type)] struct Color { red: f64, green: f64, blue: f64, alpha: f64, } /// Generic enum with constraints #[derive(Type)] enum Container { Empty, Single(T), Multiple(Vec), KeyValue(Vec<(String, T)>), } /// Enum with recursive references #[derive(Type)] enum Tree { Leaf(T), Branch { left: Box>, right: Box>, value: T, }, } /// String enum (will be converted to Swift String enum with Codable) #[derive(Type)] enum JobStatus { /// Job is queued and waiting to start Queued, /// Job is currently running Running, /// Job is paused (can be resumed) Paused, /// Job completed successfully Completed, /// Job failed with an error Failed, /// Job was cancelled by user Cancelled, } /// Mixed enum with both string-like and data variants #[derive(Type)] enum MixedEnum { /// Simple string-like variant Simple(String), /// Complex data variant WithFields { id: u32, name: String, metadata: Option>, }, /// Another simple variant Empty, } /// Event system enum #[derive(Type)] enum Event { /// User-related events User { user_id: u32, action: String, timestamp: String, }, /// System events System { component: String, level: String, message: String, }, /// Error events Error { code: u32, message: String, stack_trace: Option, }, } fn main() { println!("🚀 Advanced Unions Example - Complex enum scenarios"); println!("{}", "=".repeat(60)); // Create type collection let types = Types::default() .register::>() .register::() .register::() .register::() .register::() .register::() .register::>() .register::>() .register::() .register::() .register::(); // Export with default settings let swift = Swift::default(); let output = swift.export(&types, specta_serde::Format).unwrap(); println!("📝 Generated Swift code:\n"); println!("{}", output); // Write to file for inspection swift .export_to( "./examples/generated/AdvancedUnions.swift", &types, specta_serde::Format, ) .unwrap(); println!("✅ Advanced unions exported to AdvancedUnions.swift"); println!("\n🔍 Key Features Demonstrated:"); println!("• Complex enum variants with named fields"); println!("• Generic enums with type parameters"); println!("• String enums with automatic Codable implementation"); println!("• Mixed enums (both simple and complex variants)"); println!("• Recursive type definitions"); println!("• Nested struct references in enum variants"); println!("• Custom Codable implementations for complex enums"); println!("• Struct generation for named field variants"); println!("• Tuple variant handling"); } ================================================ FILE: specta-swift/examples/basic_types.rs ================================================ #![allow(dead_code, missing_docs)] use specta::{Type, Types}; use specta_swift::Swift; /// Comprehensive example showcasing basic Rust types and their Swift equivalents /// /// This example demonstrates how specta-swift handles fundamental Rust types /// and converts them to appropriate Swift types. /// Basic primitive types #[derive(Type)] struct Primitives { // Integer types small_int: i8, unsigned_small: u8, short_int: i16, unsigned_short: u16, regular_int: i32, unsigned_int: u32, long_int: i64, unsigned_long: u64, // Float types single_precision: f32, double_precision: f64, // Boolean and character is_active: bool, single_char: char, // String types name: String, optional_name: Option, // Collections tags: Vec, scores: Vec, user_ids: Vec, // Nested collections matrix: Vec>, string_pairs: Vec<(String, String)>, } /// Enum with different variant types #[derive(Type)] enum Status { /// Simple unit variant Active, /// Tuple variant with single value Pending(String), /// Tuple variant with multiple values Error(String, u32), /// Named field variant Loading { progress: f32, message: Option, }, } /// Generic struct demonstrating type parameters #[derive(Type)] struct ApiResponse { data: Option, error: Option, status_code: u16, headers: Vec<(String, String)>, } /// Nested struct demonstrating complex relationships #[derive(Type)] struct User { id: u32, username: String, email: String, profile: UserProfile, preferences: UserPreferences, status: Status, metadata: Option, } #[derive(Type)] struct UserProfile { first_name: String, last_name: String, bio: Option, avatar_url: Option, birth_date: Option, } #[derive(Type)] struct UserPreferences { theme: String, language: String, notifications_enabled: bool, privacy_level: u8, } #[derive(Type)] struct UserMetadata { created_at: String, last_login: Option, login_count: u32, is_verified: bool, } fn main() { println!("🚀 Basic Types Example - Generating Swift from Rust types"); println!("{}", "=".repeat(60)); // Create type collection with all our types let types = Types::default() .register::() .register::() .register::>() .register::() .register::() .register::() .register::(); // Export with default settings let swift = Swift::default(); let output = swift.export(&types, specta_serde::Format).unwrap(); println!("📝 Generated Swift code:\n"); println!("{}", output); // Write to file for inspection swift .export_to( "./examples/generated/BasicTypes.swift", &types, specta_serde::Format, ) .unwrap(); println!("✅ Basic types exported to BasicTypes.swift"); println!("\n🔍 Key Features Demonstrated:"); println!("• Primitive type mappings (i32 → Int32, f64 → Double, etc.)"); println!("• Optional types (Option → String?)"); println!("• Collections (Vec → [T])"); println!("• Nested collections (Vec> → [[Double]])"); println!("• Enum variants (unit, tuple, named fields)"); println!("• Generic types with type parameters"); println!("• Complex nested struct relationships"); println!("• Tuple types ((String, String) → (String, String))"); } ================================================ FILE: specta-swift/examples/comments_example.rs ================================================ #![allow(dead_code, missing_docs)] use specta::{Type, Types}; use specta_swift::Swift; /// A comprehensive example demonstrating multi-line comment support /// /// This example shows how Specta Swift handles complex documentation /// including: /// - Multi-line type documentation /// - Bullet points and formatting /// - Complex technical descriptions /// /// The generated Swift code will have properly formatted doc comments /// that are compatible with Swift's documentation system. #[derive(Type)] enum ApiResponse { /// Successful response containing the requested data /// /// This variant is returned when the API call completes successfully /// and contains the expected data type. The status code indicates /// the HTTP response status (200, 201, etc.). Success { /// The actual data returned by the API data: T, /// HTTP status code (200, 201, 204, etc.) status: u16, /// Optional response headers headers: Option>, }, /// Error response indicating a failure /// /// This variant is returned when the API call fails for any reason. /// The error contains detailed information about what went wrong /// and how to potentially resolve the issue. Error { /// Human-readable error message message: String, /// Machine-readable error code code: u32, /// Optional additional error details details: Option, }, /// Loading state for asynchronous operations /// /// This variant is used for long-running operations where the client /// needs to show progress to the user. The progress value ranges /// from 0.0 (not started) to 1.0 (completed). Loading { /// Progress value between 0.0 and 1.0 progress: f32, /// Optional estimated time remaining in seconds estimated_time: Option, }, } /// A user account in the system /// /// This struct represents a complete user account with all necessary /// information for authentication, authorization, and personalization. /// /// # Security Notes /// - The `password_hash` field should never be logged or exposed /// - The `api_key` is sensitive and should be treated as a secret /// - All timestamps are in UTC #[derive(Type)] struct User { /// Unique identifier for the user /// /// This ID is generated when the user first registers and never /// changes throughout the user's lifetime in the system. id: u32, /// The user's chosen username /// /// Must be unique across the entire system. Usernames are /// case-insensitive and can contain letters, numbers, and underscores. username: String, /// The user's email address /// /// Used for authentication, password resets, and notifications. /// Must be a valid email format and unique across the system. email: String, /// Whether the user account is currently active /// /// Inactive users cannot log in or perform any actions. /// This is typically set to false when an account is suspended /// or when the user requests account deletion. is_active: bool, /// When the user account was created /// /// Timestamp in UTC when the user first registered. created_at: String, /// When the user last logged in /// /// Updated on every successful login. Can be None if the user /// has never logged in (e.g., account created but not activated). last_login: Option, } fn main() { let types = Types::default() .register::>() .register::(); let swift = Swift::default(); let output = swift.export(&types, specta_serde::Format).unwrap(); println!( "Generated Swift code with comprehensive comments:\n{}", output ); // Also write to file for inspection swift .export_to( "./examples/generated/CommentsExample.swift", &types, specta_serde::Format, ) .unwrap(); println!("\nComments example written to CommentsExample.swift"); } ================================================ FILE: specta-swift/examples/comprehensive_demo.rs ================================================ #![allow(dead_code, missing_docs)] use specta::{Type, Types}; use specta_swift::Swift; use std::time::Duration; /// Comprehensive demonstration of ALL specta-swift functionality /// /// This example showcases every feature and capability of specta-swift in a single, /// realistic application scenario. It demonstrates complex type relationships, /// various enum patterns, special types, and advanced features. /// Main application types for a task management system #[derive(Type)] struct Task { id: u32, title: String, description: Option, status: TaskStatus, priority: Priority, assignee: Option, created_at: String, updated_at: String, due_date: Option, duration: Option, tags: Vec, metadata: TaskMetadata, subtasks: Vec, } /// Task status enum with mixed variants #[derive(Type)] enum TaskStatus { /// Task is waiting to be started Todo, /// Task is currently in progress InProgress { started_at: String, estimated_completion: Option, progress: f32, }, /// Task is blocked by dependencies Blocked { reason: String, blocked_by: Vec, estimated_unblock: Option, }, /// Task is under review Review { reviewer: String, review_started_at: String, comments: Vec, }, /// Task is completed Completed { completed_at: String, completion_time: Duration, final_notes: Option, }, /// Task was cancelled Cancelled { reason: String, cancelled_at: String, }, } /// Priority enum (string enum) #[derive(Type)] enum Priority { Low, Medium, High, Critical, Emergency, } /// User information #[derive(Type)] struct User { id: u32, username: String, email: String, profile: UserProfile, preferences: UserPreferences, role: UserRole, is_active: bool, last_login: Option, created_at: String, } /// User profile with nested data #[derive(Type)] struct UserProfile { first_name: String, last_name: String, bio: Option, avatar_url: Option, timezone: String, language: String, } /// User preferences #[derive(Type)] struct UserPreferences { theme: Theme, notifications: NotificationSettings, privacy: PrivacySettings, display: DisplaySettings, } /// Theme enum (string enum) #[derive(Type)] enum Theme { Light, Dark, Auto, Custom, } /// Notification settings #[derive(Type)] struct NotificationSettings { email_enabled: bool, push_enabled: bool, sms_enabled: bool, desktop_enabled: bool, frequency: NotificationFrequency, } /// Notification frequency enum #[derive(Type)] enum NotificationFrequency { Immediate, Hourly, Daily, Weekly, Never, } /// Privacy settings #[derive(Type)] struct PrivacySettings { profile_visibility: Visibility, activity_visibility: Visibility, data_sharing: DataSharing, } /// Visibility enum #[derive(Type)] enum Visibility { Public, Friends, Private, Hidden, } /// Data sharing settings #[derive(Type)] struct DataSharing { analytics: bool, marketing: bool, third_party: bool, research: bool, } /// Display settings #[derive(Type)] struct DisplaySettings { items_per_page: u32, date_format: String, time_format: String, currency: String, compact_mode: bool, } /// User role with permissions #[derive(Type)] enum UserRole { /// Regular user with basic permissions User, /// Moderator with additional permissions Moderator { permissions: Vec, department: String, }, /// Administrator with full permissions Admin { level: AdminLevel, departments: Vec, special_access: Vec, }, /// Super admin with system-wide access SuperAdmin { system_access: bool, audit_logs: bool, }, } /// Admin level enum #[derive(Type)] enum AdminLevel { Junior, Senior, Lead, Director, } /// Task metadata #[derive(Type)] struct TaskMetadata { created_by: u32, last_modified_by: u32, version: u32, custom_fields: Vec<(String, String)>, attachments: Vec, watchers: Vec, dependencies: Vec, } /// File attachment #[derive(Type)] struct Attachment { id: String, filename: String, size: u64, mime_type: String, uploaded_at: String, uploaded_by: u32, } /// Subtask with timing information #[derive(Type)] struct SubTask { id: u32, title: String, description: Option, status: SubTaskStatus, estimated_duration: Duration, actual_duration: Option, assignee: Option, created_at: String, completed_at: Option, } /// Subtask status (simple enum) #[derive(Type)] enum SubTaskStatus { Pending, InProgress, Completed, Skipped, } /// Review comment #[derive(Type)] struct ReviewComment { id: u32, author: u32, content: String, created_at: String, updated_at: String, is_resolved: bool, parent_comment: Option, attachments: Vec, } /// API response wrapper #[derive(Type)] struct ApiResponse { data: Option, error: Option, status: ResponseStatus, metadata: ResponseMetadata, } /// Response status enum #[derive(Type)] enum ResponseStatus { Success, PartialSuccess, Error, ValidationError, AuthenticationError, AuthorizationError, NotFound, RateLimited, } /// Response metadata #[derive(Type)] struct ResponseMetadata { request_id: String, timestamp: String, processing_time: Duration, version: String, pagination: Option, } /// Pagination information #[derive(Type)] struct PaginationInfo { page: u32, per_page: u32, total_pages: u32, total_items: u64, has_next: bool, has_prev: bool, } /// System health information #[derive(Type)] struct SystemHealth { status: HealthStatus, uptime: Duration, last_check: String, services: Vec, metrics: SystemMetrics, } /// Health status enum #[derive(Type)] enum HealthStatus { Healthy, Degraded, Unhealthy, Unknown, } /// Service status #[derive(Type)] struct ServiceStatus { name: String, status: HealthStatus, response_time: Duration, last_check: String, error_count: u32, } /// System metrics #[derive(Type)] struct SystemMetrics { cpu_usage: f64, memory_usage: f64, disk_usage: f64, network_usage: f64, active_users: u32, total_requests: u64, error_rate: f64, } fn main() { println!("🚀 Comprehensive Demo - Complete specta-swift functionality showcase"); println!("{}", "=".repeat(80)); // Create comprehensive type collection let types = Types::default() // Core types .register::() .register::() .register::() .register::() .register::() .register::() .register::() .register::() .register::() .register::() .register::() .register::() .register::() .register::() .register::() .register::() .register::() .register::() .register::() .register::() // API types .register::>() .register::() .register::() .register::() // System types .register::() .register::() .register::() .register::(); // Export with default settings let total_types = types.len(); let swift = Swift::default(); let output = swift.export(&types, specta_serde::Format).unwrap(); println!("📝 Generated Swift code (first 2000 characters):\n"); let preview = if output.len() > 2000 { format!( "{}...\n\n[Output truncated - see ComprehensiveDemo.swift for full output]", &output[..2000] ) } else { output.clone() }; println!("{}", preview); // Write to file for inspection swift .export_to( "./examples/generated/ComprehensiveDemo.swift", &types, specta_serde::Format, ) .unwrap(); println!("✅ Comprehensive demo exported to ComprehensiveDemo.swift"); println!("\n🔍 Complete Feature Showcase:"); println!("• ✅ Basic primitive types (i32, f64, bool, String, etc.)"); println!("• ✅ Optional types (Option → T?)"); println!("• ✅ Collections (Vec → [T])"); println!("• ✅ Nested collections (Vec> → [[T]])"); println!("• ✅ Tuple types ((String, String) → (String, String))"); println!("• ✅ Complex struct relationships"); println!("• ✅ Generic types with type parameters"); println!("• ✅ String enums with automatic Codable"); println!("• ✅ Mixed enums with custom Codable implementations"); println!("• ✅ Named field variants with struct generation"); println!("• ✅ Duration types with RustDuration helper"); println!("• ✅ Nested enum variants"); println!("• ✅ Recursive type references"); println!("• ✅ Complex metadata structures"); println!("• ✅ API response patterns"); println!("• ✅ System monitoring types"); println!("• ✅ User management with permissions"); println!("• ✅ Task management with status tracking"); println!("• ✅ File attachment handling"); println!("• ✅ Comment and review systems"); println!("• ✅ Pagination and metadata"); println!("• ✅ Health monitoring and metrics"); println!("\n📊 Statistics:"); println!("• Total types registered: {}", total_types); println!("• Generated Swift code length: {} characters", output.len()); println!("• Lines of generated code: {}", output.lines().count()); println!("\n🎉 This example demonstrates EVERY feature of specta-swift!"); println!("Check ComprehensiveDemo.swift for the complete generated Swift code."); } ================================================ FILE: specta-swift/examples/configuration_options.rs ================================================ #![allow(dead_code, missing_docs)] use specta::{Type, Types}; use specta_swift::{GenericStyle, IndentStyle, NamingConvention, OptionalStyle, Swift}; /// Comprehensive example showcasing ALL configuration options for specta-swift /// /// This example demonstrates every configuration option available in the Swift exporter, /// showing how different settings affect the generated Swift code. /// Sample types for demonstration #[derive(Type)] struct User { user_id: u32, full_name: String, email_address: Option, is_verified: bool, } #[derive(Type)] enum ApiResponse { Success { data: T, status_code: u16 }, Error { message: String, error_code: u32 }, Loading { progress: f32 }, } #[derive(Type)] struct GenericContainer { primary: T, secondary: U, metadata: Option>, } fn main() { println!("🚀 Configuration Options Example - All Swift exporter settings"); println!("{}", "=".repeat(70)); // Sample types for all examples let types = Types::default() .register::() .register::>() .register::>(); // 1. DEFAULT CONFIGURATION println!("\n📋 1. DEFAULT CONFIGURATION"); println!("{}", "-".repeat(40)); let default_swift = Swift::default(); let default_output = default_swift.export(&types, specta_serde::Format).unwrap(); println!("{}", default_output); default_swift .export_to( "./examples/generated/DefaultConfig.swift", &types, specta_serde::Format, ) .unwrap(); println!("✅ Default configuration exported to DefaultConfig.swift"); // 2. CUSTOM HEADER println!("\n📋 2. CUSTOM HEADER"); println!("{}", "-".repeat(40)); let custom_header = Swift::new() .header("// Generated by MyAwesomeApp v2.0\n// Custom header with app info\n// DO NOT EDIT MANUALLY"); let header_output = custom_header.export(&types, specta_serde::Format).unwrap(); println!("{}", header_output); custom_header .export_to( "./examples/generated/CustomHeader.swift", &types, specta_serde::Format, ) .unwrap(); println!("✅ Custom header exported to CustomHeader.swift"); // 3. DIFFERENT NAMING CONVENTIONS println!("\n📋 3. NAMING CONVENTIONS"); println!("{}", "-".repeat(40)); // PascalCase (default) let pascal_case = Swift::new().naming(NamingConvention::PascalCase); let pascal_output = pascal_case.export(&types, specta_serde::Format).unwrap(); println!("PascalCase output:\n{}", pascal_output); pascal_case .export_to( "./examples/generated/PascalCase.swift", &types, specta_serde::Format, ) .unwrap(); // camelCase let camel_case = Swift::new().naming(NamingConvention::CamelCase); let camel_output = camel_case.export(&types, specta_serde::Format).unwrap(); println!("camelCase output:\n{}", camel_output); camel_case .export_to( "./examples/generated/CamelCase.swift", &types, specta_serde::Format, ) .unwrap(); // snake_case let snake_case = Swift::new().naming(NamingConvention::SnakeCase); let snake_output = snake_case.export(&types, specta_serde::Format).unwrap(); println!("snake_case output:\n{}", snake_output); snake_case .export_to( "./examples/generated/SnakeCase.swift", &types, specta_serde::Format, ) .unwrap(); println!("✅ Naming conventions exported to separate files"); // 4. INDENTATION STYLES println!("\n📋 4. INDENTATION STYLES"); println!("{}", "-".repeat(40)); // Spaces (default: 4 spaces) let spaces_4 = Swift::new().indent(IndentStyle::Spaces(4)); let spaces_output = spaces_4.export(&types, specta_serde::Format).unwrap(); println!("4 Spaces indentation:\n{}", spaces_output); spaces_4 .export_to( "./examples/generated/Spaces4.swift", &types, specta_serde::Format, ) .unwrap(); // 2 Spaces let spaces_2 = Swift::new().indent(IndentStyle::Spaces(2)); let spaces2_output = spaces_2.export(&types, specta_serde::Format).unwrap(); println!("2 Spaces indentation:\n{}", spaces2_output); spaces_2 .export_to( "./examples/generated/Spaces2.swift", &types, specta_serde::Format, ) .unwrap(); // Tabs let tabs = Swift::new().indent(IndentStyle::Tabs); let tabs_output = tabs.export(&types, specta_serde::Format).unwrap(); println!("Tabs indentation:\n{}", tabs_output); tabs.export_to( "./examples/generated/Tabs.swift", &types, specta_serde::Format, ) .unwrap(); println!("✅ Indentation styles exported to separate files"); // 5. GENERIC STYLES println!("\n📋 5. GENERIC STYLES"); println!("{}", "-".repeat(40)); // Protocol constraints (default) let protocol_generics = Swift::new().generics(GenericStyle::Protocol); let protocol_output = protocol_generics .export(&types, specta_serde::Format) .unwrap(); println!("Protocol constraints:\n{}", protocol_output); protocol_generics .export_to( "./examples/generated/ProtocolGenerics.swift", &types, specta_serde::Format, ) .unwrap(); // Typealias constraints let typealias_generics = Swift::new().generics(GenericStyle::Typealias); let typealias_output = typealias_generics .export(&types, specta_serde::Format) .unwrap(); println!("Typealias constraints:\n{}", typealias_output); typealias_generics .export_to( "./examples/generated/TypealiasGenerics.swift", &types, specta_serde::Format, ) .unwrap(); println!("✅ Generic styles exported to separate files"); // 6. OPTIONAL STYLES println!("\n📋 6. OPTIONAL STYLES"); println!("{}", "-".repeat(40)); // Question mark syntax (default) let question_mark = Swift::new().optionals(OptionalStyle::QuestionMark); let question_output = question_mark.export(&types, specta_serde::Format).unwrap(); println!("Question mark syntax:\n{}", question_output); question_mark .export_to( "./examples/generated/QuestionMark.swift", &types, specta_serde::Format, ) .unwrap(); // Optional type syntax let optional_type = Swift::new().optionals(OptionalStyle::Optional); let optional_output = optional_type.export(&types, specta_serde::Format).unwrap(); println!("Optional type syntax:\n{}", optional_output); optional_type .export_to( "./examples/generated/OptionalType.swift", &types, specta_serde::Format, ) .unwrap(); println!("✅ Optional styles exported to separate files"); // 7. ADDITIONAL PROTOCOLS println!("\n📋 7. ADDITIONAL PROTOCOLS"); println!("{}", "-".repeat(40)); let with_protocols = Swift::new() .add_protocol("Equatable") .add_protocol("Hashable") .add_protocol("CustomStringConvertible"); let protocols_output = with_protocols.export(&types, specta_serde::Format).unwrap(); println!("With additional protocols:\n{}", protocols_output); with_protocols .export_to( "./examples/generated/WithProtocols.swift", &types, specta_serde::Format, ) .unwrap(); println!("✅ Additional protocols exported to WithProtocols.swift"); // 8. FORMAT PARAMETER SERDE TRANSFORMS println!("\n📋 8. FORMAT PARAMETER SERDE TRANSFORMS"); println!("{}", "-".repeat(40)); let with_serde = Swift::new(); let serde_output = with_serde.export(&types, specta_serde::Format).unwrap(); println!("With Serde format transform:\n{}", serde_output); with_serde .export_to( "./examples/generated/WithSerde.swift", &types, specta_serde::Format, ) .unwrap(); println!("✅ Serde format transform example exported to WithSerde.swift"); // 9. COMBINED CUSTOM CONFIGURATION println!("\n📋 9. COMBINED CUSTOM CONFIGURATION"); println!("{}", "-".repeat(40)); let combined = Swift::new() .header("// My Custom App Types\n// Generated with love ❤️") .naming(NamingConvention::CamelCase) .indent(IndentStyle::Spaces(2)) .generics(GenericStyle::Typealias) .optionals(OptionalStyle::Optional) .add_protocol("Equatable") .add_protocol("Hashable"); let combined_output = combined.export(&types, specta_serde::Format).unwrap(); println!("Combined custom configuration:\n{}", combined_output); combined .export_to( "./examples/generated/CombinedConfig.swift", &types, specta_serde::Format, ) .unwrap(); println!("✅ Combined configuration exported to CombinedConfig.swift"); println!("\n🎉 All configuration examples completed!"); println!("\n📁 Generated files:"); println!("• DefaultConfig.swift - Default settings"); println!("• CustomHeader.swift - Custom header"); println!("• PascalCase.swift, CamelCase.swift, SnakeCase.swift - Naming conventions"); println!("• Spaces4.swift, Spaces2.swift, Tabs.swift - Indentation styles"); println!("• ProtocolGenerics.swift, TypealiasGenerics.swift - Generic styles"); println!("• QuestionMark.swift, OptionalType.swift - Optional styles"); println!("• WithProtocols.swift - Additional protocols"); println!("• WithSerde.swift - Serde validation"); println!("• CombinedConfig.swift - Combined custom settings"); } ================================================ FILE: specta-swift/examples/generated/AdvancedUnions.swift ================================================ // This file has been generated by Specta. DO NOT EDIT. import Foundation /// Advanced example showcasing complex enum unions and their Swift representations /// /// This example demonstrates how specta-swift handles complex enum scenarios /// including nested types, generic enums, and custom Codable implementations. /// Complex enum with mixed variant types public enum ApiResult { case ok(ApiResultOkData) case err(ApiResultErrData) case loading(ApiResultLoadingData) } public struct ApiResultOkData: Codable { public let data: T public let status: UInt16 public let headers: [(String, String)]? public let timestamp: String } public struct ApiResultErrData: Codable { public let error: E public let code: UInt32 public let message: String public let retryAfter: UInt64? private enum CodingKeys: String, CodingKey { case error = "error" case code = "code" case message = "message" case retryAfter = "retry_after" } } public struct ApiResultLoadingData: Codable { public let progress: Float public let estimatedCompletion: String? private enum CodingKeys: String, CodingKey { case progress = "progress" case estimatedCompletion = "estimated_completion" } } // MARK: - ApiResult Codable Implementation extension ApiResult: Codable { private enum CodingKeys: String, CodingKey { case ok = "Ok" case err = "Err" case loading = "Loading" } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) if container.allKeys.count != 1 { throw DecodingError.dataCorrupted( DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Invalid number of keys found, expected one.") ) } let key = container.allKeys.first! switch key { case .ok: let data = try container.decode(ApiResultOkData.self, forKey: .ok) self = .ok(data) case .err: let data = try container.decode(ApiResultErrData.self, forKey: .err) self = .err(data) case .loading: let data = try container.decode(ApiResultLoadingData.self, forKey: .loading) self = .loading(data) } } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) switch self { case .ok(let data): try container.encode(data, forKey: .ok) case .err(let data): try container.encode(data, forKey: .err) case .loading(let data): try container.encode(data, forKey: .loading) } } } public struct Color: Codable { public let red: Double public let green: Double public let blue: Double public let alpha: Double } /// Generic enum with constraints public enum Container: Codable { case empty case single(T) case multiple([T]) case keyValue([(String, T)]) } /// Event system enum public enum Event { case user(EventUserData) case system(EventSystemData) case error(EventErrorData) } public struct EventUserData: Codable { public let userId: UInt32 public let action: String public let timestamp: String private enum CodingKeys: String, CodingKey { case userId = "user_id" case action = "action" case timestamp = "timestamp" } } public struct EventSystemData: Codable { public let component: String public let level: String public let message: String } public struct EventErrorData: Codable { public let code: UInt32 public let message: String public let stackTrace: String? private enum CodingKeys: String, CodingKey { case code = "code" case message = "message" case stackTrace = "stack_trace" } } // MARK: - Event Codable Implementation extension Event: Codable { private enum CodingKeys: String, CodingKey { case user = "User" case system = "System" case error = "Error" } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) if container.allKeys.count != 1 { throw DecodingError.dataCorrupted( DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Invalid number of keys found, expected one.") ) } let key = container.allKeys.first! switch key { case .user: let data = try container.decode(EventUserData.self, forKey: .user) self = .user(data) case .system: let data = try container.decode(EventSystemData.self, forKey: .system) self = .system(data) case .error: let data = try container.decode(EventErrorData.self, forKey: .error) self = .error(data) } } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) switch self { case .user(let data): try container.encode(data, forKey: .user) case .system(let data): try container.encode(data, forKey: .system) case .error(let data): try container.encode(data, forKey: .error) } } } /// String enum (will be converted to Swift String enum with Codable) public enum JobStatus: Codable { case queued case running case paused case completed case failed case cancelled } public struct LineStyle: Codable { public let dashPattern: [Double]? public let capStyle: String public let joinStyle: String private enum CodingKeys: String, CodingKey { case dashPattern = "dash_pattern" case capStyle = "cap_style" case joinStyle = "join_style" } } /// Mixed enum with both string-like and data variants public enum MixedEnum { case simple(String) case withFields(MixedEnumWithFieldsData) case empty } public struct MixedEnumWithFieldsData: Codable { public let id: UInt32 public let name: String public let metadata: [(String, String)]? } // MARK: - MixedEnum Codable Implementation extension MixedEnum: Codable { private enum CodingKeys: String, CodingKey { case simple = "Simple" case withFields = "WithFields" case empty = "Empty" } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) if container.allKeys.count != 1 { throw DecodingError.dataCorrupted( DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Invalid number of keys found, expected one.") ) } let key = container.allKeys.first! switch key { case .simple: // TODO: Implement tuple variant decoding for simple fatalError("Tuple variant decoding not implemented") case .withFields: let data = try container.decode(MixedEnumWithFieldsData.self, forKey: .withFields) self = .withFields(data) case .empty: self = .empty } } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) switch self { case .simple: // TODO: Implement tuple variant encoding for simple fatalError("Tuple variant encoding not implemented") case .withFields(let data): try container.encode(data, forKey: .withFields) case .empty: try container.encodeNil(forKey: .empty) } } } /// Supporting structs for the Shape enum public struct Point: Codable { public let x: Double public let y: Double } public struct Rectangle: Codable { public let topLeft: Point public let bottomRight: Point private enum CodingKeys: String, CodingKey { case topLeft = "top_left" case bottomRight = "bottom_right" } } /// Enum demonstrating different field patterns public enum Shape { case none case point(Double, Double) case circle(ShapeCircleData) case rectangle(Rectangle) case line(ShapeLineData) case complex(ShapeComplexData) } public struct ShapeCircleData: Codable { public let center: Point public let radius: Double } public struct ShapeLineData: Codable { public let start: Point public let end: Point public let style: LineStyle } public struct ShapeComplexData: Codable { public let vertices: [Point] public let fillColor: Color public let strokeColor: Color? public let strokeWidth: Double public let isClosed: Bool private enum CodingKeys: String, CodingKey { case vertices = "vertices" case fillColor = "fill_color" case strokeColor = "stroke_color" case strokeWidth = "stroke_width" case isClosed = "is_closed" } } // MARK: - Shape Codable Implementation extension Shape: Codable { private enum CodingKeys: String, CodingKey { case none = "None" case point = "Point" case circle = "Circle" case rectangle = "Rectangle" case line = "Line" case complex = "Complex" } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) if container.allKeys.count != 1 { throw DecodingError.dataCorrupted( DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Invalid number of keys found, expected one.") ) } let key = container.allKeys.first! switch key { case .none: self = .none case .point: // TODO: Implement tuple variant decoding for point fatalError("Tuple variant decoding not implemented") case .circle: let data = try container.decode(ShapeCircleData.self, forKey: .circle) self = .circle(data) case .rectangle: // TODO: Implement tuple variant decoding for rectangle fatalError("Tuple variant decoding not implemented") case .line: let data = try container.decode(ShapeLineData.self, forKey: .line) self = .line(data) case .complex: let data = try container.decode(ShapeComplexData.self, forKey: .complex) self = .complex(data) } } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) switch self { case .none: try container.encodeNil(forKey: .none) case .point: // TODO: Implement tuple variant encoding for point fatalError("Tuple variant encoding not implemented") case .circle(let data): try container.encode(data, forKey: .circle) case .rectangle: // TODO: Implement tuple variant encoding for rectangle fatalError("Tuple variant encoding not implemented") case .line(let data): try container.encode(data, forKey: .line) case .complex(let data): try container.encode(data, forKey: .complex) } } } /// Enum with recursive references public enum Tree { case leaf(T) case branch(TreeBranchData) } public struct TreeBranchData: Codable { public let left: Tree public let right: Tree public let value: T } // MARK: - Tree Codable Implementation extension Tree: Codable { private enum CodingKeys: String, CodingKey { case leaf = "Leaf" case branch = "Branch" } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) if container.allKeys.count != 1 { throw DecodingError.dataCorrupted( DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Invalid number of keys found, expected one.") ) } let key = container.allKeys.first! switch key { case .leaf: // TODO: Implement tuple variant decoding for leaf fatalError("Tuple variant decoding not implemented") case .branch: let data = try container.decode(TreeBranchData.self, forKey: .branch) self = .branch(data) } } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) switch self { case .leaf: // TODO: Implement tuple variant encoding for leaf fatalError("Tuple variant encoding not implemented") case .branch(let data): try container.encode(data, forKey: .branch) } } } ================================================ FILE: specta-swift/examples/generated/BasicTypes.swift ================================================ // This file has been generated by Specta. DO NOT EDIT. import Foundation /// Generic struct demonstrating type parameters public struct ApiResponse: Codable { public let data: T? public let error: E? public let statusCode: UInt16 public let headers: [(String, String)] private enum CodingKeys: String, CodingKey { case data = "data" case error = "error" case statusCode = "status_code" case headers = "headers" } } /// Comprehensive example showcasing basic Rust types and their Swift equivalents /// /// This example demonstrates how specta-swift handles fundamental Rust types /// and converts them to appropriate Swift types. /// Basic primitive types public struct Primitives: Codable { public let smallInt: Int8 public let unsignedSmall: UInt8 public let shortInt: Int16 public let unsignedShort: UInt16 public let regularInt: Int32 public let unsignedInt: UInt32 public let longInt: Int64 public let unsignedLong: UInt64 public let singlePrecision: Float public let doublePrecision: Double public let isActive: Bool public let singleChar: Character public let name: String public let optionalName: String? public let tags: [String] public let scores: [Double] public let userIds: [UInt32] public let matrix: [[Double]] public let stringPairs: [(String, String)] private enum CodingKeys: String, CodingKey { case smallInt = "small_int" case unsignedSmall = "unsigned_small" case shortInt = "short_int" case unsignedShort = "unsigned_short" case regularInt = "regular_int" case unsignedInt = "unsigned_int" case longInt = "long_int" case unsignedLong = "unsigned_long" case singlePrecision = "single_precision" case doublePrecision = "double_precision" case isActive = "is_active" case singleChar = "single_char" case name = "name" case optionalName = "optional_name" case tags = "tags" case scores = "scores" case userIds = "user_ids" case matrix = "matrix" case stringPairs = "string_pairs" } } /// Enum with different variant types public enum Status { case active case pending(String) case error(String, UInt32) case loading(StatusLoadingData) } public struct StatusLoadingData: Codable { public let progress: Float public let message: String? } // MARK: - Status Codable Implementation extension Status: Codable { private enum CodingKeys: String, CodingKey { case active = "Active" case pending = "Pending" case error = "Error" case loading = "Loading" } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) if container.allKeys.count != 1 { throw DecodingError.dataCorrupted( DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Invalid number of keys found, expected one.") ) } let key = container.allKeys.first! switch key { case .active: self = .active case .pending: // TODO: Implement tuple variant decoding for pending fatalError("Tuple variant decoding not implemented") case .error: // TODO: Implement tuple variant decoding for error fatalError("Tuple variant decoding not implemented") case .loading: let data = try container.decode(StatusLoadingData.self, forKey: .loading) self = .loading(data) } } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) switch self { case .active: try container.encodeNil(forKey: .active) case .pending: // TODO: Implement tuple variant encoding for pending fatalError("Tuple variant encoding not implemented") case .error: // TODO: Implement tuple variant encoding for error fatalError("Tuple variant encoding not implemented") case .loading(let data): try container.encode(data, forKey: .loading) } } } /// Nested struct demonstrating complex relationships public struct User: Codable { public let id: UInt32 public let username: String public let email: String public let profile: UserProfile public let preferences: UserPreferences public let status: Status public let metadata: UserMetadata? } public struct UserMetadata: Codable { public let createdAt: String public let lastLogin: String? public let loginCount: UInt32 public let isVerified: Bool private enum CodingKeys: String, CodingKey { case createdAt = "created_at" case lastLogin = "last_login" case loginCount = "login_count" case isVerified = "is_verified" } } public struct UserPreferences: Codable { public let theme: String public let language: String public let notificationsEnabled: Bool public let privacyLevel: UInt8 private enum CodingKeys: String, CodingKey { case theme = "theme" case language = "language" case notificationsEnabled = "notifications_enabled" case privacyLevel = "privacy_level" } } public struct UserProfile: Codable { public let firstName: String public let lastName: String public let bio: String? public let avatarUrl: String? public let birthDate: String? private enum CodingKeys: String, CodingKey { case firstName = "first_name" case lastName = "last_name" case bio = "bio" case avatarUrl = "avatar_url" case birthDate = "birth_date" } } ================================================ FILE: specta-swift/examples/generated/CamelCase.swift ================================================ // This file has been generated by Specta. DO NOT EDIT. import Foundation public enum apiResponse { case success(apiResponseSuccessData) case error(apiResponseErrorData) case loading(apiResponseLoadingData) } public struct apiResponseSuccessData: Codable { public let data: T public let statusCode: UInt16 private enum CodingKeys: String, CodingKey { case data = "data" case statusCode = "status_code" } } public struct apiResponseErrorData: Codable { public let message: String public let errorCode: UInt32 private enum CodingKeys: String, CodingKey { case message = "message" case errorCode = "error_code" } } public struct apiResponseLoadingData: Codable { public let progress: Float } // MARK: - apiResponse Codable Implementation extension apiResponse: Codable { private enum CodingKeys: String, CodingKey { case success = "Success" case error = "Error" case loading = "Loading" } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) if container.allKeys.count != 1 { throw DecodingError.dataCorrupted( DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Invalid number of keys found, expected one.") ) } let key = container.allKeys.first! switch key { case .success: let data = try container.decode(apiResponseSuccessData.self, forKey: .success) self = .success(data) case .error: let data = try container.decode(apiResponseErrorData.self, forKey: .error) self = .error(data) case .loading: let data = try container.decode(apiResponseLoadingData.self, forKey: .loading) self = .loading(data) } } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) switch self { case .success(let data): try container.encode(data, forKey: .success) case .error(let data): try container.encode(data, forKey: .error) case .loading(let data): try container.encode(data, forKey: .loading) } } } public struct genericContainer: Codable { public let primary: T public let secondary: U public let metadata: [(String, String)]? } /// Comprehensive example showcasing ALL configuration options for specta-swift /// /// This example demonstrates every configuration option available in the Swift exporter, /// showing how different settings affect the generated Swift code. /// Sample types for demonstration public struct user: Codable { public let userId: UInt32 public let fullName: String public let emailAddress: String? public let isVerified: Bool private enum CodingKeys: String, CodingKey { case userId = "user_id" case fullName = "full_name" case emailAddress = "email_address" case isVerified = "is_verified" } } ================================================ FILE: specta-swift/examples/generated/CombinedConfig.swift ================================================ // My Custom App Types // Generated with love ❤️ import Foundation import Codable import Equatable import Hashable public enum apiResponse { case success(apiResponseSuccessData) case error(apiResponseErrorData) case loading(apiResponseLoadingData) } public struct apiResponseSuccessData: Codable { public let data: T public let statusCode: UInt16 private enum CodingKeys: String, CodingKey { case data = "data" case statusCode = "status_code" } } public struct apiResponseErrorData: Codable { public let message: String public let errorCode: UInt32 private enum CodingKeys: String, CodingKey { case message = "message" case errorCode = "error_code" } } public struct apiResponseLoadingData: Codable { public let progress: Float } // MARK: - apiResponse Codable Implementation extension apiResponse: Codable { private enum CodingKeys: String, CodingKey { case success = "Success" case error = "Error" case loading = "Loading" } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) if container.allKeys.count != 1 { throw DecodingError.dataCorrupted( DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Invalid number of keys found, expected one.") ) } let key = container.allKeys.first! switch key { case .success: let data = try container.decode(apiResponseSuccessData.self, forKey: .success) self = .success(data) case .error: let data = try container.decode(apiResponseErrorData.self, forKey: .error) self = .error(data) case .loading: let data = try container.decode(apiResponseLoadingData.self, forKey: .loading) self = .loading(data) } } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) switch self { case .success(let data): try container.encode(data, forKey: .success) case .error(let data): try container.encode(data, forKey: .error) case .loading(let data): try container.encode(data, forKey: .loading) } } } public struct genericContainer: Codable { public let primary: T public let secondary: U public let metadata: Optional<[(String, String)]> } /// Comprehensive example showcasing ALL configuration options for specta-swift /// /// This example demonstrates every configuration option available in the Swift exporter, /// showing how different settings affect the generated Swift code. /// Sample types for demonstration public struct user: Codable { public let userId: UInt32 public let fullName: String public let emailAddress: Optional public let isVerified: Bool private enum CodingKeys: String, CodingKey { case userId = "user_id" case fullName = "full_name" case emailAddress = "email_address" case isVerified = "is_verified" } } ================================================ FILE: specta-swift/examples/generated/CommentsExample.swift ================================================ // This file has been generated by Specta. DO NOT EDIT. import Foundation /// A comprehensive example demonstrating multi-line comment support /// /// This example shows how Specta Swift handles complex documentation /// including: /// - Multi-line type documentation /// - Bullet points and formatting /// - Complex technical descriptions /// /// The generated Swift code will have properly formatted doc comments /// that are compatible with Swift's documentation system. public enum ApiResponse { case success(ApiResponseSuccessData) case error(ApiResponseErrorData) case loading(ApiResponseLoadingData) } public struct ApiResponseSuccessData: Codable { public let data: T public let status: UInt16 public let headers: [(String, String)]? } public struct ApiResponseErrorData: Codable { public let message: String public let code: UInt32 public let details: String? } public struct ApiResponseLoadingData: Codable { public let progress: Float public let estimatedTime: UInt64? private enum CodingKeys: String, CodingKey { case progress = "progress" case estimatedTime = "estimated_time" } } // MARK: - ApiResponse Codable Implementation extension ApiResponse: Codable { private enum CodingKeys: String, CodingKey { case success = "Success" case error = "Error" case loading = "Loading" } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) if container.allKeys.count != 1 { throw DecodingError.dataCorrupted( DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Invalid number of keys found, expected one.") ) } let key = container.allKeys.first! switch key { case .success: let data = try container.decode(ApiResponseSuccessData.self, forKey: .success) self = .success(data) case .error: let data = try container.decode(ApiResponseErrorData.self, forKey: .error) self = .error(data) case .loading: let data = try container.decode(ApiResponseLoadingData.self, forKey: .loading) self = .loading(data) } } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) switch self { case .success(let data): try container.encode(data, forKey: .success) case .error(let data): try container.encode(data, forKey: .error) case .loading(let data): try container.encode(data, forKey: .loading) } } } /// A user account in the system /// /// This struct represents a complete user account with all necessary /// information for authentication, authorization, and personalization. /// /// # Security Notes /// - The `password_hash` field should never be logged or exposed /// - The `api_key` is sensitive and should be treated as a secret /// - All timestamps are in UTC public struct User: Codable { public let id: UInt32 public let username: String public let email: String public let isActive: Bool public let createdAt: String public let lastLogin: String? private enum CodingKeys: String, CodingKey { case id = "id" case username = "username" case email = "email" case isActive = "is_active" case createdAt = "created_at" case lastLogin = "last_login" } } ================================================ FILE: specta-swift/examples/generated/ComprehensiveDemo.swift ================================================ // This file has been generated by Specta. DO NOT EDIT. import Foundation // MARK: - Duration Helper /// Helper struct to decode Rust Duration format {"secs": u64, "nanos": u32} public struct RustDuration: Codable { public let secs: UInt64 public let nanos: UInt32 public var timeInterval: TimeInterval { return Double(secs) + Double(nanos) / 1_000_000_000.0 } } // MARK: - Generated Types /// Admin level enum public enum AdminLevel: Codable { case junior case senior case lead case director } /// API response wrapper public struct ApiResponse: Codable { public let data: T? public let error: E? public let status: ResponseStatus public let metadata: ResponseMetadata } /// File attachment public struct Attachment: Codable { public let id: String public let filename: String public let size: UInt64 public let mimeType: String public let uploadedAt: String public let uploadedBy: UInt32 private enum CodingKeys: String, CodingKey { case id = "id" case filename = "filename" case size = "size" case mimeType = "mime_type" case uploadedAt = "uploaded_at" case uploadedBy = "uploaded_by" } } /// Data sharing settings public struct DataSharing: Codable { public let analytics: Bool public let marketing: Bool public let thirdParty: Bool public let research: Bool private enum CodingKeys: String, CodingKey { case analytics = "analytics" case marketing = "marketing" case thirdParty = "third_party" case research = "research" } } /// Display settings public struct DisplaySettings: Codable { public let itemsPerPage: UInt32 public let dateFormat: String public let timeFormat: String public let currency: String public let compactMode: Bool private enum CodingKeys: String, CodingKey { case itemsPerPage = "items_per_page" case dateFormat = "date_format" case timeFormat = "time_format" case currency = "currency" case compactMode = "compact_mode" } } /// Health status enum public enum HealthStatus: Codable { case healthy case degraded case unhealthy case unknown } /// Notification frequency enum public enum NotificationFrequency: Codable { case immediate case hourly case daily case weekly case never } /// Notification settings public struct NotificationSettings: Codable { public let emailEnabled: Bool public let pushEnabled: Bool public let smsEnabled: Bool public let desktopEnabled: Bool public let frequency: NotificationFrequency private enum CodingKeys: String, CodingKey { case emailEnabled = "email_enabled" case pushEnabled = "push_enabled" case smsEnabled = "sms_enabled" case desktopEnabled = "desktop_enabled" case frequency = "frequency" } } /// Pagination information public struct PaginationInfo: Codable { public let page: UInt32 public let perPage: UInt32 public let totalPages: UInt32 public let totalItems: UInt64 public let hasNext: Bool public let hasPrev: Bool private enum CodingKeys: String, CodingKey { case page = "page" case perPage = "per_page" case totalPages = "total_pages" case totalItems = "total_items" case hasNext = "has_next" case hasPrev = "has_prev" } } /// Priority enum (string enum) public enum Priority: Codable { case low case medium case high case critical case emergency } /// Privacy settings public struct PrivacySettings: Codable { public let profileVisibility: Visibility public let activityVisibility: Visibility public let dataSharing: DataSharing private enum CodingKeys: String, CodingKey { case profileVisibility = "profile_visibility" case activityVisibility = "activity_visibility" case dataSharing = "data_sharing" } } /// Response metadata public struct ResponseMetadata: Codable { public let requestId: String public let timestamp: String public let processingTime: RustDuration public let version: String public let pagination: PaginationInfo? private enum CodingKeys: String, CodingKey { case requestId = "request_id" case timestamp = "timestamp" case processingTime = "processing_time" case version = "version" case pagination = "pagination" } } /// Response status enum public enum ResponseStatus: Codable { case success case partialSuccess case error case validationError case authenticationError case authorizationError case notFound case rateLimited } /// Review comment public struct ReviewComment: Codable { public let id: UInt32 public let author: UInt32 public let content: String public let createdAt: String public let updatedAt: String public let isResolved: Bool public let parentComment: UInt32? public let attachments: [Attachment] private enum CodingKeys: String, CodingKey { case id = "id" case author = "author" case content = "content" case createdAt = "created_at" case updatedAt = "updated_at" case isResolved = "is_resolved" case parentComment = "parent_comment" case attachments = "attachments" } } /// Service status public struct ServiceStatus: Codable { public let name: String public let status: HealthStatus public let responseTime: RustDuration public let lastCheck: String public let errorCount: UInt32 private enum CodingKeys: String, CodingKey { case name = "name" case status = "status" case responseTime = "response_time" case lastCheck = "last_check" case errorCount = "error_count" } } /// Subtask with timing information public struct SubTask: Codable { public let id: UInt32 public let title: String public let description: String? public let status: SubTaskStatus public let estimatedDuration: RustDuration public let actualDuration: RustDuration? public let assignee: UInt32? public let createdAt: String public let completedAt: String? private enum CodingKeys: String, CodingKey { case id = "id" case title = "title" case description = "description" case status = "status" case estimatedDuration = "estimated_duration" case actualDuration = "actual_duration" case assignee = "assignee" case createdAt = "created_at" case completedAt = "completed_at" } } /// Subtask status (simple enum) public enum SubTaskStatus: Codable { case pending case inProgress case completed case skipped } /// System health information public struct SystemHealth: Codable { public let status: HealthStatus public let uptime: RustDuration public let lastCheck: String public let services: [ServiceStatus] public let metrics: SystemMetrics private enum CodingKeys: String, CodingKey { case status = "status" case uptime = "uptime" case lastCheck = "last_check" case services = "services" case metrics = "metrics" } } /// System metrics public struct SystemMetrics: Codable { public let cpuUsage: Double public let memoryUsage: Double public let diskUsage: Double public let networkUsage: Double public let activeUsers: UInt32 public let totalRequests: UInt64 public let errorRate: Double private enum CodingKeys: String, CodingKey { case cpuUsage = "cpu_usage" case memoryUsage = "memory_usage" case diskUsage = "disk_usage" case networkUsage = "network_usage" case activeUsers = "active_users" case totalRequests = "total_requests" case errorRate = "error_rate" } } /// Comprehensive demonstration of ALL specta-swift functionality /// /// This example showcases every feature and capability of specta-swift in a single, /// realistic application scenario. It demonstrates complex type relationships, /// various enum patterns, special types, and advanced features. /// Main application types for a task management system public struct Task: Codable { public let id: UInt32 public let title: String public let description: String? public let status: TaskStatus public let priority: Priority public let assignee: User? public let createdAt: String public let updatedAt: String public let dueDate: String? public let duration: RustDuration? public let tags: [String] public let metadata: TaskMetadata public let subtasks: [SubTask] private enum CodingKeys: String, CodingKey { case id = "id" case title = "title" case description = "description" case status = "status" case priority = "priority" case assignee = "assignee" case createdAt = "created_at" case updatedAt = "updated_at" case dueDate = "due_date" case duration = "duration" case tags = "tags" case metadata = "metadata" case subtasks = "subtasks" } } /// Task metadata public struct TaskMetadata: Codable { public let createdBy: UInt32 public let lastModifiedBy: UInt32 public let version: UInt32 public let customFields: [(String, String)] public let attachments: [Attachment] public let watchers: [UInt32] public let dependencies: [UInt32] private enum CodingKeys: String, CodingKey { case createdBy = "created_by" case lastModifiedBy = "last_modified_by" case version = "version" case customFields = "custom_fields" case attachments = "attachments" case watchers = "watchers" case dependencies = "dependencies" } } /// Task status enum with mixed variants public enum TaskStatus { case todo case inProgress(TaskStatusInProgressData) case blocked(TaskStatusBlockedData) case review(TaskStatusReviewData) case completed(TaskStatusCompletedData) case cancelled(TaskStatusCancelledData) } public struct TaskStatusInProgressData: Codable { public let startedAt: String public let estimatedCompletion: String? public let progress: Float private enum CodingKeys: String, CodingKey { case startedAt = "started_at" case estimatedCompletion = "estimated_completion" case progress = "progress" } } public struct TaskStatusBlockedData: Codable { public let reason: String public let blockedBy: [UInt32] public let estimatedUnblock: String? private enum CodingKeys: String, CodingKey { case reason = "reason" case blockedBy = "blocked_by" case estimatedUnblock = "estimated_unblock" } } public struct TaskStatusReviewData: Codable { public let reviewer: String public let reviewStartedAt: String public let comments: [ReviewComment] private enum CodingKeys: String, CodingKey { case reviewer = "reviewer" case reviewStartedAt = "review_started_at" case comments = "comments" } } public struct TaskStatusCompletedData: Codable { public let completedAt: String public let completionTime: RustDuration public let finalNotes: String? private enum CodingKeys: String, CodingKey { case completedAt = "completed_at" case completionTime = "completion_time" case finalNotes = "final_notes" } } public struct TaskStatusCancelledData: Codable { public let reason: String public let cancelledAt: String private enum CodingKeys: String, CodingKey { case reason = "reason" case cancelledAt = "cancelled_at" } } // MARK: - TaskStatus Codable Implementation extension TaskStatus: Codable { private enum CodingKeys: String, CodingKey { case todo = "Todo" case inProgress = "InProgress" case blocked = "Blocked" case review = "Review" case completed = "Completed" case cancelled = "Cancelled" } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) if container.allKeys.count != 1 { throw DecodingError.dataCorrupted( DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Invalid number of keys found, expected one.") ) } let key = container.allKeys.first! switch key { case .todo: self = .todo case .inProgress: let data = try container.decode(TaskStatusInProgressData.self, forKey: .inProgress) self = .inProgress(data) case .blocked: let data = try container.decode(TaskStatusBlockedData.self, forKey: .blocked) self = .blocked(data) case .review: let data = try container.decode(TaskStatusReviewData.self, forKey: .review) self = .review(data) case .completed: let data = try container.decode(TaskStatusCompletedData.self, forKey: .completed) self = .completed(data) case .cancelled: let data = try container.decode(TaskStatusCancelledData.self, forKey: .cancelled) self = .cancelled(data) } } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) switch self { case .todo: try container.encodeNil(forKey: .todo) case .inProgress(let data): try container.encode(data, forKey: .inProgress) case .blocked(let data): try container.encode(data, forKey: .blocked) case .review(let data): try container.encode(data, forKey: .review) case .completed(let data): try container.encode(data, forKey: .completed) case .cancelled(let data): try container.encode(data, forKey: .cancelled) } } } /// Theme enum (string enum) public enum Theme: Codable { case light case dark case auto case custom } /// User information public struct User: Codable { public let id: UInt32 public let username: String public let email: String public let profile: UserProfile public let preferences: UserPreferences public let role: UserRole public let isActive: Bool public let lastLogin: String? public let createdAt: String private enum CodingKeys: String, CodingKey { case id = "id" case username = "username" case email = "email" case profile = "profile" case preferences = "preferences" case role = "role" case isActive = "is_active" case lastLogin = "last_login" case createdAt = "created_at" } } /// User preferences public struct UserPreferences: Codable { public let theme: Theme public let notifications: NotificationSettings public let privacy: PrivacySettings public let display: DisplaySettings } /// User profile with nested data public struct UserProfile: Codable { public let firstName: String public let lastName: String public let bio: String? public let avatarUrl: String? public let timezone: String public let language: String private enum CodingKeys: String, CodingKey { case firstName = "first_name" case lastName = "last_name" case bio = "bio" case avatarUrl = "avatar_url" case timezone = "timezone" case language = "language" } } /// User role with permissions public enum UserRole { case user case moderator(UserRoleModeratorData) case admin(UserRoleAdminData) case superAdmin(UserRoleSuperAdminData) } public struct UserRoleModeratorData: Codable { public let permissions: [String] public let department: String } public struct UserRoleAdminData: Codable { public let level: AdminLevel public let departments: [String] public let specialAccess: [String] private enum CodingKeys: String, CodingKey { case level = "level" case departments = "departments" case specialAccess = "special_access" } } public struct UserRoleSuperAdminData: Codable { public let systemAccess: Bool public let auditLogs: Bool private enum CodingKeys: String, CodingKey { case systemAccess = "system_access" case auditLogs = "audit_logs" } } // MARK: - UserRole Codable Implementation extension UserRole: Codable { private enum CodingKeys: String, CodingKey { case user = "User" case moderator = "Moderator" case admin = "Admin" case superAdmin = "SuperAdmin" } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) if container.allKeys.count != 1 { throw DecodingError.dataCorrupted( DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Invalid number of keys found, expected one.") ) } let key = container.allKeys.first! switch key { case .user: self = .user case .moderator: let data = try container.decode(UserRoleModeratorData.self, forKey: .moderator) self = .moderator(data) case .admin: let data = try container.decode(UserRoleAdminData.self, forKey: .admin) self = .admin(data) case .superAdmin: let data = try container.decode(UserRoleSuperAdminData.self, forKey: .superAdmin) self = .superAdmin(data) } } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) switch self { case .user: try container.encodeNil(forKey: .user) case .moderator(let data): try container.encode(data, forKey: .moderator) case .admin(let data): try container.encode(data, forKey: .admin) case .superAdmin(let data): try container.encode(data, forKey: .superAdmin) } } } /// Visibility enum public enum Visibility: Codable { case public case friends case private case hidden } ================================================ FILE: specta-swift/examples/generated/CustomHeader.swift ================================================ // Generated by MyAwesomeApp v2.0 // Custom header with app info // DO NOT EDIT MANUALLY import Foundation public enum ApiResponse { case success(ApiResponseSuccessData) case error(ApiResponseErrorData) case loading(ApiResponseLoadingData) } public struct ApiResponseSuccessData: Codable { public let data: T public let statusCode: UInt16 private enum CodingKeys: String, CodingKey { case data = "data" case statusCode = "status_code" } } public struct ApiResponseErrorData: Codable { public let message: String public let errorCode: UInt32 private enum CodingKeys: String, CodingKey { case message = "message" case errorCode = "error_code" } } public struct ApiResponseLoadingData: Codable { public let progress: Float } // MARK: - ApiResponse Codable Implementation extension ApiResponse: Codable { private enum CodingKeys: String, CodingKey { case success = "Success" case error = "Error" case loading = "Loading" } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) if container.allKeys.count != 1 { throw DecodingError.dataCorrupted( DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Invalid number of keys found, expected one.") ) } let key = container.allKeys.first! switch key { case .success: let data = try container.decode(ApiResponseSuccessData.self, forKey: .success) self = .success(data) case .error: let data = try container.decode(ApiResponseErrorData.self, forKey: .error) self = .error(data) case .loading: let data = try container.decode(ApiResponseLoadingData.self, forKey: .loading) self = .loading(data) } } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) switch self { case .success(let data): try container.encode(data, forKey: .success) case .error(let data): try container.encode(data, forKey: .error) case .loading(let data): try container.encode(data, forKey: .loading) } } } public struct GenericContainer: Codable { public let primary: T public let secondary: U public let metadata: [(String, String)]? } /// Comprehensive example showcasing ALL configuration options for specta-swift /// /// This example demonstrates every configuration option available in the Swift exporter, /// showing how different settings affect the generated Swift code. /// Sample types for demonstration public struct User: Codable { public let userId: UInt32 public let fullName: String public let emailAddress: String? public let isVerified: Bool private enum CodingKeys: String, CodingKey { case userId = "user_id" case fullName = "full_name" case emailAddress = "email_address" case isVerified = "is_verified" } } ================================================ FILE: specta-swift/examples/generated/CustomTypes.swift ================================================ // Generated by MyApp - Custom Header import Foundation public enum api_result { case success(api_resultSuccessData) case error(api_resultErrorData) case loading(api_resultLoadingData) } public struct api_resultSuccessData: Codable { public let data: T public let status: UInt16 } public struct api_resultErrorData: Codable { public let message: String public let code: UInt32 } public struct api_resultLoadingData: Codable { public let progress: Float } // MARK: - api_result Codable Implementation extension api_result: Codable { private enum CodingKeys: String, CodingKey { case success = "Success" case error = "Error" case loading = "Loading" } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) if container.allKeys.count != 1 { throw DecodingError.dataCorrupted( DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Invalid number of keys found, expected one.") ) } let key = container.allKeys.first! switch key { case .success: let data = try container.decode(api_resultSuccessData.self, forKey: .success) self = .success(data) case .error: let data = try container.decode(api_resultErrorData.self, forKey: .error) self = .error(data) case .loading: let data = try container.decode(api_resultLoadingData.self, forKey: .loading) self = .loading(data) } } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) switch self { case .success(let data): try container.encode(data, forKey: .success) case .error(let data): try container.encode(data, forKey: .error) case .loading(let data): try container.encode(data, forKey: .loading) } } } public struct user: Codable { public let id: UInt32 public let name: String public let email: Optional public let role: user_role } public enum user_role { case guest case user(user_roleUserData) case admin(user_roleAdminData) case super_admin(user_roleSuperAdminData) } public struct user_roleUserData: Codable { public let permissions: [String] } public struct user_roleAdminData: Codable { public let level: UInt8 public let department: String } public struct user_roleSuperAdminData: Codable { public let access_level: UInt32 } // MARK: - user_role Codable Implementation extension user_role: Codable { private enum CodingKeys: String, CodingKey { case guest = "Guest" case user = "User" case admin = "Admin" case super_admin = "SuperAdmin" } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) if container.allKeys.count != 1 { throw DecodingError.dataCorrupted( DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Invalid number of keys found, expected one.") ) } let key = container.allKeys.first! switch key { case .guest: self = .guest case .user: let data = try container.decode(user_roleUserData.self, forKey: .user) self = .user(data) case .admin: let data = try container.decode(user_roleAdminData.self, forKey: .admin) self = .admin(data) case .super_admin: let data = try container.decode(user_roleSuperAdminData.self, forKey: .super_admin) self = .super_admin(data) } } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) switch self { case .guest: try container.encodeNil(forKey: .guest) case .user(let data): try container.encode(data, forKey: .user) case .admin(let data): try container.encode(data, forKey: .admin) case .super_admin(let data): try container.encode(data, forKey: .super_admin) } } } ================================================ FILE: specta-swift/examples/generated/DefaultConfig.swift ================================================ // This file has been generated by Specta. DO NOT EDIT. import Foundation public enum ApiResponse { case success(ApiResponseSuccessData) case error(ApiResponseErrorData) case loading(ApiResponseLoadingData) } public struct ApiResponseSuccessData: Codable { public let data: T public let statusCode: UInt16 private enum CodingKeys: String, CodingKey { case data = "data" case statusCode = "status_code" } } public struct ApiResponseErrorData: Codable { public let message: String public let errorCode: UInt32 private enum CodingKeys: String, CodingKey { case message = "message" case errorCode = "error_code" } } public struct ApiResponseLoadingData: Codable { public let progress: Float } // MARK: - ApiResponse Codable Implementation extension ApiResponse: Codable { private enum CodingKeys: String, CodingKey { case success = "Success" case error = "Error" case loading = "Loading" } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) if container.allKeys.count != 1 { throw DecodingError.dataCorrupted( DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Invalid number of keys found, expected one.") ) } let key = container.allKeys.first! switch key { case .success: let data = try container.decode(ApiResponseSuccessData.self, forKey: .success) self = .success(data) case .error: let data = try container.decode(ApiResponseErrorData.self, forKey: .error) self = .error(data) case .loading: let data = try container.decode(ApiResponseLoadingData.self, forKey: .loading) self = .loading(data) } } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) switch self { case .success(let data): try container.encode(data, forKey: .success) case .error(let data): try container.encode(data, forKey: .error) case .loading(let data): try container.encode(data, forKey: .loading) } } } public struct GenericContainer: Codable { public let primary: T public let secondary: U public let metadata: [(String, String)]? } /// Comprehensive example showcasing ALL configuration options for specta-swift /// /// This example demonstrates every configuration option available in the Swift exporter, /// showing how different settings affect the generated Swift code. /// Sample types for demonstration public struct User: Codable { public let userId: UInt32 public let fullName: String public let emailAddress: String? public let isVerified: Bool private enum CodingKeys: String, CodingKey { case userId = "user_id" case fullName = "full_name" case emailAddress = "email_address" case isVerified = "is_verified" } } ================================================ FILE: specta-swift/examples/generated/OptionalType.swift ================================================ // This file has been generated by Specta. DO NOT EDIT. import Foundation public enum ApiResponse { case success(ApiResponseSuccessData) case error(ApiResponseErrorData) case loading(ApiResponseLoadingData) } public struct ApiResponseSuccessData: Codable { public let data: T public let statusCode: UInt16 private enum CodingKeys: String, CodingKey { case data = "data" case statusCode = "status_code" } } public struct ApiResponseErrorData: Codable { public let message: String public let errorCode: UInt32 private enum CodingKeys: String, CodingKey { case message = "message" case errorCode = "error_code" } } public struct ApiResponseLoadingData: Codable { public let progress: Float } // MARK: - ApiResponse Codable Implementation extension ApiResponse: Codable { private enum CodingKeys: String, CodingKey { case success = "Success" case error = "Error" case loading = "Loading" } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) if container.allKeys.count != 1 { throw DecodingError.dataCorrupted( DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Invalid number of keys found, expected one.") ) } let key = container.allKeys.first! switch key { case .success: let data = try container.decode(ApiResponseSuccessData.self, forKey: .success) self = .success(data) case .error: let data = try container.decode(ApiResponseErrorData.self, forKey: .error) self = .error(data) case .loading: let data = try container.decode(ApiResponseLoadingData.self, forKey: .loading) self = .loading(data) } } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) switch self { case .success(let data): try container.encode(data, forKey: .success) case .error(let data): try container.encode(data, forKey: .error) case .loading(let data): try container.encode(data, forKey: .loading) } } } public struct GenericContainer: Codable { public let primary: T public let secondary: U public let metadata: Optional<[(String, String)]> } /// Comprehensive example showcasing ALL configuration options for specta-swift /// /// This example demonstrates every configuration option available in the Swift exporter, /// showing how different settings affect the generated Swift code. /// Sample types for demonstration public struct User: Codable { public let userId: UInt32 public let fullName: String public let emailAddress: Optional public let isVerified: Bool private enum CodingKeys: String, CodingKey { case userId = "user_id" case fullName = "full_name" case emailAddress = "email_address" case isVerified = "is_verified" } } ================================================ FILE: specta-swift/examples/generated/PascalCase.swift ================================================ // This file has been generated by Specta. DO NOT EDIT. import Foundation public enum ApiResponse { case success(ApiResponseSuccessData) case error(ApiResponseErrorData) case loading(ApiResponseLoadingData) } public struct ApiResponseSuccessData: Codable { public let data: T public let statusCode: UInt16 private enum CodingKeys: String, CodingKey { case data = "data" case statusCode = "status_code" } } public struct ApiResponseErrorData: Codable { public let message: String public let errorCode: UInt32 private enum CodingKeys: String, CodingKey { case message = "message" case errorCode = "error_code" } } public struct ApiResponseLoadingData: Codable { public let progress: Float } // MARK: - ApiResponse Codable Implementation extension ApiResponse: Codable { private enum CodingKeys: String, CodingKey { case success = "Success" case error = "Error" case loading = "Loading" } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) if container.allKeys.count != 1 { throw DecodingError.dataCorrupted( DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Invalid number of keys found, expected one.") ) } let key = container.allKeys.first! switch key { case .success: let data = try container.decode(ApiResponseSuccessData.self, forKey: .success) self = .success(data) case .error: let data = try container.decode(ApiResponseErrorData.self, forKey: .error) self = .error(data) case .loading: let data = try container.decode(ApiResponseLoadingData.self, forKey: .loading) self = .loading(data) } } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) switch self { case .success(let data): try container.encode(data, forKey: .success) case .error(let data): try container.encode(data, forKey: .error) case .loading(let data): try container.encode(data, forKey: .loading) } } } public struct GenericContainer: Codable { public let primary: T public let secondary: U public let metadata: [(String, String)]? } /// Comprehensive example showcasing ALL configuration options for specta-swift /// /// This example demonstrates every configuration option available in the Swift exporter, /// showing how different settings affect the generated Swift code. /// Sample types for demonstration public struct User: Codable { public let userId: UInt32 public let fullName: String public let emailAddress: String? public let isVerified: Bool private enum CodingKeys: String, CodingKey { case userId = "user_id" case fullName = "full_name" case emailAddress = "email_address" case isVerified = "is_verified" } } ================================================ FILE: specta-swift/examples/generated/ProtocolGenerics.swift ================================================ // This file has been generated by Specta. DO NOT EDIT. import Foundation public enum ApiResponse { case success(ApiResponseSuccessData) case error(ApiResponseErrorData) case loading(ApiResponseLoadingData) } public struct ApiResponseSuccessData: Codable { public let data: T public let statusCode: UInt16 private enum CodingKeys: String, CodingKey { case data = "data" case statusCode = "status_code" } } public struct ApiResponseErrorData: Codable { public let message: String public let errorCode: UInt32 private enum CodingKeys: String, CodingKey { case message = "message" case errorCode = "error_code" } } public struct ApiResponseLoadingData: Codable { public let progress: Float } // MARK: - ApiResponse Codable Implementation extension ApiResponse: Codable { private enum CodingKeys: String, CodingKey { case success = "Success" case error = "Error" case loading = "Loading" } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) if container.allKeys.count != 1 { throw DecodingError.dataCorrupted( DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Invalid number of keys found, expected one.") ) } let key = container.allKeys.first! switch key { case .success: let data = try container.decode(ApiResponseSuccessData.self, forKey: .success) self = .success(data) case .error: let data = try container.decode(ApiResponseErrorData.self, forKey: .error) self = .error(data) case .loading: let data = try container.decode(ApiResponseLoadingData.self, forKey: .loading) self = .loading(data) } } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) switch self { case .success(let data): try container.encode(data, forKey: .success) case .error(let data): try container.encode(data, forKey: .error) case .loading(let data): try container.encode(data, forKey: .loading) } } } public struct GenericContainer: Codable { public let primary: T public let secondary: U public let metadata: [(String, String)]? } /// Comprehensive example showcasing ALL configuration options for specta-swift /// /// This example demonstrates every configuration option available in the Swift exporter, /// showing how different settings affect the generated Swift code. /// Sample types for demonstration public struct User: Codable { public let userId: UInt32 public let fullName: String public let emailAddress: String? public let isVerified: Bool private enum CodingKeys: String, CodingKey { case userId = "user_id" case fullName = "full_name" case emailAddress = "email_address" case isVerified = "is_verified" } } ================================================ FILE: specta-swift/examples/generated/QuestionMark.swift ================================================ // This file has been generated by Specta. DO NOT EDIT. import Foundation public enum ApiResponse { case success(ApiResponseSuccessData) case error(ApiResponseErrorData) case loading(ApiResponseLoadingData) } public struct ApiResponseSuccessData: Codable { public let data: T public let statusCode: UInt16 private enum CodingKeys: String, CodingKey { case data = "data" case statusCode = "status_code" } } public struct ApiResponseErrorData: Codable { public let message: String public let errorCode: UInt32 private enum CodingKeys: String, CodingKey { case message = "message" case errorCode = "error_code" } } public struct ApiResponseLoadingData: Codable { public let progress: Float } // MARK: - ApiResponse Codable Implementation extension ApiResponse: Codable { private enum CodingKeys: String, CodingKey { case success = "Success" case error = "Error" case loading = "Loading" } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) if container.allKeys.count != 1 { throw DecodingError.dataCorrupted( DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Invalid number of keys found, expected one.") ) } let key = container.allKeys.first! switch key { case .success: let data = try container.decode(ApiResponseSuccessData.self, forKey: .success) self = .success(data) case .error: let data = try container.decode(ApiResponseErrorData.self, forKey: .error) self = .error(data) case .loading: let data = try container.decode(ApiResponseLoadingData.self, forKey: .loading) self = .loading(data) } } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) switch self { case .success(let data): try container.encode(data, forKey: .success) case .error(let data): try container.encode(data, forKey: .error) case .loading(let data): try container.encode(data, forKey: .loading) } } } public struct GenericContainer: Codable { public let primary: T public let secondary: U public let metadata: [(String, String)]? } /// Comprehensive example showcasing ALL configuration options for specta-swift /// /// This example demonstrates every configuration option available in the Swift exporter, /// showing how different settings affect the generated Swift code. /// Sample types for demonstration public struct User: Codable { public let userId: UInt32 public let fullName: String public let emailAddress: String? public let isVerified: Bool private enum CodingKeys: String, CodingKey { case userId = "user_id" case fullName = "full_name" case emailAddress = "email_address" case isVerified = "is_verified" } } ================================================ FILE: specta-swift/examples/generated/SimpleTypes.swift ================================================ // This file has been generated by Specta. DO NOT EDIT. import Foundation public enum ApiResult { case success(ApiResultSuccessData) case error(ApiResultErrorData) case loading(ApiResultLoadingData) } public struct ApiResultSuccessData: Codable { public let data: T public let status: UInt16 } public struct ApiResultErrorData: Codable { public let message: String public let code: UInt32 } public struct ApiResultLoadingData: Codable { public let progress: Float } // MARK: - ApiResult Codable Implementation extension ApiResult: Codable { private enum CodingKeys: String, CodingKey { case success = "Success" case error = "Error" case loading = "Loading" } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) if container.allKeys.count != 1 { throw DecodingError.dataCorrupted( DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Invalid number of keys found, expected one.") ) } let key = container.allKeys.first! switch key { case .success: let data = try container.decode(ApiResultSuccessData.self, forKey: .success) self = .success(data) case .error: let data = try container.decode(ApiResultErrorData.self, forKey: .error) self = .error(data) case .loading: let data = try container.decode(ApiResultLoadingData.self, forKey: .loading) self = .loading(data) } } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) switch self { case .success(let data): try container.encode(data, forKey: .success) case .error(let data): try container.encode(data, forKey: .error) case .loading(let data): try container.encode(data, forKey: .loading) } } } public struct User: Codable { public let id: UInt32 public let name: String public let email: String? public let role: UserRole } public enum UserRole { case guest case user(UserRoleUserData) case admin(UserRoleAdminData) case superAdmin(UserRoleSuperAdminData) } public struct UserRoleUserData: Codable { public let permissions: [String] } public struct UserRoleAdminData: Codable { public let level: UInt8 public let department: String } public struct UserRoleSuperAdminData: Codable { public let accessLevel: UInt32 private enum CodingKeys: String, CodingKey { case accessLevel = "access_level" } } // MARK: - UserRole Codable Implementation extension UserRole: Codable { private enum CodingKeys: String, CodingKey { case guest = "Guest" case user = "User" case admin = "Admin" case superAdmin = "SuperAdmin" } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) if container.allKeys.count != 1 { throw DecodingError.dataCorrupted( DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Invalid number of keys found, expected one.") ) } let key = container.allKeys.first! switch key { case .guest: self = .guest case .user: let data = try container.decode(UserRoleUserData.self, forKey: .user) self = .user(data) case .admin: let data = try container.decode(UserRoleAdminData.self, forKey: .admin) self = .admin(data) case .superAdmin: let data = try container.decode(UserRoleSuperAdminData.self, forKey: .superAdmin) self = .superAdmin(data) } } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) switch self { case .guest: try container.encodeNil(forKey: .guest) case .user(let data): try container.encode(data, forKey: .user) case .admin(let data): try container.encode(data, forKey: .admin) case .superAdmin(let data): try container.encode(data, forKey: .superAdmin) } } } ================================================ FILE: specta-swift/examples/generated/SnakeCase.swift ================================================ // This file has been generated by Specta. DO NOT EDIT. import Foundation public enum api_response { case success(api_responseSuccessData) case error(api_responseErrorData) case loading(api_responseLoadingData) } public struct api_responseSuccessData: Codable { public let data: T public let status_code: UInt16 } public struct api_responseErrorData: Codable { public let message: String public let error_code: UInt32 } public struct api_responseLoadingData: Codable { public let progress: Float } // MARK: - api_response Codable Implementation extension api_response: Codable { private enum CodingKeys: String, CodingKey { case success = "Success" case error = "Error" case loading = "Loading" } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) if container.allKeys.count != 1 { throw DecodingError.dataCorrupted( DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Invalid number of keys found, expected one.") ) } let key = container.allKeys.first! switch key { case .success: let data = try container.decode(api_responseSuccessData.self, forKey: .success) self = .success(data) case .error: let data = try container.decode(api_responseErrorData.self, forKey: .error) self = .error(data) case .loading: let data = try container.decode(api_responseLoadingData.self, forKey: .loading) self = .loading(data) } } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) switch self { case .success(let data): try container.encode(data, forKey: .success) case .error(let data): try container.encode(data, forKey: .error) case .loading(let data): try container.encode(data, forKey: .loading) } } } public struct generic_container: Codable { public let primary: T public let secondary: U public let metadata: [(String, String)]? } /// Comprehensive example showcasing ALL configuration options for specta-swift /// /// This example demonstrates every configuration option available in the Swift exporter, /// showing how different settings affect the generated Swift code. /// Sample types for demonstration public struct user: Codable { public let user_id: UInt32 public let full_name: String public let email_address: String? public let is_verified: Bool } ================================================ FILE: specta-swift/examples/generated/Spaces2.swift ================================================ // This file has been generated by Specta. DO NOT EDIT. import Foundation public enum ApiResponse { case success(ApiResponseSuccessData) case error(ApiResponseErrorData) case loading(ApiResponseLoadingData) } public struct ApiResponseSuccessData: Codable { public let data: T public let statusCode: UInt16 private enum CodingKeys: String, CodingKey { case data = "data" case statusCode = "status_code" } } public struct ApiResponseErrorData: Codable { public let message: String public let errorCode: UInt32 private enum CodingKeys: String, CodingKey { case message = "message" case errorCode = "error_code" } } public struct ApiResponseLoadingData: Codable { public let progress: Float } // MARK: - ApiResponse Codable Implementation extension ApiResponse: Codable { private enum CodingKeys: String, CodingKey { case success = "Success" case error = "Error" case loading = "Loading" } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) if container.allKeys.count != 1 { throw DecodingError.dataCorrupted( DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Invalid number of keys found, expected one.") ) } let key = container.allKeys.first! switch key { case .success: let data = try container.decode(ApiResponseSuccessData.self, forKey: .success) self = .success(data) case .error: let data = try container.decode(ApiResponseErrorData.self, forKey: .error) self = .error(data) case .loading: let data = try container.decode(ApiResponseLoadingData.self, forKey: .loading) self = .loading(data) } } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) switch self { case .success(let data): try container.encode(data, forKey: .success) case .error(let data): try container.encode(data, forKey: .error) case .loading(let data): try container.encode(data, forKey: .loading) } } } public struct GenericContainer: Codable { public let primary: T public let secondary: U public let metadata: [(String, String)]? } /// Comprehensive example showcasing ALL configuration options for specta-swift /// /// This example demonstrates every configuration option available in the Swift exporter, /// showing how different settings affect the generated Swift code. /// Sample types for demonstration public struct User: Codable { public let userId: UInt32 public let fullName: String public let emailAddress: String? public let isVerified: Bool private enum CodingKeys: String, CodingKey { case userId = "user_id" case fullName = "full_name" case emailAddress = "email_address" case isVerified = "is_verified" } } ================================================ FILE: specta-swift/examples/generated/Spaces4.swift ================================================ // This file has been generated by Specta. DO NOT EDIT. import Foundation public enum ApiResponse { case success(ApiResponseSuccessData) case error(ApiResponseErrorData) case loading(ApiResponseLoadingData) } public struct ApiResponseSuccessData: Codable { public let data: T public let statusCode: UInt16 private enum CodingKeys: String, CodingKey { case data = "data" case statusCode = "status_code" } } public struct ApiResponseErrorData: Codable { public let message: String public let errorCode: UInt32 private enum CodingKeys: String, CodingKey { case message = "message" case errorCode = "error_code" } } public struct ApiResponseLoadingData: Codable { public let progress: Float } // MARK: - ApiResponse Codable Implementation extension ApiResponse: Codable { private enum CodingKeys: String, CodingKey { case success = "Success" case error = "Error" case loading = "Loading" } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) if container.allKeys.count != 1 { throw DecodingError.dataCorrupted( DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Invalid number of keys found, expected one.") ) } let key = container.allKeys.first! switch key { case .success: let data = try container.decode(ApiResponseSuccessData.self, forKey: .success) self = .success(data) case .error: let data = try container.decode(ApiResponseErrorData.self, forKey: .error) self = .error(data) case .loading: let data = try container.decode(ApiResponseLoadingData.self, forKey: .loading) self = .loading(data) } } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) switch self { case .success(let data): try container.encode(data, forKey: .success) case .error(let data): try container.encode(data, forKey: .error) case .loading(let data): try container.encode(data, forKey: .loading) } } } public struct GenericContainer: Codable { public let primary: T public let secondary: U public let metadata: [(String, String)]? } /// Comprehensive example showcasing ALL configuration options for specta-swift /// /// This example demonstrates every configuration option available in the Swift exporter, /// showing how different settings affect the generated Swift code. /// Sample types for demonstration public struct User: Codable { public let userId: UInt32 public let fullName: String public let emailAddress: String? public let isVerified: Bool private enum CodingKeys: String, CodingKey { case userId = "user_id" case fullName = "full_name" case emailAddress = "email_address" case isVerified = "is_verified" } } ================================================ FILE: specta-swift/examples/generated/SpecialTypes.swift ================================================ // This file has been generated by Specta. DO NOT EDIT. import Foundation // MARK: - Duration Helper /// Helper struct to decode Rust Duration format {"secs": u64, "nanos": u32} public struct RustDuration: Codable { public let secs: UInt64 public let nanos: UInt32 public var timeInterval: TimeInterval { return Double(secs) + Double(nanos) / 1_000_000_000.0 } } // MARK: - Generated Types /// API response with timing information public struct ApiResponse: Codable { public let data: String public let processingDuration: RustDuration public let cacheDuration: RustDuration? public let transferDuration: RustDuration public let statusCode: UInt16 private enum CodingKeys: String, CodingKey { case data = "data" case processingDuration = "processing_duration" case cacheDuration = "cache_duration" case transferDuration = "transfer_duration" case statusCode = "status_code" } } /// Struct with various timestamp types public struct EventLog: Codable { public let eventId: String public let timestamp: String public let duration: RustDuration public let metadata: [(String, String)]? private enum CodingKeys: String, CodingKey { case eventId = "event_id" case timestamp = "timestamp" case duration = "duration" case metadata = "metadata" } } /// Example showcasing special type handling in specta-swift /// /// This example demonstrates how specta-swift handles special Rust types /// like Duration, UUID, chrono types, and other commonly used types /// that need special conversion to Swift equivalents. /// Struct with Duration fields (will be converted to RustDuration helper) public struct IndexerMetrics: Codable { public let totalDuration: RustDuration public let discoveryDuration: RustDuration public let processingDuration: RustDuration public let contentDuration: RustDuration public let filesProcessed: UInt32 public let avgTimePerFile: RustDuration private enum CodingKeys: String, CodingKey { case totalDuration = "total_duration" case discoveryDuration = "discovery_duration" case processingDuration = "processing_duration" case contentDuration = "content_duration" case filesProcessed = "files_processed" case avgTimePerFile = "avg_time_per_file" } } /// Job status with timing public enum JobStatus { case queued case running(JobStatusRunningData) case completed(JobStatusCompletedData) case failed(JobStatusFailedData) } public struct JobStatusRunningData: Codable { public let startedAt: String public let elapsedTime: RustDuration public let estimatedCompletion: String? private enum CodingKeys: String, CodingKey { case startedAt = "started_at" case elapsedTime = "elapsed_time" case estimatedCompletion = "estimated_completion" } } public struct JobStatusCompletedData: Codable { public let startedAt: String public let completedAt: String public let totalDuration: RustDuration public let result: String private enum CodingKeys: String, CodingKey { case startedAt = "started_at" case completedAt = "completed_at" case totalDuration = "total_duration" case result = "result" } } public struct JobStatusFailedData: Codable { public let startedAt: String public let failedAt: String public let duration: RustDuration public let errorMessage: String private enum CodingKeys: String, CodingKey { case startedAt = "started_at" case failedAt = "failed_at" case duration = "duration" case errorMessage = "error_message" } } // MARK: - JobStatus Codable Implementation extension JobStatus: Codable { private enum CodingKeys: String, CodingKey { case queued = "Queued" case running = "Running" case completed = "Completed" case failed = "Failed" } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) if container.allKeys.count != 1 { throw DecodingError.dataCorrupted( DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Invalid number of keys found, expected one.") ) } let key = container.allKeys.first! switch key { case .queued: self = .queued case .running: let data = try container.decode(JobStatusRunningData.self, forKey: .running) self = .running(data) case .completed: let data = try container.decode(JobStatusCompletedData.self, forKey: .completed) self = .completed(data) case .failed: let data = try container.decode(JobStatusFailedData.self, forKey: .failed) self = .failed(data) } } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) switch self { case .queued: try container.encodeNil(forKey: .queued) case .running(let data): try container.encode(data, forKey: .running) case .completed(let data): try container.encode(data, forKey: .completed) case .failed(let data): try container.encode(data, forKey: .failed) } } } /// Performance metrics struct public struct PerformanceMetrics: Codable { public let responseTime: RustDuration public let processingTime: RustDuration public let queryTime: RustDuration public let networkLatency: RustDuration public let totalTime: RustDuration private enum CodingKeys: String, CodingKey { case responseTime = "response_time" case processingTime = "processing_time" case queryTime = "query_time" case networkLatency = "network_latency" case totalTime = "total_time" } } /// Complex struct mixing Duration with other types public struct SystemHealth: Codable { public let uptime: RustDuration public let lastCheck: RustDuration public let avgResponseTime: RustDuration public let status: String public let memoryUsage: Double public let cpuUsage: Double private enum CodingKeys: String, CodingKey { case uptime = "uptime" case lastCheck = "last_check" case avgResponseTime = "avg_response_time" case status = "status" case memoryUsage = "memory_usage" case cpuUsage = "cpu_usage" } } /// Configuration struct with timing information public struct TaskConfig: Codable { public let name: String public let timeout: RustDuration public let retryInterval: RustDuration public let backoffDuration: RustDuration public let enabled: Bool private enum CodingKeys: String, CodingKey { case name = "name" case timeout = "timeout" case retryInterval = "retry_interval" case backoffDuration = "backoff_duration" case enabled = "enabled" } } ================================================ FILE: specta-swift/examples/generated/StringEnums.swift ================================================ // This file has been generated by Specta. DO NOT EDIT. import Foundation /// Mixed enum with both string-like and data variants public enum ApiResult { case success case successWithData(ApiResultSuccessWithDataData) case error(ApiResultErrorData) case loading } public struct ApiResultSuccessWithDataData: Codable { public let data: String public let statusCode: UInt16 private enum CodingKeys: String, CodingKey { case data = "data" case statusCode = "status_code" } } public struct ApiResultErrorData: Codable { public let message: String public let code: UInt32 } // MARK: - ApiResult Codable Implementation extension ApiResult: Codable { private enum CodingKeys: String, CodingKey { case success = "Success" case successWithData = "SuccessWithData" case error = "Error" case loading = "Loading" } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) if container.allKeys.count != 1 { throw DecodingError.dataCorrupted( DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Invalid number of keys found, expected one.") ) } let key = container.allKeys.first! switch key { case .success: self = .success case .successWithData: let data = try container.decode(ApiResultSuccessWithDataData.self, forKey: .successWithData) self = .successWithData(data) case .error: let data = try container.decode(ApiResultErrorData.self, forKey: .error) self = .error(data) case .loading: self = .loading } } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) switch self { case .success: try container.encodeNil(forKey: .success) case .successWithData(let data): try container.encode(data, forKey: .successWithData) case .error(let data): try container.encode(data, forKey: .error) case .loading: try container.encodeNil(forKey: .loading) } } } /// String enum with more complex values public enum Environment: Codable { case development case staging case production case testing } /// Complex enum with multiple data variants public enum EventType { case userCreated case userUpdated(EventTypeUserUpdatedData) case userDeleted(EventTypeUserDeletedData) case systemEvent(EventTypeSystemEventData) } public struct EventTypeUserUpdatedData: Codable { public let userId: UInt32 public let changes: [(String, String)] private enum CodingKeys: String, CodingKey { case userId = "user_id" case changes = "changes" } } public struct EventTypeUserDeletedData: Codable { public let userId: UInt32 public let reason: String private enum CodingKeys: String, CodingKey { case userId = "user_id" case reason = "reason" } } public struct EventTypeSystemEventData: Codable { public let component: String public let level: String public let message: String } // MARK: - EventType Codable Implementation extension EventType: Codable { private enum CodingKeys: String, CodingKey { case userCreated = "UserCreated" case userUpdated = "UserUpdated" case userDeleted = "UserDeleted" case systemEvent = "SystemEvent" } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) if container.allKeys.count != 1 { throw DecodingError.dataCorrupted( DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Invalid number of keys found, expected one.") ) } let key = container.allKeys.first! switch key { case .userCreated: self = .userCreated case .userUpdated: let data = try container.decode(EventTypeUserUpdatedData.self, forKey: .userUpdated) self = .userUpdated(data) case .userDeleted: let data = try container.decode(EventTypeUserDeletedData.self, forKey: .userDeleted) self = .userDeleted(data) case .systemEvent: let data = try container.decode(EventTypeSystemEventData.self, forKey: .systemEvent) self = .systemEvent(data) } } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) switch self { case .userCreated: try container.encodeNil(forKey: .userCreated) case .userUpdated(let data): try container.encode(data, forKey: .userUpdated) case .userDeleted(let data): try container.encode(data, forKey: .userDeleted) case .systemEvent(let data): try container.encode(data, forKey: .systemEvent) } } } /// String enum for file types public enum FileType: Codable { case image case video case audio case document case archive case unknown } /// Comprehensive example showcasing string enums and custom Codable implementations /// /// This example demonstrates how specta-swift handles string enums, mixed enums, /// and generates appropriate Codable implementations for different enum patterns. /// Simple string enum (will be converted to Swift String enum with Codable) public enum HttpStatus: Codable { case ok case created case accepted case noContent case badRequest case unauthorized case notFound case internalServerError } /// String enum for job states public enum JobState: Codable { case queued case running case paused case completed case failed case cancelled } /// Mixed enum with complex variants public enum NotificationType { case email case push case sms case webhook(NotificationTypeWebhookData) case inApp(NotificationTypeInAppData) } public struct NotificationTypeWebhookData: Codable { public let url: String public let headers: [(String, String)] public let retryCount: UInt32 private enum CodingKeys: String, CodingKey { case url = "url" case headers = "headers" case retryCount = "retry_count" } } public struct NotificationTypeInAppData: Codable { public let title: String public let message: String public let priority: String } // MARK: - NotificationType Codable Implementation extension NotificationType: Codable { private enum CodingKeys: String, CodingKey { case email = "Email" case push = "Push" case sms = "Sms" case webhook = "Webhook" case inApp = "InApp" } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) if container.allKeys.count != 1 { throw DecodingError.dataCorrupted( DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Invalid number of keys found, expected one.") ) } let key = container.allKeys.first! switch key { case .email: self = .email case .push: self = .push case .sms: self = .sms case .webhook: let data = try container.decode(NotificationTypeWebhookData.self, forKey: .webhook) self = .webhook(data) case .inApp: let data = try container.decode(NotificationTypeInAppData.self, forKey: .inApp) self = .inApp(data) } } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) switch self { case .email: try container.encodeNil(forKey: .email) case .push: try container.encodeNil(forKey: .push) case .sms: try container.encodeNil(forKey: .sms) case .webhook(let data): try container.encode(data, forKey: .webhook) case .inApp(let data): try container.encode(data, forKey: .inApp) } } } /// Enum with generic type parameter public enum Result: Codable { case ok(T) case err(E) } /// Complex mixed enum public enum UserAction { case login case logout case updateProfile(UserActionUpdateProfileData) case changePassword(UserActionChangePasswordData) case deleteAccount } public struct UserActionUpdateProfileData: Codable { public let name: String public let email: String public let avatarUrl: String? private enum CodingKeys: String, CodingKey { case name = "name" case email = "email" case avatarUrl = "avatar_url" } } public struct UserActionChangePasswordData: Codable { public let oldPassword: String public let newPassword: String private enum CodingKeys: String, CodingKey { case oldPassword = "old_password" case newPassword = "new_password" } } // MARK: - UserAction Codable Implementation extension UserAction: Codable { private enum CodingKeys: String, CodingKey { case login = "Login" case logout = "Logout" case updateProfile = "UpdateProfile" case changePassword = "ChangePassword" case deleteAccount = "DeleteAccount" } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) if container.allKeys.count != 1 { throw DecodingError.dataCorrupted( DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Invalid number of keys found, expected one.") ) } let key = container.allKeys.first! switch key { case .login: self = .login case .logout: self = .logout case .updateProfile: let data = try container.decode(UserActionUpdateProfileData.self, forKey: .updateProfile) self = .updateProfile(data) case .changePassword: let data = try container.decode(UserActionChangePasswordData.self, forKey: .changePassword) self = .changePassword(data) case .deleteAccount: self = .deleteAccount } } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) switch self { case .login: try container.encodeNil(forKey: .login) case .logout: try container.encodeNil(forKey: .logout) case .updateProfile(let data): try container.encode(data, forKey: .updateProfile) case .changePassword(let data): try container.encode(data, forKey: .changePassword) case .deleteAccount: try container.encodeNil(forKey: .deleteAccount) } } } ================================================ FILE: specta-swift/examples/generated/Tabs.swift ================================================ // This file has been generated by Specta. DO NOT EDIT. import Foundation public enum ApiResponse { case success(ApiResponseSuccessData) case error(ApiResponseErrorData) case loading(ApiResponseLoadingData) } public struct ApiResponseSuccessData: Codable { public let data: T public let statusCode: UInt16 private enum CodingKeys: String, CodingKey { case data = "data" case statusCode = "status_code" } } public struct ApiResponseErrorData: Codable { public let message: String public let errorCode: UInt32 private enum CodingKeys: String, CodingKey { case message = "message" case errorCode = "error_code" } } public struct ApiResponseLoadingData: Codable { public let progress: Float } // MARK: - ApiResponse Codable Implementation extension ApiResponse: Codable { private enum CodingKeys: String, CodingKey { case success = "Success" case error = "Error" case loading = "Loading" } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) if container.allKeys.count != 1 { throw DecodingError.dataCorrupted( DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Invalid number of keys found, expected one.") ) } let key = container.allKeys.first! switch key { case .success: let data = try container.decode(ApiResponseSuccessData.self, forKey: .success) self = .success(data) case .error: let data = try container.decode(ApiResponseErrorData.self, forKey: .error) self = .error(data) case .loading: let data = try container.decode(ApiResponseLoadingData.self, forKey: .loading) self = .loading(data) } } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) switch self { case .success(let data): try container.encode(data, forKey: .success) case .error(let data): try container.encode(data, forKey: .error) case .loading(let data): try container.encode(data, forKey: .loading) } } } public struct GenericContainer: Codable { public let primary: T public let secondary: U public let metadata: [(String, String)]? } /// Comprehensive example showcasing ALL configuration options for specta-swift /// /// This example demonstrates every configuration option available in the Swift exporter, /// showing how different settings affect the generated Swift code. /// Sample types for demonstration public struct User: Codable { public let userId: UInt32 public let fullName: String public let emailAddress: String? public let isVerified: Bool private enum CodingKeys: String, CodingKey { case userId = "user_id" case fullName = "full_name" case emailAddress = "email_address" case isVerified = "is_verified" } } ================================================ FILE: specta-swift/examples/generated/TypealiasGenerics.swift ================================================ // This file has been generated by Specta. DO NOT EDIT. import Foundation public enum ApiResponse { case success(ApiResponseSuccessData) case error(ApiResponseErrorData) case loading(ApiResponseLoadingData) } public struct ApiResponseSuccessData: Codable { public let data: T public let statusCode: UInt16 private enum CodingKeys: String, CodingKey { case data = "data" case statusCode = "status_code" } } public struct ApiResponseErrorData: Codable { public let message: String public let errorCode: UInt32 private enum CodingKeys: String, CodingKey { case message = "message" case errorCode = "error_code" } } public struct ApiResponseLoadingData: Codable { public let progress: Float } // MARK: - ApiResponse Codable Implementation extension ApiResponse: Codable { private enum CodingKeys: String, CodingKey { case success = "Success" case error = "Error" case loading = "Loading" } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) if container.allKeys.count != 1 { throw DecodingError.dataCorrupted( DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Invalid number of keys found, expected one.") ) } let key = container.allKeys.first! switch key { case .success: let data = try container.decode(ApiResponseSuccessData.self, forKey: .success) self = .success(data) case .error: let data = try container.decode(ApiResponseErrorData.self, forKey: .error) self = .error(data) case .loading: let data = try container.decode(ApiResponseLoadingData.self, forKey: .loading) self = .loading(data) } } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) switch self { case .success(let data): try container.encode(data, forKey: .success) case .error(let data): try container.encode(data, forKey: .error) case .loading(let data): try container.encode(data, forKey: .loading) } } } public struct GenericContainer: Codable { public let primary: T public let secondary: U public let metadata: [(String, String)]? } /// Comprehensive example showcasing ALL configuration options for specta-swift /// /// This example demonstrates every configuration option available in the Swift exporter, /// showing how different settings affect the generated Swift code. /// Sample types for demonstration public struct User: Codable { public let userId: UInt32 public let fullName: String public let emailAddress: String? public let isVerified: Bool private enum CodingKeys: String, CodingKey { case userId = "user_id" case fullName = "full_name" case emailAddress = "email_address" case isVerified = "is_verified" } } ================================================ FILE: specta-swift/examples/generated/WithProtocols.swift ================================================ // This file has been generated by Specta. DO NOT EDIT. import Foundation import Equatable import Hashable import CustomStringConvertible public enum ApiResponse { case success(ApiResponseSuccessData) case error(ApiResponseErrorData) case loading(ApiResponseLoadingData) } public struct ApiResponseSuccessData: Codable { public let data: T public let statusCode: UInt16 private enum CodingKeys: String, CodingKey { case data = "data" case statusCode = "status_code" } } public struct ApiResponseErrorData: Codable { public let message: String public let errorCode: UInt32 private enum CodingKeys: String, CodingKey { case message = "message" case errorCode = "error_code" } } public struct ApiResponseLoadingData: Codable { public let progress: Float } // MARK: - ApiResponse Codable Implementation extension ApiResponse: Codable { private enum CodingKeys: String, CodingKey { case success = "Success" case error = "Error" case loading = "Loading" } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) if container.allKeys.count != 1 { throw DecodingError.dataCorrupted( DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Invalid number of keys found, expected one.") ) } let key = container.allKeys.first! switch key { case .success: let data = try container.decode(ApiResponseSuccessData.self, forKey: .success) self = .success(data) case .error: let data = try container.decode(ApiResponseErrorData.self, forKey: .error) self = .error(data) case .loading: let data = try container.decode(ApiResponseLoadingData.self, forKey: .loading) self = .loading(data) } } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) switch self { case .success(let data): try container.encode(data, forKey: .success) case .error(let data): try container.encode(data, forKey: .error) case .loading(let data): try container.encode(data, forKey: .loading) } } } public struct GenericContainer: Codable { public let primary: T public let secondary: U public let metadata: [(String, String)]? } /// Comprehensive example showcasing ALL configuration options for specta-swift /// /// This example demonstrates every configuration option available in the Swift exporter, /// showing how different settings affect the generated Swift code. /// Sample types for demonstration public struct User: Codable { public let userId: UInt32 public let fullName: String public let emailAddress: String? public let isVerified: Bool private enum CodingKeys: String, CodingKey { case userId = "user_id" case fullName = "full_name" case emailAddress = "email_address" case isVerified = "is_verified" } } ================================================ FILE: specta-swift/examples/generated/WithSerde.swift ================================================ // This file has been generated by Specta. DO NOT EDIT. import Foundation import Codable public enum ApiResponse { case success(ApiResponseSuccessData) case error(ApiResponseErrorData) case loading(ApiResponseLoadingData) } public struct ApiResponseSuccessData: Codable { public let data: T public let statusCode: UInt16 private enum CodingKeys: String, CodingKey { case data = "data" case statusCode = "status_code" } } public struct ApiResponseErrorData: Codable { public let message: String public let errorCode: UInt32 private enum CodingKeys: String, CodingKey { case message = "message" case errorCode = "error_code" } } public struct ApiResponseLoadingData: Codable { public let progress: Float } // MARK: - ApiResponse Codable Implementation extension ApiResponse: Codable { private enum CodingKeys: String, CodingKey { case success = "Success" case error = "Error" case loading = "Loading" } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) if container.allKeys.count != 1 { throw DecodingError.dataCorrupted( DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Invalid number of keys found, expected one.") ) } let key = container.allKeys.first! switch key { case .success: let data = try container.decode(ApiResponseSuccessData.self, forKey: .success) self = .success(data) case .error: let data = try container.decode(ApiResponseErrorData.self, forKey: .error) self = .error(data) case .loading: let data = try container.decode(ApiResponseLoadingData.self, forKey: .loading) self = .loading(data) } } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) switch self { case .success(let data): try container.encode(data, forKey: .success) case .error(let data): try container.encode(data, forKey: .error) case .loading(let data): try container.encode(data, forKey: .loading) } } } public struct GenericContainer: Codable { public let primary: T public let secondary: U public let metadata: [(String, String)]? } /// Comprehensive example showcasing ALL configuration options for specta-swift /// /// This example demonstrates every configuration option available in the Swift exporter, /// showing how different settings affect the generated Swift code. /// Sample types for demonstration public struct User: Codable { public let userId: UInt32 public let fullName: String public let emailAddress: String? public let isVerified: Bool private enum CodingKeys: String, CodingKey { case userId = "user_id" case fullName = "full_name" case emailAddress = "email_address" case isVerified = "is_verified" } } ================================================ FILE: specta-swift/examples/simple_usage.rs ================================================ #![allow(dead_code, missing_docs)] use specta::{Type, Types}; use specta_swift::Swift; // Simple user management types #[derive(Type)] struct User { id: u32, name: String, email: Option, role: UserRole, } #[derive(Type)] enum UserRole { Guest, User { permissions: Vec }, Admin { level: u8, department: String }, SuperAdmin { access_level: u32 }, } #[derive(Type)] enum ApiResult { Success { data: T, status: u16 }, Error { message: String, code: u32 }, Loading { progress: f32 }, } fn main() { // Create a type collection let types = Types::default() .register::() .register::() .register::>(); // Export to Swift with default settings let swift = Swift::default(); swift .export_to( "./examples/generated/SimpleTypes.swift", &types, specta_serde::Format, ) .unwrap(); println!("Simple types exported to SimpleTypes.swift"); // Export with custom settings let custom_swift = Swift::new() .header("// Generated by MyApp - Custom Header") .naming(specta_swift::NamingConvention::SnakeCase) .optionals(specta_swift::OptionalStyle::Optional); custom_swift .export_to( "./examples/generated/CustomTypes.swift", &types, specta_serde::Format, ) .unwrap(); println!("Custom types exported to CustomTypes.swift"); } ================================================ FILE: specta-swift/examples/special_types.rs ================================================ #![allow(dead_code, missing_docs)] use specta::{Type, Types}; use specta_swift::Swift; use std::time::Duration; /// Example showcasing special type handling in specta-swift /// /// This example demonstrates how specta-swift handles special Rust types /// like Duration, UUID, chrono types, and other commonly used types /// that need special conversion to Swift equivalents. /// Struct with Duration fields (will be converted to RustDuration helper) #[derive(Type)] struct IndexerMetrics { /// Total time spent indexing total_duration: Duration, /// Time spent discovering files discovery_duration: Duration, /// Time spent processing content processing_duration: Duration, /// Time spent analyzing content content_duration: Duration, /// Number of files processed files_processed: u32, /// Average processing time per file avg_time_per_file: Duration, } /// Struct with various timestamp types #[derive(Type)] struct EventLog { /// Event ID event_id: String, /// When the event occurred timestamp: String, /// Event duration duration: Duration, /// Additional metadata metadata: Option>, } /// Configuration struct with timing information #[derive(Type)] struct TaskConfig { /// Task name name: String, /// Maximum execution time timeout: Duration, /// Retry interval retry_interval: Duration, /// Backoff duration backoff_duration: Duration, /// Whether task is enabled enabled: bool, } /// Performance metrics struct #[derive(Type)] struct PerformanceMetrics { /// Response time response_time: Duration, /// Processing time processing_time: Duration, /// Database query time query_time: Duration, /// Network latency network_latency: Duration, /// Total time total_time: Duration, } /// API response with timing information #[derive(Type)] struct ApiResponse { /// Response data data: String, /// Processing duration processing_duration: Duration, /// Cache hit duration (if applicable) cache_duration: Option, /// Network transfer duration transfer_duration: Duration, /// Status code status_code: u16, } /// Job status with timing #[derive(Type)] enum JobStatus { /// Job is queued Queued, /// Job is running with timing info Running { started_at: String, elapsed_time: Duration, estimated_completion: Option, }, /// Job completed successfully Completed { started_at: String, completed_at: String, total_duration: Duration, result: String, }, /// Job failed with error and timing Failed { started_at: String, failed_at: String, duration: Duration, error_message: String, }, } /// Complex struct mixing Duration with other types #[derive(Type)] struct SystemHealth { /// System uptime uptime: Duration, /// Last health check last_check: Duration, /// Average response time avg_response_time: Duration, /// System status status: String, /// Memory usage percentage memory_usage: f64, /// CPU usage percentage cpu_usage: f64, } fn main() { println!("🚀 Special Types Example - Duration and timing types"); println!("{}", "=".repeat(60)); // Create type collection with all our special types let types = Types::default() .register::() .register::() .register::() .register::() .register::() .register::() .register::(); // Export with default settings let swift = Swift::default(); let output = swift.export(&types, specta_serde::Format).unwrap(); println!("📝 Generated Swift code:\n"); println!("{}", output); // Write to file for inspection swift .export_to( "./examples/generated/SpecialTypes.swift", &types, specta_serde::Format, ) .unwrap(); println!("✅ Special types exported to SpecialTypes.swift"); println!("\n🔍 Key Features Demonstrated:"); println!("• Duration type mapping to RustDuration helper struct"); println!("• Automatic helper struct generation for Duration types"); println!("• timeInterval property for easy Swift integration"); println!("• Duration fields in structs and enum variants"); println!("• Optional Duration fields"); println!("• Complex timing-related data structures"); println!("• Performance metrics with multiple Duration fields"); println!("\n💡 Duration Helper Features:"); println!("• RustDuration struct with secs and nanos fields"); println!("• timeInterval computed property (Double)"); println!("• Proper Codable implementation for Rust format"); println!("• Automatic injection when Duration types are detected"); println!("\n📋 Generated Helper Struct:"); println!("```swift"); println!("public struct RustDuration: Codable {{"); println!(" public let secs: UInt64"); println!(" public let nanos: UInt32"); println!(" "); println!(" public var timeInterval: TimeInterval {{"); println!(" return Double(secs) + Double(nanos) / 1_000_000_000.0"); println!(" }}"); println!("}}"); println!("```"); } ================================================ FILE: specta-swift/examples/string_enums.rs ================================================ #![allow(dead_code, missing_docs)] use specta::{Type, Types}; use specta_swift::Swift; /// Comprehensive example showcasing string enums and custom Codable implementations /// /// This example demonstrates how specta-swift handles string enums, mixed enums, /// and generates appropriate Codable implementations for different enum patterns. /// Simple string enum (will be converted to Swift String enum with Codable) #[derive(Type)] enum HttpStatus { /// Request was successful Ok, /// Resource was created Created, /// Request was accepted Accepted, /// No content to return NoContent, /// Bad request BadRequest, /// Unauthorized access Unauthorized, /// Resource not found NotFound, /// Internal server error InternalServerError, } /// String enum with more complex values #[derive(Type)] enum Environment { /// Development environment Development, /// Staging environment Staging, /// Production environment Production, /// Testing environment Testing, } /// Mixed enum with both string-like and data variants #[derive(Type)] enum ApiResult { /// Simple success case Success, /// Success with data SuccessWithData { data: String, status_code: u16 }, /// Error case Error { message: String, code: u32 }, /// Loading state Loading, } /// Complex mixed enum #[derive(Type)] enum UserAction { /// Simple login action Login, /// Logout action Logout, /// Update profile with data UpdateProfile { name: String, email: String, avatar_url: Option, }, /// Change password ChangePassword { old_password: String, new_password: String, }, /// Delete account DeleteAccount, } /// String enum for job states #[derive(Type)] enum JobState { /// Job is waiting in queue Queued, /// Job is currently running Running, /// Job is paused Paused, /// Job completed successfully Completed, /// Job failed with error Failed, /// Job was cancelled Cancelled, } /// Mixed enum with complex variants #[derive(Type)] enum NotificationType { /// Simple email notification Email, /// Push notification Push, /// SMS notification Sms, /// Webhook notification with payload Webhook { url: String, headers: Vec<(String, String)>, retry_count: u32, }, /// In-app notification InApp { title: String, message: String, priority: String, }, } /// Enum with generic type parameter #[derive(Type)] enum Result { /// Success with data Ok(T), /// Error with error details Err(E), } /// Complex enum with multiple data variants #[derive(Type)] enum EventType { /// User created event UserCreated, /// User updated event UserUpdated { user_id: u32, changes: Vec<(String, String)>, }, /// User deleted event UserDeleted { user_id: u32, reason: String }, /// System event SystemEvent { component: String, level: String, message: String, }, } /// String enum for file types #[derive(Type)] enum FileType { /// Image files Image, /// Video files Video, /// Audio files Audio, /// Document files Document, /// Archive files Archive, /// Unknown file type Unknown, } fn main() { println!("🚀 String Enums Example - String enums and custom Codable"); println!("{}", "=".repeat(60)); // Create type collection with all our enum types let types = Types::default() .register::() .register::() .register::() .register::() .register::() .register::() .register::>() .register::() .register::(); // Export with default settings let swift = Swift::default(); let output = swift.export(&types, specta_serde::Format).unwrap(); println!("📝 Generated Swift code:\n"); println!("{}", output); // Write to file for inspection swift .export_to( "./examples/generated/StringEnums.swift", &types, specta_serde::Format, ) .unwrap(); println!("✅ String enums exported to StringEnums.swift"); println!("\n🔍 Key Features Demonstrated:"); println!("• Pure string enums (String, Codable)"); println!("• Mixed enums with both simple and complex variants"); println!("• Custom Codable implementations for complex enums"); println!("• Struct generation for named field variants"); println!("• Generic enum support"); println!("• Proper Swift enum case naming"); println!("• Automatic protocol conformance"); println!("\n📋 String Enum Features:"); println!("• Automatic String and Codable conformance"); println!("• Simple enum cases without associated values"); println!("• Clean Swift enum representation"); println!("\n📋 Mixed Enum Features:"); println!("• Custom Codable implementation generation"); println!("• Struct generation for named field variants"); println!("• Proper key mapping (Rust → Swift naming)"); println!("• Error handling in Codable implementations"); println!("• Support for both simple and complex variants"); println!("\n💡 Generated Codable Features:"); println!("• CodingKeys enum for key mapping"); println!("• Custom init(from decoder:) implementation"); println!("• Custom encode(to encoder:) implementation"); println!("• Error handling for invalid data"); println!("• Support for nested data structures"); } ================================================ FILE: specta-swift/src/error.rs ================================================ //! Error types for the Swift language exporter. use thiserror::Error; /// Errors that can occur during Swift code generation. #[derive(Debug, Error)] pub enum Error { /// Swift does not support this type. #[error("Unsupported type: {0}")] UnsupportedType(String), /// Invalid identifier for Swift. #[error("Invalid identifier: {0}")] InvalidIdentifier(String), /// Circular reference detected in type definitions. #[error("Circular reference detected")] CircularReference, /// Generic constraint error. #[error("Generic constraint error: {0}")] GenericConstraint(String), /// IO error during file operations. #[error("IO error: {0}")] Io(#[from] std::io::Error), /// Invalid configuration. #[error("Configuration error: {0}")] Configuration(String), /// Custom format callback failed. #[error("Format error: {message}: {source}")] Format { /// Context describing which format callback failed. message: &'static str, /// The underlying format error. source: specta::FormatError, }, } impl Error { pub(crate) fn format(message: &'static str, source: specta::FormatError) -> Self { Self::Format { message, source } } } ================================================ FILE: specta-swift/src/lib.rs ================================================ //! [Swift](https://www.swift.org) language exporter for [Specta](specta). //! //! This crate provides functionality to export Rust types to Swift code. //! //! # Usage //! //! Add `specta`, `specta-serde`, and `specta-swift` to your project: //! //! ```bash //! cargo add specta@2.0.0-rc.24 --features derive,collect //! cargo add specta-serde@0.0.11 //! cargo add specta-swift@0.0.2 //! ``` //! //! Next copy the following into your `main.rs` file: //! //! ```rust //! use specta::{Type, Types}; //! use specta_swift::Swift; //! //! #[derive(Type)] //! pub struct MyType { //! pub field: MyOtherType, //! } //! //! #[derive(Type)] //! pub struct MyOtherType { //! pub other_field: String, //! } //! //! let types = Types::default() //! // We don't need to specify `MyOtherType` because it's referenced by `MyType` //! .register::(); //! //! Swift::default() //! .export_to("./Types.swift", &types, specta_serde::Format) //! .unwrap(); //! ``` //! //! Now you're set up with Specta Swift! //! //! If you get tired of listing all your types, checkout the `specta::collect` function. #![cfg_attr(docsrs, feature(doc_cfg))] #![doc( html_logo_url = "https://github.com/specta-rs/specta/raw/main/.github/logo-128.png", html_favicon_url = "https://github.com/specta-rs/specta/raw/main/.github/logo-128.png" )] mod error; mod primitives; mod swift; pub use error::Error; pub use swift::{GenericStyle, IndentStyle, NamingConvention, OptionalStyle, Swift}; ================================================ FILE: specta-swift/src/primitives.rs ================================================ //! Primitive type conversion from Rust to Swift. use specta::{ Format, Types, datatype::{ DataType, Enum, Fields, Generic, NamedReferenceType, Primitive, Reference, Variant, }, }; use crate::error::Error; use crate::swift::Swift; fn string_literal_raw_value(dt: &DataType) -> Option<&str> { let DataType::Enum(literal_enum) = dt else { return None; }; let [(raw_value, literal_variant)] = literal_enum.variants.as_slice() else { return None; }; match &literal_variant.fields { Fields::Unit => Some(raw_value.as_ref()), Fields::Unnamed(fields) => { let [field] = fields.fields.as_slice() else { return None; }; string_literal_raw_value(field.ty.as_ref()?) } Fields::Named(fields) => { let [(_, field)] = fields.fields.as_slice() else { return None; }; string_literal_raw_value(field.ty.as_ref()?) } } } fn enum_string_raw_value(variant: &Variant) -> Option<&str> { let payload = match &variant.fields { Fields::Unnamed(fields) => { let [field] = fields.fields.as_slice() else { return None; }; field.ty.as_ref()? } Fields::Named(fields) => { let [(_, field)] = fields.fields.as_slice() else { return None; }; field.ty.as_ref()? } Fields::Unit => return None, }; string_literal_raw_value(payload) } fn resolved_string_enum(e: &Enum) -> Option> { e.variants .iter() .map(|(variant_name, variant)| { enum_string_raw_value(variant).map(|raw| (variant_name.as_ref(), raw)) }) .collect() } fn serde_variant_payload<'a>(variant_name: &str, variant: &'a Variant) -> Option<&'a DataType> { let Fields::Named(fields) = &variant.fields else { return None; }; let [(payload_name, payload_field)] = fields.fields.as_slice() else { return None; }; payload_name .as_ref() .eq_ignore_ascii_case(variant_name) .then_some(payload_field.ty.as_ref()) .flatten() } fn self_named_struct_payload<'a>(variant_name: &str, dt: &'a DataType) -> Option<&'a DataType> { let DataType::Struct(strct) = dt else { return None; }; let Fields::Named(fields) = &strct.fields else { return None; }; let [(field_name, field)] = fields.fields.as_slice() else { return None; }; field_name .as_ref() .eq_ignore_ascii_case(variant_name) .then_some(field.ty.as_ref()) .flatten() } fn normalized_payload<'a>(variant_name: &str, payload: &'a DataType) -> &'a DataType { let mut current = payload; while let Some(inner) = self_named_struct_payload(variant_name, current) { current = inner; } current } fn is_unit_payload(variant_name: &str, dt: &DataType) -> bool { let dt = normalized_payload(variant_name, dt); if string_literal_raw_value(dt).is_some() { return true; } let DataType::Enum(enm) = dt else { return false; }; let [(_, variant)] = enm.variants.as_slice() else { return false; }; match &variant.fields { Fields::Unit => true, Fields::Unnamed(fields) => fields.fields.is_empty(), Fields::Named(fields) => fields.fields.is_empty(), } } fn enum_payload_to_swift_type( swift: &Swift, format: Option<&dyn Format>, types: &Types, variant_name: &str, payload: &DataType, generic_scope: &[Generic], ) -> Result { let payload = normalized_payload(variant_name, payload); Ok(match payload { DataType::Tuple(tuple) if tuple.elements.len() > 1 => tuple .elements .iter() .map(|element| datatype_to_swift(swift, format, types, element, generic_scope.to_vec())) .collect::, _>>()? .join(", "), _ => datatype_to_swift(swift, format, types, payload, generic_scope.to_vec())?, }) } fn should_emit_variant_wrapper(variant_name: &str, variant: &Variant) -> bool { let Fields::Named(fields) = &variant.fields else { return false; }; if fields.fields.is_empty() { return false; } let Some(payload) = serde_variant_payload(variant_name, variant) else { return true; }; let payload = normalized_payload(variant_name, payload); matches!( payload, DataType::Struct(strct) if matches!( &strct.fields, Fields::Named(named) if !named.fields.is_empty() ) ) } fn wrapper_variant_fields<'a>(variant_name: &str, variant: &'a Variant) -> Option<&'a Fields> { if let Some(payload) = serde_variant_payload(variant_name, variant) { let DataType::Struct(strct) = normalized_payload(variant_name, payload) else { return None; }; return Some(&strct.fields); } Some(&variant.fields) } fn is_unit_like_variant(variant_name: &str, variant: &Variant) -> bool { match &variant.fields { Fields::Unit => true, Fields::Unnamed(fields) => { fields.fields.is_empty() || (fields.fields.len() == 1 && fields.fields[0] .ty .as_ref() .is_some_and(|ty| is_unit_payload(variant_name, ty))) } Fields::Named(fields) => { fields.fields.is_empty() || serde_variant_payload(variant_name, variant) .is_some_and(|payload| is_unit_payload(variant_name, payload)) } } } /// Export a single type to Swift. pub fn export_type( swift: &Swift, format: Option<&dyn Format>, types: &Types, ndt: &specta::datatype::NamedDataType, ) -> Result { if !matches!(&ndt.ty, Some(DataType::Struct(_) | DataType::Enum(_))) { return Ok(String::new()); } let mut result = String::new(); // Add JSDoc-style comments if present if !ndt.docs.is_empty() { let docs = &ndt.docs; // Handle multi-line comments properly for line in docs.lines() { result.push_str("/// "); // Trim leading whitespace from the line to avoid extra spaces result.push_str(line.trim_start()); result.push('\n'); } } // Add deprecated annotation if present if let Some(deprecated) = ndt.deprecated.as_ref() { let message = deprecated .note .as_deref() .filter(|note| !note.trim().is_empty()) .map(ToString::to_string) .unwrap_or_else(|| "This type is deprecated".to_string()); result.push_str(&format!( "@available(*, deprecated, message: \"{}\")\n", message )); } let generic_scope = ndt .generics .iter() .map(|generic| generic.reference()) .collect::>(); // Format based on type match ndt.ty.as_ref().expect("checked above") { DataType::Struct(s) => { let type_def = struct_to_swift(swift, format, types, s, generic_scope.clone())?; let name = swift.naming.convert(&ndt.name); let generics = if ndt.generics.is_empty() { String::new() } else { format!( "<{}>", ndt.generics .iter() .map(|g| g.name.as_ref().to_string()) .collect::>() .join(", ") ) }; result.push_str(&format!("public struct {}{}: Codable {{\n", name, generics)); result.push_str(&type_def); result.push('}'); } DataType::Enum(e) => { let formatted_enum = match apply_datatype_format( None, types, ndt.ty.as_ref().expect("checked above"), )? { DataType::Enum(e) => Some(e), _ => None, }; let e = formatted_enum .as_ref() .filter(|e| resolved_string_enum(e).is_some()) .unwrap_or(e); let name = swift.naming.convert(&ndt.name); let generics = if ndt.generics.is_empty() { String::new() } else { format!( "<{}>", ndt.generics .iter() .map(|g| g.name.as_ref().to_string()) .collect::>() .join(", ") ) }; // Check if this is a string enum let is_string_enum_val = resolved_string_enum(e).is_some(); // Check if this enum has struct-like variants (needs custom Codable) let has_struct_variants = e .variants .iter() .any(|(variant_name, variant)| should_emit_variant_wrapper(variant_name, variant)); let has_serde_payload_variants = format.is_some() && e.variants.iter().any(|(variant_name, variant)| { serde_variant_payload(variant_name, variant) .is_some_and(|_| !is_unit_like_variant(variant_name, variant)) }); let needs_custom_codable = has_struct_variants || has_serde_payload_variants; // Determine protocols based on whether we'll generate custom Codable let protocols = if is_string_enum_val { if needs_custom_codable { "String" // Custom Codable will be generated } else { "String, Codable" } } else if needs_custom_codable { "" // Custom Codable will be generated } else { "Codable" }; let protocol_part = if protocols.is_empty() { String::new() } else { format!(": {}", protocols) }; result.push_str(&format!( "public enum {}{}{} {{\n", name, generics, protocol_part )); let enum_body = enum_to_swift(swift, format, types, e, generic_scope.clone(), Some(&name))?; result.push_str(&enum_body); result.push('}'); // Generate struct definitions for named field variants let struct_definitions = generate_enum_structs(swift, format, types, e, generic_scope.clone(), &name)?; result.push_str(&struct_definitions); // Generate custom Codable implementation for enums with struct variants if needs_custom_codable { let codable_impl = generate_enum_codable_impl( swift, format, types, e, generic_scope.clone(), &name, )?; result.push_str(&codable_impl); } } _ => { return Ok(String::new()); } } Ok(result) } /// Convert a DataType to Swift syntax. pub fn datatype_to_swift( swift: &Swift, format: Option<&dyn Format>, types: &Types, dt: &DataType, generic_scope: Vec, ) -> Result { let dt = apply_datatype_format(format, types, dt)?; match &dt { DataType::Primitive(p) => primitive_to_swift(p), // DataType::Literal(l) => literal_to_swift(l), DataType::List(l) => list_to_swift(swift, format, types, l, generic_scope.clone()), DataType::Map(m) => map_to_swift(swift, format, types, m, generic_scope.clone()), DataType::Nullable(def) => { let inner = datatype_to_swift(swift, format, types, def, generic_scope)?; Ok(match swift.optionals { crate::swift::OptionalStyle::QuestionMark => format!("{}?", inner), crate::swift::OptionalStyle::Optional => format!("Optional<{}>", inner), }) } DataType::Struct(s) => { // Check if this is a Duration struct by looking at its fields if is_duration_struct(s) { return Ok("RustDuration".to_string()); } struct_to_swift(swift, format, types, s, generic_scope) } DataType::Enum(e) => enum_to_swift(swift, format, types, e, generic_scope, None), DataType::Tuple(t) => tuple_to_swift(swift, format, types, t, generic_scope.clone()), DataType::Reference(r) => reference_to_swift(swift, format, types, r, &generic_scope), DataType::Generic(g) => generic_to_swift(g, &generic_scope), DataType::Intersection(_) => Err(Error::UnsupportedType( "Intersection types are not supported by Swift exporter".to_string(), )), } } fn apply_datatype_format( format: Option<&dyn Format>, types: &Types, dt: &DataType, ) -> Result { if contains_generic_reference(dt) { let Some(format) = format else { return apply_datatype_format_children(None, types, dt.clone()); }; match format.map_type(types, dt) { Ok(std::borrow::Cow::Borrowed(dt)) => { return apply_datatype_format_children(Some(format), types, dt.clone()); } Ok(std::borrow::Cow::Owned(dt)) => { return apply_datatype_format_children(Some(format), types, dt); } Err(err) if err.to_string().contains("Unresolved generic reference") => { return apply_datatype_format_children(Some(format), types, dt.clone()); } Err(err) => return Err(Error::format("datatype formatter failed", err)), } } if contains_recursive_reference(dt) { return apply_datatype_format_children(format, types, dt.clone()); } let Some(format) = format else { return apply_datatype_format_children(None, types, dt.clone()); }; let mapped = format .map_type(types, dt) .map_err(|err| Error::format("datatype formatter failed", err))?; match mapped { std::borrow::Cow::Borrowed(dt) => { apply_datatype_format_children(Some(format), types, dt.clone()) } std::borrow::Cow::Owned(dt) => apply_datatype_format_children(Some(format), types, dt), } } fn apply_datatype_format_children( format: Option<&dyn Format>, types: &Types, mut dt: DataType, ) -> Result { match &mut dt { DataType::Primitive(_) => {} DataType::List(list) => { *list.ty = apply_datatype_format(format, types, &list.ty)?; } DataType::Map(map) => { let key = apply_datatype_format(format, types, map.key_ty())?; let value = apply_datatype_format(format, types, map.value_ty())?; map.set_key_ty(key); map.set_value_ty(value); } DataType::Nullable(inner) => { **inner = apply_datatype_format(format, types, inner)?; } DataType::Struct(strct) => map_fields(format, types, &mut strct.fields)?, DataType::Enum(enm) => { for (_, variant) in &mut enm.variants { map_fields(format, types, &mut variant.fields)?; } } DataType::Tuple(tuple) => { for element in &mut tuple.elements { *element = apply_datatype_format(format, types, element)?; } } DataType::Intersection(intersection) => { for element in intersection { *element = apply_datatype_format(format, types, element)?; } } DataType::Reference(Reference::Named(reference)) => match &mut reference.inner { specta::datatype::NamedReferenceType::Reference { generics, .. } => { for (_, generic) in generics { *generic = apply_datatype_format(format, types, generic)?; } } specta::datatype::NamedReferenceType::Inline { .. } | specta::datatype::NamedReferenceType::Recursive => {} }, DataType::Reference(Reference::Opaque(_)) | DataType::Generic(_) => {} } Ok(dt) } fn map_fields( format: Option<&dyn Format>, types: &Types, fields: &mut Fields, ) -> Result<(), Error> { match fields { Fields::Unit => {} Fields::Unnamed(unnamed) => { for field in &mut unnamed.fields { if let Some(ty) = field.ty.as_mut() { *ty = apply_datatype_format(format, types, ty)?; } } } Fields::Named(named) => { for (_, field) in &mut named.fields { if let Some(ty) = field.ty.as_mut() { *ty = apply_datatype_format(format, types, ty)?; } } } } Ok(()) } fn contains_generic_reference(dt: &DataType) -> bool { match dt { DataType::Primitive(_) => false, DataType::List(list) => contains_generic_reference(&list.ty), DataType::Map(map) => { contains_generic_reference(map.key_ty()) || contains_generic_reference(map.value_ty()) } DataType::Nullable(inner) => contains_generic_reference(inner), DataType::Struct(strct) => fields_contain_generic_reference(&strct.fields), DataType::Enum(enm) => enm .variants .iter() .any(|(_, variant)| fields_contain_generic_reference(&variant.fields)), DataType::Tuple(tuple) => tuple.elements.iter().any(contains_generic_reference), DataType::Reference(Reference::Named(reference)) => match &reference.inner { NamedReferenceType::Reference { generics, .. } => generics .iter() .any(|(_, generic)| contains_generic_reference(generic)), NamedReferenceType::Inline { .. } | NamedReferenceType::Recursive => false, }, DataType::Reference(Reference::Opaque(_)) => false, DataType::Generic(_) => true, DataType::Intersection(types) => types.iter().any(contains_generic_reference), } } fn fields_contain_generic_reference(fields: &Fields) -> bool { match fields { Fields::Unit => false, Fields::Unnamed(unnamed) => unnamed .fields .iter() .any(|field| field.ty.as_ref().is_some_and(contains_generic_reference)), Fields::Named(named) => named .fields .iter() .any(|(_, field)| field.ty.as_ref().is_some_and(contains_generic_reference)), } } fn contains_recursive_reference(dt: &DataType) -> bool { match dt { DataType::Primitive(_) | DataType::Generic(_) | DataType::Reference(Reference::Opaque(_)) => false, DataType::List(list) => contains_recursive_reference(&list.ty), DataType::Map(map) => { contains_recursive_reference(map.key_ty()) || contains_recursive_reference(map.value_ty()) } DataType::Nullable(inner) => contains_recursive_reference(inner), DataType::Struct(strct) => fields_contain_recursive_reference(&strct.fields), DataType::Enum(enm) => enm .variants .iter() .any(|(_, variant)| fields_contain_recursive_reference(&variant.fields)), DataType::Tuple(tuple) => tuple.elements.iter().any(contains_recursive_reference), DataType::Reference(Reference::Named(reference)) => match &reference.inner { NamedReferenceType::Recursive => true, NamedReferenceType::Reference { generics, .. } => generics .iter() .any(|(_, generic)| contains_recursive_reference(generic)), NamedReferenceType::Inline { .. } => false, }, DataType::Intersection(types) => types.iter().any(contains_recursive_reference), } } fn fields_contain_recursive_reference(fields: &Fields) -> bool { match fields { Fields::Unit => false, Fields::Unnamed(unnamed) => unnamed .fields .iter() .any(|field| field.ty.as_ref().is_some_and(contains_recursive_reference)), Fields::Named(named) => named .fields .iter() .any(|(_, field)| field.ty.as_ref().is_some_and(contains_recursive_reference)), } } /// Check if a struct is a Duration by examining its fields pub fn is_duration_struct(s: &specta::datatype::Struct) -> bool { match &s.fields { specta::datatype::Fields::Named(fields) => { let field_names: Vec = fields .fields .iter() .map(|(name, _)| name.to_string()) .collect(); // Duration has exactly two fields: "secs" (u64) and "nanos" (u32) field_names.len() == 2 && field_names.contains(&"secs".to_string()) && field_names.contains(&"nanos".to_string()) } _ => false, } } /// Convert primitive types to Swift. fn primitive_to_swift(primitive: &Primitive) -> Result { Ok(match primitive { Primitive::i8 => "Int8".to_string(), Primitive::i16 => "Int16".to_string(), Primitive::i32 => "Int32".to_string(), Primitive::i64 => "Int64".to_string(), Primitive::isize => "Int".to_string(), Primitive::u8 => "UInt8".to_string(), Primitive::u16 => "UInt16".to_string(), Primitive::u32 => "UInt32".to_string(), Primitive::u64 => "UInt64".to_string(), Primitive::usize => "UInt".to_string(), Primitive::f32 => "Float".to_string(), Primitive::f64 => "Double".to_string(), Primitive::bool => "Bool".to_string(), Primitive::char => "Character".to_string(), Primitive::str => "String".to_string(), Primitive::i128 | Primitive::u128 => { return Err(Error::UnsupportedType( "Swift does not support 128-bit integers".to_string(), )); } Primitive::f16 => { return Err(Error::UnsupportedType( "Swift does not support f16".to_string(), )); } Primitive::f128 => { return Err(Error::UnsupportedType( "Swift does not support f128".to_string(), )); } }) } // /// Convert literal types to Swift. // fn literal_to_swift(literal: &specta::datatype::Literal) -> Result { // Ok(match literal { // specta::datatype::Literal::i8(v) => v.to_string(), // specta::datatype::Literal::i16(v) => v.to_string(), // specta::datatype::Literal::i32(v) => v.to_string(), // specta::datatype::Literal::u8(v) => v.to_string(), // specta::datatype::Literal::u16(v) => v.to_string(), // specta::datatype::Literal::u32(v) => v.to_string(), // specta::datatype::Literal::f32(v) => v.to_string(), // specta::datatype::Literal::f64(v) => v.to_string(), // specta::datatype::Literal::bool(v) => v.to_string(), // specta::datatype::Literal::String(s) => format!("\"{}\"", s), // specta::datatype::Literal::char(c) => format!("\"{}\"", c), // specta::datatype::Literal::None => "nil".to_string(), // _ => { // return Err(Error::UnsupportedType( // "Unsupported literal type".to_string(), // )); // } // }) // } /// Convert list types to Swift arrays. fn list_to_swift( swift: &Swift, format: Option<&dyn Format>, types: &Types, list: &specta::datatype::List, generic_scope: Vec, ) -> Result { let element_type = datatype_to_swift(swift, format, types, &list.ty, generic_scope)?; Ok(format!("[{}]", element_type)) } /// Convert map types to Swift dictionaries. fn map_to_swift( swift: &Swift, format: Option<&dyn Format>, types: &Types, map: &specta::datatype::Map, generic_scope: Vec, ) -> Result { let key_type = datatype_to_swift(swift, format, types, map.key_ty(), generic_scope.clone())?; let value_type = datatype_to_swift(swift, format, types, map.value_ty(), generic_scope)?; Ok(format!("[{}: {}]", key_type, value_type)) } /// Convert struct types to Swift. fn struct_to_swift( swift: &Swift, format: Option<&dyn Format>, types: &Types, s: &specta::datatype::Struct, generic_scope: Vec, ) -> Result { match &s.fields { specta::datatype::Fields::Unit => Ok("Void".to_string()), specta::datatype::Fields::Unnamed(fields) => { if fields.fields.is_empty() { Ok("Void".to_string()) } else if fields.fields.len() == 1 { // Single field tuple struct - convert to a proper struct with a 'value' field let field_type = datatype_to_swift( swift, format, types, fields.fields[0] .ty .as_ref() .expect("tuple field should have a type"), generic_scope, )?; Ok(format!(" let value: {}\n", field_type)) } else { // Multiple field tuple struct - convert to a proper struct with numbered fields let mut result = String::new(); for (i, field) in fields.fields.iter().enumerate() { let field_type = datatype_to_swift( swift, format, types, field.ty.as_ref().expect("tuple field should have a type"), generic_scope.clone(), )?; result.push_str(&format!(" public let field{}: {}\n", i, field_type)); } Ok(result) } } specta::datatype::Fields::Named(fields) => { let mut result = String::new(); let mut field_mappings = Vec::new(); for (original_field_name, field) in &fields.fields { let field_type = if let Some(ty) = field.ty.as_ref() { datatype_to_swift(swift, format, types, ty, generic_scope.clone())? } else { continue; }; let optional_marker = if field.optional { "?" } else { "" }; let swift_field_name = swift.naming.convert_field(original_field_name.as_ref()); result.push_str(&format!( " public let {}: {}{}\n", swift_field_name, field_type, optional_marker )); field_mappings.push((swift_field_name, original_field_name.to_string())); } // Generate custom CodingKeys if field names were converted let needs_custom_coding_keys = field_mappings .iter() .any(|(swift_name, rust_name)| swift_name != rust_name); if needs_custom_coding_keys { result.push_str("\n private enum CodingKeys: String, CodingKey {\n"); for (swift_name, rust_name) in &field_mappings { result.push_str(&format!( " case {} = \"{}\"\n", swift_name, rust_name )); } result.push_str(" }\n"); } Ok(result) } } } /// Convert enum types to Swift. fn enum_to_swift( swift: &Swift, format: Option<&dyn Format>, types: &Types, e: &specta::datatype::Enum, generic_scope: Vec, enum_name: Option<&str>, ) -> Result { let mut result = String::new(); // Check if this is a string enum let is_string_enum = resolved_string_enum(e).is_some(); for (original_variant_name, variant) in &e.variants { if variant.skip { continue; } let variant_name = swift .naming .convert_enum_case(original_variant_name.as_ref()); match &variant.fields { specta::datatype::Fields::Unit => { if is_string_enum { let raw_value = enum_string_raw_value(variant) .unwrap_or_else(|| original_variant_name.as_ref()); result.push_str(&format!(" case {} = \"{}\"\n", variant_name, raw_value)); } else { result.push_str(&format!(" case {}\n", variant_name)); } } specta::datatype::Fields::Unnamed(fields) => { if is_string_enum { let raw_value = enum_string_raw_value(variant) .unwrap_or_else(|| original_variant_name.as_ref()); result.push_str(&format!(" case {} = \"{}\"\n", variant_name, raw_value)); } else if fields.fields.is_empty() || fields.fields.len() == 1 && fields.fields[0] .ty .as_ref() .is_some_and(|ty| is_unit_payload(original_variant_name, ty)) { result.push_str(&format!(" case {}\n", variant_name)); } else { let types_str = fields .fields .iter() .map(|f| { datatype_to_swift( swift, format, types, f.ty.as_ref() .expect("enum variant field should have a type"), generic_scope.clone(), ) }) .collect::, _>>()? .join(", "); result.push_str(&format!(" case {}({})\n", variant_name, types_str)); } } specta::datatype::Fields::Named(fields) => { if fields.fields.is_empty() { result.push_str(&format!(" case {}\n", variant_name)); } else if !should_emit_variant_wrapper(original_variant_name, variant) { let payload = serde_variant_payload(original_variant_name, variant) .expect("serde payload variants should contain a payload"); if is_unit_payload(original_variant_name, payload) { result.push_str(&format!(" case {}\n", variant_name)); } else { let payload_ty = enum_payload_to_swift_type( swift, format, types, original_variant_name, payload, &generic_scope, )?; result.push_str(&format!(" case {}({})\n", variant_name, payload_ty)); } } else { // Generate struct for named fields // Use the original variant name for PascalCase struct name let pascal_variant_name = to_pascal_case(original_variant_name); let struct_name = if let Some(enum_name) = enum_name { format!("{}{}Data", enum_name, pascal_variant_name) } else { format!("{}Data", pascal_variant_name) }; // Generate enum case that references the struct result.push_str(&format!(" case {}({})\n", variant_name, struct_name)); } } } } Ok(result) } /// Generate struct definitions for enum variants with named fields fn generate_enum_structs( swift: &Swift, format: Option<&dyn Format>, types: &Types, e: &specta::datatype::Enum, generic_scope: Vec, enum_name: &str, ) -> Result { let mut result = String::new(); for (original_variant_name, variant) in &e.variants { if variant.skip { continue; } if let Some(Fields::Named(fields)) = wrapper_variant_fields(original_variant_name, variant) && !fields.fields.is_empty() && should_emit_variant_wrapper(original_variant_name, variant) { let pascal_variant_name = to_pascal_case(original_variant_name.as_ref()); let struct_name = format!("{}{}Data", enum_name, pascal_variant_name); // Generate struct definition with custom CodingKeys for field name mapping result.push_str(&format!("\npublic struct {}: Codable {{\n", struct_name)); // Generate struct fields let mut field_mappings = Vec::new(); for (original_field_name, field) in &fields.fields { if let Some(ty) = field.ty.as_ref() { let field_type = datatype_to_swift(swift, format, types, ty, generic_scope.clone())?; let optional_marker = if field.optional { "?" } else { "" }; let swift_field_name = swift.naming.convert_field(original_field_name.as_ref()); result.push_str(&format!( " public let {}: {}{}\n", swift_field_name, field_type, optional_marker )); field_mappings.push((swift_field_name, original_field_name.to_string())); } } // Generate custom CodingKeys if field names were converted let needs_custom_coding_keys = field_mappings .iter() .any(|(swift_name, rust_name)| swift_name != rust_name); if needs_custom_coding_keys { result.push_str("\n private enum CodingKeys: String, CodingKey {\n"); for (swift_name, rust_name) in &field_mappings { result.push_str(&format!( " case {} = \"{}\"\n", swift_name, rust_name )); } result.push_str(" }\n"); } result.push_str("}\n"); } } Ok(result) } /// Convert a string to PascalCase fn to_pascal_case(s: &str) -> String { // If it's already PascalCase (starts with uppercase), return as-is if s.chars().next().is_some_and(|c| c.is_uppercase()) { return s.to_string(); } // Otherwise, convert snake_case to PascalCase let mut result = String::new(); let mut capitalize_next = true; for c in s.chars() { if c == '_' || c == '-' { capitalize_next = true; } else if capitalize_next { result.push(c.to_uppercase().next().unwrap_or(c)); capitalize_next = false; } else { result.push(c.to_lowercase().next().unwrap_or(c)); } } result } /// Convert tuple types to Swift. fn tuple_to_swift( swift: &Swift, format: Option<&dyn Format>, types: &Types, t: &specta::datatype::Tuple, generic_scope: Vec, ) -> Result { if t.elements.is_empty() { Ok("Void".to_string()) } else if t.elements.len() == 1 { datatype_to_swift(swift, format, types, &t.elements[0], generic_scope) } else { let types_str = t .elements .iter() .map(|e| datatype_to_swift(swift, format, types, e, generic_scope.clone())) .collect::, _>>()? .join(", "); Ok(format!("({})", types_str)) } } /// Convert reference types to Swift. fn reference_to_swift( swift: &Swift, format: Option<&dyn Format>, types: &Types, r: &specta::datatype::Reference, generic_scope: &[Generic], ) -> Result { match r { Reference::Named(r) => { let Some(ndt) = types.get(r) else { return Err(Error::InvalidIdentifier( "Reference to unknown type".to_string(), )); }; if let NamedReferenceType::Inline { dt, .. } = &r.inner && !matches!(dt.as_ref(), DataType::Enum(_)) && !contains_recursive_reference(dt) { return datatype_to_swift(swift, format, types, dt, generic_scope.to_vec()); } let generics = match &r.inner { NamedReferenceType::Reference { generics, .. } => generics.as_slice(), NamedReferenceType::Inline { .. } | NamedReferenceType::Recursive => &[], }; let name = swift.naming.convert(&ndt.name); if ndt.name.as_ref() == "String" { return Ok("String".to_string()); } if ndt.name.as_ref() == "Vec" && let [(_, element)] = generics { let element = datatype_to_swift(swift, format, types, element, generic_scope.to_vec())?; return Ok(format!("[{element}]")); } if generics.is_empty() { Ok(name) } else { let generics = generics .iter() .map(|(_, t)| { datatype_to_swift(swift, format, types, t, generic_scope.to_vec()) }) .collect::, _>>()? .join(", "); Ok(format!("{}<{}>", name, generics)) } } Reference::Opaque(_) => Err(Error::UnsupportedType( "Opaque references are not supported by Swift exporter".to_string(), )), } } /// Convert generic types to Swift. fn generic_to_swift( g: &specta::datatype::GenericReference, generic_scope: &[Generic], ) -> Result { generic_scope .iter() .find_map(|generic| (generic.reference() == *g).then(|| generic.name().to_string())) .ok_or_else(|| Error::GenericConstraint(format!("Unresolved generic reference: {g:?}"))) } /// Generate custom Codable implementation for enums with struct-like variants fn generate_enum_codable_impl( swift: &Swift, format: Option<&dyn Format>, types: &Types, e: &specta::datatype::Enum, generic_scope: Vec, enum_name: &str, ) -> Result { let mut result = String::new(); result.push_str(&format!( "\n// MARK: - {} Codable Implementation\n", enum_name )); result.push_str(&format!("extension {}: Codable {{\n", enum_name)); // Generate CodingKeys enum result.push_str(" private enum CodingKeys: String, CodingKey {\n"); for (original_variant_name, variant) in &e.variants { if variant.skip { continue; } let swift_case_name = swift .naming .convert_enum_case(original_variant_name.as_ref()); result.push_str(&format!( " case {} = \"{}\"\n", swift_case_name, original_variant_name )); } result.push_str(" }\n\n"); // Generate init(from decoder:) result.push_str(" public init(from decoder: Decoder) throws {\n"); result.push_str(" let container = try decoder.container(keyedBy: CodingKeys.self)\n"); result.push_str(" \n"); result.push_str(" if container.allKeys.count != 1 {\n"); result.push_str(" throw DecodingError.dataCorrupted(\n"); result.push_str(" DecodingError.Context(codingPath: decoder.codingPath, debugDescription: \"Invalid number of keys found, expected one.\")\n"); result.push_str(" )\n"); result.push_str(" }\n\n"); result.push_str(" let key = container.allKeys.first!\n"); result.push_str(" switch key {\n"); for (original_variant_name, variant) in &e.variants { if variant.skip { continue; } let swift_case_name = swift .naming .convert_enum_case(original_variant_name.as_ref()); match &variant.fields { specta::datatype::Fields::Unit => { result.push_str(&format!(" case .{}:\n", swift_case_name)); result.push_str(&format!(" self = .{}\n", swift_case_name)); } specta::datatype::Fields::Unnamed(fields) => { if fields.fields.is_empty() || fields.fields.len() == 1 && fields.fields[0] .ty .as_ref() .is_some_and(|ty| is_unit_payload(original_variant_name, ty)) { result.push_str(&format!(" case .{}:\n", swift_case_name)); result.push_str(&format!(" self = .{}\n", swift_case_name)); } else if fields.fields.len() == 1 { let payload_ty = datatype_to_swift( swift, format, types, fields.fields[0] .ty .as_ref() .expect("enum variant field should have a type"), generic_scope.clone(), )?; result.push_str(&format!(" case .{}:\n", swift_case_name)); result.push_str(&format!( " let data = try container.decode({}.self, forKey: .{})\n", payload_ty, swift_case_name )); result.push_str(&format!(" self = .{}(data)\n", swift_case_name)); } else { // For tuple variants, decode as array result.push_str(&format!(" case .{}:\n", swift_case_name)); result.push_str(&format!( " // TODO: Implement tuple variant decoding for {}\n", swift_case_name )); result.push_str( " fatalError(\"Tuple variant decoding not implemented\")\n", ); } } specta::datatype::Fields::Named(_) => { if should_emit_variant_wrapper(original_variant_name, variant) { let pascal_variant_name = to_pascal_case(original_variant_name.as_ref()); let struct_name = format!("{}{}Data", enum_name, pascal_variant_name); result.push_str(&format!(" case .{}:\n", swift_case_name)); result.push_str(&format!( " let data = try container.decode({}.self, forKey: .{})\n", struct_name, swift_case_name )); result.push_str(&format!(" self = .{}(data)\n", swift_case_name)); } else { let payload = serde_variant_payload(original_variant_name, variant) .expect("serde payload variants should contain a payload"); result.push_str(&format!(" case .{}:\n", swift_case_name)); if is_unit_payload(original_variant_name, payload) { result.push_str(&format!(" self = .{}\n", swift_case_name)); } else { let payload_ty = enum_payload_to_swift_type( swift, format, types, original_variant_name, payload, &generic_scope, )?; result.push_str(&format!( " let data = try container.decode({}.self, forKey: .{})\n", payload_ty, swift_case_name )); result .push_str(&format!(" self = .{}(data)\n", swift_case_name)); } } } } } result.push_str(" }\n"); result.push_str(" }\n\n"); // Generate encode(to encoder:) result.push_str(" public func encode(to encoder: Encoder) throws {\n"); result.push_str(" var container = encoder.container(keyedBy: CodingKeys.self)\n"); result.push_str(" \n"); result.push_str(" switch self {\n"); for (original_variant_name, variant) in &e.variants { if variant.skip { continue; } let swift_case_name = swift .naming .convert_enum_case(original_variant_name.as_ref()); match &variant.fields { specta::datatype::Fields::Unit => { result.push_str(&format!(" case .{}:\n", swift_case_name)); result.push_str(&format!( " try container.encodeNil(forKey: .{})\n", swift_case_name )); } specta::datatype::Fields::Unnamed(fields) => { if fields.fields.len() == 1 && fields.fields[0] .ty .as_ref() .is_some_and(|ty| is_unit_payload(original_variant_name, ty)) { result.push_str(&format!(" case .{}:\n", swift_case_name)); result.push_str(&format!( " try container.encodeNil(forKey: .{})\n", swift_case_name )); continue; } else if fields.fields.len() == 1 { result.push_str(&format!(" case .{}(let data):\n", swift_case_name)); result.push_str(&format!( " try container.encode(data, forKey: .{})\n", swift_case_name )); continue; } // TODO: Handle tuple variants result.push_str(&format!(" case .{}:\n", swift_case_name)); result.push_str(&format!( " // TODO: Implement tuple variant encoding for {}\n", swift_case_name )); result.push_str( " fatalError(\"Tuple variant encoding not implemented\")\n", ); } specta::datatype::Fields::Named(_) => { if should_emit_variant_wrapper(original_variant_name, variant) { result.push_str(&format!(" case .{}(let data):\n", swift_case_name)); result.push_str(&format!( " try container.encode(data, forKey: .{})\n", swift_case_name )); } else { let payload = serde_variant_payload(original_variant_name, variant) .expect("serde payload variants should contain a payload"); if is_unit_payload(original_variant_name, payload) { result.push_str(&format!(" case .{}:\n", swift_case_name)); result.push_str(&format!( " try container.encodeNil(forKey: .{})\n", swift_case_name )); } else { result.push_str(&format!(" case .{}(let data):\n", swift_case_name)); result.push_str(&format!( " try container.encode(data, forKey: .{})\n", swift_case_name )); } } } } } result.push_str(" }\n"); result.push_str(" }\n"); result.push_str("}\n"); Ok(result) } ================================================ FILE: specta-swift/src/swift.rs ================================================ //! Swift language exporter configuration and main export functionality. use std::{borrow::Cow, fmt, path::Path}; use specta::{ Format, Types, datatype::{DataType, Fields, Reference}, }; use crate::Error; use crate::primitives::{export_type, is_duration_struct}; /// Swift language exporter. #[derive(Clone)] pub struct Swift { /// Header comment for generated files. pub header: Cow<'static, str>, /// Indentation style for generated code. pub indent: IndentStyle, /// Naming convention for identifiers. pub naming: NamingConvention, /// Generic type style. pub generics: GenericStyle, /// Optional type style. pub optionals: OptionalStyle, /// Additional protocols to conform to. pub protocols: Vec>, } impl fmt::Debug for Swift { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Swift") .field("header", &self.header) .field("indent", &self.indent) .field("naming", &self.naming) .field("generics", &self.generics) .field("optionals", &self.optionals) .field("protocols", &self.protocols) .finish() } } /// Indentation style for generated Swift code. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum IndentStyle { /// Use spaces for indentation. Spaces(usize), /// Use tabs for indentation. Tabs, } impl Default for IndentStyle { fn default() -> Self { Self::Spaces(4) } } /// Naming convention for Swift identifiers. #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] pub enum NamingConvention { /// PascalCase naming (default for Swift types). #[default] PascalCase, /// camelCase naming. CamelCase, /// snake_case naming. SnakeCase, } /// Generic type style for Swift. #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] pub enum GenericStyle { /// Use protocol constraints: ``. #[default] Protocol, /// Use where clauses: ` where T: Codable`. Typealias, } /// Optional type style for Swift. #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] pub enum OptionalStyle { /// Use question mark syntax: `String?`. #[default] QuestionMark, /// Use Optional type: `Optional`. Optional, } impl Default for Swift { fn default() -> Self { Self { header: "// This file has been generated by Specta. DO NOT EDIT.".into(), indent: IndentStyle::default(), naming: NamingConvention::default(), generics: GenericStyle::default(), optionals: OptionalStyle::default(), protocols: vec![], } } } impl Swift { /// Create a new Swift exporter with default configuration. pub fn new() -> Self { Self::default() } /// Set the header comment for generated files. pub fn header(mut self, header: impl Into>) -> Self { self.header = header.into(); self } /// Set the indentation style. pub fn indent(mut self, style: IndentStyle) -> Self { self.indent = style; self } /// Set the naming convention. pub fn naming(mut self, convention: NamingConvention) -> Self { self.naming = convention; self } /// Set the generic type style. pub fn generics(mut self, style: GenericStyle) -> Self { self.generics = style; self } /// Set the optional type style. pub fn optionals(mut self, style: OptionalStyle) -> Self { self.optionals = style; self } /// Add a protocol that all types should conform to. pub fn add_protocol(mut self, protocol: impl Into>) -> Self { self.protocols.push(protocol.into()); self } /// Export types to a Swift string. pub fn export(&self, types: &Types, format: impl Format) -> Result { let exporter = self.clone(); let formatted_types = format_types(types, &format)?.into_owned(); let raw_types = &formatted_types; let mut result = String::new(); // Add header if !exporter.header.is_empty() { result.push_str(&exporter.header); result.push('\n'); } // Add imports result.push_str("import Foundation\n"); for protocol in &exporter.protocols { result.push_str(&format!("import {}\n", protocol)); } result.push('\n'); // Check if we need to inject Duration helper if needs_duration_helper(raw_types) { result.push_str(&generate_duration_helper()); } // Export types for ndt in raw_types.into_sorted_iter() { let exported = export_type(&exporter, Some(&format), raw_types, ndt)?; if !exported.is_empty() { result.push_str(&exported); result.push_str("\n\n"); } } Ok(result) } /// Export types to a file. pub fn export_to( &self, path: impl AsRef, types: &Types, format: impl Format, ) -> Result<(), Error> { let content = self.export(types, format)?; std::fs::write(path, content)?; Ok(()) } } fn format_types<'a>(types: &'a Types, format: &'a dyn Format) -> Result, Error> { format .map_types(types) .map_err(|err| Error::format("type graph formatter failed", err)) } impl NamingConvention { /// Convert a string to the appropriate naming convention. pub fn convert(&self, name: &str) -> String { match self { Self::PascalCase => self.to_pascal_case(name), Self::CamelCase => self.to_camel_case(name), Self::SnakeCase => self.to_snake_case(name), } } /// Convert a string to camelCase (for field names). pub fn convert_to_camel_case(&self, name: &str) -> String { self.to_camel_case(name) } /// Convert a string to the appropriate naming convention for fields. pub fn convert_field(&self, name: &str) -> String { match self { Self::PascalCase => self.to_camel_case(name), // Fields should be camelCase even with PascalCase Self::CamelCase => self.to_camel_case(name), Self::SnakeCase => self.to_snake_case(name), } } /// Convert a string to the appropriate naming convention for enum cases. pub fn convert_enum_case(&self, name: &str) -> String { match self { Self::PascalCase => self.to_camel_case(name), // Enum cases should be camelCase Self::CamelCase => self.to_camel_case(name), Self::SnakeCase => self.to_snake_case(name), } } #[allow(clippy::wrong_self_convention)] fn to_camel_case(&self, name: &str) -> String { // Convert snake_case or PascalCase to camelCase if name.contains('_') { // Handle snake_case let parts: Vec<&str> = name.split('_').collect(); if parts.is_empty() { return name.to_string(); } let mut result = String::new(); for (i, part) in parts.iter().enumerate() { if i == 0 { result.push_str(&part.to_lowercase()); } else { let mut chars = part.chars(); match chars.next() { None => continue, Some(first) => { result.push(first.to_uppercase().next().unwrap_or(first)); for c in chars { result.extend(c.to_lowercase()); } } } } } result } else { if name.chars().any(|c| c.is_ascii_alphabetic()) && name .chars() .all(|c| !c.is_ascii_alphabetic() || c.is_ascii_uppercase()) { return name.to_ascii_lowercase(); } // Handle PascalCase - convert to camelCase let mut chars = name.chars(); match chars.next() { None => name.to_string(), Some(first) => { let mut result = String::new(); result.push(first.to_lowercase().next().unwrap_or(first)); for c in chars { result.push(c); // Keep the rest as-is for PascalCase } result } } } } #[allow(clippy::wrong_self_convention)] fn to_pascal_case(&self, name: &str) -> String { // Convert snake_case to PascalCase name.split('_') .map(|part| { let mut chars = part.chars(); match chars.next() { None => String::new(), Some(first) => first.to_uppercase().chain(chars).collect(), } }) .collect() } #[allow(clippy::wrong_self_convention)] fn to_snake_case(&self, name: &str) -> String { // Convert camelCase/PascalCase to snake_case let mut result = String::new(); let chars = name.chars(); for c in chars { if c.is_uppercase() && !result.is_empty() { result.push('_'); } result.push(c.to_lowercase().next().unwrap_or(c)); } result } } /// Check if the type collection contains any Duration types that need the helper fn needs_duration_helper(types: &Types) -> bool { for ndt in types.into_sorted_iter() { if ndt.name == "Duration" { return true; } // Also check if any struct fields contain Duration if let Some(DataType::Struct(s)) = &ndt.ty && let Fields::Named(fields) = &s.fields { for (_, field) in &fields.fields { if let Some(ty) = field.ty.as_ref() { if let DataType::Reference(Reference::Named(r)) = ty && let Some(referenced_ndt) = types.get(r) && referenced_ndt.name == "Duration" { return true; } // Also check if the field type is a Duration struct directly if let DataType::Struct(struct_ty) = ty && is_duration_struct(struct_ty) { return true; } } } } } false } /// Generate the Duration helper struct fn generate_duration_helper() -> String { "// MARK: - Duration Helper\n".to_string() + "/// Helper struct to decode Rust Duration format {\"secs\": u64, \"nanos\": u32}\n" + "public struct RustDuration: Codable {\n" + " public let secs: UInt64\n" + " public let nanos: UInt32\n" + " \n" + " public var timeInterval: TimeInterval {\n" + " return Double(secs) + Double(nanos) / 1_000_000_000.0\n" + " }\n" + "}\n\n" + "// MARK: - Generated Types\n\n" } ================================================ FILE: specta-swift/tests/Cargo.toml ================================================ [package] name = "specta-swift-tests" version = "0.0.0" edition = "2021" publish = false [[test]] name = "basic" path = "basic.rs" [dependencies] specta = { path = "../../specta", features = ["derive", "uuid", "chrono"] } specta-swift = { path = "../" } uuid = "1.12.1" chrono = { version = "0.4.40", features = ["clock"] } ================================================ FILE: specta-swift/tests/advanced_unions.rs ================================================ #![allow(dead_code, missing_docs)] use specta::{Type, Types}; use specta_swift::Swift; #[derive(Type)] struct Point { x: f64, y: f64, } #[derive(Type)] struct Circle { center: Point, radius: f64, } #[derive(Type)] struct Rectangle { top_left: Point, bottom_right: Point, } #[derive(Type)] struct Line { start: Point, end: Point, } #[derive(Type)] enum Shape { // Unit variant None, // Simple tuple variant Point(f64, f64), // Named fields variant Circle { center: Point, radius: f64, }, // Nested struct variant Rectangle(Rectangle), // Complex nested variant Line { start: Point, end: Point, }, // Mixed variant with multiple nested types Complex { shapes: Vec, metadata: Option, }, } #[derive(Type)] enum ApiResponse { // Success with data Success { data: T, status: u16, headers: Vec<(String, String)>, }, // Error with details Error { code: u32, message: String, details: Option, }, // Loading state Loading { progress: f32, estimated_time: Option, }, // Redirect Redirect { url: String, permanent: bool, }, } #[derive(Type)] enum DatabaseResult { // Success with data and metadata Ok { data: T, affected_rows: u64, execution_time: f64, }, // Error with error type and context Err { error: E, query: String, retry_count: u32, }, // Connection issues ConnectionError { host: String, port: u16, reason: String, }, // Timeout Timeout { duration: f64, operation: String, }, } #[test] fn test_complex_unions() { let types = Types::default() .register::() .register::() .register::() .register::() .register::() .register::>() .register::>(); let swift = Swift::default(); let output = swift.export(&types, specta_serde::Format).unwrap(); println!("Complex unions Swift code:\n{}", output); // Test that all types are generated assert!(output.contains("struct Point")); assert!(output.contains("struct Circle")); assert!(output.contains("struct Rectangle")); assert!(output.contains("struct Line")); assert!(output.contains("enum Shape")); assert!(output.contains("enum ApiResponse")); assert!(output.contains("enum DatabaseResult")); // Test Shape enum variants assert!(output.contains("case none")); assert!(output.contains("case point(Double, Double)")); assert!(output.contains("case circle")); assert!(output.contains("case rectangle(Rectangle)")); assert!(output.contains("case line")); assert!(output.contains("case complex")); // Test ApiResponse enum variants assert!(output.contains("case success")); assert!(output.contains("case error")); assert!(output.contains("case loading")); assert!(output.contains("case redirect")); // Test DatabaseResult enum variants assert!(output.contains("case ok")); assert!(output.contains("case err")); assert!(output.contains("case connectionError")); assert!(output.contains("case timeout")); // Test that nested structs are properly referenced assert!(output.contains("center: Point")); assert!(output.contains("radius: Double")); assert!(output.contains("topLeft: Point")); assert!(output.contains("bottomRight: Point")); assert!(output.contains("start: Point")); assert!(output.contains("end: Point")); } #[test] fn test_union_with_generics() { let types = Types::default() .register::>() .register::>(); let swift = Swift::default(); let output = swift.export(&types, specta_serde::Format).unwrap(); println!("Generic unions Swift code:\n{}", output); // Test generic enum definitions assert!(output.contains("enum ApiResponse")); assert!(output.contains("enum DatabaseResult")); // Test that Codable is added via extension assert!(output.contains("extension ApiResponse: Codable")); assert!(output.contains("extension DatabaseResult: Codable")); // Test that generic types are used in variants assert!(output.contains("data: T")); assert!(output.contains("error: E")); assert!(output.contains("details: T?")); } #[test] fn test_union_naming_conventions() { let types = Types::default().register::(); // Test with different naming conventions let swift_pascal = Swift::new().naming(specta_swift::NamingConvention::PascalCase); let swift_snake = Swift::new().naming(specta_swift::NamingConvention::SnakeCase); let output_pascal = swift_pascal.export(&types, specta_serde::Format).unwrap(); let output_snake = swift_snake.export(&types, specta_serde::Format).unwrap(); println!("PascalCase output:\n{}", output_pascal); println!("SnakeCase output:\n{}", output_snake); // PascalCase should have camelCase enum cases assert!(output_pascal.contains("case none")); assert!(output_pascal.contains("case point")); assert!(output_pascal.contains("case circle")); // SnakeCase should have snake_case enum cases assert!(output_snake.contains("case none")); assert!(output_snake.contains("case point")); assert!(output_snake.contains("case circle")); } ================================================ FILE: specta-swift/tests/basic.rs ================================================ #![allow(dead_code, missing_docs)] use specta::{Type, Types}; use specta_swift::Swift; #[derive(Type)] struct User { name: String, age: u32, active: bool, } #[derive(Type)] enum Status { Active, Inactive, Pending { reason: String }, Error(String), } #[test] fn test_basic_export() { let types = Types::default().register::().register::(); let swift = Swift::default(); let output = swift.export(&types, specta_serde::Format).unwrap(); println!("Generated Swift code:\n{}", output); // Basic assertions assert!(output.contains("struct User")); assert!(output.contains("enum Status")); assert!(output.contains("let name: String")); assert!(output.contains("let age: UInt32")); assert!(output.contains("case active")); assert!(output.contains("case pending")); } ================================================ FILE: specta-swift/tests/common_types.rs ================================================ #![allow(dead_code, missing_docs)] use specta::{Type, Types}; use specta_swift::Swift; // Test with common types that might not have Type implementations #[derive(Type)] struct TestStruct { // Basic types that should work id: u32, name: String, email: Option, // These might not have Type implementations // uuid: uuid::Uuid, // Commented out - likely not supported // created_at: chrono::DateTime, // Commented out - likely not supported } #[derive(Type)] enum TestEnum { Unit, Tuple(String, u32), Named { id: u32, name: String }, } #[test] fn test_common_types() { let types = Types::default() .register::() .register::(); let swift = Swift::default(); let output = swift.export(&types, specta_serde::Format).unwrap(); println!("Generated Swift code:\n{}", output); // Test that basic types work assert!(output.contains("struct TestStruct")); assert!(output.contains("enum TestEnum")); assert!(output.contains("let id: UInt32")); assert!(output.contains("let name: String")); assert!(output.contains("let email: String?")); } // Test what happens when we try to use unsupported types #[test] fn test_unsupported_types() { // This test will fail to compile if UUID doesn't have Type implementation // Uncomment to test: /* #[derive(Type)] struct WithUuid { id: uuid::Uuid, } let types = Types::default().register::(); let swift = Swift::default(); let output = swift.export(&types).unwrap(); println!("UUID support: {}", output); */ } ================================================ FILE: specta-swift/tests/comprehensive.rs ================================================ #![allow(dead_code, missing_docs)] use specta::{Type, Types}; use specta_swift::Swift; #[derive(Type)] struct User { id: u32, name: String, email: Option, age: u8, is_active: bool, metadata: UserMetadata, tags: Vec, scores: Vec, } #[derive(Type)] struct UserMetadata { created_at: String, last_login: Option, preferences: UserPreferences, } #[derive(Type)] struct UserPreferences { theme: String, notifications: bool, language: String, } #[derive(Type)] enum UserRole { Admin, User, Guest, Moderator { permissions: Vec }, Custom { name: String, level: u8 }, } #[derive(Type)] enum ApiResponse { Success(T), Error { code: u32, message: String }, Loading, } #[derive(Type)] struct ApiResult { data: Option, error: Option, status: u16, } #[test] fn test_comprehensive_export() { let types = Types::default() .register::() .register::() .register::() .register::() .register::>() .register::>(); let swift = Swift::default(); let output = swift.export(&types, specta_serde::Format).unwrap(); println!("Generated Swift code:\n{}", output); // Test struct generation assert!(output.contains("struct User")); assert!(output.contains("struct UserMetadata")); assert!(output.contains("struct UserPreferences")); assert!(output.contains("struct ApiResult")); // Test enum generation assert!(output.contains("enum UserRole")); assert!(output.contains("enum ApiResponse")); // Test field types assert!(output.contains("let id: UInt32")); assert!(output.contains("let name: String")); assert!(output.contains("let email: String?")); assert!(output.contains("let age: UInt8")); assert!(output.contains("let isActive: Bool")); assert!(output.contains("let metadata: UserMetadata")); assert!(output.contains("let tags: [String]")); assert!(output.contains("let scores: [Double]")); // Test enum cases assert!(output.contains("case admin")); assert!(output.contains("case user")); assert!(output.contains("case guest")); assert!(output.contains("case moderator")); assert!(output.contains("case custom")); // Test generic types (they appear as generic definitions, not concrete instantiations) assert!(output.contains("enum ApiResponse")); assert!(output.contains("struct ApiResult")); // Test optional types assert!(output.contains("let email: String?")); assert!(output.contains("let lastLogin: String?")); assert!(output.contains("let data: T?")); assert!(output.contains("let error: E?")); // Test array types assert!(output.contains("let tags: [String]")); assert!(output.contains("let scores: [Double]")); assert!(output.contains("permissions: [String]")); } #[test] fn test_naming_conventions() { let types = Types::default().register::(); let swift = Swift::default(); let output = swift.export(&types, specta_serde::Format).unwrap(); // Test PascalCase for type names assert!(output.contains("struct User")); // Test camelCase for field names assert!(output.contains("let isActive: Bool")); // snake_case -> camelCase assert!(output.contains("let createdAt: String")); // snake_case -> camelCase } #[test] fn test_swift_configuration() { let types = Types::default().register::(); // Test with custom configuration let swift = Swift::new() .header("// Custom header") .naming(specta_swift::NamingConvention::SnakeCase) .optionals(specta_swift::OptionalStyle::Optional); let output = swift.export(&types, specta_serde::Format).unwrap(); println!("Snake case output:\n{}", output); assert!(output.contains("// Custom header")); assert!(output.contains("struct user")); // snake_case type names assert!(output.contains("let is_active: Bool")); // snake_case field names assert!(output.contains("let email: Optional")); // Optional style } ================================================ FILE: specta-swift/tests/multiline_comments.rs ================================================ #![allow(dead_code, missing_docs)] use specta::{Type, Types}; use specta_swift::Swift; /// A path within the Spacedrive Virtual Distributed File System /// /// This is the core abstraction that enables cross-device operations. /// An SdPath can represent: /// - A physical file at a specific path on a specific device /// - A content-addressed file that can be sourced from any device /// /// This enum-based approach enables resilient file operations by allowing /// content-based paths to be resolved to optimal physical locations at runtime. #[derive(Type)] enum SdPath { /// A physical file path on a specific device Physical { /// The device ID where this file is located device_id: String, /// The file path on the device path: String, }, /// A content-addressed file that can be sourced from any device Content { /// The content hash of the file hash: String, /// Optional preferred device for this content preferred_device: Option, }, } /// A simple struct with a single-line comment #[derive(Type)] struct SimpleStruct { /// The name of the struct name: String, } #[test] fn test_multiline_comments() { let types = Types::default() .register::() .register::(); let swift = Swift::default(); let output = swift.export(&types, specta_serde::Format).unwrap(); println!("Generated Swift code with comments:\n{}", output); // Test that multi-line comments are properly formatted assert!(output.contains("/// A path within the Spacedrive Virtual Distributed File System")); assert!( output.contains("/// This is the core abstraction that enables cross-device operations.") ); assert!(output.contains("/// An SdPath can represent:")); assert!(output.contains("/// - A physical file at a specific path on a specific device")); assert!(output.contains("/// - A content-addressed file that can be sourced from any device")); assert!(output.contains("/// This enum-based approach enables resilient file operations")); // Test that single-line comments work too assert!(output.contains("/// A simple struct with a single-line comment")); // Note: Field-level comments are not currently supported by Specta // The enum cases and struct fields don't have individual comments // because Specta doesn't extract field-level documentation by default } ================================================ FILE: specta-swift/tests/string_enum_implementation.rs ================================================ #![allow(dead_code, missing_docs)] use serde::{Deserialize, Serialize}; use specta::{Type, Types}; use specta_swift::Swift; #[derive(Type, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub enum JobStatus { Queued, Running, Paused, Completed, Failed, Cancelled, } #[derive(Type, Serialize, Deserialize)] #[serde(rename_all = "UPPERCASE")] pub enum Priority { Low, Medium, High, } #[derive(Type, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub enum LogLevel { Debug, Info, Warning, Error, } #[derive(Type, Serialize, Deserialize)] #[serde(rename_all = "PascalCase")] pub enum UserRole { Admin, Moderator, User, Guest, } #[derive(Type, Serialize, Deserialize)] #[serde(rename_all = "kebab-case")] pub enum ApiStatus { Online, Offline, Maintenance, } #[derive(Type, Serialize, Deserialize)] #[serde(rename_all = "SCREAMING-KEBAB-CASE")] pub enum DatabaseStatus { Connected, Disconnected, Reconnecting, } // This should NOT be a string enum (has data fields) #[derive(Type, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub enum MixedEnum { Unit, WithData(String), WithFields { name: String, value: i32 }, } // This should NOT be a string enum (no rename_all) #[derive(Type)] pub enum RegularEnum { Variant1, Variant2, Variant3, } #[test] fn test_string_enum_snake_case() { let types = Types::default().register::(); let swift = Swift::default(); let result = swift.export(&types, specta_serde::Format).unwrap(); println!("Generated Swift for JobStatus:"); println!("{}", result); assert!(result.contains("enum JobStatus: String, Codable")); assert!(result.contains("case queued = \"queued\"")); assert!(result.contains("case running = \"running\"")); assert!(result.contains("case completed = \"completed\"")); assert!(result.contains("case failed = \"failed\"")); assert!(result.contains("case cancelled = \"cancelled\"")); } #[test] fn test_string_enum_uppercase() { let types = Types::default().register::(); let swift = Swift::default(); let result = swift.export(&types, specta_serde::Format).unwrap(); println!("Generated Swift for Priority:"); println!("{}", result); assert!(result.contains("enum Priority: String, Codable")); assert!(result.contains("case low = \"LOW\"")); assert!(result.contains("case medium = \"MEDIUM\"")); assert!(result.contains("case high = \"HIGH\"")); } #[test] fn test_string_enum_camel_case() { let types = Types::default().register::(); let swift = Swift::default(); let result = swift.export(&types, specta_serde::Format).unwrap(); println!("Generated Swift for LogLevel:"); println!("{}", result); assert!(result.contains("enum LogLevel: String, Codable")); assert!(result.contains("case debug = \"debug\"")); assert!(result.contains("case info = \"info\"")); assert!(result.contains("case warning = \"warning\"")); assert!(result.contains("case error = \"error\"")); } #[test] fn test_string_enum_pascal_case() { let types = Types::default().register::(); let swift = Swift::default(); let result = swift.export(&types, specta_serde::Format).unwrap(); println!("Generated Swift for UserRole:"); println!("{}", result); assert!(result.contains("enum UserRole: String, Codable")); assert!(result.contains("case admin = \"Admin\"")); assert!(result.contains("case moderator = \"Moderator\"")); assert!(result.contains("case user = \"User\"")); assert!(result.contains("case guest = \"Guest\"")); } #[test] fn test_string_enum_kebab_case() { let types = Types::default().register::(); let swift = Swift::default(); let result = swift.export(&types, specta_serde::Format).unwrap(); println!("Generated Swift for ApiStatus:"); println!("{}", result); assert!(result.contains("enum ApiStatus: String, Codable")); assert!(result.contains("case online = \"online\"")); assert!(result.contains("case offline = \"offline\"")); assert!(result.contains("case maintenance = \"maintenance\"")); } #[test] fn test_string_enum_screaming_kebab_case() { let types = Types::default().register::(); let swift = Swift::default(); let result = swift.export(&types, specta_serde::Format).unwrap(); println!("Generated Swift for DatabaseStatus:"); println!("{}", result); assert!(result.contains("enum DatabaseStatus: String, Codable")); assert!(result.contains("case connected = \"CONNECTED\"")); assert!(result.contains("case disconnected = \"DISCONNECTED\"")); assert!(result.contains("case reconnecting = \"RECONNECTING\"")); } #[test] fn test_mixed_enum_not_string() { let types = Types::default().register::(); let swift = Swift::default(); let result = swift.export(&types, specta_serde::Format).unwrap(); println!("Generated Swift for MixedEnum:"); println!("{}", result); // Should NOT be a string enum (has data fields) - no redundant Codable in declaration assert!(result.contains("enum MixedEnum")); assert!(!result.contains("enum MixedEnum: Codable")); assert!(!result.contains("enum MixedEnum: String, Codable")); // Should have Codable in extension instead assert!(result.contains("extension MixedEnum: Codable")); assert!(result.contains("case unit")); assert!(result.contains("case withData(String)")); assert!(result.contains("case withFields(MixedEnumWithFieldsData)")); assert!(result.contains("struct MixedEnumWithFieldsData: Codable")); assert!(result.contains("let name: String")); assert!(result.contains("let value: Int32")); assert!(!result.contains("case unit( case unit")); assert!(!result.contains("public let withFields: public let")); assert!(!result.contains("public let withData: public let")); } #[test] fn test_regular_enum_not_string() { let types = Types::default().register::(); let swift = Swift::default(); let result = swift.export(&types, specta_serde::Format).unwrap(); println!("Generated Swift for RegularEnum:"); println!("{}", result); assert!(result.contains("enum RegularEnum: String, Codable")); assert!(result.contains("case variant1 = \"Variant1\"")); assert!(result.contains("case variant2 = \"Variant2\"")); assert!(result.contains("case variant3 = \"Variant3\"")); } #[test] fn test_all_string_enums_together() { let string_types = Types::default() .register::() .register::() .register::() .register::() .register::() .register::(); let other_types = Types::default() .register::() .register::(); let swift = Swift::default(); let result = swift.export(&string_types, specta_serde::Format).unwrap(); let raw_result = swift.export(&other_types, specta_serde::Format).unwrap(); println!("Generated Swift for all enums:"); println!("{}", result); assert!(result.contains("enum JobStatus: String, Codable")); assert!(result.contains("enum Priority: String, Codable")); assert!(result.contains("enum LogLevel: String, Codable")); assert!(result.contains("enum UserRole: String, Codable")); assert!(result.contains("enum ApiStatus: String, Codable")); assert!(result.contains("enum DatabaseStatus: String, Codable")); assert!(raw_result.contains("enum MixedEnum")); assert!(raw_result.contains("enum RegularEnum: String, Codable")); assert!(raw_result.contains("extension MixedEnum: Codable")); } ================================================ FILE: specta-swift/tests/string_enum_test.rs ================================================ #![allow(dead_code, missing_docs)] use serde::{Deserialize, Serialize}; use specta::{Type, Types}; use specta_swift::Swift; /// Test enum with snake_case rename_all. #[derive(Type, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] enum JobStatus { Completed, Running, Failed, PendingApproval, } /// Test enum without rename_all. #[derive(Type)] enum RegularEnum { Option1, Option2, Option3, } #[test] fn test_string_enum_generation() { let swift = Swift::default(); let serde_resolved = Types::default().register::(); let raw_resolved = Types::default().register::(); let string_output = swift.export(&serde_resolved, specta_serde::Format).unwrap(); let raw_output = swift.export(&raw_resolved, specta_serde::Format).unwrap(); println!("String enum test output:\n{}", string_output); println!("Regular enum test output:\n{}", raw_output); assert!(string_output.contains("enum JobStatus: String, Codable")); assert!(string_output.contains("case completed = \"completed\"")); assert!(string_output.contains("case running = \"running\"")); assert!(string_output.contains("case failed = \"failed\"")); assert!(string_output.contains("case pendingApproval = \"pending_approval\"")); assert!(raw_output.contains("enum RegularEnum: String, Codable")); assert!(raw_output.contains("case option1 = \"Option1\"")); assert!(raw_output.contains("case option2 = \"Option2\"")); assert!(raw_output.contains("case option3 = \"Option3\"")); } ================================================ FILE: specta-swift/tests/struct_reuse_test.rs ================================================ #![allow(dead_code, missing_docs)] use specta::{Type, Types}; use specta_swift::Swift; #[derive(Type)] struct UserData { id: u32, name: String, email: Option, } #[derive(Type)] enum ApiResponse { Success(UserData), Error { message: String, code: u32 }, Loading, } #[derive(Type)] struct ApiRequest { user: UserData, action: String, } #[test] fn test_struct_reuse_between_standalone_and_enum() { let types = Types::default() .register::() .register::() .register::(); let swift = Swift::default(); let output = swift.export(&types, specta_serde::Format).unwrap(); println!("Generated Swift for struct reuse test:"); println!("{}", output); // Check that UserData is defined as a standalone struct assert!(output.contains("public struct UserData: Codable")); assert!(output.contains("public let id: UInt32")); assert!(output.contains("public let name: String")); assert!(output.contains("public let email: String?")); // Check that ApiResponse uses UserData directly (not a generated struct) assert!(output.contains("case success(UserData)")); // Check that ApiRequest also uses UserData directly assert!(output.contains("public struct ApiRequest: Codable")); assert!(output.contains("public let user: UserData")); assert!(output.contains("public let action: String")); // Ensure we don't have duplicate UserData definitions let user_data_count = output.matches("public struct UserData: Codable").count(); assert_eq!(user_data_count, 1, "UserData should be defined only once"); // Ensure we don't have any generated structs like ApiResponseSuccessData assert!( !output.contains("ApiResponseSuccessData"), "Should not generate ApiResponseSuccessData when UserData is standalone" ); } #[test] fn test_struct_reuse_with_different_ordering() { // Test with different ordering - enum first, then standalone struct let types = Types::default() .register::() .register::() .register::(); let swift = Swift::default(); let output = swift.export(&types, specta_serde::Format).unwrap(); println!("Generated Swift for struct reuse test (enum first):"); println!("{}", output); // Check that UserData is still defined as a standalone struct assert!(output.contains("public struct UserData: Codable")); // Check that ApiResponse uses UserData directly assert!(output.contains("case success(UserData)")); // Ensure we don't have duplicate UserData definitions let user_data_count = output.matches("public struct UserData: Codable").count(); assert_eq!(user_data_count, 1, "UserData should be defined only once"); // Ensure we don't have any generated structs like ApiResponseSuccessData assert!( !output.contains("ApiResponseSuccessData"), "Should not generate ApiResponseSuccessData when UserData is standalone" ); } ================================================ FILE: specta-swift/tests/struct_variants.rs ================================================ #![allow(dead_code, missing_docs)] use specta::{Type, Types}; use specta_swift::Swift; /// Test enum with struct-like variants (named fields) #[derive(Type)] pub enum Event { /// Job started event with named fields JobStarted { job_id: String, job_type: String }, /// Job completed event with named fields JobCompleted { job_id: String, result: String, duration: u64, }, /// Simple unit variant JobCancelled, /// Tuple variant (unnamed fields) JobFailed(String, u32), } /// Test enum with mixed variant types #[derive(Type)] pub enum ApiResponse { /// Success with data Success { data: String, status: u16 }, /// Error with details Error { message: String, code: u32, details: Option, }, /// Loading state Loading, /// Tuple variant Redirect(String), } #[test] fn test_struct_variants_generation() { let types = Types::default() .register::() .register::(); let swift = Swift::default(); let result = swift.export(&types, specta_serde::Format).unwrap(); println!("Generated Swift for struct variants:"); println!("{}", result); // Event enum should have struct-like cases assert!(result.contains("enum Event")); assert!(result.contains("case jobStarted(EventJobStartedData)")); assert!(result.contains("case jobCompleted(EventJobCompletedData)")); assert!(result.contains("case jobCancelled")); assert!(result.contains("case jobFailed(String, UInt32)")); // Should generate structs for named field variants assert!(result.contains("struct EventJobStartedData: Codable")); assert!(result.contains("let jobId: String")); assert!(result.contains("let jobType: String")); assert!(result.contains("struct EventJobCompletedData: Codable")); assert!(result.contains("let jobId: String")); assert!(result.contains("let result: String")); assert!(result.contains("let duration: UInt64")); // ApiResponse enum should have struct-like cases assert!(result.contains("enum ApiResponse")); assert!(result.contains("case success(ApiResponseSuccessData)")); assert!(result.contains("case error(ApiResponseErrorData)")); assert!(result.contains("case loading")); assert!(result.contains("case redirect(String)")); // Should generate structs for ApiResponse variants assert!(result.contains("struct ApiResponseSuccessData: Codable")); assert!(result.contains("let data: String")); assert!(result.contains("let status: UInt16")); assert!(result.contains("struct ApiResponseErrorData: Codable")); assert!(result.contains("let message: String")); assert!(result.contains("let code: UInt32")); assert!(result.contains("let details: String?")); } ================================================ FILE: specta-swift/tests/unions.rs ================================================ #![allow(dead_code, missing_docs)] use specta::{Type, Types}; use specta_swift::Swift; #[derive(Type)] struct User { id: u32, name: String, email: Option, } #[derive(Type)] struct Admin { id: u32, name: String, permissions: Vec, level: u8, } #[derive(Type)] struct Guest { session_id: String, expires_at: String, } #[derive(Type)] enum UserType { // Unit variant Anonymous, // Tuple variant User(String, u32), // Named fields variant (should become a struct-like case) Admin { id: u32, name: String, permissions: Vec, }, // Nested struct variant Registered(User), // Complex nested struct variant SuperAdmin(Admin), // Mixed variant with nested struct Guest { info: Guest, created_at: String, }, } #[derive(Type)] enum ApiResult { Success { data: T, status: u16, }, Error { error: E, code: u32, message: String, }, Loading { progress: f32, }, } #[derive(Type)] enum ComplexUnion { // Simple unit None, // Tuple with multiple types Tuple(String, u32, bool), // Named fields NamedFields { id: u32, name: String, active: bool, }, // Nested struct UserStruct(User), // Nested enum UserType(UserType), // Complex nested structure Complex { user: User, metadata: Vec, settings: Option, }, } #[test] fn test_enum_with_nested_structs() { let types = Types::default() .register::() .register::() .register::() .register::() .register::>() .register::(); let swift = Swift::default(); let output = swift.export(&types, specta_serde::Format).unwrap(); println!("Generated Swift code:\n{}", output); // Test enum generation assert!(output.contains("enum UserType")); assert!(output.contains("enum ApiResult")); assert!(output.contains("enum ComplexUnion")); // Test unit variants assert!(output.contains("case anonymous")); assert!(output.contains("case none")); // Test tuple variants assert!(output.contains("case user(String, UInt32)")); assert!(output.contains("case tuple(String, UInt32, Bool)")); // Test named field variants (should be struct-like) assert!(output.contains("case admin(UserTypeAdminData)")); assert!(output.contains("case guest(UserTypeGuestData)")); assert!(output.contains("case success(ApiResultSuccessData)")); assert!(output.contains("case error(ApiResultErrorData)")); assert!(output.contains("case loading(ApiResultLoadingData)")); assert!(output.contains("case namedFields(ComplexUnionNamedFieldsData)")); assert!(output.contains("case complex(ComplexUnionComplexData)")); // Test nested struct variants assert!(output.contains("case registered(User)")); assert!(output.contains("case superAdmin(Admin)")); assert!(output.contains("case userStruct(User)")); assert!(output.contains("case userType(UserType)")); // Test that nested structs are properly defined assert!(output.contains("struct User")); assert!(output.contains("struct Admin")); assert!(output.contains("struct Guest")); } #[test] fn test_swift_union_syntax() { let types = Types::default().register::(); let swift = Swift::default(); let output = swift.export(&types, specta_serde::Format).unwrap(); println!("UserType Swift code:\n{}", output); // Verify proper Swift enum syntax (no redundant Codable in declaration) assert!(output.contains("enum UserType {")); // Unit variant assert!(output.contains("case anonymous")); // Tuple variant assert!(output.contains("case user(String, UInt32)")); // Named fields should be struct-like assert!(output.contains("case admin(UserTypeAdminData)")); assert!(output.contains("case registered(User)")); assert!(output.contains("case superAdmin(Admin)")); assert!(output.contains("case guest(UserTypeGuestData)")); } ================================================ FILE: specta-swift/tests/uuid_simple.rs ================================================ #![allow(dead_code, missing_docs)] use specta::{Type, Types}; use specta_swift::Swift; // Test with UUID - this should work now that we have the uuid feature enabled #[derive(Type)] struct WithUuid { id: uuid::Uuid, name: String, } #[derive(Type)] struct WithChrono { created_at: chrono::DateTime, updated_at: chrono::NaiveDateTime, name: String, } #[test] fn test_uuid_support() { let types = Types::default().register::(); let swift = Swift::default(); let output = swift.export(&types, specta_serde::Format).unwrap(); println!("UUID support test:\n{}", output); // UUID should be converted to String in Swift assert!(output.contains("let id: String")); assert!(output.contains("let name: String")); } #[test] fn test_chrono_support() { let types = Types::default().register::(); let swift = Swift::default(); let output = swift.export(&types, specta_serde::Format).unwrap(); println!("Chrono support test:\n{}", output); // Chrono types should be converted to String in Swift assert!(output.contains("let createdAt: String")); assert!(output.contains("let updatedAt: String")); assert!(output.contains("let name: String")); } ================================================ FILE: specta-swift/tests/uuid_test.rs ================================================ //! Integration tests for Swift UUID and chrono support. #![allow(dead_code, missing_docs)] use specta::{Type, Types}; use specta_swift::Swift; #[derive(Type)] struct WithUuid { id: uuid::Uuid, name: String, } #[test] fn test_uuid_support() { let types = Types::default().register::(); let swift = Swift::default(); let output = swift.export(&types, specta_serde::Format).unwrap(); println!("UUID support test:\n{}", output); // UUID should be converted to String in Swift assert!(output.contains("let id: String")); assert!(output.contains("let name: String")); } #[derive(Type)] struct WithChrono { created_at: chrono::DateTime, updated_at: chrono::NaiveDateTime, name: String, } #[test] fn test_chrono_support() { let types = Types::default().register::(); let swift = Swift::default(); let output = swift.export(&types, specta_serde::Format).unwrap(); println!("Chrono support test:\n{}", output); // Chrono types should be converted to String in Swift assert!(output.contains("let createdAt: String")); assert!(output.contains("let updatedAt: String")); assert!(output.contains("let name: String")); } ================================================ FILE: specta-tags/Cargo.toml ================================================ [package] name = "specta-tags" description = "Analyze Specta datatypes and generate inline JavaScript transforms" version = "0.0.0" authors = ["Oscar Beaumont "] edition = "2024" license = "MIT" repository = "https://github.com/specta-rs/specta" documentation = "https://docs.rs/specta-tags/latest/specta-tags" keywords = ["async", "specta", "rspc", "typescript", "typesafe"] categories = ["web-programming", "asynchronous"] readme = "../README.md" # /bin/sh RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features [package.metadata."docs.rs"] all-features = true rustdoc-args = ["--cfg", "docsrs"] [lints] workspace = true [dependencies] specta = { version = "=2.0.0-rc.24", path = "../specta" } serde = "1" serde_json = "1" [dev-dependencies] serde = { version = "1", features = ["derive"] } bytes = "1.11.1" chrono = "0.4.44" specta = { version = "=2.0.0-rc.24", path = "../specta", features = ["derive", "chrono", "bytes"] } specta-serde = { version = "0.0.11", path = "../specta-serde" } ================================================ FILE: specta-tags/src/lib.rs ================================================ //! Analyze Specta datatypes and generate inline JavaScript transforms. //! //! `TransformPlan` walks a resolved `specta::DataType` tree, tags values that need //! JavaScript-side conversion, and renders a plain JavaScript expression that applies //! those conversions at runtime. //! //! This is intended for cases where a transport serializes values like `u128`, dates, //! or bytes into JSON-compatible representations and the client needs to restore their //! richer JavaScript forms. //! //! ```rust //! use specta::{Type, Types}; //! //! #[derive(Type)] //! struct Event { //! id: u128, //! } //! //! let mut types = Types::default(); //! let dt = Event::definition(&mut types); //! let plan = specta_tags::TransformPlan::analyze(&dt, &types); //! let js = plan.map("value"); //! assert!(js.contains("BigInt")); //! assert!(js.contains("[\"id\"]")); //! ``` #![cfg_attr(docsrs, feature(doc_cfg))] #![doc( html_logo_url = "https://github.com/specta-rs/specta/raw/main/.github/logo-128.png", html_favicon_url = "https://github.com/specta-rs/specta/raw/main/.github/logo-128.png" )] use std::{borrow::Cow, sync::Arc}; use specta::{ Types, datatype::{ DataType, Fields, GenericReference, NamedReference, NamedReferenceType, Primitive, Reference, }, }; // TODO: Allow configuring custom named types via NDT name and module path using config params. // TODO: Tagging-style system for `rspc` w/ runtime // TODO: Core changes to `BigInt` handling with Typescript exporter??? // TODO: How to handle `UInt8Array`? // TODO: Could we support `Custom` tags? If the runtime is fixed thats hard. // TODO: Documentations -> Explain how input types *just work* (double check that though) /// A tag is used to identify the transformation required for a given data type. #[derive(Clone)] pub enum Tag { /// [BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt) BigInt, /// [Uint8Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array) Uint8Array, /// [Date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) Date, /// A custom tag. /// /// TODO: Document this Custom(Arc Cow<'static, str> + Send + Sync>), } impl std::fmt::Debug for Tag { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::BigInt => f.write_str("BigInt"), Self::Uint8Array => f.write_str("Uint8Array"), Self::Date => f.write_str("Date"), Self::Custom(_) => f.write_str("Custom()"), } } } /// A compiled transform plan for a resolved Specta datatype. /// /// Use [`TransformPlan::analyze`] to build the plan, then [`TransformPlan::map`] to /// render the JavaScript expression that applies the required runtime conversions. #[derive(Debug)] pub struct TransformPlan { plan: PlanNode, } impl TransformPlan { /// Analyzes a resolved datatype and records the JavaScript conversions it needs. pub fn analyze(dt: &DataType, types: &Types) -> Self { // Scan all `DataType` references, etc. and collect tags and their object location for `Self::map` to use. // // You should match on `NamedDataType`'s name and module path to determine known named types. Self { plan: Analyzer.analyze(dt, types, &[], &mut Vec::new()), } } /// Renders a JavaScript expression that transforms the provided input expression. /// /// When no runtime conversions are required this returns the original expression. /// Otherwise it returns a new expression that applies the necessary `BigInt`, /// `Date`, or `Uint8Array` conversions inline. pub fn map<'a>(&self, t: &'a str) -> Cow<'a, str> { // If `t` is a struct and has tags we wanna decompose it to something like: // `{ ...t, field_with_override: { nested_override: new Date(t.field_with_override.nested_override) } }` // // If a nested tag doesn't have tags we should just return it to avoid deconstructing it. // // Otherwise we need to traverse the structure to apply the tags inline. // This should just be plain JS code so should work in Typescript (via inference) and in JS. // // If it has no tags we can just return `t` as is. if self.plan.is_identity() { return t.into(); } Cow::Owned(Renderer::default().render(&self.plan, t)) } } #[derive(Debug)] enum PlanNode { Identity, Leaf(Tag), Nullable(Box), List(Box), Tuple(Vec), Object(Vec), Map(Box), Enum(Vec), } impl PlanNode { fn is_identity(&self) -> bool { match self { Self::Identity => true, Self::Leaf(_) => false, Self::Nullable(inner) | Self::List(inner) | Self::Map(inner) => inner.is_identity(), Self::Tuple(items) => items.iter().all(Self::is_identity), Self::Object(fields) => fields.iter().all(ObjectFieldPlan::is_identity), Self::Enum(variants) => variants.iter().all(|v| v.plan.is_identity()), } } } #[derive(Debug)] enum ObjectFieldPlan { Named(String, PlanNode), } impl ObjectFieldPlan { fn is_identity(&self) -> bool { match self { Self::Named(_, plan) => plan.is_identity(), } } } #[derive(Debug)] struct EnumVariantPlan { matcher: EnumVariantMatcher, plan: PlanNode, } #[derive(Debug, Clone)] enum EnumVariantMatcher { HasField(String), Tagged { field: String, value: String }, Direct, } #[derive(Clone, Copy)] enum KnownNamedTag { Date, Uint8Array, } // TODO: Review everything in this! const BUILTIN_MATCHERS: &[(&str, &str, KnownNamedTag)] = &[ // BigInt-like wrapper // ("tauri_specta", "BigInt", KnownNamedTag::BigInt), // TODO: Fix this // Date-like ("std::time", "SystemTime", KnownNamedTag::Date), ("toml::value", "Datetime", KnownNamedTag::Date), ("chrono", "NaiveDateTime", KnownNamedTag::Date), ("chrono", "NaiveDate", KnownNamedTag::Date), ("chrono", "Date", KnownNamedTag::Date), ("chrono", "DateTime", KnownNamedTag::Date), ("time", "PrimitiveDateTime", KnownNamedTag::Date), ("time", "OffsetDateTime", KnownNamedTag::Date), ("time", "Date", KnownNamedTag::Date), ("jiff", "Timestamp", KnownNamedTag::Date), ("jiff", "Zoned", KnownNamedTag::Date), ("jiff::civil", "Date", KnownNamedTag::Date), ("jiff::civil", "DateTime", KnownNamedTag::Date), ("bson", "DateTime", KnownNamedTag::Date), // Byte-like ("bytes", "Bytes", KnownNamedTag::Uint8Array), ("bytes", "BytesMut", KnownNamedTag::Uint8Array), ]; #[derive(Default)] struct Analyzer; impl Analyzer { fn analyze( &self, dt: &DataType, types: &Types, generics: &[(GenericReference, DataType)], stack: &mut Vec, ) -> PlanNode { match dt { DataType::Primitive(Primitive::i64) | DataType::Primitive(Primitive::u64) | DataType::Primitive(Primitive::i128) | DataType::Primitive(Primitive::u128) => PlanNode::Leaf(Tag::BigInt), DataType::Primitive(_) => PlanNode::Identity, DataType::List(list) => { let inner = self.analyze(&list.ty, types, generics, stack); if inner.is_identity() { PlanNode::Identity } else { PlanNode::List(Box::new(inner)) } } DataType::Map(map) => { let inner = self.analyze(map.value_ty(), types, generics, stack); if inner.is_identity() { PlanNode::Identity } else { PlanNode::Map(Box::new(inner)) } } DataType::Struct(st) => self.analyze_fields(&st.fields, types, generics, stack), DataType::Enum(en) => { let mut variants = Vec::new(); for (name, variant) in en.variants.iter().filter(|(_, v)| !v.skip) { if let Some(variant) = self.analyze_enum_variant(name, variant, types, generics, stack) && !variant.plan.is_identity() { variants.push(variant); } } if variants.is_empty() { PlanNode::Identity } else { PlanNode::Enum(variants) } } DataType::Tuple(tuple) => { let items = tuple .elements .iter() .map(|ty| self.analyze(ty, types, generics, stack)) .collect::>(); if items.iter().all(PlanNode::is_identity) { PlanNode::Identity } else { PlanNode::Tuple(items) } } DataType::Nullable(inner) => { let inner = self.analyze(inner, types, generics, stack); if inner.is_identity() { PlanNode::Identity } else { PlanNode::Nullable(Box::new(inner)) } } DataType::Reference(Reference::Named(reference)) => { if let Some(ndt) = types.get(reference) { if let Some(tag) = self.resolve_named_tag(&ndt.module_path, &ndt.name) { return match tag { KnownNamedTag::Date => PlanNode::Leaf(Tag::Date), KnownNamedTag::Uint8Array => PlanNode::Leaf(Tag::Uint8Array), }; } if stack.contains(reference) { return PlanNode::Identity; } if let NamedReferenceType::Inline { dt, .. } = &reference.inner { return self.analyze(dt, types, &[], stack); } stack.push(reference.clone()); let Some(ty) = &ndt.ty else { stack.pop(); return PlanNode::Identity; }; let (ty, generics) = match &reference.inner { NamedReferenceType::Reference { generics, .. } => (ty, generics.as_slice()), NamedReferenceType::Inline { dt, .. } => (dt.as_ref(), &[][..]), NamedReferenceType::Recursive => (ty, &[][..]), }; let out = self.analyze(ty, types, generics, stack); stack.pop(); out } else if let NamedReferenceType::Inline { dt, .. } = &reference.inner { self.analyze(dt, types, &[], stack) } else { PlanNode::Identity } } DataType::Generic(generic) => generics .iter() .find(|(key, _)| key == generic) .map(|(_, dt)| self.analyze(dt, types, &[], stack)) .unwrap_or(PlanNode::Identity), DataType::Reference(Reference::Opaque(_)) => PlanNode::Identity, DataType::Intersection(intersection) => { let items = intersection .iter() .map(|ty| self.analyze(ty, types, generics, stack)) .collect::>(); if items.iter().all(PlanNode::is_identity) { PlanNode::Identity } else { PlanNode::Tuple(items) } } } } fn analyze_fields( &self, fields: &Fields, types: &Types, generics: &[(GenericReference, DataType)], stack: &mut Vec, ) -> PlanNode { match fields { Fields::Unit => PlanNode::Identity, Fields::Unnamed(fields) => { let items = fields .fields .iter() .filter_map(|field| field.ty.as_ref()) .map(|ty| self.analyze(ty, types, generics, stack)) .collect::>(); if items.iter().all(PlanNode::is_identity) { PlanNode::Identity } else { PlanNode::Tuple(items) } } Fields::Named(fields) => { let object = fields .fields .iter() .filter_map(|(name, field)| { let ty = field.ty.as_ref()?; let plan = self.analyze(ty, types, generics, stack); if plan.is_identity() { None } else { Some(ObjectFieldPlan::Named(name.to_string(), plan)) } }) .collect::>(); if object.is_empty() { PlanNode::Identity } else { PlanNode::Object(object) } } } } fn resolve_named_tag(&self, module_path: &str, name: &str) -> Option { BUILTIN_MATCHERS .iter() .find(|(module, ty_name, _)| module_path == *module && name == *ty_name) .map(|(_, _, kind)| *kind) } fn analyze_enum_variant( &self, name: &str, variant: &specta::datatype::Variant, types: &Types, generics: &[(GenericReference, DataType)], stack: &mut Vec, ) -> Option { let plan = self.analyze_fields(&variant.fields, types, generics, stack); let matcher = match &variant.fields { Fields::Unit | Fields::Unnamed(_) => EnumVariantMatcher::Direct, Fields::Named(fields) => { let literal_fields = fields .fields .iter() .filter_map(|(field_name, field)| { string_literal(field.ty.as_ref()?) .map(|value| (field_name.to_string(), value)) }) .collect::>(); if literal_fields.len() == 1 { let (field, value) = &literal_fields[0]; EnumVariantMatcher::Tagged { field: field.clone(), value: value.clone(), } } else if fields.fields.len() == 1 { let (field_name, _) = &fields.fields[0]; EnumVariantMatcher::HasField(field_name.to_string()) } else { let _ = name; EnumVariantMatcher::Direct } } }; Some(EnumVariantPlan { matcher, plan }) } } #[derive(Default)] struct Renderer { ident_counter: usize, } impl Renderer { fn render(&mut self, plan: &PlanNode, input: &str) -> String { match plan { PlanNode::Identity => input.to_string(), PlanNode::Leaf(tag) => self.render_leaf(tag, input), PlanNode::Nullable(inner) => { let inner = self.render(inner, input); format!("({input} == null ? {input} : {inner})") } PlanNode::List(inner) => { let item = self.next_ident("item"); let inner = self.render(inner, &item); format!("{input}.map(({item}) => {inner})") } PlanNode::Tuple(items) => { let rendered = items .iter() .enumerate() .map(|(idx, plan)| { let source = format!("{input}[{idx}]"); self.render(plan, &source) }) .collect::>() .join(", "); format!("[{rendered}]") } PlanNode::Object(fields) => self.render_object(fields, input), PlanNode::Map(inner) => { let key = self.next_ident("key"); let value = self.next_ident("value"); let inner = self.render(inner, &value); format!( "Object.fromEntries(Object.entries({input}).map(([{key}, {value}]) => [{key}, {inner}]))" ) } PlanNode::Enum(variants) => self.render_enum(variants, input), } } fn render_object(&mut self, fields: &[ObjectFieldPlan], input: &str) -> String { let value = self.next_ident("value"); let mut out = format!("(() => {{ let {value} = {input};"); for field in fields { match field { ObjectFieldPlan::Named(field, plan) => { let key = js_string(field); let source = format!("{value}[{key}]"); let next = self.render(plan, &source); out.push_str(&format!( " {{ const next = {next}; if (next !== {source}) {value} = {{ ...{value}, {key}: next }}; }}" )); } } } out.push_str(&format!(" return {value}; }})()")); out } fn render_leaf(&mut self, tag: &Tag, input: &str) -> String { match tag { Tag::BigInt => format!("BigInt({input})"), Tag::Uint8Array => format!("Uint8Array.from({input})"), Tag::Date => format!("new Date({input})"), Tag::Custom(handler) => handler(input).into_owned(), } } fn render_enum(&mut self, variants: &[EnumVariantPlan], input: &str) -> String { let value = self.next_ident("value"); let mut out = format!("(() => {{ const {value} = {input};"); if variants.is_empty() { out.push_str(&format!(" return {value}; }})()")); return out; } for variant in variants { if variant.plan.is_identity() { continue; } let next = self.render(&variant.plan, &value); match &variant.matcher { EnumVariantMatcher::HasField(field) => { let field = js_string(field); out.push_str(&format!( " if ({value} != null && typeof {value} === \"object\" && !Array.isArray({value}) && Object.prototype.hasOwnProperty.call({value}, {field})) {{ const next = {next}; if (next !== {value}) return next; return {value}; }}" )); } EnumVariantMatcher::Tagged { field, value: tag } => { let field = js_string(field); let tag = js_string(tag); out.push_str(&format!( " if ({value} != null && typeof {value} === \"object\" && !Array.isArray({value}) && {value}[{field}] === {tag}) {{ const next = {next}; if (next !== {value}) return next; return {value}; }}" )); } EnumVariantMatcher::Direct => { out.push_str(&format!( " {{ const next = {next}; if (next !== {value}) return next; }}" )); } } } out.push_str(&format!(" return {value}; }})()")); out } fn next_ident(&mut self, prefix: &str) -> String { self.ident_counter += 1; format!("__{prefix}{}", self.ident_counter) } } fn js_string(value: &str) -> String { serde_json::to_string(value).expect("failed to encode JavaScript string") } fn string_literal(ty: &DataType) -> Option { let DataType::Enum(enm) = ty else { return None; }; let [(name, variant)] = enm.variants.as_slice() else { return None; }; matches!(&variant.fields, Fields::Unit).then(|| name.to_string()) } #[cfg(test)] mod tests { use serde::{Deserialize, Serialize}; use specta::{Format as _, Type, Types}; use super::TransformPlan; #[allow(dead_code)] #[derive(Type)] struct Inner { bigint: u128, date: chrono::DateTime, bytes: bytes::Bytes, } #[allow(dead_code)] #[derive(Type)] struct Root { bigint: u128, date: chrono::DateTime, bytes: bytes::Bytes, nested: Inner, list: Vec, } #[test] fn map_renders_trusting_transforms() { let mut types = Types::default(); let dt = Root::definition(&mut types); let plan = TransformPlan::analyze(&dt, &types); let js = plan.map("v"); assert!( js.contains("BigInt(") && js.contains("[\"bigint\"]") && js.contains("[\"nested\"]") ); assert!( js.contains("new Date(") && js.contains("[\"date\"]") && js.contains("[\"nested\"]") ); assert!( js.contains("Uint8Array.from(") && js.contains("[\"bytes\"]") && js.contains("[\"nested\"]") ); assert!(js.contains("[\"list\"]") && js.contains(".map((__item")); assert!(!js.contains("typeof ")); assert!(!js.contains("Array.isArray(")); assert!(!js.contains("Number.isInteger(")); assert!(!js.contains("try {")); assert!(!js.contains(" catch ")); } #[derive(Type, Serialize, Deserialize)] #[serde(tag = "kind")] enum TaggedEnum { A { count: u128 }, } #[derive(Type, Serialize, Deserialize)] #[serde(tag = "kind", content = "payload")] enum AdjacentEnum { A { count: u128 }, } #[test] fn map_renders_from_serde_applied_internal_enum_shape() { let format = specta_serde::Format; let resolved = format .map_types(&Types::default().register::()) .unwrap() .into_owned(); let dt = resolved .into_sorted_iter() .find(|ty| ty.name.as_ref() == "TaggedEnum") .expect("TaggedEnum should be registered") .ty .clone(); let js = TransformPlan::analyze(dt.as_ref().unwrap(), &resolved).map("v"); assert!(js.contains("[\"kind\"] === \"A\"")); assert!(js.contains("BigInt(")); assert!(js.contains("[\"count\"]")); } #[test] fn map_renders_from_serde_applied_adjacent_enum_shape() { let format = specta_serde::Format; let resolved = format .map_types(&Types::default().register::()) .unwrap() .into_owned(); let dt = resolved .into_sorted_iter() .find(|ty| ty.name.as_ref() == "AdjacentEnum") .expect("AdjacentEnum should be registered") .ty .clone(); let js = TransformPlan::analyze(dt.as_ref().unwrap(), &resolved).map("v"); assert!(js.contains("[\"kind\"] === \"A\"")); assert!(js.contains("payload")); assert!(js.contains("BigInt(")); } } ================================================ FILE: specta-typescript/Cargo.toml ================================================ [package] name = "specta-typescript" description = "Export your Rust types to TypeScript" version = "0.0.11" authors = ["Oscar Beaumont "] edition = "2024" license = "MIT" repository = "https://github.com/specta-rs/specta" documentation = "https://docs.rs/specta-typescript/latest/specta-typescript" keywords = ["async", "specta", "rspc", "typescript", "typesafe"] categories = ["web-programming", "asynchronous"] readme = "../README.md" # /bin/sh RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features [package.metadata."docs.rs"] all-features = true rustdoc-args = ["--cfg", "docsrs"] [lints] workspace = true [features] default = [] # Implement `serde::Serialize` and `serde::Deserialize` for Typescript-specific types (Any, Unknown, Never) serde = ["dep:serde"] [dependencies] specta = { version = "=2.0.0-rc.24", path = "../specta" } serde = { version = "1", default-features = false, optional = true } [dev-dependencies] serde = { version = "1", features = ["derive"] } specta = { version = "=2.0.0-rc.24", path = "../specta", features = ["derive", "collect"] } specta-serde = { path = "../specta-serde" } specta-util = { path = "../specta-util", features = ["serde"] } ================================================ FILE: specta-typescript/bindings.ts ================================================ // This file has been generated by Specta. Do not edit this file manually. export type MyOtherType = { other_field: string, }; export type MyType = { field: MyOtherType, }; ================================================ FILE: specta-typescript/src/branded.rs ================================================ use std::borrow::Cow; use specta::datatype::DataType; /// Create a branded tuple struct type that exports to TypeScript with a custom name. /// /// This macro generates a single-field tuple struct and implements the `Type` trait /// for it, allowing you to create "branded" types that maintain distinct identities /// in TypeScript. /// /// # Examples /// /// Basic usage: /// ```ignore /// branded!(pub struct AccountId(String)); /// ``` /// /// With custom TypeScript name: /// ```ignore /// branded!(pub struct AccountId(String) as "accountId"); /// ``` /// /// With attributes: /// ```ignore /// branded!(#[derive(Serialize)] pub struct UserId(String)); /// ``` /// /// With generics: /// ```ignore /// branded!(pub struct Id(T) as "id"); /// ``` /// /// # Requirements /// /// This macro requires that the `specta` crate is in scope and available as a dependency. /// /// # Notes /// /// - The struct must be a tuple struct with exactly one field /// - The `Type` implementation is currently a `todo!()` placeholder /// - The `as "name"` syntax is optional; if omitted, the struct name is used #[macro_export] macro_rules! branded { // Pattern with generics and optional TypeScript name ( $(#[$attr:meta])* $vis:vis struct $ident:ident<$($generic:ident),+ $(,)?> ( $ty:ty ) $(as $ts_name:literal)? ) => { $(#[$attr])* $vis struct $ident<$($generic),+>($ty); impl<$($generic: specta::Type),+> specta::Type for $ident<$($generic),+> { fn definition(types: &mut specta::Types) -> specta::datatype::DataType { let ty = <$ty as specta::Type>::definition(types); let brand: &'static str = branded!(@brand $ident $( $ts_name )?); specta::datatype::DataType::Reference( specta::datatype::Reference::opaque( $crate::Branded::new(std::borrow::Cow::Borrowed(brand), ty) ) ) } } }; // Pattern without generics ( $(#[$attr:meta])* $vis:vis struct $ident:ident ( $ty:ty ) $(as $ts_name:literal)? ) => { $(#[$attr])* $vis struct $ident($ty); impl specta::Type for $ident { fn definition(types: &mut specta::Types) -> specta::datatype::DataType { let ty = <$ty as specta::Type>::definition(types); let brand: &'static str = branded!(@brand $ident $( $ts_name )?); specta::datatype::DataType::Reference( specta::datatype::Reference::opaque( $crate::Branded::new(std::borrow::Cow::Borrowed(brand), ty) ) ) } } }; // Internal (@brand $ident:ident $ts_name:literal) => { $ts_name }; (@brand $ident:ident) => { stringify!($ident) }; } #[derive(Debug, Clone, PartialEq, Eq, Hash)] /// Runtime payload for a TypeScript branded type. pub struct Branded { brand: Cow<'static, str>, ty: DataType, } impl Branded { /// Construct a branded type from a brand label and inner type. pub fn new(brand: impl Into>, ty: DataType) -> Self { Self { brand: brand.into(), ty, } } /// Get the brand label. pub fn brand(&self) -> &Cow<'static, str> { &self.brand } /// Get the inner data type. pub fn ty(&self) -> &DataType { &self.ty } } ================================================ FILE: specta-typescript/src/error.rs ================================================ use std::{borrow::Cow, error, fmt, io, panic::Location, path::PathBuf}; use specta::datatype::OpaqueReference; use crate::Layout; use super::legacy::ExportPath; /// The error type for the TypeScript exporter. /// /// ## BigInt Forbidden /// /// Specta Typescript intentionally forbids exporting BigInt-style Rust integer types. /// This includes [usize], [isize], [i64], [u64], [u128], [i128] and [f128]. /// /// This guard exists because `JSON.parse` will truncate large integers to fit into a JavaScript `number` type so we explicitly forbid exporting them. /// /// We take the stance that correctness matters more than developer experience as people using Rust generally strive for correctness. /// /// If you encounter this error, there are a few common migration paths (in order of preference): /// /// 1. Use a Specta-based framework which can handle these types /// - None currently exist but it would theoretically be possible refer to [#203](https://github.com/specta-rs/specta/issues/203) for more information. /// /// 2. Use a smaller integer types (any of `u8`/`i8`/`u16`/`i16`/`u32`/`i32`/`f64`). /// - Only possible when the biggest integer you need to represent is small enough to be represented by a `number` in JS. /// - This approach forces your application code to handle overflow/underflow values explicitly /// - Downside is that it can introduce annoying glue code and doesn't actually work if your need large values. /// /// 3. Serialize the value as a string /// - This can be done using `#[specta(type = String)]` for the type combined with a Serde `#[serde(with = "...")]` attribute for runtime. /// - Downside is that it can introduce annoying glue code, both on in Rust and in JS as you will need to turn it back into a `new BigInt(myString)` in JS but this will support numbers of any size losslessly. /// /// 4. **UNSAFE:** Accept precision loss on per-field basis /// - Accept that large numbers may be deserialized differently than they are in Rust and use `#[specta(type = specta_typescript::Number)]` to bypass this warning on a per-field basis. /// - Marking each field explicitly encodes the decision similar to an `unsafe` block, ensuring everyone working on your codebase is aware of the risk and where it exists within the codebase. /// - This doesn't work for external implementations like `serde_json::Value` which contain `BigInt`'s as you don't control the definition. /// /// 5. **UNSAFE:** Accept precision loss using [`specta_util::Remapper`](https://docs.rs/specta-util/latest/specta_util/struct.Remapper.html) /// - You can apply a `Remapper` to your [`Types`](specta::Types) collection to override types. This would allow you to remap `usize`/`isize`/`i64`/`u64`/`i128`/`u128`/`f128` into `number`. /// - This is highly not recommended but it might be required if your using `serde_json::Value` or other built-in impls which contain `BigInt`'s as you can't override them. /// #[non_exhaustive] pub struct Error { kind: ErrorKind, } type FrameworkSource = Box; const BIGINT_DOCS_URL: &str = "https://docs.rs/specta-typescript/latest/specta_typescript/struct.Error.html#bigint-forbidden"; #[allow(dead_code)] enum ErrorKind { InvalidMapKey { path: String, reason: Cow<'static, str>, }, /// Attempted to export a bigint type but the configuration forbids it. BigIntForbidden { path: String, }, /// A type's name conflicts with a reserved keyword in Typescript. ForbiddenName { path: String, name: &'static str, }, /// A type's name contains invalid characters or is not valid. InvalidName { path: String, name: Cow<'static, str>, }, /// Detected multiple items within the same scope with the same name. /// Typescript doesn't support this so we error out. /// /// Using anything other than [Layout::FlatFile] should make this basically impossible. DuplicateTypeName { name: Cow<'static, str>, first: String, second: String, }, /// An filesystem IO error. /// This is possible when using `Typescript::export_to` when writing to a file or formatting the file. Io(io::Error), /// Failed to read a directory while exporting files. ReadDir { path: PathBuf, source: io::Error, }, /// Failed to inspect filesystem metadata while exporting files. Metadata { path: PathBuf, source: io::Error, }, /// Failed to remove a stale file while exporting files. RemoveFile { path: PathBuf, source: io::Error, }, /// Failed to remove an empty directory while exporting files. RemoveDir { path: PathBuf, source: io::Error, }, /// Found an opaque reference which the Typescript exporter doesn't know how to handle. /// You may be referencing a type which is not supported by the Typescript exporter. UnsupportedOpaqueReference(OpaqueReference), /// Found a named reference that cannot be resolved from the provided /// [`Types`](specta::Types). DanglingNamedReference { reference: String, }, /// Found a recursive named reference while expanding an inline type. InfiniteRecursiveInlineType { reference: String, }, /// An error occurred in your exporter framework. Framework { message: Cow<'static, str>, source: FrameworkSource, }, /// An error occurred in a format callback. Format { message: Cow<'static, str>, source: FrameworkSource, }, // // // TODO: Break // // BigIntForbiddenLegacy(ExportPath), ForbiddenNameLegacy(ExportPath, &'static str), InvalidNameLegacy(ExportPath, String), FmtLegacy(std::fmt::Error), UnableToExport(Layout), } impl Error { pub(crate) fn invalid_map_key( path: impl Into, reason: impl Into>, ) -> Self { Self { kind: ErrorKind::InvalidMapKey { path: path.into(), reason: reason.into(), }, } } /// Construct an error for framework-specific logic. pub fn framework( message: impl Into>, source: impl Into>, ) -> Self { Self { kind: ErrorKind::Framework { message: message.into(), source: source.into(), }, } } /// Construct an error for custom format callbacks. pub(crate) fn format( message: impl Into>, source: impl Into>, ) -> Self { Self { kind: ErrorKind::Format { message: message.into(), source: source.into(), }, } } pub(crate) fn bigint_forbidden(path: String) -> Self { Self { kind: ErrorKind::BigIntForbidden { path }, } } pub(crate) fn invalid_name(path: String, name: impl Into>) -> Self { Self { kind: ErrorKind::InvalidName { path, name: name.into(), }, } } pub(crate) fn duplicate_type_name( name: Cow<'static, str>, first: Location<'static>, second: Location<'static>, ) -> Self { Self { kind: ErrorKind::DuplicateTypeName { name, first: format_location(first), second: format_location(second), }, } } pub(crate) fn read_dir(path: PathBuf, source: io::Error) -> Self { Self { kind: ErrorKind::ReadDir { path, source }, } } pub(crate) fn metadata(path: PathBuf, source: io::Error) -> Self { Self { kind: ErrorKind::Metadata { path, source }, } } pub(crate) fn remove_file(path: PathBuf, source: io::Error) -> Self { Self { kind: ErrorKind::RemoveFile { path, source }, } } pub(crate) fn remove_dir(path: PathBuf, source: io::Error) -> Self { Self { kind: ErrorKind::RemoveDir { path, source }, } } pub(crate) fn unsupported_opaque_reference(reference: OpaqueReference) -> Self { Self { kind: ErrorKind::UnsupportedOpaqueReference(reference), } } pub(crate) fn dangling_named_reference(reference: String) -> Self { Self { kind: ErrorKind::DanglingNamedReference { reference }, } } pub(crate) fn infinite_recursive_inline_type(reference: String) -> Self { Self { kind: ErrorKind::InfiniteRecursiveInlineType { reference }, } } pub(crate) fn forbidden_name_legacy(path: ExportPath, name: &'static str) -> Self { Self { kind: ErrorKind::ForbiddenNameLegacy(path, name), } } pub(crate) fn invalid_name_legacy(path: ExportPath, name: String) -> Self { Self { kind: ErrorKind::InvalidNameLegacy(path, name), } } pub(crate) fn unable_to_export(layout: Layout) -> Self { Self { kind: ErrorKind::UnableToExport(layout), } } } impl From for Error { fn from(error: io::Error) -> Self { Self { kind: ErrorKind::Io(error), } } } impl From for Error { fn from(error: std::fmt::Error) -> Self { Self { kind: ErrorKind::FmtLegacy(error), } } } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.kind { ErrorKind::InvalidMapKey { path, reason } => { write!(f, "Invalid map key at '{path}': {reason}") } ErrorKind::BigIntForbidden { path } => write!( f, "Attempted to export {path:?} but Specta forbids exporting BigInt-style types (usize, isize, i64, u64, i128, u128) to avoid precision loss. See {BIGINT_DOCS_URL} for a full explanation." ), ErrorKind::ForbiddenName { path, name } => write!( f, "Attempted to export {path:?} but was unable to due toname {name:?} conflicting with a reserved keyword in Typescript. Try renaming it or using `#[specta(rename = \"new name\")]`" ), ErrorKind::InvalidName { path, name } => write!( f, "Attempted to export {path:?} but was unable to due to name {name:?} containing an invalid character. Try renaming it or using `#[specta(rename = \"new name\")]`" ), ErrorKind::DuplicateTypeName { name, first, second, } => write!( f, "Detected multiple types with the same name: {name:?} at {first} and {second}" ), ErrorKind::Io(err) => write!(f, "IO error: {err}"), ErrorKind::ReadDir { path, source } => { write!(f, "Failed to read directory '{}': {source}", path.display()) } ErrorKind::Metadata { path, source } => { write!( f, "Failed to read metadata for '{}': {source}", path.display() ) } ErrorKind::RemoveFile { path, source } => { write!(f, "Failed to remove file '{}': {source}", path.display()) } ErrorKind::RemoveDir { path, source } => { write!( f, "Failed to remove directory '{}': {source}", path.display() ) } ErrorKind::UnsupportedOpaqueReference(reference) => write!( f, "Found unsupported opaque reference '{}'. It is not supported by the Typescript exporter.", reference.type_name() ), ErrorKind::DanglingNamedReference { reference } => write!( f, "Found dangling named reference {reference}. The referenced type is missing from the resolved type collection." ), ErrorKind::InfiniteRecursiveInlineType { reference } => write!( f, "Found infinitely recursive inline named reference {reference}. Recursive inline types cannot be expanded because they would produce an infinite Typescript type." ), ErrorKind::Framework { message, source } => { let source = source.to_string(); if message.is_empty() && source.is_empty() { write!(f, "Framework error") } else if source.is_empty() { write!(f, "Framework error: {message}") } else { write!(f, "Framework error: {message}: {source}") } } ErrorKind::Format { message, source } => { let source = source.to_string(); if message.is_empty() && source.is_empty() { write!(f, "Format error") } else if source.is_empty() { write!(f, "Format error: {message}") } else { write!(f, "Format error: {message}: {source}") } } ErrorKind::BigIntForbiddenLegacy(path) => write!( f, "Attempted to export {path:?} but Specta forbids exporting BigInt-style types (usize, isize, i64, u64, i128, u128) to avoid precision loss. See {BIGINT_DOCS_URL} for a full explanation." ), ErrorKind::ForbiddenNameLegacy(path, name) => write!( f, "Attempted to export {path:?} but was unable to due to name {name:?} conflicting with a reserved keyword in Typescript. Try renaming it or using `#[specta(rename = \"new name\")]`" ), ErrorKind::InvalidNameLegacy(path, name) => write!( f, "Attempted to export {path:?} but was unable to due to name {name:?} containing an invalid character. Try renaming it or using `#[specta(rename = \"new name\")]`" ), ErrorKind::FmtLegacy(err) => write!(f, "formatter: {err:?}"), ErrorKind::UnableToExport(layout) => write!( f, "Unable to export layout {layout} with the current configuration. Maybe try `Exporter::export_to` or switching to Typescript." ), } } } impl fmt::Debug for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(self, f) } } impl error::Error for Error { fn source(&self) -> Option<&(dyn error::Error + 'static)> { match &self.kind { ErrorKind::Io(error) => Some(error), ErrorKind::ReadDir { source, .. } | ErrorKind::Metadata { source, .. } | ErrorKind::RemoveFile { source, .. } | ErrorKind::RemoveDir { source, .. } => Some(source), ErrorKind::Framework { source, .. } | ErrorKind::Format { source, .. } => { Some(source.as_ref()) } ErrorKind::FmtLegacy(error) => Some(error), _ => None, } } } fn format_location(location: Location<'static>) -> String { format!( "{}:{}:{}", location.file(), location.line(), location.column() ) } ================================================ FILE: specta-typescript/src/exporter.rs ================================================ use std::{ borrow::Cow, collections::{BTreeMap, BTreeSet, HashMap, HashSet}, fmt, ops::Deref, panic::Location, path::{Path, PathBuf}, sync::Arc, }; use specta::{ Format, Types, datatype::{DataType, Fields, NamedDataType, NamedReference, NamedReferenceType, Reference}, }; use crate::{Branded, Error, primitives, references}; /// Allows configuring the format of the final types file #[derive(Debug, Clone, Copy, Default, PartialEq, Eq)] pub enum Layout { /// Produce a Typescript namespace for each Rust module Namespaces, /// Produce a dedicated file for each Rust module Files, /// Include the full module path in the types name but keep a flat structure. ModulePrefixedName, /// Flatten all of the types into a single file of types. /// This mode doesn't support having multiple types with the same name. #[default] FlatFile, } impl fmt::Display for Layout { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{self:?}") } } #[derive(Clone)] #[allow(clippy::type_complexity)] struct RuntimeFn(Arc Result, Error> + Send + Sync>); impl fmt::Debug for RuntimeFn { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "RuntimeFn({:p})", self.0) } } #[derive(Clone)] #[allow(clippy::type_complexity)] pub struct BrandedTypeImpl( pub(crate) Arc< dyn for<'a> Fn(BrandedTypeExporter<'a>, &Branded) -> Result, Error> + Send + Sync, >, ); impl fmt::Debug for BrandedTypeImpl { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "BrandedTypeImpl({:p})", self.0) } } /// Typescript language exporter. #[derive(Debug, Clone)] #[non_exhaustive] pub struct Exporter { /// Custom header prepended to exported files. pub header: Cow<'static, str>, framework_runtime: Option, pub(crate) branded_type_impl: Option, framework_prelude: Cow<'static, str>, /// Output layout mode for generated TypeScript. pub layout: Layout, pub(crate) jsdoc: bool, } impl Exporter { // You should get this from either a [Typescript] or [JSDoc], not construct it directly. pub(crate) fn default() -> Exporter { Exporter { header: Cow::Borrowed(""), framework_runtime: None, branded_type_impl: None, framework_prelude: Cow::Borrowed( "// This file has been generated by Specta. Do not edit this file manually.", ), layout: Default::default(), jsdoc: false, } } /// Provide a prelude which is added to the start of all exported files. pub fn framework_prelude(mut self, prelude: impl Into>) -> Self { self.framework_prelude = prelude.into(); self } /// Add some custom Typescript or Javascript code that is exported as part of the bindings. /// It's appending to the types file for single-file layouts or put in a root `index.{ts/js}` for multi-file. /// /// The closure is wrapped in [`specta::collect()`] to capture any referenced types. /// Ensure you call `T::reference()` within the closure if you want an import to be created. pub fn framework_runtime( mut self, builder: impl Fn(FrameworkExporter) -> Result, Error> + Send + Sync + 'static, ) -> Self { self.framework_runtime = Some(RuntimeFn(Arc::new(builder))); self } /// Configure how `specta_typescript::branded!` types are rendered with exporter context. /// /// This callback receives both the branded payload and a [`BrandedTypeExporter`], allowing /// you to call [`BrandedTypeExporter::inline`] / [`BrandedTypeExporter::reference`] while /// preserving the current export configuration. /// /// # Examples /// /// `ts-brand` style: /// ```rust /// # use std::borrow::Cow; /// # use specta_typescript::{Branded, Error, Typescript}; /// let exporter = Typescript::default().branded_type_impl(|ctx, branded| { /// let datatype = ctx.inline(branded.ty())?; /// /// Ok(Cow::Owned(format!( /// "import(\"ts-brand\").Brand<{}, \"{}\">", /// datatype, /// branded.brand() /// ))) /// }); /// # let _ = exporter; /// ``` /// /// Effect style: /// ```rust /// # use std::borrow::Cow; /// # use specta_typescript::{Branded, Error, Typescript}; /// let exporter = Typescript::default().branded_type_impl(|ctx, branded| { /// let datatype = ctx.inline(branded.ty())?; /// /// Ok(Cow::Owned(format!( /// "{} & import(\"effect\").Brand.Brand<\"{}\">", /// datatype, /// branded.brand() /// ))) /// }); /// # let _ = exporter; /// ``` pub fn branded_type_impl( mut self, builder: impl for<'a> Fn(BrandedTypeExporter<'a>, &Branded) -> Result, Error> + Send + Sync + 'static, ) -> Self { self.branded_type_impl = Some(BrandedTypeImpl(Arc::new(builder))); self } /// Configure a header for the file. /// /// This is perfect for configuring lint ignore rules or other file-level comments. pub fn header(mut self, header: impl Into>) -> Self { self.header = header.into(); self } /// Configure the bindings layout pub fn layout(mut self, layout: Layout) -> Self { self.layout = layout; self } /// Export the files into a single string. /// /// Note: This returns an error if the format is `Format::Files`. pub fn export(&self, types: &Types, format: impl Format) -> Result { fn inner(exporter: Exporter, types: &Types, format: &dyn Format) -> Result { let types = format_types(types, &format)?; let types = types.as_ref(); if let Layout::Files = exporter.layout { return Err(Error::unable_to_export(exporter.layout)); } if let Layout::Namespaces = exporter.layout && exporter.jsdoc { return Err(Error::unable_to_export(exporter.layout)); } let mut out = render_file_header(&exporter)?; let mut has_manually_exported_user_types = false; let mut runtime = Ok(Cow::default()); if let Some(framework_runtime) = &exporter.framework_runtime { runtime = (framework_runtime.0)(FrameworkExporter { exporter: &exporter, format: Some(&format), has_manually_exported_user_types: &mut has_manually_exported_user_types, files_root_types: "", types, }); } let runtime = runtime?; // Framework runtime if !runtime.is_empty() { out += "\n"; } out += &runtime; if !runtime.is_empty() { out += "\n"; } // User types (if not included in framework runtime) if !has_manually_exported_user_types { render_types(&mut out, &exporter, Some(&format), types, "")?; } Ok(out) } inner(self.clone(), types, &format) } /// Export the types to a specific file/folder. /// /// When configured when `format` is `Format::Files`, you must provide a directory path. /// Otherwise, you must provide the path of a single file. /// pub fn export_to( &self, path: impl AsRef, types: &Types, format: impl Format, ) -> Result<(), Error> { fn inner( exporter: Exporter, path: &Path, types: &Types, format: &dyn Format, ) -> Result<(), Error> { let formatted_types = format_types(types, &format)?; let types = formatted_types.as_ref(); if exporter.layout != Layout::Files { let mut result = render_file_header(&exporter)?; let mut has_manually_exported_user_types = false; let mut runtime = Ok(Cow::default()); if let Some(framework_runtime) = &exporter.framework_runtime { runtime = (framework_runtime.0)(FrameworkExporter { exporter: &exporter, format: Some(&format), has_manually_exported_user_types: &mut has_manually_exported_user_types, files_root_types: "", types, }); } let runtime = runtime?; if !runtime.is_empty() { result.push('\n'); result.push_str(&runtime); result.push('\n'); } if !has_manually_exported_user_types { render_types(&mut result, &exporter, Some(&format), types, "")?; } if let Some(parent) = path.parent() { std::fs::create_dir_all(parent)?; }; std::fs::write(path, result)?; return Ok(()); } fn export( exporter: &Exporter, format: Option<&dyn Format>, types: &Types, module: &mut Module, s: &mut String, path: &Path, files: &mut HashMap, ) -> Result { module.types.sort_by(|a, b| { a.name .cmp(&b.name) .then(a.module_path.cmp(&b.module_path)) .then(a.location.cmp(&b.location)) }); let (rendered_types_result, referenced_types) = references::with_module_path(module.module_path.as_ref(), || { references::collect_references(|| { let mut rendered = String::new(); let exports = render_flat_types( &mut rendered, exporter, format, types, module.types.iter().copied(), "", )?; Ok::<_, Error>((rendered, exports)) }) }); let (rendered_types, exports) = rendered_types_result?; let import_paths = referenced_types .into_iter() .map(|r| reference_module_path(types, &r)) .collect::, _>>()? .into_iter() .flatten() .filter(|module_path| module_path != module.module_path.as_ref()) .collect::>(); if !import_paths.is_empty() { s.push('\n'); s.push_str(&module_import_block( exporter, module.module_path.as_ref(), &import_paths, )); } if !import_paths.is_empty() && !rendered_types.is_empty() { s.push('\n'); } s.push_str(&rendered_types); for (name, module) in &mut module.children { // This doesn't account for `NamedDataType::requires_reference` // but we keep it for performance. if module.types.is_empty() && module.children.is_empty() { continue; } let mut path = path.join(name); let mut out = render_file_header(exporter)?; let has_types = export(exporter, format, types, module, &mut out, &path, files)?; if has_types { path.set_extension(if exporter.jsdoc { "js" } else { "ts" }); files.insert(path, out); } } Ok(!exports.is_empty()) } let mut files = HashMap::new(); let mut runtime_path = path.join("index"); runtime_path.set_extension(if exporter.jsdoc { "js" } else { "ts" }); let mut root_types = String::new(); export( &exporter, Some(&format), types, &mut build_module_graph(types), &mut root_types, path, &mut files, )?; { let mut has_manually_exported_user_types = false; let mut runtime = Cow::default(); let mut runtime_references = HashSet::new(); if let Some(framework_runtime) = &exporter.framework_runtime { let (runtime_result, referenced_types) = references::with_module_path("", || { references::collect_references(|| { (framework_runtime.0)(FrameworkExporter { exporter: &exporter, format: Some(&format), has_manually_exported_user_types: &mut has_manually_exported_user_types, files_root_types: &root_types, types, }) }) }); runtime = runtime_result?; runtime_references = referenced_types; } let should_export_user_types = !has_manually_exported_user_types && !root_types.is_empty(); if !runtime.is_empty() || should_export_user_types { files.insert(runtime_path, { let mut out = render_file_header(&exporter)?; let mut body = String::new(); // Framework runtime if !runtime.is_empty() { body.push_str(&runtime); } // User types (if not included in framework runtime) if should_export_user_types { if !body.is_empty() { body.push('\n'); } body.push_str(&root_types); } let import_paths = runtime_references .into_iter() .map(|r| reference_module_path(types, &r)) .collect::, _>>()? .into_iter() .flatten() .filter(|module_path| !module_path.is_empty()) .collect::>(); let import_paths = import_paths .into_iter() .filter(|module_path| { !body.contains(&module_import_statement(&exporter, "", module_path)) }) .collect::>(); if !import_paths.is_empty() { out.push('\n'); out.push_str(&module_import_block(&exporter, "", &import_paths)); } if !body.is_empty() { out.push('\n'); if !import_paths.is_empty() { out.push('\n'); } out.push_str(&body); } out }); } } match path.metadata() { Ok(meta) if !meta.is_dir() => std::fs::remove_file(path).or_else(|source| { if source.kind() == std::io::ErrorKind::NotFound { Ok(()) } else { Err(Error::remove_file(path.to_path_buf(), source)) } })?, Ok(_) => {} Err(err) if err.kind() == std::io::ErrorKind::NotFound => {} Err(source) => { return Err(Error::metadata(path.to_path_buf(), source)); } } for (path, content) in &files { path.parent().map(std::fs::create_dir_all).transpose()?; std::fs::write(path, content)?; } cleanup_stale_files(path, &files, &exporter)?; Ok(()) } inner(self.clone(), path.as_ref(), types, &format) } } fn reference_module_path(types: &Types, r: &NamedReference) -> Result, Error> { match &r.inner { NamedReferenceType::Reference { .. } => { Ok(types.get(r).map(|ndt| ndt.module_path.as_ref().to_string())) } NamedReferenceType::Inline { .. } => Ok(None), NamedReferenceType::Recursive => { Ok(types.get(r).map(|ndt| ndt.module_path.as_ref().to_string())) } } } fn format_types<'a>(types: &'a Types, format: &dyn Format) -> Result, Error> { Ok( match format .map_types(types) .map_err(|err| Error::format("type graph formatter failed", err))? { Cow::Borrowed(_) => Cow::Borrowed(types), Cow::Owned(types) => Cow::Owned(types), }, ) } fn map_datatype_format( format: Option<&dyn Format>, types: &Types, dt: &DataType, ) -> Result { if matches!(dt, DataType::Generic(_)) { return Ok(dt.clone()); } fn contains_generic_reference(dt: &DataType) -> Result { Ok(match dt { DataType::Primitive(_) => false, DataType::List(list) => contains_generic_reference(&list.ty)?, DataType::Map(map) => { contains_generic_reference(map.key_ty())? || contains_generic_reference(map.value_ty())? } DataType::Nullable(inner) => contains_generic_reference(inner)?, DataType::Struct(strct) => match &strct.fields { Fields::Unit => false, Fields::Unnamed(unnamed) => unnamed .fields .iter() .filter_map(|field| field.ty.as_ref()) .try_fold(false, |found, ty| { Ok::<_, Error>(found || contains_generic_reference(ty)?) })?, Fields::Named(named) => named .fields .iter() .filter_map(|(_, field)| field.ty.as_ref()) .try_fold(false, |found, ty| { Ok::<_, Error>(found || contains_generic_reference(ty)?) })?, }, DataType::Enum(enm) => enm.variants.iter().try_fold(false, |found, (_, variant)| { let variant_found = match &variant.fields { Fields::Unit => false, Fields::Unnamed(unnamed) => unnamed .fields .iter() .filter_map(|field| field.ty.as_ref()) .try_fold(false, |found, ty| { Ok::<_, Error>(found || contains_generic_reference(ty)?) })?, Fields::Named(named) => named .fields .iter() .filter_map(|(_, field)| field.ty.as_ref()) .try_fold(false, |found, ty| { Ok::<_, Error>(found || contains_generic_reference(ty)?) })?, }; Ok::<_, Error>(found || variant_found) })?, DataType::Tuple(tuple) => tuple.elements.iter().try_fold(false, |found, ty| { Ok::<_, Error>(found || contains_generic_reference(ty)?) })?, DataType::Reference(Reference::Named(reference)) => match &reference.inner { NamedReferenceType::Reference { generics, .. } => { generics.iter().try_fold(false, |found, (_, dt)| { Ok::<_, Error>(found || contains_generic_reference(dt)?) })? } NamedReferenceType::Inline { .. } => false, NamedReferenceType::Recursive => false, }, DataType::Generic(_) => true, DataType::Reference(Reference::Opaque(_)) => false, DataType::Intersection(types) => types.iter().try_fold(false, |found, ty| { Ok::<_, Error>(found || contains_generic_reference(ty)?) })?, }) } if contains_generic_reference(dt)? { let Some(format) = format else { return map_datatype_format_children(None, types, dt.clone()); }; match format.map_type(types, dt) { Ok(Cow::Borrowed(dt)) => { return map_datatype_format_children(Some(format), types, dt.clone()); } Ok(Cow::Owned(dt)) => return map_datatype_format_children(Some(format), types, dt), Err(err) if err.to_string().contains("Unresolved generic reference") => { return map_datatype_format_children(Some(format), types, dt.clone()); } Err(err) => return Err(Error::format("datatype formatter failed", err)), } } let Some(format) = format else { return Ok(dt.clone()); }; let mapped = format .map_type(types, dt) .map_err(|err| Error::format("datatype formatter failed", err))?; match mapped { Cow::Borrowed(dt) => map_datatype_format_children(Some(format), types, dt.clone()), Cow::Owned(dt) => map_datatype_format_children(Some(format), types, dt), } } fn map_datatype_format_children( format: Option<&dyn Format>, types: &Types, mut dt: DataType, ) -> Result { match &mut dt { DataType::Primitive(_) => {} DataType::List(list) => { *list.ty = map_datatype_format(format, types, &list.ty)?; } DataType::Map(map) => { let key = map_datatype_format(format, types, map.key_ty())?; let value = map_datatype_format(format, types, map.value_ty())?; map.set_key_ty(key); map.set_value_ty(value); } DataType::Nullable(inner) => { **inner = map_datatype_format(format, types, inner)?; } DataType::Struct(strct) => map_datatype_fields(format, types, &mut strct.fields)?, DataType::Enum(enm) => { for (_, variant) in &mut enm.variants { map_datatype_fields(format, types, &mut variant.fields)?; } } DataType::Tuple(tuple) => { for element in &mut tuple.elements { *element = map_datatype_format(format, types, element)?; } } DataType::Intersection(types_) => { for ty in types_ { *ty = map_datatype_format(format, types, ty)?; } } DataType::Reference(Reference::Named(reference)) => { if let NamedReferenceType::Inline { dt, .. } = &mut reference.inner { **dt = map_datatype_format(format, types, dt)?; } for (_, dt) in named_reference_generics_mut(reference) { *dt = map_datatype_format(format, types, dt)?; } } DataType::Generic(_) => {} DataType::Reference(Reference::Opaque(reference)) => { if let Some(branded) = reference.downcast_ref::() { dt = Reference::opaque(Branded::new( branded.brand().clone(), map_datatype_format(format, types, branded.ty())?, )) .into(); } } } Ok(dt) } fn named_reference_generics_mut( reference: &mut NamedReference, ) -> &mut [(specta::datatype::Generic, DataType)] { match &mut reference.inner { NamedReferenceType::Reference { generics, .. } => generics, NamedReferenceType::Inline { .. } | NamedReferenceType::Recursive => &mut [], } } fn map_datatype_fields( format: Option<&dyn Format>, types: &Types, fields: &mut Fields, ) -> Result<(), Error> { match fields { Fields::Unit => {} Fields::Unnamed(unnamed) => { for field in &mut unnamed.fields { if let Some(ty) = field.ty.as_mut() { *ty = map_datatype_format(format, types, ty)?; } } } Fields::Named(named) => { for (_, field) in &mut named.fields { if let Some(ty) = field.ty.as_mut() { *ty = map_datatype_format(format, types, ty)?; } } } } Ok(()) } fn map_named_datatype_format( format: Option<&dyn Format>, types: &Types, ndt: &NamedDataType, ) -> Result { let mut mapped = ndt.clone(); mapped.ty = ndt .ty .clone() .map(|ty| map_datatype_format_children(format, types, ty)) .transpose()?; Ok(mapped) } impl AsRef for Exporter { fn as_ref(&self) -> &Exporter { self } } impl AsMut for Exporter { fn as_mut(&mut self) -> &mut Exporter { self } } /// Reference to Typescript language exporter for branded type callbacks. pub struct BrandedTypeExporter<'a> { pub(crate) exporter: &'a Exporter, pub(crate) format: Option<&'a dyn Format>, /// Collected types currently being exported. pub types: &'a Types, } impl fmt::Debug for BrandedTypeExporter<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.exporter.fmt(f) } } impl AsRef for BrandedTypeExporter<'_> { fn as_ref(&self) -> &Exporter { self } } impl Deref for BrandedTypeExporter<'_> { type Target = Exporter; fn deref(&self) -> &Self::Target { self.exporter } } impl BrandedTypeExporter<'_> { /// [primitives::inline] pub fn inline(&self, dt: &DataType) -> Result { let mapped = map_datatype_format(self.format, self.types, dt)?; primitives::inline(self, self.types, &mapped) } /// [primitives::reference] pub fn reference(&self, r: &Reference) -> Result { let mapped = map_datatype_format(self.format, self.types, &DataType::Reference(r.clone()))?; match mapped { DataType::Reference(reference) => primitives::reference(self, self.types, &reference), dt => primitives::inline(self, self.types, &dt), } } } /// Reference to Typescript language exporter for framework pub struct FrameworkExporter<'a> { exporter: &'a Exporter, format: Option<&'a dyn Format>, has_manually_exported_user_types: &'a mut bool, // For `Layout::Files` we need to inject the value files_root_types: &'a str, /// Collected types currently being exported. pub types: &'a Types, } impl fmt::Debug for FrameworkExporter<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.exporter.fmt(f) } } impl AsRef for FrameworkExporter<'_> { fn as_ref(&self) -> &Exporter { self } } impl Deref for FrameworkExporter<'_> { type Target = Exporter; fn deref(&self) -> &Self::Target { self.exporter } } impl FrameworkExporter<'_> { /// Render the types within the [`Types`](specta::Types). /// /// This will only work if used within [`Exporter::framework_runtime`]. /// It allows frameworks to intersperse their user types into their runtime code. pub fn render_types(&mut self) -> Result, Error> { let mut s = String::new(); render_types( &mut s, self.exporter, self.format, self.types, self.files_root_types, )?; *self.has_manually_exported_user_types = true; Ok(Cow::Owned(s)) } /// [primitives::inline] pub fn inline(&self, dt: &DataType) -> Result { let mapped = map_datatype_format(self.format, self.types, dt)?; primitives::inline(self, self.types, &mapped) } /// [primitives::reference] pub fn reference(&self, r: &Reference) -> Result { let mapped = map_datatype_format(self.format, self.types, &DataType::Reference(r.clone()))?; match mapped { DataType::Reference(reference) => primitives::reference(self, self.types, &reference), dt => primitives::inline(self, self.types, &dt), } } /// [primitives::export] pub fn export<'a>( &self, ndts: impl Iterator, indent: &'a str, ) -> Result { let mapped = ndts .map(|ndt| map_named_datatype_format(self.format, self.types, ndt)) .collect::, _>>()?; primitives::export(self, self.types, mapped.iter(), indent) } } struct Module<'a> { types: Vec<&'a NamedDataType>, children: BTreeMap<&'a str, Module<'a>>, module_path: Cow<'static, str>, } fn build_module_graph(types: &Types) -> Module<'_> { types.into_unsorted_iter().fold( Module { types: Default::default(), children: Default::default(), module_path: Default::default(), }, |mut ns, ndt| { let path = &ndt.module_path; if path.is_empty() { ns.types.push(ndt); } else { let mut current = &mut ns; let mut current_path = String::new(); for segment in path.split("::") { if !current_path.is_empty() { current_path.push_str("::"); } current_path.push_str(segment); current = current.children.entry(segment).or_insert_with(|| Module { types: Default::default(), children: Default::default(), module_path: current_path.clone().into(), }); } current.types.push(ndt); } ns }, ) } fn render_file_header(exporter: &Exporter) -> Result { let mut out = exporter.header.to_string(); if !exporter.header.is_empty() { out += "\n"; } out += &exporter.framework_prelude; if !exporter.framework_prelude.is_empty() { out += "\n"; } Ok(out) } fn render_types( s: &mut String, exporter: &Exporter, format: Option<&dyn Format>, types: &Types, files_user_types: &str, ) -> Result<(), Error> { match exporter.layout { Layout::Namespaces => { fn has_renderable_content(module: &Module<'_>) -> bool { module.types.iter().any(|ndt| ndt.ty.is_some()) || module.children.values().any(has_renderable_content) } fn export<'a>( exporter: &Exporter, format: Option<&dyn Format>, types: &Types, s: &mut String, module: impl ExactSizeIterator)>, depth: usize, ) -> Result<(), Error> { let namespace_indent = "\t".repeat(depth); let content_indent = "\t".repeat(depth + 1); for (name, module) in module { if !has_renderable_content(module) { continue; } s.push('\n'); s.push_str(&namespace_indent); if depth != 0 && *name != "$specta$" { s.push_str("export "); } s.push_str("namespace "); s.push_str(name); s.push_str(" {\n"); // Types module.types.sort_by(|a, b| { a.name .cmp(&b.name) .then(a.module_path.cmp(&b.module_path)) .then(a.location.cmp(&b.location)) }); render_flat_types( s, exporter, format, types, module.types.iter().copied(), &content_indent, )?; // Namespaces export( exporter, format, types, s, module.children.iter_mut(), depth + 1, )?; s.push_str(&namespace_indent); s.push_str("}\n"); } Ok(()) } let mut module = build_module_graph(types); let reexports = { let mut reexports = String::new(); for name in module .children .iter() .filter_map(|(name, module)| has_renderable_content(module).then_some(*name)) .chain( module .types .iter() .filter(|ndt| ndt.ty.is_some()) .map(|ndt| ndt.name.as_ref()), ) { reexports.push_str("export import "); reexports.push_str(name); reexports.push_str(" = $s$."); reexports.push_str(name); reexports.push_str(";\n"); } reexports }; export( exporter, format, types, s, [(&"$s$", &mut module)].into_iter(), 0, )?; s.push_str(&reexports); } Layout::ModulePrefixedName | Layout::FlatFile => { render_flat_types(s, exporter, format, types, types.into_sorted_iter(), "")?; } // The types will get their own files // So we keep the user types empty for easy downstream detection. Layout::Files => { if !files_user_types.is_empty() { s.push_str(files_user_types); } } } Ok(()) } // Implementation of `Layout::ModulePrefixedName | Layout::FlatFile`, // but is used by `Layout::Namespace` and `Layout::Files` fn render_flat_types<'a>( s: &mut String, exporter: &Exporter, format: Option<&dyn Format>, types: &Types, ndts: impl ExactSizeIterator, indent: &str, ) -> Result>, Error> { let mut exports = HashMap::with_capacity(ndts.len()); let ndts = ndts .filter(|ndt| ndt.ty.is_some()) .map(|ndt| { let export_name = exported_type_name(exporter, ndt); if let Some(other) = exports.insert(export_name.to_string(), ndt.location) { return Err(Error::duplicate_type_name(export_name, ndt.location, other)); } Ok(ndt) }) .collect::, _>>()?; primitives::export_internal(s, exporter, format, types, ndts.into_iter(), indent)?; Ok(exports) } /// Collect all TypeScript/JavaScript files in a directory recursively fn collect_existing_files(root: &Path) -> Result, Error> { if !root.exists() { return Ok(HashSet::new()); } let mut files = HashSet::new(); let entries = std::fs::read_dir(root).map_err(|source| Error::read_dir(root.to_path_buf(), source))?; for entry in entries { let entry = entry.map_err(|source| Error::read_dir(root.to_path_buf(), source))?; let path = entry.path(); let file_type = entry .file_type() .map_err(|source| Error::metadata(path.clone(), source))?; if file_type.is_symlink() { continue; } if file_type.is_dir() { files.extend(collect_existing_files(&path)?); } else if matches!(path.extension().and_then(|e| e.to_str()), Some("ts" | "js")) { files.insert(path); } } Ok(files) } fn is_generated_specta_file(path: &Path, exporter: &Exporter) -> Result { match std::fs::read_to_string(path) { Ok(contents) => Ok((!exporter.framework_prelude.is_empty() && contents.contains(exporter.framework_prelude.as_ref())) || contents.contains("generated by Specta")), Err(err) if err.kind() == std::io::ErrorKind::InvalidData => Ok(false), Err(source) => Err(Error::from(source)), } } /// Remove empty directories recursively, stopping at the root fn remove_empty_dirs(path: &Path, root: &Path) -> Result<(), Error> { let entries = std::fs::read_dir(path).map_err(|source| Error::read_dir(path.to_path_buf(), source))?; for entry in entries { let entry = entry.map_err(|source| Error::read_dir(path.to_path_buf(), source))?; let entry_path = entry.path(); let file_type = entry .file_type() .map_err(|source| Error::metadata(entry_path.clone(), source))?; if file_type.is_symlink() { continue; } if file_type.is_dir() { remove_empty_dirs(&entry_path, root)?; } } let is_empty = path .read_dir() .map_err(|source| Error::read_dir(path.to_path_buf(), source))? .next() .is_none(); if path != root && is_empty { match std::fs::remove_dir(path) { Ok(()) => {} Err(err) if err.kind() == std::io::ErrorKind::NotFound => {} Err(source) => { return Err(Error::remove_dir(path.to_path_buf(), source)); } } } Ok(()) } /// Delete stale files and clean up empty directories fn cleanup_stale_files( root: &Path, current_files: &HashMap, exporter: &Exporter, ) -> Result<(), Error> { for path in collect_existing_files(root)? { if current_files.contains_key(&path) || !is_generated_specta_file(&path, exporter)? { continue; } std::fs::remove_file(&path).or_else(|source| { if source.kind() == std::io::ErrorKind::NotFound { Ok(()) } else { Err(Error::remove_file(path.clone(), source)) } })?; } remove_empty_dirs(root, root)?; Ok(()) } fn exported_type_name(exporter: &Exporter, ndt: &NamedDataType) -> Cow<'static, str> { match exporter.layout { Layout::ModulePrefixedName => { let mut s = ndt.module_path.split("::").collect::>().join("_"); s.push('_'); s.push_str(&ndt.name); Cow::Owned(s) } _ => ndt.name.clone(), } } pub(crate) fn module_alias(module_path: &str) -> String { if module_path.is_empty() { "$root".to_string() } else { module_path.split("::").collect::>().join("$") } } fn module_import_statement( exporter: &Exporter, from_module_path: &str, to_module_path: &str, ) -> String { let import_keyword = if exporter.jsdoc { "import" } else { "import type" }; format!( "{} * as {} from \"{}\";", import_keyword, module_alias(to_module_path), module_import_path(from_module_path, to_module_path) ) } fn module_import_block( exporter: &Exporter, from_module_path: &str, import_paths: &BTreeSet, ) -> String { if exporter.jsdoc { let mut out = String::from("/**\n"); for module_path in import_paths { out.push_str(" * @typedef {import(\""); out.push_str(&module_import_path(from_module_path, module_path)); out.push_str("\")} "); out.push_str(&module_alias(module_path)); out.push('\n'); } out.push_str(" */"); out } else { import_paths .iter() .map(|module_path| module_import_statement(exporter, from_module_path, module_path)) .collect::>() .join("\n") } } fn module_import_path(from_module_path: &str, to_module_path: &str) -> String { fn module_file_segments(module_path: &str) -> Vec<&str> { if module_path.is_empty() { vec!["index"] } else { module_path.split("::").collect() } } let from_file_segments = module_file_segments(from_module_path); let from_dir_segments = &from_file_segments[..from_file_segments.len() - 1]; let to_file_segments = module_file_segments(to_module_path); let shared = from_dir_segments .iter() .zip(to_file_segments.iter()) .take_while(|(a, b)| a == b) .count(); let mut relative_parts = Vec::new(); relative_parts.extend(std::iter::repeat_n( "..", from_dir_segments.len().saturating_sub(shared), )); relative_parts.extend(to_file_segments.iter().skip(shared).copied()); if relative_parts .first() .is_none_or(|v| *v != "." && *v != "..") { relative_parts.insert(0, "."); } relative_parts.join("/") } ================================================ FILE: specta-typescript/src/jsdoc.rs ================================================ use std::{borrow::Cow, path::Path}; use specta::{Format, Types}; use crate::{Branded, BrandedTypeExporter, Error, Exporter, Layout}; /// JSDoc language exporter. #[derive(Debug, Clone)] #[non_exhaustive] pub struct JSDoc(Exporter); impl Default for JSDoc { fn default() -> Self { let mut exporter = Exporter::default(); exporter.jsdoc = true; exporter.into() } } impl From for Exporter { fn from(value: JSDoc) -> Self { value.0 } } impl From for JSDoc { fn from(mut value: Exporter) -> Self { value.jsdoc = true; Self(value) } } impl JSDoc { /// Construct a new JSDoc exporter with the default options configured. pub fn new() -> Self { Default::default() } /// Configure a header for the file. /// /// This is perfect for configuring lint ignore rules or other file-level comments. pub fn header(self, header: impl Into>) -> Self { Self(self.0.header(header)) } /// Configure the layout of the generated file pub fn layout(self, layout: Layout) -> Self { Self(self.0.layout(layout)) } /// Configure how `specta_typescript::branded!` types are rendered. /// /// See [`Exporter::branded_type_impl`] for details. pub fn branded_type_impl( self, builder: impl for<'a> Fn(BrandedTypeExporter<'a>, &Branded) -> Result, Error> + Send + Sync + 'static, ) -> Self { Self(self.0.branded_type_impl(builder)) } /// Export the files into a single string. /// /// Note: This returns an error if the format is `Format::Files`. pub fn export(&self, types: &Types, format: impl Format) -> Result { self.0.export(types, format) } /// Export the types to a specific file/folder. /// /// When configured when `format` is `Format::Files`, you must provide a directory path. /// Otherwise, you must provide the path of a single file. /// pub fn export_to( &self, path: impl AsRef, types: &Types, format: impl Format, ) -> Result<(), Error> { self.0.export_to(path, types, format) } } impl AsRef for JSDoc { fn as_ref(&self) -> &Exporter { &self.0 } } impl AsMut for JSDoc { fn as_mut(&mut self) -> &mut Exporter { &mut self.0 } } ================================================ FILE: specta-typescript/src/legacy.rs ================================================ // TODO: Drop this stuff use std::{ borrow::Cow, collections::BTreeSet, fmt::{self, Write}, }; use specta::{ Types, datatype::{ DataType, Deprecated, Enum, Field, Fields, GenericReference, NamedReferenceType, Reference, Struct, Tuple, Variant, }, }; use crate::{Error, Exporter, reserved_names::RESERVED_TYPE_NAMES}; #[derive(Clone, Debug)] pub(crate) enum PathItem { // Type(Cow<'static, str>), // TypeExtended(Cow<'static, str>, &'static str), Field(Cow<'static, str>), Variant(Cow<'static, str>), } #[derive(Clone)] pub(crate) struct ExportContext<'a> { pub(crate) cfg: &'a Exporter, pub(crate) path: Vec, } impl ExportContext<'_> { pub(crate) fn with(&self, item: PathItem) -> Self { Self { path: self.path.iter().cloned().chain([item]).collect(), ..*self } } pub(crate) fn export_path(&self) -> ExportPath { ExportPath::new(&self.path) } } /// Represents the path of an error in the export tree. /// This is designed to be opaque, meaning it's internal format and `Display` impl are subject to change at will. pub struct ExportPath(String); impl ExportPath { pub(crate) fn new(path: &[PathItem]) -> Self { let mut s = String::new(); let mut path = path.iter().peekable(); while let Some(item) = path.next() { s.push_str(match item { // PathItem::Type(v) => v, // PathItem::TypeExtended(_, loc) => loc, PathItem::Field(v) => v, PathItem::Variant(v) => v, }); if let Some(next) = path.peek() { s.push_str(match next { // PathItem::Type(_) => " -> ", // PathItem::TypeExtended(_, _) => " -> ", PathItem::Field(_) => ".", PathItem::Variant(_) => "::", }); } else { break; } } Self(s) } } impl PartialEq for ExportPath { fn eq(&self, other: &Self) -> bool { self.0 == other.0 } } impl fmt::Debug for ExportPath { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(&self.0) } } impl fmt::Display for ExportPath { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.0) } } #[allow(missing_docs)] pub(crate) type Result = std::result::Result; pub(crate) type Output = Result; #[allow(clippy::ptr_arg)] fn inner_comments( deprecated: Option<&Deprecated>, docs: &str, other: String, start_with_newline: bool, prefix: &str, ) -> String { let mut comments = String::new(); js_doc(&mut comments, docs, deprecated); if comments.is_empty() { return other; } let mut out = String::new(); if start_with_newline { out.push('\n'); } for line in comments.lines() { out.push_str(prefix); out.push_str(line); out.push('\n'); } out.push_str(&other); out } pub(crate) fn datatype_inner( ctx: ExportContext, typ: &DataType, types: &Types, s: &mut String, generics: &[(GenericReference, DataType)], ) -> Result<()> { crate::primitives::datatype(s, ctx.cfg, None, types, typ, vec![], None, "", generics) } // Can be used with `StructUnnamedFields.fields` or `EnumNamedFields.fields` fn unnamed_fields_datatype( ctx: ExportContext, fields: &[(&Field, &DataType)], types: &Types, s: &mut String, prefix: &str, generics: &[(GenericReference, DataType)], force_inline: bool, ) -> Result<()> { match fields { [(field, ty)] => { let mut v = String::new(); crate::primitives::datatype_with_inline_attr( &mut v, ctx.cfg, None, types, ty, vec![], None, "", generics, force_inline, )?; s.push_str(&inner_comments( field.deprecated.as_ref(), &field.docs, v, true, prefix, )); } fields => { s.push('['); for (i, (field, ty)) in fields.iter().enumerate() { if i != 0 { s.push_str(", "); } let mut v = String::new(); crate::primitives::datatype_with_inline_attr( &mut v, ctx.cfg, None, types, ty, vec![], None, "", generics, force_inline, )?; s.push_str(&inner_comments( field.deprecated.as_ref(), &field.docs, v, true, prefix, )); } s.push(']'); } } Ok(()) } pub(crate) fn tuple_datatype( ctx: ExportContext, tuple: &Tuple, types: &Types, generics: &[(GenericReference, DataType)], ) -> Output { match tuple.elements.as_slice() { [] => Ok(NULL.to_string()), tys => Ok(format!( "[{}]", tys.iter() .map(|v| { let mut s = String::new(); datatype_inner(ctx.clone(), v, types, &mut s, generics).map(|_| s) }) .collect::>>()? .join(", ") )), } } pub(crate) fn struct_datatype( ctx: ExportContext, strct: &Struct, types: &Types, s: &mut String, prefix: &str, generics: &[(GenericReference, DataType)], ) -> Result<()> { match &strct.fields { Fields::Unit => s.push_str(NULL), Fields::Unnamed(unnamed) => unnamed_fields_datatype( ctx, &unnamed .fields .iter() .filter_map(|field| field.ty.as_ref().map(|ty| (field, ty))) .collect::>(), types, s, prefix, generics, false, )?, Fields::Named(named) => { let fields = named .fields .iter() .filter_map(|(name, field)| field.ty.as_ref().map(|ty| (name, (field, ty)))) .collect::>(); if fields.is_empty() { // TODO: Handle this // match (named.tag().as_ref(), parent_name) { // (Some(tag), Some(key)) => write!(s, r#"{{ "{tag}": "{key}" }}"#)?, // (_, _) => write!(s, "Record<{STRING}, {NEVER}>")?, // } write!(s, "Record<{STRING}, {NEVER}>")?; return Ok(()); } let flattened: Vec<(&Cow<'static, str>, (&Field, &DataType))> = Vec::new(); let non_flattened = fields.clone(); let mut flattened_sections = flattened .into_iter() .map(|(_key, (field, ty))| { let mut s = String::new(); crate::primitives::datatype_with_inline_attr( &mut s, ctx.cfg, None, types, ty, vec![], None, "", generics, false, ) .map(|_| { inner_comments( field.deprecated.as_ref(), &field.docs, format!("({s})"), true, prefix, ) }) }) .collect::>>()?; let unflattened_fields = non_flattened .into_iter() .map(|(key, field_ref)| { let (field, ty) = field_ref; let field_prefix = format!("{prefix}\t"); let mut other = String::new(); object_field_to_ts( ctx.with(PathItem::Field(key.clone())), key.clone(), (field, ty), types, &mut other, generics, &field_prefix, false, None, )?; let docs = field .docs .trim() .is_empty() .then(|| inline_reference_docs(types, (field, ty), false)) .flatten() .unwrap_or(&field.docs); Ok(inner_comments( field.deprecated.as_ref(), docs, other, false, &field_prefix, )) }) .collect::>>()?; // TODO: Handle this // if let (Some(tag), Some(key)) = (&named.tag(), parent_name) { // unflattened_fields.push(format!("{tag}: \"{key}\"")); // } if !unflattened_fields.is_empty() { let mut s = "{".to_string(); for field in unflattened_fields { s.push('\n'); s.push_str(&field); s.push(','); } s.push('\n'); s.push_str(prefix); s.push('}'); flattened_sections.insert(0, s); } // Remove duplicates while preserving source order. let mut seen = BTreeSet::new(); flattened_sections.retain(|section| seen.insert(section.clone())); s.push_str(&flattened_sections.join(" & ")); } } Ok(()) } fn enum_variant_datatype( ctx: ExportContext, types: &Types, name: Cow<'static, str>, variant: &Variant, prefix: &str, generics: &[(GenericReference, DataType)], ty_override: Option>, ) -> Result> { match &variant.fields { Fields::Unit if name.is_empty() => Err(Error::invalid_name_legacy( ctx.export_path(), "anonymous unit enum variants cannot be exported to Typescript".to_string(), )), Fields::Unit => Ok(Some(sanitise_key(name, true).to_string())), Fields::Named(_) if name.is_empty() => Err(Error::invalid_name_legacy( ctx.export_path(), "anonymous named-field enum variants cannot be exported to Typescript".to_string(), )), Fields::Named(obj) => { let all_fields = obj .fields .iter() .filter_map(|(name, field)| field.ty.as_ref().map(|ty| (name, (field, ty)))) .collect::>(); let flattened: Vec<(&Cow<'static, str>, (&Field, &DataType))> = Vec::new(); let non_flattened = all_fields.clone(); let field_sections = flattened .into_iter() .map(|(_key, (field, ty))| { let mut s = String::new(); crate::primitives::datatype_with_inline_attr( &mut s, ctx.cfg, None, types, ty, vec![], None, "", generics, false, ) .map(|_| { inner_comments( field.deprecated.as_ref(), &field.docs, format!("({s})"), true, prefix, ) }) }) .collect::>>()?; let mut regular_fields = vec![]; // TODO // let mut regular_fields = if let Some(tag) = &obj.tag() { // let sanitised_name = sanitise_key(name, true); // vec![format!("{tag}: {sanitised_name}")] // } else { // vec![] // }; regular_fields.extend( non_flattened .into_iter() .map(|(name, field_ref)| { let (field, ty) = field_ref; let mut other = String::new(); object_field_to_ts( ctx.with(PathItem::Field(name.clone())), name.clone(), (field, ty), types, &mut other, generics, "", false, ty_override .as_ref() .filter(|override_ty| override_ty.key == name.as_ref()) .map(|override_ty| override_ty.ty), )?; let docs = field .docs .trim() .is_empty() .then(|| inline_reference_docs(types, (field, ty), false)) .flatten() .unwrap_or(&field.docs); Ok(inner_comments( field.deprecated.as_ref(), docs, other, true, prefix, )) }) .collect::>>()?, ); Ok(Some(match (&field_sections[..], ®ular_fields[..]) { ([], []) => format!("Record<{STRING}, {NEVER}>").to_string(), ([], fields) => format!("{{ {} }}", fields.join("; ")), (_, []) => field_sections.join(" & "), (_, _) => { let mut sections = vec![format!("{{ {} }}", regular_fields.join("; "))]; sections.extend(field_sections); sections.join(" & ") } })) } Fields::Unnamed(obj) => { let fields = obj .fields .iter() .filter_map(|field| field.ty.as_ref()) .map(|ty| { let mut s = String::new(); crate::primitives::datatype_with_inline_attr( &mut s, ctx.cfg, None, types, ty, vec![], None, "", generics, false, ) .map(|_| s) }) .collect::>>()?; Ok(match &fields[..] { [] => { // If the actual length is 0, we know `#[serde(skip)]` was not used. if obj.fields.is_empty() { Some("[]".to_string()) } else { // We wanna render `{tag}` not `{tag}: {type}` (where `{type}` is what this function returns) None } } // If the actual length is 1, we know `#[serde(skip)]` was not used. [field] if obj.fields.len() == 1 => Some(field.to_string()), fields => Some(format!("[{}]", fields.join(", "))), }) } } } struct EnumVariantOutput { value: String, strict_keys: Option>, } #[derive(Debug, Clone)] struct DiscriminatorAnalysis { key: String, known_literals: Vec, fallback_variant_idx: Option, } #[derive(Debug, Clone, Copy)] struct VariantTypeOverride<'a> { key: &'a str, ty: &'a str, } #[derive(Debug, Clone)] enum DiscriminatorValue { StringLiteral(String), String, } fn analyze_discriminator( variants: &[&(Cow<'static, str>, Variant)], ) -> Option { if variants.iter().any(|(name, _)| name.is_empty()) { return None; } let mut key = None::; let mut known_literals = BTreeSet::new(); let mut fallback_variant_idx = None; for (idx, (_, variant)) in variants.iter().enumerate() { let (variant_key, value) = variant_discriminator(variant)?; if let Some(expected) = &key { if expected != &variant_key { return None; } } else { key = Some(variant_key.clone()); } match value { DiscriminatorValue::StringLiteral(value) => { known_literals.insert(value); } DiscriminatorValue::String => { if fallback_variant_idx.replace(idx).is_some() { return None; } } } } if known_literals.is_empty() { return None; } Some(DiscriminatorAnalysis { key: key.expect("at least one variant when called"), known_literals: known_literals.into_iter().collect(), fallback_variant_idx, }) } fn variant_discriminator(variant: &Variant) -> Option<(String, DiscriminatorValue)> { let Fields::Named(named) = &variant.fields else { return None; }; let (name, field) = named.fields.iter().find(|(_, field)| !field.optional)?; let ty = field.ty.as_ref()?; if matches!(ty, DataType::Primitive(specta::datatype::Primitive::str)) { return Some((name.to_string(), DiscriminatorValue::String)); } string_literal_datatype_value(ty) .map(|value| (name.to_string(), DiscriminatorValue::StringLiteral(value))) } fn string_literal_datatype_value(ty: &DataType) -> Option { let DataType::Enum(enm) = ty else { return None; }; let mut variants = enm.variants.iter(); let (name, variant) = variants.next()?; if variants.next().is_some() { return None; } if !matches!(&variant.fields, Fields::Unit) { return None; } Some(name.to_string()) } fn exclude_known_literals_type(literals: &[String]) -> Option { if literals.is_empty() { return None; } let known = literals .iter() .map(|value| format!("\"{}\"", escape_typescript_string_literal(value.as_str()))) .collect::>() .join(" | "); Some(format!("Exclude")) } fn untagged_strict_keys(variant: &Variant) -> Option> { match &variant.fields { Fields::Named(obj) => { let all_fields = obj .fields .iter() .filter_map(|(name, field)| field.ty.as_ref().map(|ty| (name, (field, ty)))) .collect::>(); Some( all_fields .into_iter() .map(|(name, _)| sanitise_key(name.clone(), false).to_string()) .collect(), ) } _ => None, } } fn has_anonymous_variant(variants: &[&(Cow<'static, str>, Variant)]) -> bool { variants.iter().any(|(name, _)| name.is_empty()) } fn strictify_enum_variants(variants: &mut [EnumVariantOutput]) { let strict_key_universe = variants .iter() .filter_map(|variant| variant.strict_keys.as_ref()) .flat_map(|keys| keys.iter().cloned()) .collect::>(); if strict_key_universe.len() < 2 { return; } for variant in variants { let Some(keys) = variant.strict_keys.as_ref() else { continue; }; let missing_keys = strict_key_universe .iter() .filter(|key| !keys.contains(*key)) .map(|key| format!("{key}?: {NEVER}")) .collect::>(); if missing_keys.is_empty() { continue; } variant.value = format!("({}) & {{ {} }}", variant.value, missing_keys.join("; ")); } } pub(crate) fn enum_datatype( ctx: ExportContext, e: &Enum, types: &Types, s: &mut String, prefix: &str, generics: &[(GenericReference, DataType)], ) -> Result<()> { if e.variants.is_empty() { return Ok(write!(s, "{NEVER}")?); } let filtered_variants = e .variants .iter() .filter(|(_, variant)| !variant.skip) .collect::>(); let discriminator = analyze_discriminator(&filtered_variants); let fallback_override = discriminator.as_ref().and_then(|discriminator| { discriminator.fallback_variant_idx.and_then(|idx| { exclude_known_literals_type(&discriminator.known_literals) .map(|ty| (idx, discriminator.key.as_str(), ty)) }) }); let mut rendered_variants = Vec::with_capacity(filtered_variants.len()); for (idx, (variant_name, variant)) in filtered_variants.iter().enumerate() { let variant_override = fallback_override .as_ref() .and_then(|(fallback_idx, key, ty)| { if *fallback_idx == idx { Some(VariantTypeOverride { key, ty: ty.as_str(), }) } else { None } }); let ts_values = enum_variant_datatype( ctx.with(PathItem::Variant(variant_name.clone())), types, variant_name.clone(), variant, prefix, generics, variant_override, )?; rendered_variants.push(EnumVariantOutput { value: ts_values.unwrap_or_else(|| NEVER.to_string()), strict_keys: untagged_strict_keys(variant), }); } if discriminator.is_none() && !has_anonymous_variant(&filtered_variants) { strictify_enum_variants(&mut rendered_variants); } let mut variants = filtered_variants .into_iter() .zip(rendered_variants) .map(|((_, variant), rendered)| { inner_comments( variant.deprecated.as_ref(), &variant.docs, rendered.value, true, prefix, ) }) .collect::>(); let mut seen = BTreeSet::new(); variants.retain(|variant| seen.insert(variant.clone())); // If all variants are skipped, the enum has no valid values if variants.is_empty() { s.push_str(NEVER); } else { s.push_str(&variants.join(" | ")); } Ok(()) } /// convert an object field into a Typescript string fn object_field_to_ts( ctx: ExportContext, key: Cow<'static, str>, field_ref: (&Field, &DataType), types: &Types, s: &mut String, generics: &[(GenericReference, DataType)], prefix: &str, force_inline: bool, ty_override: Option<&str>, ) -> Result<()> { let (field, ty) = field_ref; let field_name_safe = sanitise_key(key, false); // https://github.com/specta-rs/rspc/issues/100#issuecomment-1373092211 let (key, ty) = match field.optional { true => (format!("{field_name_safe}?").into(), ty), false => (field_name_safe, ty), }; let value = match ty_override { Some(ty_override) => ty_override.to_string(), None => { let mut value = String::new(); crate::primitives::datatype_with_inline_attr( &mut value, ctx.cfg, None, types, ty, vec![], None, prefix, generics, force_inline, )?; value } }; Ok(write!(s, "{prefix}{key}: {value}",)?) } fn inline_reference_docs<'a>( types: &'a Types, (_field, ty): (&Field, &'a DataType), force_inline: bool, ) -> Option<&'a str> { let DataType::Reference(Reference::Named(r)) = ty else { return None; }; if !force_inline { return None; } match &r.inner { NamedReferenceType::Reference { .. } => types .get(r) .filter(|ndt| !ndt.docs.trim().is_empty()) .map(|ndt| ndt.docs.as_ref()), NamedReferenceType::Inline { .. } | NamedReferenceType::Recursive => None, } } /// sanitise a string to be a valid Typescript key fn sanitise_key<'a>(field_name: Cow<'static, str>, force_string: bool) -> Cow<'a, str> { let valid = is_identifier(&field_name); if force_string || !valid { format!(r#""{}""#, escape_typescript_string_literal(&field_name)).into() } else { field_name } } pub(crate) fn is_identifier(name: &str) -> bool { let mut chars = name.chars(); let Some(first) = chars.next() else { return false; }; (first.is_ascii_alphabetic() || first == '_' || first == '$') && chars.all(|ch| ch.is_ascii_alphanumeric() || ch == '_' || ch == '$') } pub(crate) fn escape_typescript_string_literal(value: &str) -> Cow<'_, str> { if !value.chars().any(|ch| { ch == '"' || ch == '\\' || ch == '\u{2028}' || ch == '\u{2029}' || ch.is_control() }) { return Cow::Borrowed(value); } let mut escaped = String::with_capacity(value.len()); for ch in value.chars() { match ch { '"' => escaped.push_str(r#"\""#), '\\' => escaped.push_str(r#"\\"#), '\n' => escaped.push_str(r#"\n"#), '\r' => escaped.push_str(r#"\r"#), '\t' => escaped.push_str(r#"\t"#), '\u{2028}' => escaped.push_str(r#"\u2028"#), '\u{2029}' => escaped.push_str(r#"\u2029"#), ch if ch.is_control() => { write!(escaped, r#"\u{:04X}"#, ch as u32).expect("infallible"); } _ => escaped.push(ch), } } Cow::Owned(escaped) } pub(crate) fn sanitise_type_name(ctx: ExportContext, ident: &str) -> Output { if let Some(name) = RESERVED_TYPE_NAMES.iter().find(|v| **v == ident) { return Err(Error::forbidden_name_legacy(ctx.export_path(), name)); } if let Some(first_char) = ident.chars().next() && !first_char.is_alphabetic() && first_char != '_' { return Err(Error::invalid_name_legacy( ctx.export_path(), ident.to_string(), )); } if ident .find(|c: char| !c.is_alphanumeric() && c != '_') .is_some() { return Err(Error::invalid_name_legacy( ctx.export_path(), ident.to_string(), )); } Ok(ident.to_string()) } const STRING: &str = "string"; const NULL: &str = "null"; const NEVER: &str = "never"; // TODO: Merge this into main expoerter pub(crate) fn js_doc(s: &mut String, docs: &str, deprecated: Option<&Deprecated>) { // Early return - no-op if nothing to document if docs.is_empty() && deprecated.is_none() { return; } if deprecated.is_none() { let mut lines = docs.lines(); if let (Some(line), None) = (lines.next(), lines.next()) { s.push_str("/** "); s.push_str(&escape_jsdoc_text(line)); s.push_str(" */\n"); return; } } // Start JSDoc comment s.push_str("/**\n"); // Add documentation lines if !docs.is_empty() { for line in docs.lines() { s.push_str(" * "); s.push_str(&escape_jsdoc_text(line)); s.push('\n'); } } // Add @deprecated tag if present if let Some(typ) = deprecated { s.push_str(" * @deprecated"); if let Some(details) = deprecated_details(typ) { s.push(' '); s.push_str(&details); } s.push('\n'); } // Close JSDoc comment s.push_str(" */\n"); } pub(crate) fn escape_jsdoc_text(text: &str) -> Cow<'_, str> { if text.contains("*/") { Cow::Owned(text.replace("*/", "*\\/")) } else { Cow::Borrowed(text) } } pub(crate) fn deprecated_details(typ: &Deprecated) -> Option { let note = typ.note.as_deref().map(str::trim).filter(|v| !v.is_empty()); let since: Option<&str> = None; match (note, since) { (Some(note), Some(since)) => Some(format!("{note} since {since}")), (Some(note), None) => Some(note.to_string()), (None, Some(since)) => Some(format!("since {since}")), (None, None) => None, } } // pub fn typedef_named_datatype( // cfg: &Typescript, // typ: &NamedDataType, // types: &Types, // ) -> Output { // typedef_named_datatype_inner( // &ExportContext { // cfg, // path: vec![], // }, // typ, // types, // ) // } // fn typedef_named_datatype_inner( // ctx: &ExportContext, // typ: &NamedDataType, // types: &Types, // ) -> Output { // let name = typ.name(); // let docs = typ.docs(); // let deprecated = typ.deprecated(); // let item = typ.ty(); // let ctx = ctx.with(PathItem::Type(name.clone())); // let name = sanitise_type_name(ctx.clone(), name)?; // let mut inline_ts = String::new(); // datatype_inner( // ctx.clone(), // &FunctionReturnType::Value(typ.ty().clone()), // types, // &mut inline_ts, // )?; // let mut builder = js_doc_builder(docs, deprecated); // typ.generics()() // .into_iter() // .for_each(|generic| builder.push_generic(generic)); // builder.push_internal(["@typedef { ", &inline_ts, " } ", &name]); // Ok(builder.build()) // } ================================================ FILE: specta-typescript/src/lib.rs ================================================ //! [TypeScript](https://www.typescriptlang.org) language exporter. //! //! # Usage //! //! Add `specta`, `specta-serde`, and `specta-typescript` to your project: //! //! ```bash //! cargo add specta@2.0.0-rc.24 --features derive,collect //! cargo add specta-serde@0.0.11 //! cargo add specta-typescript@0.0.11 //! ``` //! //! Next copy the following into your `main.rs` file: //! //! ```rust //! use specta::{Type, Types}; //! use specta_typescript::Typescript; //! //! #[derive(Type)] //! pub struct MyType { //! pub field: MyOtherType, //! } //! //! //! #[derive(Type)] //! pub struct MyOtherType { //! pub other_field: String, //! } //! //! let mut types = Types::default() //! // We don't need to specify `MyOtherType` because it's referenced by `MyType` //! .register::(); //! Typescript::default() //! .export_to( //! "./bindings.ts", //! &types, //! specta_serde::Format, //! ) //! .unwrap(); //! ``` //! //! Now your setup with Specta! //! //! If you get tired of listing all your types manually? Checkout `specta::collect`! //! #![cfg_attr(docsrs, feature(doc_cfg))] #![doc( html_logo_url = "https://github.com/specta-rs/specta/raw/main/.github/logo-128.png", html_favicon_url = "https://github.com/specta-rs/specta/raw/main/.github/logo-128.png" )] mod branded; mod error; mod exporter; mod jsdoc; mod legacy; // TODO: Remove this mod map_keys; mod opaque; pub mod primitives; mod references; pub(crate) mod reserved_names; mod types; mod typescript; pub use branded::Branded; pub use error::Error; pub use exporter::{BrandedTypeExporter, Exporter, FrameworkExporter, Layout}; pub use jsdoc::JSDoc; pub use opaque::define; pub use references::collect_references; pub use types::{Any, Never, Number, Unknown}; pub use typescript::Typescript; ================================================ FILE: specta-typescript/src/map_keys.rs ================================================ use std::collections::HashSet; use specta::{ Types, datatype::{DataType, Fields, Generic, NamedReferenceType, Primitive, Reference}, }; use crate::Error; pub(crate) fn validate_map_key( key_ty: &DataType, types: &Types, path: String, ) -> Result<(), Error> { validate_map_key_inner(key_ty, types, path, &mut HashSet::new()) } fn validate_map_key_inner( key_ty: &DataType, types: &Types, path: String, visiting_named_refs: &mut HashSet, ) -> Result<(), Error> { fn unwrap_synthetic_variant_fields<'a>( variant_name: &str, fields: &'a Fields, ) -> Option<&'a Fields> { let Fields::Named(named) = fields else { return None; }; let mut live_fields = named .fields .iter() .filter_map(|(name, field)| field.ty.as_ref().map(|ty| (name.as_ref(), ty))); let (field_name, DataType::Enum(inner)) = live_fields.next()? else { return None; }; if field_name != variant_name || live_fields.next().is_some() { return None; } match inner.variants.as_slice() { [(inner_name, inner_variant)] if inner_name == variant_name => { Some(&inner_variant.fields) } _ => None, } } match key_ty { DataType::Primitive(primitive) if primitive_is_valid_key(primitive.clone()) => Ok(()), DataType::Primitive(other) => Err(Error::invalid_map_key( path, invalid_primitive_reason(other.clone()), )), DataType::Enum(enm) => { for (variant_name, variant) in &enm.variants { let fields = unwrap_synthetic_variant_fields(variant_name, &variant.fields) .unwrap_or(&variant.fields); match fields { Fields::Unit => {} Fields::Unnamed(unnamed) => { let non_skipped = unnamed .fields .iter() .filter_map(|field| field.ty.as_ref()) .count(); if non_skipped != 1 { return Err(Error::invalid_map_key( &path, format!( "enum key variant '{variant_name}' must serialize as a newtype value" ), )); } } Fields::Named(_) => { return Err(Error::invalid_map_key( &path, format!( "enum key variant '{variant_name}' serializes as a struct variant, which serde_json rejects" ), )); } } } Ok(()) } DataType::Struct(strct) => { let Fields::Unnamed(unnamed) = &strct.fields else { return Err(Error::invalid_map_key( path, "struct keys must serialize as a newtype struct to be valid serde_json map keys", )); }; let mut non_skipped = unnamed.fields.iter().filter_map(|field| field.ty.as_ref()); let Some(inner_ty) = non_skipped.next() else { return Err(Error::invalid_map_key( path, "newtype struct map keys must have exactly one serializable field", )); }; if non_skipped.next().is_some() { return Err(Error::invalid_map_key( path, "newtype struct map keys must have exactly one serializable field", )); } validate_map_key_inner(inner_ty, types, path, visiting_named_refs) } DataType::Reference(Reference::Named(reference)) => { let reference_key = Reference::Named(reference.clone()); if !visiting_named_refs.insert(reference_key.clone()) { return Err(Error::invalid_map_key( path, "recursive map key reference cycle detected", )); } let result = match &reference.inner { NamedReferenceType::Reference { generics, .. } => { if let Some(ndt) = types.get(reference) { if let Some(ty) = ndt.ty.as_ref() { let mut ty = ty.clone(); substitute_generics(&mut ty, generics); validate_map_key_inner(&ty, types, path, visiting_named_refs) } else { Err(Error::invalid_map_key( path, format!("unresolved named map key reference {reference:?}"), )) } } else { Err(Error::invalid_map_key( path, format!("unresolved named map key reference {reference:?}"), )) } } NamedReferenceType::Inline { dt, .. } => { validate_map_key_inner(dt, types, path, visiting_named_refs) } NamedReferenceType::Recursive => Err(Error::invalid_map_key( path, format!("recursive inline named map key reference {reference:?}"), )), }; visiting_named_refs.remove(&reference_key); result } DataType::Generic(_) => Ok(()), DataType::Reference(Reference::Opaque(_)) => Err(Error::invalid_map_key( path, "opaque references cannot be validated as serde_json map keys", )), DataType::Tuple(_) => Err(Error::invalid_map_key( path, "tuple keys are not supported by serde_json map key serialization", )), DataType::List(_) | DataType::Map(_) | DataType::Nullable(_) | DataType::Intersection(_) => Err(Error::invalid_map_key( path, "collection, map, and nullable keys are not supported by serde_json map key serialization", )), } } fn substitute_generics(dt: &mut DataType, generics: &[(Generic, DataType)]) { match dt { DataType::Generic(generic) => { if let Some((_, ty)) = generics.iter().find(|(reference, _)| reference == generic) { *dt = ty.clone(); } } DataType::List(list) => substitute_generics(&mut list.ty, generics), DataType::Map(map) => { substitute_generics(map.key_ty_mut(), generics); substitute_generics(map.value_ty_mut(), generics); } DataType::Nullable(inner) => substitute_generics(inner, generics), DataType::Struct(strct) => substitute_field_generics(&mut strct.fields, generics), DataType::Enum(enm) => { for (_, variant) in &mut enm.variants { substitute_field_generics(&mut variant.fields, generics); } } DataType::Tuple(tuple) => { for ty in &mut tuple.elements { substitute_generics(ty, generics); } } DataType::Reference(Reference::Named(reference)) => { if let NamedReferenceType::Reference { generics: reference_generics, .. } = &mut reference.inner { for (_, ty) in reference_generics { substitute_generics(ty, generics); } } } DataType::Intersection(types) => { for ty in types { substitute_generics(ty, generics); } } DataType::Primitive(_) | DataType::Reference(Reference::Opaque(_)) => {} } } fn substitute_field_generics(fields: &mut Fields, generics: &[(Generic, DataType)]) { match fields { Fields::Unit => {} Fields::Unnamed(unnamed) => { for field in &mut unnamed.fields { if let Some(ty) = &mut field.ty { substitute_generics(ty, generics); } } } Fields::Named(named) => { for (_, field) in &mut named.fields { if let Some(ty) = &mut field.ty { substitute_generics(ty, generics); } } } } } fn primitive_is_valid_key(primitive: Primitive) -> bool { matches!( primitive, Primitive::bool | Primitive::i8 | Primitive::i16 | Primitive::i32 | Primitive::i64 | Primitive::i128 | Primitive::isize | Primitive::u8 | Primitive::u16 | Primitive::u32 | Primitive::u64 | Primitive::u128 | Primitive::usize | Primitive::f32 | Primitive::f64 | Primitive::str | Primitive::char ) } fn invalid_primitive_reason(primitive: Primitive) -> &'static str { match primitive { Primitive::f16 | Primitive::f128 => { "f16 and f128 keys are not supported by serde_json map key serialization" } _ => "unsupported primitive key type for serde_json map key serialization", } } ================================================ FILE: specta-typescript/src/opaque.rs ================================================ use std::borrow::Cow; use specta::datatype::Reference; #[derive(PartialEq, Eq, Hash)] pub(crate) struct Define(pub(crate) Cow<'static, str>); #[derive(PartialEq, Eq, Hash)] pub(crate) struct Any; #[derive(PartialEq, Eq, Hash)] pub(crate) struct Unknown; #[derive(PartialEq, Eq, Hash)] pub(crate) struct Never; #[derive(PartialEq, Eq, Hash)] pub(crate) struct Number; /// Define a custom Typescript string which can be used as a `DataType::Reference`. /// /// This is an advanced feature which should be used with caution. pub fn define(raw: impl Into>) -> Reference { Reference::opaque(Define(raw.into())) } ================================================ FILE: specta-typescript/src/primitives.rs ================================================ //! Primitives provide building blocks for Specta-based libraries. //! //! These are for advanced usecases, you should generally use [crate::Typescript] or //! [crate::JSDoc] in end-user applications. use std::{borrow::Cow, fmt::Write as _}; use specta::{ Format, Types, datatype::{ DataType, Deprecated, Enum, Fields, GenericDefinition, GenericReference, List, Map, NamedDataType, NamedReference, NamedReferenceType, OpaqueReference, Primitive, Reference, Tuple, Variant, }, }; use crate::{ Branded, BrandedTypeExporter, Error, Exporter, Layout, legacy::{ ExportContext, deprecated_details, escape_jsdoc_text, escape_typescript_string_literal, is_identifier, js_doc, }, map_keys, opaque, }; /// Generate a group of `export Type = ...` Typescript string for a specific [`NamedDataType`]. /// /// This method leaves the following up to the implementer: /// - Ensuring all referenced types are exported /// - Handling multiple type with overlapping names /// - Transforming the type for your serialization format (Eg. Serde) /// /// We recommend passing in your types in bulk instead of doing individual calls as it leaves formatting to us and also allows us to merge the JSDoc types into a single large comment. /// /// If you are using a custom format such as `serde::format` with the high-level exporter, /// these primitive helpers do not apply that mapping automatically. Standalone primitive usage /// should map both the full [`Types`] graph and any top-level [`DataType`] values with matching /// helpers first. /// pub fn export<'a>( exporter: &dyn AsRef, types: &Types, ndts: impl Iterator, indent: &str, ) -> Result { let mut s = String::new(); export_internal(&mut s, exporter.as_ref(), None, types, ndts, indent)?; Ok(s) } pub(crate) fn export_internal<'a>( s: &mut String, exporter: &Exporter, format: Option<&dyn Format>, types: &Types, ndts: impl Iterator, indent: &str, ) -> Result<(), Error> { let ndts = ndts.filter(|ndt| ndt.ty.is_some()); if exporter.jsdoc { let mut ndts = ndts.peekable(); if ndts.peek().is_none() { return Ok(()); } s.push_str(indent); s.push_str("/**\n"); for (index, ndt) in ndts.enumerate() { if index != 0 { s.push_str(indent); s.push_str("\t*\n"); } append_typedef_body(s, exporter, format, types, ndt, indent)?; } s.push_str(indent); s.push_str("\t*/\n"); return Ok(()); } for (index, ndt) in ndts.enumerate() { if index != 0 { s.push('\n'); } export_single_internal(s, exporter, format, types, ndt, indent)?; } Ok(()) } fn export_single_internal( s: &mut String, exporter: &Exporter, format: Option<&dyn Format>, types: &Types, ndt: &NamedDataType, indent: &str, ) -> Result<(), Error> { if exporter.jsdoc { let mut typedef = String::new(); typedef_internal(&mut typedef, exporter, format, types, ndt)?; for line in typedef.lines() { s.push_str(indent); s.push_str(line); s.push('\n'); } return Ok(()); } // TODO: Modernise this let name = crate::legacy::sanitise_type_name( crate::legacy::ExportContext { cfg: exporter, path: vec![], }, &match exporter.layout { Layout::ModulePrefixedName => { let mut s = ndt.module_path.split("::").collect::>().join("_"); s.push('_'); s.push_str(&ndt.name); Cow::Owned(s) } _ => ndt.name.clone(), }, )?; let mut comments = String::new(); js_doc(&mut comments, &ndt.docs, ndt.deprecated.as_ref()); if !comments.is_empty() { for line in comments.lines() { s.push_str(indent); s.push_str(line); s.push('\n'); } } s.push_str(indent); s.push_str("export type "); s.push_str(&name); write_generic_parameters(s, exporter, types, &ndt.generics)?; s.push_str(" = "); datatype( s, exporter, format, types, ndt.ty.as_ref().expect("named datatype must have a body"), vec![ndt.name.clone()], Some(ndt.name.as_ref()), indent, Default::default(), )?; s.push_str(";\n"); Ok(()) } /// Generate an inlined Typescript string for a specific [`DataType`]. /// /// This methods leaves all the same things as the [`export`] method up to the user. /// /// Note that calling this method with a tagged struct or enum may cause the tag to not be exported. /// The type should be wrapped in a [`NamedDataType`] to provide a proper name. /// /// You are responsible for apply Serde or other format mapping to the top-level datatype in the /// same way as the [`Types`] graph before calling this helper. /// pub fn inline( exporter: &dyn AsRef, types: &Types, dt: &DataType, ) -> Result { let mut s = String::new(); inline_datatype( &mut s, exporter.as_ref(), None, types, dt, vec![], None, "", 0, &[], )?; Ok(s) } // This can be used internally to prevent cloning `Typescript` instances. // Externally this shouldn't be a concern so we don't expose it. pub(crate) fn typedef_internal( s: &mut String, exporter: &Exporter, format: Option<&dyn Format>, types: &Types, dt: &NamedDataType, ) -> Result<(), Error> { s.push_str("/**\n"); append_typedef_body(s, exporter, format, types, dt, "")?; s.push_str("\t*/"); Ok(()) } fn append_jsdoc_properties( s: &mut String, exporter: &Exporter, format: Option<&dyn Format>, types: &Types, dt_name: &str, dt: &DataType, indent: &str, ) -> Result<(), Error> { match dt { DataType::Struct(strct) => match &strct.fields { Fields::Unit => {} Fields::Unnamed(unnamed) => { for (idx, field) in unnamed.fields.iter().enumerate() { let Some(ty) = field.ty.as_ref() else { continue; }; let mut ty_str = String::new(); let datatype_prefix = format!("{indent}\t*\t"); datatype( &mut ty_str, exporter, format, types, ty, vec![Cow::Owned(dt_name.to_owned()), idx.to_string().into()], Some(dt_name), &datatype_prefix, Default::default(), )?; push_jsdoc_property( s, &ty_str, &idx.to_string(), field.optional, &field.docs, field.deprecated.as_ref(), indent, ); } } Fields::Named(named) => { for (name, field) in &named.fields { let Some(ty) = field.ty.as_ref() else { continue; }; let mut ty_str = String::new(); let datatype_prefix = format!("{indent}\t*\t"); datatype( &mut ty_str, exporter, format, types, ty, vec![Cow::Owned(dt_name.to_owned()), name.clone()], Some(dt_name), &datatype_prefix, Default::default(), )?; push_jsdoc_property( s, &ty_str, name, field.optional, &field.docs, field.deprecated.as_ref(), indent, ); } } }, DataType::Enum(enm) => { for (variant_name, variant) in enm.variants.iter().filter(|(_, v)| !v.skip) { let mut one_variant_enum = enm.clone(); one_variant_enum .variants .retain(|(name, _)| name == variant_name); let mut variant_ty = String::new(); crate::legacy::enum_datatype( ExportContext { cfg: exporter, path: vec![], }, &one_variant_enum, types, &mut variant_ty, "", &[], )?; push_jsdoc_property( s, &variant_ty, variant_name, false, &variant.docs, variant.deprecated.as_ref(), indent, ); } } DataType::Intersection(types_) => { for ty in types_ { append_jsdoc_properties(s, exporter, format, types, dt_name, ty, indent)?; } } _ => {} } Ok(()) } fn push_jsdoc_property( s: &mut String, ty: &str, name: &str, optional: bool, docs: &str, deprecated: Option<&Deprecated>, indent: &str, ) { s.push_str(indent); s.push_str("\t* @property {"); push_jsdoc_type(s, ty, indent); s.push_str("} "); s.push_str(&jsdoc_property_name(name, optional)); if let Some(description) = jsdoc_description(docs, deprecated) { s.push_str(" - "); s.push_str(&description); } s.push('\n'); } fn push_jsdoc_type(s: &mut String, ty: &str, indent: &str) { let mut lines = ty.lines(); if let Some(first_line) = lines.next() { s.push_str(first_line); } for line in lines { s.push('\n'); if line .strip_prefix(indent) .is_some_and(|rest| rest.starts_with("\t*")) { s.push_str(line); } else { s.push_str(indent); s.push_str("\t* "); s.push_str(line); } } } fn jsdoc_property_name(name: &str, optional: bool) -> String { let name = if is_identifier(name) { name.to_string() } else { format!("\"{}\"", escape_typescript_string_literal(name)) }; if optional { format!("[{name}]") } else { name } } fn append_typedef_body( s: &mut String, exporter: &Exporter, format: Option<&dyn Format>, types: &Types, dt: &NamedDataType, indent: &str, ) -> Result<(), Error> { let name = &dt.name; let mut type_name = String::from(name.as_ref()); write_generic_parameters(&mut type_name, exporter, types, &dt.generics)?; let mut typedef_ty = String::new(); let datatype_prefix = format!("{indent}\t*\t"); datatype( &mut typedef_ty, exporter, format, types, dt.ty.as_ref().expect("named datatype must have a body"), vec![dt.name.clone()], Some(dt.name.as_ref()), &datatype_prefix, Default::default(), )?; if !dt.docs.is_empty() { for line in dt.docs.lines() { s.push_str(indent); s.push_str("\t* "); s.push_str(&escape_jsdoc_text(line)); s.push('\n'); } s.push_str(indent); s.push_str("\t*\n"); } if let Some(deprecated) = dt.deprecated.as_ref() { s.push_str(indent); s.push_str("\t* @deprecated"); if let Some(details) = deprecated_details(deprecated) { s.push(' '); s.push_str(&details); } s.push('\n'); } s.push_str(indent); s.push_str("\t* @typedef {"); push_jsdoc_type(s, &typedef_ty, indent); s.push_str("} "); s.push_str(&type_name); s.push('\n'); if let Some(ty) = &dt.ty { append_jsdoc_properties(s, exporter, format, types, dt.name.as_ref(), ty, indent)?; } Ok(()) } fn write_generic_parameters( s: &mut String, exporter: &Exporter, types: &Types, generics: &[GenericDefinition], ) -> Result<(), Error> { if generics.is_empty() { return Ok(()); } s.push('<'); for (index, generic) in generics.iter().enumerate() { if index != 0 { s.push_str(", "); } s.push_str(generic.name.as_ref()); if let Some(default) = &generic.default { let mut rendered_default = String::new(); shallow_inline_datatype( &mut rendered_default, exporter, None, types, default, Vec::new(), None, "", Default::default(), )?; s.push_str(" = "); s.push_str(&rendered_default); } } s.push('>'); Ok(()) } fn jsdoc_description(docs: &str, deprecated: Option<&Deprecated>) -> Option { let docs = docs .lines() .map(str::trim) .filter(|line| !line.is_empty()) .map(|line| escape_jsdoc_text(line).into_owned()) .collect::>() .join(" "); let deprecated = deprecated.map(|deprecated| { let mut value = String::from("@deprecated"); if let Some(details) = deprecated_details(deprecated) { value.push(' '); value.push_str(&escape_jsdoc_text(&details)); } value }); match (docs.is_empty(), deprecated) { (true, None) => None, (true, Some(deprecated)) => Some(deprecated), (false, None) => Some(docs), (false, Some(deprecated)) => Some(format!("{docs} {deprecated}")), } } /// Generate an Typescript string to refer to a specific [`DataType`]. /// /// For primitives this will include the literal type but for named type it will contain a reference. /// /// See [`export`] for the list of things to consider when using this. pub fn reference( exporter: &dyn AsRef, types: &Types, r: &Reference, ) -> Result { let mut s = String::new(); datatype( &mut s, exporter.as_ref(), None, types, &DataType::Reference(r.clone()), vec![], None, "", &[], )?; Ok(s) } pub(crate) fn datatype_with_inline_attr( s: &mut String, exporter: &Exporter, format: Option<&dyn Format>, types: &Types, dt: &DataType, location: Vec>, parent_name: Option<&str>, prefix: &str, generics: &[(GenericReference, DataType)], inline: bool, ) -> Result<(), Error> { if inline { return shallow_inline_datatype( s, exporter, format, types, dt, location, parent_name, prefix, generics, ); } datatype( s, exporter, format, types, dt, location, parent_name, prefix, generics, ) } fn write_generic_reference(s: &mut String, generic: &GenericReference) { s.push_str(generic.name()); } fn scoped_reference_generics( parent_generics: &[(GenericReference, DataType)], reference_generics: &[(GenericReference, DataType)], ) -> Vec<(GenericReference, DataType)> { parent_generics .iter() .filter(|(parent_generic, _)| { !reference_generics .iter() .any(|(child_generic, _)| child_generic == parent_generic) }) .cloned() .collect() } fn named_reference_generics(r: &NamedReference) -> Result<&[(GenericReference, DataType)], Error> { match &r.inner { NamedReferenceType::Reference { generics, .. } => Ok(generics), NamedReferenceType::Inline { .. } => Ok(&[]), NamedReferenceType::Recursive => Ok(&[]), } } fn named_reference_ty<'a>(types: &'a Types, r: &'a NamedReference) -> Result<&'a DataType, Error> { match &r.inner { NamedReferenceType::Reference { .. } => types .get(r) .and_then(|ndt| ndt.ty.as_ref()) .ok_or_else(|| Error::dangling_named_reference(format!("{r:?}"))), NamedReferenceType::Inline { dt, .. } => Ok(dt), NamedReferenceType::Recursive => types .get(r) .and_then(|ndt| ndt.ty.as_ref()) .ok_or_else(|| Error::infinite_recursive_inline_type(format!("{r:?}"))), } } fn resolve_scoped_generic_default( default: &DataType, scoped_generics: &[(GenericReference, DataType)], ) -> DataType { match default { DataType::Generic(default) => scoped_generics .iter() .find_map(|(reference, dt)| (reference == default).then_some(dt.clone())) .unwrap_or_else(|| DataType::Generic(default.clone())), default => default.clone(), } } fn resolved_reference_generics( ndt: &specta::datatype::NamedDataType, r: &NamedReference, parent_generics: &[(GenericReference, DataType)], ) -> Option<(Vec, bool, Vec<(GenericReference, DataType)>)> { let reference_generics = named_reference_generics(r).ok()?; let mut scoped_generics = scoped_reference_generics(parent_generics, reference_generics); let mut all_default = true; let mut rendered_generics = Vec::with_capacity(ndt.generics.len()); for generic in ndt.generics.iter() { let explicit = reference_generics .iter() .find(|(reference, _)| *reference == generic.reference()) .map(|(_, dt)| dt.clone()); let resolved_default = generic .default .as_ref() .map(|default| resolve_scoped_generic_default(default, &scoped_generics)); let resolved = explicit.or_else(|| resolved_default.clone()).or_else(|| { Some(DataType::Reference(Reference::opaque( crate::opaque::Unknown, ))) }); let resolved = resolved?; all_default &= resolved_default .as_ref() .is_some_and(|default| default == &resolved); scoped_generics.push((generic.reference(), resolved.clone())); rendered_generics.push(resolved); } Some((rendered_generics, all_default, scoped_generics)) } fn shallow_inline_datatype( s: &mut String, exporter: &Exporter, format: Option<&dyn Format>, types: &Types, dt: &DataType, location: Vec>, parent_name: Option<&str>, prefix: &str, generics: &[(GenericReference, DataType)], ) -> Result<(), Error> { match dt { DataType::Primitive(p) => s.push_str(primitive_dt(p, location)?), DataType::Generic(g) => write_generic_reference(s, g), DataType::List(list) => { let mut inner = String::new(); shallow_inline_datatype( &mut inner, exporter, format, types, &list.ty, location, parent_name, prefix, generics, )?; let inner = if (inner.contains(' ') && !inner.ends_with('}')) || (inner.contains(' ') && (inner.contains('&') || inner.contains('|'))) { format!("({inner})") } else { inner }; if let Some(length) = list.length { s.push('['); for i in 0..length { if i != 0 { s.push_str(", "); } s.push_str(&inner); } s.push(']'); } else { write!(s, "{inner}[]")?; } } DataType::Map(map) => { let path = map_key_path(&location); map_keys::validate_map_key(map.key_ty(), types, format!("{path}."))?; let rendered_key = map_key_render_type(map.key_ty().clone()); fn is_exhaustive(dt: &DataType, types: &Types) -> bool { match dt { DataType::Enum(e) => e.variants.iter().filter(|(_, v)| !v.skip).count() == 0, DataType::Reference(Reference::Named(r)) => { match named_reference_ty(types, r) { Ok(ty) => is_exhaustive(ty, types), Err(_) => false, } } DataType::Reference(Reference::Opaque(_)) => false, _ => true, } } let exhaustive = is_exhaustive(&rendered_key, types); if !exhaustive { s.push_str("Partial<"); } s.push_str("{ [key in "); map_key_datatype( s, exporter, format, types, &rendered_key, location.clone(), parent_name, prefix, generics, )?; s.push_str("]: "); shallow_inline_datatype( s, exporter, format, types, map.value_ty(), location, parent_name, prefix, generics, )?; s.push_str(" }"); if !exhaustive { s.push('>'); } } DataType::Nullable(dt) => { let mut inner = String::new(); shallow_inline_datatype( &mut inner, exporter, format, types, dt, location, parent_name, prefix, generics, )?; s.push_str(&inner); if inner != "null" && !inner.ends_with(" | null") { s.push_str(" | null"); } } DataType::Intersection(types_) => intersection_dt( s, exporter, format, types, types_, location, parent_name, prefix, generics, shallow_intersection_part_datatype, )?, DataType::Struct(st) => { crate::legacy::struct_datatype( crate::legacy::ExportContext { cfg: exporter, path: vec![], }, st, types, s, prefix, generics, )?; } DataType::Enum(enm) => { crate::legacy::enum_datatype( crate::legacy::ExportContext { cfg: exporter, path: vec![], }, enm, types, s, prefix, generics, )?; } DataType::Tuple(tuple) => match tuple.elements.as_slice() { [] => s.push_str("null"), elements => { s.push('['); for (idx, dt) in elements.iter().enumerate() { if idx != 0 { s.push_str(", "); } shallow_inline_datatype( s, exporter, format, types, dt, location.clone(), parent_name, prefix, generics, )?; } s.push(']'); } }, DataType::Reference(r) => match r { Reference::Named(r) => { let ty = named_reference_ty(types, r)?; let reference_generics = named_reference_generics(r)?; shallow_inline_datatype( s, exporter, format, types, ty, location, parent_name, prefix, reference_generics, ) } Reference::Opaque(_) => { reference_dt(s, exporter, format, types, r, location, prefix, generics) } }?, } Ok(()) } type DatatypeRenderer = fn( &mut String, &Exporter, Option<&dyn Format>, &Types, &DataType, Vec>, Option<&str>, &str, &[(GenericReference, DataType)], ) -> Result<(), Error>; fn shallow_intersection_part_datatype( s: &mut String, exporter: &Exporter, format: Option<&dyn Format>, types: &Types, dt: &DataType, location: Vec>, parent_name: Option<&str>, prefix: &str, generics: &[(GenericReference, DataType)], ) -> Result<(), Error> { match dt { DataType::Reference(r) => { reference_dt(s, exporter, format, types, r, location, prefix, generics) } _ => shallow_inline_datatype( s, exporter, format, types, dt, location, parent_name, prefix, generics, ), } } fn intersection_dt( s: &mut String, exporter: &Exporter, format: Option<&dyn Format>, types: &Types, parts: &[DataType], location: Vec>, parent_name: Option<&str>, prefix: &str, generics: &[(GenericReference, DataType)], render: DatatypeRenderer, ) -> Result<(), Error> { let mut rendered = Vec::with_capacity(parts.len()); for part in parts { let mut out = String::new(); render( &mut out, exporter, format, types, part, location.clone(), parent_name, prefix, generics, )?; rendered.push(format!("({out})")); } s.push_str(&rendered.join(" & ")); Ok(()) } // Internal function to handle inlining without cloning DataType nodes fn inline_datatype( s: &mut String, exporter: &Exporter, format: Option<&dyn Format>, types: &Types, dt: &DataType, location: Vec>, parent_name: Option<&str>, prefix: &str, depth: usize, generics: &[(GenericReference, DataType)], ) -> Result<(), Error> { // Prevent infinite recursion if depth == 25 { return Err(Error::invalid_name( location.join("."), "Type recursion limit exceeded during inline expansion", )); } match dt { DataType::Primitive(p) => s.push_str(primitive_dt(p, location)?), DataType::Generic(g) => write_generic_reference(s, g), DataType::List(l) => { // Inline the list element type let mut dt_str = String::new(); crate::legacy::datatype_inner( crate::legacy::ExportContext { cfg: exporter, path: vec![], }, &l.ty, types, &mut dt_str, generics, )?; let dt_str = if (dt_str.contains(' ') && !dt_str.ends_with('}')) || (dt_str.contains(' ') && (dt_str.contains('&') || dt_str.contains('|'))) { format!("({dt_str})") } else { dt_str }; if let Some(length) = l.length { s.push('['); for n in 0..length { if n != 0 { s.push_str(", "); } s.push_str(&dt_str); } s.push(']'); } else { write!(s, "{dt_str}[]")?; } } DataType::Map(m) => map_dt(s, exporter, format, types, m, location, generics)?, DataType::Nullable(def) => { let mut inner = String::new(); inline_datatype( &mut inner, exporter, format, types, def, location, parent_name, prefix, depth + 1, generics, )?; s.push_str(&inner); if inner != "null" && !inner.ends_with(" | null") { s.push_str(" | null"); } } DataType::Struct(st) => { // If we have generics to resolve, handle the struct inline to preserve context if !generics.is_empty() { use specta::datatype::Fields; match &st.fields { Fields::Unit => s.push_str("null"), Fields::Named(named) => { s.push('{'); let mut has_field = false; for (key, field) in &named.fields { // Skip fields without a type (e.g., flattened or skipped fields) let Some(field_ty) = field.ty.as_ref() else { continue; }; has_field = true; s.push('\n'); s.push_str(prefix); s.push('\t'); s.push_str(key); s.push_str(": "); inline_datatype( s, exporter, format, types, field_ty, location.clone(), parent_name, prefix, depth + 1, generics, )?; s.push(','); } if has_field { s.push('\n'); s.push_str(prefix); } s.push('}'); } Fields::Unnamed(_) => { // For unnamed fields, fall back to legacy handling crate::legacy::struct_datatype( crate::legacy::ExportContext { cfg: exporter, path: vec![], }, st, types, s, prefix, generics, )? } } } else { // No generics, use legacy path crate::legacy::struct_datatype( crate::legacy::ExportContext { cfg: exporter, path: vec![], }, st, types, s, prefix, Default::default(), )? } } DataType::Enum(e) => enum_dt(s, exporter, types, e, prefix, generics)?, DataType::Tuple(t) => tuple_dt(s, exporter, types, t, generics)?, DataType::Intersection(types_) => intersection_dt( s, exporter, format, types, types_, location, parent_name, prefix, generics, datatype, )?, DataType::Reference(r) => { if let Reference::Named(r) = r && let Ok(ty) = named_reference_ty(types, r) { let reference_generics = named_reference_generics(r)?; inline_datatype( s, exporter, format, types, ty, location, parent_name, prefix, depth + 1, reference_generics, )?; } else { reference_dt(s, exporter, format, types, r, location, prefix, generics)?; } } } Ok(()) } pub(crate) fn datatype( s: &mut String, exporter: &Exporter, format: Option<&dyn Format>, types: &Types, dt: &DataType, location: Vec>, _parent_name: Option<&str>, prefix: &str, generics: &[(GenericReference, DataType)], ) -> Result<(), Error> { // TODO: Validating the variant from `dt` can be flattened match dt { DataType::Primitive(p) => s.push_str(primitive_dt(p, location)?), DataType::List(l) => list_dt(s, exporter, types, l, generics)?, DataType::Map(m) => map_dt(s, exporter, format, types, m, location, generics)?, DataType::Nullable(def) => { // TODO: Replace legacy stuff let mut inner = String::new(); crate::legacy::datatype_inner( crate::legacy::ExportContext { cfg: exporter, path: vec![], }, def, types, &mut inner, generics, )?; s.push_str(&inner); if inner != "null" && !inner.ends_with(" | null") { s.push_str(" | null"); } // datatype(s, ts, types, &*t, location, state)?; // let or_null = " | null"; // if !s.ends_with(or_null) { // s.push_str(or_null); // } } DataType::Struct(st) => { // location.push(st.name().clone()); // fields_dt(s, ts, types, st.name(), &&st.fields, location, state)? crate::legacy::struct_datatype( crate::legacy::ExportContext { cfg: exporter, path: vec![], }, st, types, s, prefix, generics, )? } DataType::Enum(e) => enum_dt(s, exporter, types, e, prefix, generics)?, DataType::Tuple(t) => tuple_dt(s, exporter, types, t, generics)?, DataType::Intersection(types_) => { for (idx, ty) in types_.iter().enumerate() { if idx != 0 { s.push_str(" & "); } datatype( s, exporter, format, types, ty, location.clone(), _parent_name, prefix, generics, )?; } } DataType::Generic(g) => write_generic_reference(s, g), DataType::Reference(r) => { reference_dt(s, exporter, format, types, r, location, prefix, generics)? } }; Ok(()) } fn primitive_dt(p: &Primitive, location: Vec>) -> Result<&'static str, Error> { use Primitive::*; Ok(match p { i8 | i16 | i32 | u8 | u16 | u32 => "number", // `null` comes from `NaN`, `Infinity` and `-Infinity`. Is done by JS APIs and Serde JSON. f16 | f32 | f64 /* this looks wrong but `f64` is the direct equivalent of `number` */ => "number | null", usize | isize | i64 | u64 | i128 | u128 | f128 => { return Err(Error::bigint_forbidden(location.join("."))); } Primitive::bool => "boolean", str | char => "string", }) } fn list_dt( s: &mut String, exporter: &Exporter, types: &Types, l: &List, generics: &[(GenericReference, DataType)], ) -> Result<(), Error> { // TODO: This is the legacy stuff { let mut dt = String::new(); crate::legacy::datatype_inner( crate::legacy::ExportContext { cfg: exporter, path: vec![], }, &l.ty, types, &mut dt, generics, )?; let dt = if (dt.contains(' ') && !dt.ends_with('}')) // This is to do with maintaining order of operations. // Eg `{} | {}` must be wrapped in parens like `({} | {})[]` but `{}` doesn't cause `{}[]` is valid || (dt.contains(' ') && (dt.contains('&') || dt.contains('|'))) { format!("({dt})") } else { dt }; if let Some(length) = l.length { s.push('['); for n in 0..length { if n != 0 { s.push_str(", "); } s.push_str(&dt); } s.push(']'); } else { write!(s, "{dt}[]")?; } } // // We use `T[]` instead of `Array` to avoid issues with circular references. // let mut result = String::new(); // datatype(&mut result, ts, types, &&l.ty, location, state)?; // let result = if (result.contains(' ') && !result.ends_with('}')) // // This is to do with maintaining order of operations. // // Eg `{} | {}` must be wrapped in parens like `({} | {})[]` but `{}` doesn't cause `{}[]` is valid // || (result.contains(' ') && (result.contains('&') || result.contains('|'))) // { // format!("({result})") // } else { // result // }; // match l.length { // Some(len) => { // s.push_str("["); // iter_with_sep( // s, // 0..len, // |s, _| { // s.push_str(&result); // Ok(()) // }, // ", ", // )?; // s.push_str("]"); // } // None => { // s.push_str(&result); // s.push_str("[]"); // } // } Ok(()) } fn map_key_datatype( s: &mut String, exporter: &Exporter, format: Option<&dyn Format>, types: &Types, key_ty: &DataType, location: Vec>, parent_name: Option<&str>, prefix: &str, generics: &[(GenericReference, DataType)], ) -> Result<(), Error> { match key_ty { DataType::Reference(r) => { reference_dt(s, exporter, format, types, r, location, prefix, generics) } key_ty => shallow_inline_datatype( s, exporter, format, types, key_ty, location, parent_name, prefix, generics, ), } } fn map_dt( s: &mut String, exporter: &Exporter, format: Option<&dyn Format>, types: &Types, m: &Map, location: Vec>, generics: &[(GenericReference, DataType)], ) -> Result<(), Error> { let path = map_key_path(&location); map_keys::validate_map_key(m.key_ty(), types, format!("{path}."))?; { fn is_exhaustive(dt: &DataType, types: &Types) -> bool { match dt { DataType::Enum(e) => e.variants.iter().filter(|(_, v)| !v.skip).count() == 0, DataType::Reference(Reference::Named(r)) => match named_reference_ty(types, r) { Ok(ty) => is_exhaustive(ty, types), Err(_) => false, }, DataType::Reference(Reference::Opaque(_)) => false, _ => true, } } let resolved_key = map_key_render_type(m.key_ty().clone()); let is_exhaustive = is_exhaustive(&resolved_key, types); // We use `{ [key in K]: V }` instead of `Record` to avoid issues with circular references. // Wrapped in Partial<> because otherwise TypeScript would enforce exhaustiveness. if !is_exhaustive { s.push_str("Partial<"); } s.push_str("{ [key in "); map_key_datatype( s, exporter, format, types, &resolved_key, location, None, "", generics, )?; s.push_str("]: "); crate::legacy::datatype_inner( crate::legacy::ExportContext { cfg: exporter, path: vec![], }, m.value_ty(), types, s, generics, )?; s.push_str(" }"); if !is_exhaustive { s.push('>'); } } // assert!(flattening, "todo: map flattening"); // // We use `{ [key in K]: V }` instead of `Record` to avoid issues with circular references. // // Wrapped in Partial<> because otherwise TypeScript would enforce exhaustiveness. // s.push_str("Partial<{ [key in "); // datatype(s, ts, types, m.key_ty(), location.clone(), state)?; // s.push_str("]: "); // datatype(s, ts, types, m.value_ty(), location, state)?; // s.push_str(" }>"); Ok(()) } fn map_key_path(location: &[Cow<'static, str>]) -> String { if location.is_empty() { return "HashMap".to_string(); } location.join(".") } fn map_key_render_type(dt: DataType) -> DataType { if matches!(dt, DataType::Primitive(Primitive::bool)) { return bool_key_literal_datatype(); } dt } fn bool_key_literal_datatype() -> DataType { let mut bool_enum = Enum::default(); bool_enum .variants .push((Cow::Borrowed("true"), Variant::unit())); bool_enum .variants .push((Cow::Borrowed("false"), Variant::unit())); DataType::Enum(bool_enum) } fn enum_dt( s: &mut String, exporter: &Exporter, types: &Types, e: &Enum, prefix: &str, generics: &[(GenericReference, DataType)], ) -> Result<(), Error> { // TODO: Drop legacy stuff { crate::legacy::enum_datatype( crate::legacy::ExportContext { cfg: exporter, path: vec![], }, e, types, s, prefix, generics, )? } // assert!(!state.flattening, "todo: support for flattening enums"); // TODO // location.push(e.name().clone()); // let variants = &e.variants.iter().filter(|(_, variant)| !variant.skip); // if variants.clone().next().is_none() // /* is_empty */ // { // s.push_str("never"); // return Ok(()); // } // let mut variants = variants // .into_iter() // .map(|(variant_name, variant)| { // let mut s = String::new(); // let mut location = location.clone(); // location.push(variant_name.clone()); // // TODO // // variant.deprecated.as_ref() // // &variant.docs // match &e.repr() { // EnumRepr::Untagged => { // fields_dt(&mut s, ts, types, variant_name, variant.fields(), location, state)?; // }, // EnumRepr::External => match variant.fields() { // Fields::Unit => { // s.push_str("\""); // s.push_str(variant_name); // s.push_str("\""); // }, // Fields::Unnamed(n) if n.fields().into_iter().filter(|f| f.ty().is_some()).next().is_none() /* is_empty */ => { // // We detect `#[specta(skip)]` by checking if the unfiltered fields are also empty. // if n.fields().is_empty() { // s.push_str("{ "); // s.push_str(&escape_key(variant_name)); // s.push_str(": [] }"); // } else { // s.push_str("\""); // s.push_str(variant_name); // s.push_str("\""); // } // } // _ => { // s.push_str("{ "); // s.push_str(&escape_key(variant_name)); // s.push_str(": "); // fields_dt(&mut s, ts, types, variant_name, variant.fields(), location, state)?; // s.push_str(" }"); // } // } // EnumRepr::Internal { tag } => { // // TODO: Unconditionally wrapping in `(` kinda sucks. // write!(s, "({{ {}: \"{}\"", escape_key(tag), variant_name).expect("infallible"); // match variant.fields() { // Fields::Unit => { // s.push_str(" })"); // }, // // Fields::Unnamed(f) if f.fields.iter().filter(|f| f.ty().is_some()).count() == 1 => { // // // let mut fields = f.fields().into_iter().filter(|f| f.ty().is_some()); // // s.push_str("______"); // TODO // // // // if fields.len // // // // TODO: Having no fields are skipping is valid // // // // TODO: Having more than 1 field is invalid // // // // TODO: Check if the field's type is object-like and can be merged. // // // todo!(); // // } // f => { // // TODO: Cleanup and explain this // let mut skip_join = false; // if let Fields::Unnamed(f) = &f { // let mut fields = f.fields.iter().filter(|f| f.ty().is_some()); // if let (Some(v), None) = (fields.next(), fields.next()) { // if let Some(DataType::Tuple(tuple)) = &v.ty() { // skip_join = &tuple.elements.len() == 0; // } // } // } // if skip_join { // s.push_str(" })"); // } else { // s.push_str(" } & "); // // TODO: Can we be smart enough to omit the `{` and `}` if this is an object // fields_dt(&mut s, ts, types, variant_name, f, location, state)?; // s.push_str(")"); // } // // match f { // // // Checked above // // Fields::Unit => unreachable!(), // // Fields::Unnamed(unnamed_fields) => unnamed_fields, // // Fields::Named(named_fields) => todo!(), // // } // // println!("{:?}", f); // TODO: If object we can join in fields like this, else `} & ...` // // flattened_fields_dt(&mut s, ts, types, variant_name, f, location, false)?; // TODO: Fix `flattening` // } // } // } // EnumRepr::Adjacent { tag, content } => { // write!(s, "{{ {}: \"{}\"", escape_key(tag), variant_name).expect("infallible"); // match variant.fields() { // Fields::Unit => {}, // f => { // write!(s, "; {}: ", escape_key(content)).expect("infallible"); // fields_dt(&mut s, ts, types, variant_name, f, location, state)?; // } // } // s.push_str(" }"); // } // } // Ok(s) // }) // .collect::, Error>>()?; // // TODO: Instead of deduplicating on the string, we should do it in the AST. // // This would avoid the intermediate `String` allocations and be more reliable. // variants.dedup(); // iter_with_sep( // s, // variants, // |s, v| { // s.push_str(&v); // Ok(()) // }, // " | ", // )?; Ok(()) } // fn fields_dt( // s: &mut String, // ts: &Typescript, // types: &Types, // name: &Cow<'static, str>, // f: &Fields, // location: Vec>, // state: State, // ) -> Result<(), Error> { // match f { // Fields::Unit => { // assert!(!state.flattening, "todo: support for flattening enums"); // TODO // s.push_str("null") // } // Fields::Unnamed(f) => { // assert!(!state.flattening, "todo: support for flattening enums"); // TODO // let mut fields = f.fields().into_iter().filter(|f| f.ty().is_some()); // // A single field usually becomes `T`. // // but when `#[serde(skip)]` is used it should be `[T]`. // if fields.clone().count() == 1 && f.fields.len() == 1 { // return field_dt( // s, // ts, // types, // None, // fields.next().expect("checked above"), // location, // state, // ); // } // s.push_str("["); // iter_with_sep( // s, // fields.enumerate(), // |s, (i, f)| { // let mut location = location.clone(); // location.push(i.to_string().into()); // field_dt(s, ts, types, None, f, location, state) // }, // ", ", // )?; // s.push_str("]"); // } // Fields::Named(f) => { // let fields = f.fields().into_iter().filter(|(_, f)| f.ty().is_some()); // if fields.clone().next().is_none() // /* is_empty */ // { // assert!(!state.flattening, "todo: support for flattening enums"); // TODO // if let Some(tag) = f.tag() { // if !state.flattening {} // write!(s, "{{ {}: \"{name}\" }}", escape_key(tag)).expect("infallible"); // } else { // s.push_str("Record"); // } // return Ok(()); // } // if !state.flattening { // s.push_str("{ "); // } // if let Some(tag) = &f.tag() { // write!(s, "{}: \"{name}\"; ", escape_key(tag)).expect("infallible"); // } // iter_with_sep( // s, // fields, // |s, (key, f)| { // let mut location = location.clone(); // location.push(key.clone()); // field_dt(s, ts, types, Some(key), f, location, state) // }, // "; ", // )?; // if !state.flattening { // s.push_str(" }"); // } // } // } // Ok(()) // } // // TODO: Remove this to avoid so much duplicate logic // fn flattened_fields_dt( // s: &mut String, // ts: &Typescript, // types: &Types, // name: &Cow<'static, str>, // f: &Fields, // location: Vec>, // state: State, // ) -> Result<(), Error> { // match f { // Fields::Unit => todo!(), // s.push_str("null"), // Fields::Unnamed(f) => { // // TODO: Validate flattening? // let mut fields = f.fields().into_iter().filter(|f| f.ty().is_some()); // // A single field usually becomes `T`. // // but when `#[serde(skip)]` is used it should be `[T]`. // if fields.clone().count() == 1 && f.fields.len() == 1 { // return field_dt( // s, // ts, // types, // None, // fields.next().expect("checked above"), // location, // state, // ); // } // s.push_str("["); // iter_with_sep( // s, // fields.enumerate(), // |s, (i, f)| { // let mut location = location.clone(); // location.push(i.to_string().into()); // field_dt(s, ts, types, None, f, location, state) // }, // ", ", // )?; // s.push_str("]"); // } // Fields::Named(f) => { // let fields = f.fields().into_iter().filter(|(_, f)| f.ty().is_some()); // if fields.clone().next().is_none() // /* is_empty */ // { // if let Some(tag) = f.tag() { // write!(s, "{{ {}: \"{name}\" }}", escape_key(tag)).expect("infallible"); // } else { // s.push_str("Record"); // } // return Ok(()); // } // // s.push_str("{ "); // TODO // if let Some(tag) = &f.tag() { // write!(s, "{}: \"{name}\"; ", escape_key(tag)).expect("infallible"); // } // iter_with_sep( // s, // fields, // |s, (key, f)| { // let mut location = location.clone(); // location.push(key.clone()); // field_dt(s, ts, types, Some(key), f, location, state) // }, // "; ", // )?; // // s.push_str(" }"); // TODO // } // } // Ok(()) // } // fn field_dt( // s: &mut String, // ts: &Typescript, // types: &Types, // key: Option<&Cow<'static, str>>, // f: &Field, // location: Vec>, // state: State, // ) -> Result<(), Error> { // let Some(ty) = f.ty() else { // // These should be filtered out before getting here. // unreachable!() // }; // // TODO // // field.deprecated.as_ref(), // // &field.docs, // let ty = if f.inline() { // specta::datatype::inline_dt(types, ty.clone()) // } else { // ty.clone() // }; // if !f.flatten() { // if let Some(key) = key { // s.push_str(&*escape_key(key)); // // https://github.com/specta-rs/rspc/issues/100#issuecomment-1373092211 // if f.optional() { // s.push_str("?"); // } // s.push_str(": "); // } // } else { // // TODO: We need to validate the inner type can be flattened safely??? // // data // // match ty { // // DataType::Any => todo!(), // // DataType::Unknown => todo!(), // // DataType::Primitive(primitive_type) => todo!(), // // DataType::Literal(literal_type) => todo!(), // // DataType::List(list) => todo!(), // // DataType::Map(map) => todo!(), // // DataType::Nullable(data_type) => todo!(), // // DataType::Struct(st) => { // // // location.push(st.name().clone()); // TODO // // flattened_fields_dt(s, ts, types, st.name(), &&st.fields, location)? // // } // // // flattened_fields_dt(s, ts, types, &ty, location)?, // // DataType::Enum(enum_type) => todo!(), // // DataType::Tuple(tuple_type) => todo!(), // // DataType::Reference(reference) => todo!(), // // DataType::Generic(generic_type) => todo!(), // // }; // } // // TODO: Only flatten when object is inline? // datatype( // s, // ts, // types, // &ty, // location, // State { // flattening: state.flattening || f.flatten(), // }, // )?; // // TODO: This is not always correct but is it ever correct? // // If we can't use `?` (Eg. in a tuple) we manually join it. // // if key.is_none() && f.optional() { // // s.push_str(" | undefined"); // // } // Ok(()) // } fn tuple_dt( s: &mut String, exporter: &Exporter, types: &Types, t: &Tuple, generics: &[(GenericReference, DataType)], ) -> Result<(), Error> { { s.push_str(&crate::legacy::tuple_datatype( crate::legacy::ExportContext { cfg: exporter, path: vec![], }, t, types, generics, )?); } // match &t.elements()[..] { // [] => s.push_str("null"), // elems => { // s.push_str("["); // iter_with_sep( // s, // elems.into_iter().enumerate(), // |s, (i, dt)| { // let mut location = location.clone(); // location.push(i.to_string().into()); // datatype(s, ts, types, &dt, location, state) // }, // ", ", // )?; // s.push_str("]"); // } // } Ok(()) } fn reference_dt( s: &mut String, exporter: &Exporter, format: Option<&dyn Format>, types: &Types, r: &Reference, location: Vec>, prefix: &str, generics: &[(GenericReference, DataType)], ) -> Result<(), Error> { match r { Reference::Named(r) => match &r.inner { NamedReferenceType::Reference { .. } => { reference_named_dt(s, exporter, types, r, generics) } NamedReferenceType::Inline { dt, .. } => inline_datatype( s, exporter, format, types, dt, location, None, prefix, 0, generics, ), NamedReferenceType::Recursive => reference_named_dt(s, exporter, types, r, generics), }, Reference::Opaque(r) => reference_opaque_dt(s, exporter, format, types, r), } } fn reference_opaque_dt( s: &mut String, exporter: &Exporter, format: Option<&dyn Format>, types: &Types, r: &OpaqueReference, ) -> Result<(), Error> { if let Some(def) = r.downcast_ref::() { s.push_str(&def.0); return Ok(()); } else if r.downcast_ref::().is_some() { s.push_str("any"); return Ok(()); } else if r.downcast_ref::().is_some() { s.push_str("unknown"); return Ok(()); } else if r.downcast_ref::().is_some() { s.push_str("never"); return Ok(()); } else if r.downcast_ref::().is_some() { s.push_str("number"); return Ok(()); } else if let Some(def) = r.downcast_ref::() { if let Some(branded_type) = exporter .branded_type_impl .as_ref() .map(|builder| { (builder.0)( BrandedTypeExporter { exporter, format, types, }, def, ) }) .transpose()? { s.push_str(branded_type.as_ref()); return Ok(()); } // TODO: Build onto `s` instead of appending a separate string match def.ty() { DataType::Reference(r) => reference_dt(s, exporter, format, types, r, vec![], "", &[])?, ty => inline_datatype(s, exporter, format, types, ty, vec![], None, "", 0, &[])?, } s.push_str(r#" & { { readonly __brand: ""#); s.push_str(def.brand()); s.push_str("\" }"); return Ok(()); } Err(Error::unsupported_opaque_reference(r.clone())) } fn reference_named_dt( s: &mut String, exporter: &Exporter, types: &Types, r: &NamedReference, generics: &[(GenericReference, DataType)], ) -> Result<(), Error> { // TODO: Legacy stuff { let ndt = types .get(r) .ok_or_else(|| Error::dangling_named_reference(format!("{r:?}")))?; // We check it's valid before tracking crate::references::track_nr(r); let name = match exporter.layout { Layout::ModulePrefixedName => { let mut s = ndt.module_path.split("::").collect::>().join("_"); s.push('_'); s.push_str(&ndt.name); Cow::Owned(s) } Layout::Namespaces => { if ndt.module_path.is_empty() { ndt.name.clone() } else { let mut path = ndt.module_path .split("::") .fold("$s$.".to_string(), |mut s, segment| { s.push_str(segment); s.push('.'); s }); path.push_str(&ndt.name); Cow::Owned(path) } } Layout::Files => { let current_module_path = crate::references::current_module_path().unwrap_or_default(); if ndt.module_path == current_module_path { ndt.name.clone() } else { let mut path = crate::exporter::module_alias(&ndt.module_path); path.push('.'); path.push_str(&ndt.name); Cow::Owned(path) } } _ => ndt.name.clone(), }; let (rendered_generics, omit_generics, scoped_generics) = resolved_reference_generics(ndt, r, generics) .ok_or_else(|| Error::dangling_named_reference(format!("{r:?}")))?; s.push_str(&name); if !omit_generics && !rendered_generics.is_empty() { s.push('<'); for (i, dt) in rendered_generics.iter().enumerate() { if i != 0 { s.push_str(", "); } crate::legacy::datatype_inner( crate::legacy::ExportContext { cfg: exporter, path: vec![], }, dt, types, s, &scoped_generics, )?; } s.push('>'); } } // let ndt = types // .get(r.sid()) // // Should be impossible without a bug in Specta. // .unwrap_or_else(|| panic!("Missing {:?} in `Types`", r.sid())); // if r.inline() { // todo!("inline reference!"); // } // s.push_str(&ndt.name); // // TODO: We could possible break this out, the root `export` function also has to emit generics. // match r.generics()() { // [] => {} // generics => { // s.push('<'); // // TODO: Should we push a location for which generic? // iter_with_sep( // s, // generics, // |s, dt| datatype(s, ts, types, &dt, location.clone(), state), // ", ", // )?; // s.push('>'); // } // } Ok(()) } // fn validate_name( // ident: &Cow<'static, str>, // location: &Vec>, // ) -> Result<(), Error> { // // TODO: Use a perfect hash-map for faster lookups? // if let Some(name) = RESERVED_TYPE_NAMES.iter().find(|v| **v == ident) { // return Err(Error::ForbiddenName { // path: location.join("."), // name, // }); // } // if ident.is_empty() { // return Err(Error::InvalidName { // path: location.join("."), // name: ident.clone(), // }); // } // if let Some(first_char) = ident.chars().next() { // if !first_char.is_alphabetic() && first_char != '_' { // return Err(Error::InvalidName { // path: location.join("."), // name: ident.clone(), // }); // } // } // if ident // .find(|c: char| !c.is_alphanumeric() && c != '_') // .is_some() // { // return Err(Error::InvalidName { // path: location.join("."), // name: ident.clone(), // }); // } // Ok(()) // } // fn escape_key(name: &Cow<'static, str>) -> Cow<'static, str> { // let needs_escaping = name // .chars() // .all(|c| c.is_alphanumeric() || c == '_' || c == '$') // && name // .chars() // .next() // .map(|first| !first.is_numeric()) // .unwrap_or(true); // if !needs_escaping { // format!(r#""{name}""#).into() // } else { // name.clone() // } // } // fn comment() { // // TODO: Different JSDoc modes // // TODO: Regular comments // // TODO: Deprecated // // TODO: When enabled: arguments, result types // } // /// Iterate with separate and error handling // fn iter_with_sep( // s: &mut String, // i: impl IntoIterator, // mut item: impl FnMut(&mut String, T) -> Result<(), Error>, // sep: &'static str, // ) -> Result<(), Error> { // for (i, e) in i.into_iter().enumerate() { // if i != 0 { // s.push_str(sep); // } // (item)(s, e)?; // } // Ok(()) // } ================================================ FILE: specta-typescript/src/references.rs ================================================ use std::{cell::RefCell, collections::HashSet}; use specta::datatype::NamedReference; thread_local! { static REFERENCED_TYPES: RefCell>>> = const { RefCell::new(None) }; static MODULE_PATH_CONTEXT: RefCell> = const { RefCell::new(Vec::new()) }; } pub(crate) fn with_module_path(module_path: &str, func: impl FnOnce() -> R) -> R { struct Guard; impl Drop for Guard { fn drop(&mut self) { MODULE_PATH_CONTEXT.with_borrow_mut(|ctx| { ctx.pop(); }); } } MODULE_PATH_CONTEXT.with_borrow_mut(|ctx| { ctx.push(module_path.to_string()); }); let guard = Guard; let result = func(); std::mem::forget(guard); MODULE_PATH_CONTEXT.with_borrow_mut(|ctx| { ctx.pop(); }); result } pub(crate) fn current_module_path() -> Option { MODULE_PATH_CONTEXT.with_borrow(|ctx| ctx.last().cloned()) } /// This function collects all Typescript references which are created within the given closure. /// /// This can be used for determining the imports required in a particular file. pub fn collect_references(func: impl FnOnce() -> R) -> (R, HashSet) { struct Guard; impl Drop for Guard { fn drop(&mut self) { REFERENCED_TYPES.with_borrow_mut(|types| { if let Some(v) = types { // Last collection means we can drop all memory if v.len() == 1 { *types = None; } else { // Otherwise just remove the current collection. v.pop(); } } }) } } // If we have no collection, register one // If we already have one create a new context. REFERENCED_TYPES.with_borrow_mut(|v| { if let Some(v) = v { v.push(Default::default()); } else { *v = Some(vec![Default::default()]); } }); let guard = Guard; let result = func(); // We only use the guard when unwinding std::mem::forget(guard); ( result, REFERENCED_TYPES.with_borrow_mut(|types| { types .as_mut() .expect("COLLECTED_TYPES is unset but it should be set") .pop() .expect("COLLECTED_TYPES is missing a valid collection context") }), ) } /// Used internally to track a named references. pub(crate) fn track_nr(r: &NamedReference) { REFERENCED_TYPES.with_borrow_mut(|ctxs| { if let Some(ctxs) = ctxs { for ctx in ctxs { ctx.insert(r.clone()); } } }); } ================================================ FILE: specta-typescript/src/reserved_names.rs ================================================ /// Taken from: https://github.com/microsoft/TypeScript/blob/fad889283e710ee947e8412e173d2c050107a3c1/src/compiler/types.ts#L276 pub(crate) const RESERVED_TYPE_NAMES: &[&str] = &[ "break", "case", "catch", "class", "const", "continue", "debugger", "default", "delete", "do", "else", "enum", "export", "extends", "false", "finally", "for", "function", "if", "import", "in", "instanceof", "new", "null", "return", "super", "switch", "this", "throw", "true", "try", "typeof", "var", "void", "while", "with", "as", "implements", "interface", "let", "package", "private", "protected", "public", "static", "yield", "any", "boolean", "constructor", "declare", "get", "module", "require", "number", "set", "string", "symbol", "type", "from", "of", ]; ================================================ FILE: specta-typescript/src/types.rs ================================================ use std::fmt::Debug; use specta::{ Type, Types, datatype::{DataType, Reference}, }; use crate::opaque; /// Cast a Rust type to a Typescript `any` type. /// ///
/// /// **WARNING:** When used with `Option>`, Typescript will not prompt you about nullability checks as `any | null` is coalesced to `any` in Typescript. /// ///
/// /// # Examples /// /// This can be used as a type override. /// ```rust /// use serde::Serialize; /// use specta::Type; /// use specta_typescript::Any; /// /// #[derive(Serialize, Type)] /// pub struct Demo { /// #[specta(type = Any)] /// pub field: String, /// } /// ``` /// /// Or it can be used as a wrapper type. /// ```rust /// use serde::Serialize; /// use specta::Type; /// use specta_typescript::Any; /// /// # #[cfg(feature = "serde")] { /// #[derive(Serialize, Type)] /// pub struct Demo { /// pub field: Any, /// } /// # } /// ``` pub struct Any(T); impl Type for Any { fn definition(_: &mut Types) -> DataType { DataType::Reference(Reference::opaque(opaque::Any)) } } impl Debug for Any { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_tuple("Any").field(&self.0).finish() } } impl Clone for Any { fn clone(&self) -> Self { Self(self.0.clone()) } } impl Default for Any { fn default() -> Self { Self(T::default()) } } #[cfg(feature = "serde")] #[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl serde::Serialize for Any { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { T::serialize(&self.0, serializer) } } #[cfg(feature = "serde")] #[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl<'de, T: serde::Deserialize<'de>> serde::Deserialize<'de> for Any { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { T::deserialize(deserializer).map(Self) } } /// Cast a Rust type to a Typescript `unknown` type. /// /// # Examples /// /// This can be used as a type override. /// ```rust /// use serde::Serialize; /// use specta::Type; /// use specta_typescript::Unknown; /// /// #[derive(Serialize, Type)] /// pub struct Demo { /// #[specta(type = Unknown)] /// pub field: String, /// } /// ``` /// /// Or it can be used as a wrapper type. /// ```rust /// use serde::Serialize; /// use specta::Type; /// use specta_typescript::Unknown; /// /// # #[cfg(feature = "serde")] { /// #[derive(Serialize, Type)] /// pub struct Demo { /// pub field: Unknown, /// } /// # } /// ``` pub struct Unknown(T); impl Type for Unknown { fn definition(_: &mut Types) -> DataType { DataType::Reference(Reference::opaque(opaque::Unknown)) } } impl Debug for Unknown { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_tuple("Any").field(&self.0).finish() } } impl Clone for Unknown { fn clone(&self) -> Self { Self(self.0.clone()) } } impl Default for Unknown { fn default() -> Self { Self(T::default()) } } #[cfg(feature = "serde")] #[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl serde::Serialize for Unknown { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { T::serialize(&self.0, serializer) } } #[cfg(feature = "serde")] #[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl<'de, T: serde::Deserialize<'de>> serde::Deserialize<'de> for Unknown { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { T::deserialize(deserializer).map(Self) } } /// Cast a Rust type to a Typescript `never` type. /// /// # Examples /// /// This can be used as a type override. /// ```rust /// use serde::Serialize; /// use specta::Type; /// use specta_typescript::Never; /// /// #[derive(Serialize, Type)] /// pub struct Demo { /// #[specta(type = Never)] /// pub field: String, /// } /// ``` /// /// Or it can be used as a wrapper type. /// ```rust /// use serde::Serialize; /// use specta::Type; /// use specta_typescript::Never; /// /// # #[cfg(feature = "serde")] { /// #[derive(Serialize, Type)] /// pub struct Demo { /// pub field: Never, /// } /// # } /// ``` pub struct Never(T); impl Type for Never { fn definition(_: &mut Types) -> DataType { DataType::Reference(Reference::opaque(opaque::Never)) } } impl Debug for Never { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_tuple("Any").field(&self.0).finish() } } impl Clone for Never { fn clone(&self) -> Self { Self(self.0.clone()) } } impl Default for Never { fn default() -> Self { Self(T::default()) } } #[cfg(feature = "serde")] #[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl serde::Serialize for Never { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { T::serialize(&self.0, serializer) } } #[cfg(feature = "serde")] #[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl<'de, T: serde::Deserialize<'de>> serde::Deserialize<'de> for Never { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { T::deserialize(deserializer).map(Self) } } /// Cast a Rust type to a Typescript `number` type. /// /// This can be used to opt into exporting BigInt-style Rust integer types as /// Typescript `number` when precision loss is acceptable. /// /// # Examples /// /// This can be used as a type override. /// ```rust /// use serde::Serialize; /// use specta::Type; /// use specta_typescript::Number; /// /// #[derive(Serialize, Type)] /// pub struct Demo { /// #[specta(type = Number)] /// pub field: i128, /// } /// ``` /// /// Or it can be used as a wrapper type. /// ```rust /// use serde::Serialize; /// use specta::Type; /// use specta_typescript::Number; /// /// # #[cfg(feature = "serde")] { /// #[derive(Serialize, Type)] /// pub struct Demo { /// pub field: Number, /// } /// # } /// ``` pub struct Number(T); impl Type for Number { fn definition(_: &mut Types) -> DataType { DataType::Reference(Reference::opaque(opaque::Number)) } } impl Debug for Number { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_tuple("Number").field(&self.0).finish() } } impl Clone for Number { fn clone(&self) -> Self { Self(self.0.clone()) } } impl Default for Number { fn default() -> Self { Self(T::default()) } } #[cfg(feature = "serde")] #[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl serde::Serialize for Number { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { T::serialize(&self.0, serializer) } } #[cfg(feature = "serde")] #[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl<'de, T: serde::Deserialize<'de>> serde::Deserialize<'de> for Number { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { T::deserialize(deserializer).map(Self) } } ================================================ FILE: specta-typescript/src/typescript.rs ================================================ use std::{borrow::Cow, path::Path}; use specta::{Format, Types}; use crate::{Branded, BrandedTypeExporter, Error, Exporter, Layout}; /// JSDoc language exporter. #[derive(Debug, Clone)] #[non_exhaustive] pub struct Typescript(Exporter); impl Default for Typescript { fn default() -> Self { Exporter::default().into() } } impl From for Exporter { fn from(value: Typescript) -> Self { value.0 } } impl From for Typescript { fn from(mut value: Exporter) -> Self { value.jsdoc = false; Self(value) } } impl Typescript { /// Construct a new JSDoc exporter with the default options configured. pub fn new() -> Self { Default::default() } /// Configure a header for the file. /// /// This is perfect for configuring lint ignore rules or other file-level comments. pub fn header(self, header: impl Into>) -> Self { Self(self.0.header(header)) } /// Configure the layout of the generated file pub fn layout(self, layout: Layout) -> Self { Self(self.0.layout(layout)) } /// Configure how `specta_typescript::branded!` types are rendered. /// /// See [`Exporter::branded_type_impl`] for details. pub fn branded_type_impl( self, builder: impl for<'a> Fn(BrandedTypeExporter<'a>, &Branded) -> Result, Error> + Send + Sync + 'static, ) -> Self { Self(self.0.branded_type_impl(builder)) } /// Export the files into a single string. /// /// Note: This returns an error if the format is `Format::Files`. pub fn export(&self, types: &Types, format: impl Format) -> Result { self.0.export(types, format) } /// Export the types to a specific file/folder. /// /// When configured when `format` is `Format::Files`, you must provide a directory path. /// Otherwise, you must provide the path of a single file. /// pub fn export_to( &self, path: impl AsRef, types: &Types, format: impl Format, ) -> Result<(), Error> { self.0.export_to(path, types, format) } } impl AsRef for Typescript { fn as_ref(&self) -> &Exporter { &self.0 } } impl AsMut for Typescript { fn as_mut(&mut self) -> &mut Exporter { &mut self.0 } } ================================================ FILE: specta-util/Cargo.toml ================================================ [package] name = "specta-util" description = "High-level utilities for working with Specta" version = "0.0.11" authors = ["Oscar Beaumont "] edition = "2024" license = "MIT" repository = "https://github.com/specta-rs/specta" documentation = "https://docs.rs/specta-util/latest/specta-util" keywords = ["async", "specta", "rspc", "typescript", "typesafe"] categories = ["web-programming", "asynchronous"] readme = "../README.md" # /bin/sh RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features [package.metadata."docs.rs"] all-features = true rustdoc-args = ["--cfg", "docsrs"] [features] default = [] ## Support for [serde](https://serde.rs) serde = ["dep:serde"] [lints] workspace = true [dependencies] specta = { version = "=2.0.0-rc.24", path = "../specta" } serde = { version = "1", optional = true, default-features = false } serde_json = { version = "1", optional = true, default-features = false, features = ["std"] } ================================================ FILE: specta-util/src/array.rs ================================================ use std::marker::PhantomData; use specta::{ Type, Types, datatype::{DataType, List}, }; /// Declares a fixed-length array type for Specta exporters. /// /// This is primarily useful with `#[specta(type = ...)]` when you want an array /// field to keep its length information in exported schemas. /// /// A plain Rust array like `[u8; 2]` may be exported as `number[]` if Specta /// deems it's unable to safely export it as `[number, number]`. This limitation /// is due to the fact that Specta can't track the inference of const generics and /// hence can't fully support them. Using `FixedArray` will always encode the /// length so it can be used to force override Specta's conservative behaviour when you know what your doing. /// /// ```ignore /// use specta::Type; /// /// /// #[derive(Type)] /// struct DemoA { /// a: [u8; 2], // becomes `[number, number]` /// /// #[specta(type = specta_util::FixedArray<2, u8>)] /// d: [u8; 2], // becomes `[number, number]` /// } /// /// #[derive(Type)] /// struct DemoB { /// // These are generalised by Specta as we can't know if a specific type is using `N` or a constant, and we don't know what `N` is. /// // If you `#[specta(inline)]` or `#[serde(flatten)]` the `[number, number]` will be restored as we are able to track it properly. /// data: [u32; N], // becomes `number[]` /// a: [u8; 2], // becomes `number[]` /// /// #[specta(type = specta_util::FixedArray<2, u8>)] /// d: [u8; 2], // becomes `[number, number]` /// } /// ``` pub struct FixedArray(PhantomData<[T; N]>); impl Type for FixedArray { fn definition(types: &mut Types) -> DataType { let mut l = List::new(T::definition(types)); // Refer to the type documentation for the safety around this. l.length = Some(N); DataType::List(l) } } ================================================ FILE: specta-util/src/lib.rs ================================================ //! Extended functionality for [Specta](specta). #![cfg_attr(docsrs, feature(doc_cfg))] #![doc( html_logo_url = "https://github.com/specta-rs/specta/raw/main/.github/logo-128.png", html_favicon_url = "https://github.com/specta-rs/specta/raw/main/.github/logo-128.png" )] #[cfg(feature = "serde")] #[cfg_attr(docsrs, doc(cfg(feature = "serde")))] mod selection; mod array; mod remapper; pub use array::FixedArray; pub use remapper::Remapper; ================================================ FILE: specta-util/src/remapper.rs ================================================ use specta::{ Types, datatype::{DataType, Fields, NamedReferenceType, Reference}, }; /// Recursively replaces [`DataType`]s within a [`DataType`] structure from a set of remap rules. /// /// `Remapper` is useful when a type should be represented differently for export /// without changing the original Rust type or derive output. It performs [`DataType`] /// equality checks while walking the [`DataType`] structure applying the transformations. /// /// Rules are applied in the order they are registered. For each visited /// [`DataType`], every matching rule is applied, with each rule seeing the /// result of the previous matching rule. /// ///
/// /// **WARNING:** This is an advanced API! /// /// It needs to be used carefully as it can easily break the safety of the end to end type contract. /// /// You must ensure you have Serde applying the same transformations to the runtime data for it to be sound. /// ///
/// /// # Examples /// /// Remap `u32` to `str` and `i32` to `bool`: /// /// ```rust /// use specta::{Types, datatype::{DataType, Field, List, NamedDataType, Primitive, Struct}}; /// use specta_util::Remapper; /// /// let remapper = Remapper::new() /// .rule(Primitive::u32.into(), Primitive::str.into()) /// .rule(Primitive::i32.into(), Primitive::bool.into()); /// /// // For a single `DataType` /// assert_eq!( /// remapper.remap_dt(DataType::List(List::new(Primitive::u32.into()))), /// DataType::List(List::new(Primitive::str.into())) /// ); /// /// // For a whole collection of types /// # #[allow(unused)] /// let types: Types = remapper.remap_types(Types::default()); /// ``` #[derive(Debug, Clone, Default)] pub struct Remapper { rules: Vec<(DataType, DataType)>, } impl Remapper { /// Creates a remapper with no rules. pub fn new() -> Self { Self::default() } /// Registers a rule that replaces exact matches of `from` with `to`. /// /// Rules are checked in the order they are registered. pub fn rule(mut self, from: DataType, to: DataType) -> Self { self.rules.push((from, to)); self } /// Applies the remap operation to a datatype, returning the remapped datatype. pub fn remap_dt(&self, mut dt: DataType) -> DataType { self.remap_internal(&mut dt); dt } /// Applies the remap operation to every datatype in a [`Types`] collection, returning the remapped collection. pub fn remap_types(&self, types: Types) -> Types { types.map(|mut ndt| { ndt.generics.to_mut().iter_mut().for_each(|generic| { if let Some(dt) = &mut generic.default { self.remap_internal(dt); } }); if let Some(dt) = &mut ndt.ty { self.remap_internal(dt); } ndt }) } fn remap_internal(&self, dt: &mut DataType) { self.remap_rules(dt); match dt { DataType::Primitive(_) | DataType::Generic(_) => {} DataType::List(list) => self.remap_internal(&mut list.ty), DataType::Map(map) => { self.remap_internal(map.key_ty_mut()); self.remap_internal(map.value_ty_mut()); } DataType::Struct(s) => self.remap_fields(&mut s.fields), DataType::Enum(e) => { for (_, variant) in &mut e.variants { self.remap_fields(&mut variant.fields); } } DataType::Tuple(tuple) => { for dt in &mut tuple.elements { self.remap_internal(dt); } } DataType::Nullable(dt) => self.remap_internal(dt), DataType::Intersection(dts) => { for dt in dts { self.remap_internal(dt); } } DataType::Reference(r) => self.remap_reference(r), } } fn remap_rules(&self, dt: &mut DataType) { for (from, to) in &self.rules { if *dt == *from { *dt = to.clone(); } } } fn remap_fields(&self, fields: &mut Fields) { match fields { Fields::Unit => {} Fields::Unnamed(fields) => { for field in &mut fields.fields { if let Some(dt) = &mut field.ty { self.remap_internal(dt); } } } Fields::Named(fields) => { for (_, field) in &mut fields.fields { if let Some(dt) = &mut field.ty { self.remap_internal(dt); } } } } } fn remap_reference(&self, reference: &mut Reference) { let Reference::Named(reference) = reference else { return; }; match &mut reference.inner { NamedReferenceType::Recursive => {} NamedReferenceType::Inline { dt, .. } => self.remap_internal(dt), NamedReferenceType::Reference { generics, .. } => { for (_, dt) in generics { self.remap_internal(dt); } } } } } #[cfg(test)] mod tests { use specta::{ Types, datatype::{DataType, Field, List, NamedDataType, Primitive, Struct, Tuple}, }; use super::Remapper; #[test] fn remaps_multiple_rules_in_one_crawl() { let dt = DataType::Tuple(Tuple::new(vec![ Primitive::u32.into(), Primitive::i32.into(), ])); let remapped = Remapper::new() .rule(Primitive::u32.into(), Primitive::str.into()) .rule(Primitive::i32.into(), Primitive::bool.into()) .remap_dt(dt); assert_eq!( remapped, DataType::Tuple(Tuple::new(vec![ Primitive::str.into(), Primitive::bool.into() ])) ); } #[test] fn rules_are_piped_in_registration_order() { let remapped = Remapper::new() .rule(Primitive::u32.into(), Primitive::i32.into()) .rule(Primitive::i32.into(), Primitive::bool.into()) .remap_dt(Primitive::u32.into()); assert_eq!(remapped, Primitive::bool.into()); } #[test] fn replacement_is_recrawled() { let remapped = Remapper::new() .rule( Primitive::u32.into(), DataType::List(List::new(Primitive::i32.into())), ) .rule(Primitive::i32.into(), Primitive::bool.into()) .remap_dt(Primitive::u32.into()); assert_eq!(remapped, DataType::List(List::new(Primitive::bool.into()))); } #[test] fn remaps_named_type_bodies() { let mut types = Types::default(); NamedDataType::new("User", &mut types, |_, ty| { ty.ty = Some( Struct::named() .field("id", Field::new(Primitive::u32.into())) .field("active", Field::new(Primitive::i32.into())) .build(), ); }); let types = Remapper::new() .rule(Primitive::u32.into(), Primitive::str.into()) .rule(Primitive::i32.into(), Primitive::bool.into()) .remap_types(types); let debug = format!("{types:?}"); assert!(debug.contains("Primitive(str)")); assert!(debug.contains("Primitive(bool)")); } } ================================================ FILE: specta-util/src/selection.rs ================================================ // TODO: Should `specta-util` rexport `specta` for these macros??? /// Specta compatible selection of struct fields. /// /// ```ignore /// use specta_typescript::legacy::inline_ref; /// use specta_util::selection; /// /// #[derive(Clone)] /// struct MyStruct { /// name: String, /// age: i32, /// is_verified: bool, /// password: String, /// } /// /// let person = MyStruct { /// name: "Monty".into(), /// age: 7, /// is_verified: true, /// password: "password".into(), /// }; /// let people = vec![person.clone(), person.clone()]; /// /// // Selection creates an anonymous struct with the subset of fields you want. /// assert_eq!(inline_ref(&selection!(person, { /// name, /// age /// }), &Default::default()).unwrap(), "{ name: string; age: number }"); /// /// // You can apply the selection to an array. /// assert_eq!(inline_ref(&selection!(people, [{ /// name, /// age /// }]), &Default::default()).unwrap(), "{ name: string; age: number }[]"); /// ``` // TODO: better docs w/ example #[macro_export] macro_rules! selection { ( $s:expr, { $($n:ident),+ $(,)? } as $name:ident ) => {{ #[allow(non_camel_case_types)] mod selection { #[derive(serde::Serialize, specta::Type)] #[specta(inline)] pub struct $name<$($n,)*> { $(pub $n: $n),* } } use selection::$name; #[allow(non_camel_case_types)] $name { $($n: $s.$n,)* } }}; ( $s:expr, { $($n:ident),+ $(,)? } ) => {{ $crate::selection!($s, { $($n),+ } as Selection) }}; ( $s:expr, [{ $($n:ident),+ $(,)? }] as $name:ident ) => {{ #[allow(non_camel_case_types)] mod selection { #[derive(serde::Serialize, specta::Type)] #[specta(inline)] pub struct $name<$($n,)*> { $(pub $n: $n),* } } use selection::$name; #[allow(non_camel_case_types)] $s.into_iter().map(|v| $name { $($n: v.$n,)* }).collect::>() }}; ( $s:expr, [{ $($n:ident),+ $(,)? }] ) => {{ $crate::selection!($s, [{ $($n),+ }] as Selection) }}; } ================================================ FILE: specta-zod/Cargo.toml ================================================ [package] name = "specta-zod" description = "Export your Rust types to Zod schemas for TypeScript" version = "0.0.2" authors = ["Oscar Beaumont "] edition = "2024" license = "MIT" repository = "https://github.com/specta-rs/specta" documentation = "https://docs.rs/specta-zod/latest/specta-zod" keywords = ["async", "specta", "rspc", "typescript", "typesafe"] categories = ["web-programming", "asynchronous"] readme = "../README.md" # /bin/sh RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features [package.metadata."docs.rs"] all-features = true rustdoc-args = ["--cfg", "docsrs"] [lints] workspace = true [features] default = [] # Implement `serde::Serialize` for Zod-specific wrapper types (Any, Unknown, Never) serde = ["dep:serde"] [dependencies] specta = { version = "=2.0.0-rc.24", path = "../specta" } serde = { version = "1", default-features = false, optional = true } specta-typescript = { version = "=0.0.11", path = "../specta-typescript" } # TODO: Don't depend on serde specta-serde = { version = "=0.0.11", path = "../specta-serde" } thiserror = "2" # TODO: Remove this [dev-dependencies] specta-util = { path = "../specta-util" } ================================================ FILE: specta-zod/src/error.rs ================================================ use std::{borrow::Cow, error, fmt, io, panic::Location, path::PathBuf}; use specta::datatype::OpaqueReference; use crate::Layout; /// The error type for the Zod exporter. #[non_exhaustive] pub struct Error { kind: ErrorKind, } type FrameworkSource = Box; #[allow(dead_code)] enum ErrorKind { BigIntForbidden { path: String, }, InvalidName { path: String, name: Cow<'static, str>, }, ForbiddenName { path: String, name: Cow<'static, str>, }, DuplicateTypeName { name: Cow<'static, str>, first: String, second: String, }, Io(io::Error), ReadDir { path: PathBuf, source: io::Error, }, Metadata { path: PathBuf, source: io::Error, }, RemoveFile { path: PathBuf, source: io::Error, }, RemoveDir { path: PathBuf, source: io::Error, }, UnsupportedOpaqueReference(OpaqueReference), DanglingNamedReference { reference: String, }, Framework { message: Cow<'static, str>, source: FrameworkSource, }, UnableToExport(Layout), } impl Error { /// Construct an error for framework-specific logic. pub fn framework( message: impl Into>, source: impl Into>, ) -> Self { Self { kind: ErrorKind::Framework { message: message.into(), source: source.into(), }, } } pub(crate) fn bigint_forbidden(path: String) -> Self { Self { kind: ErrorKind::BigIntForbidden { path }, } } pub(crate) fn invalid_name(path: String, name: impl Into>) -> Self { Self { kind: ErrorKind::InvalidName { path, name: name.into(), }, } } pub(crate) fn forbidden_name(path: String, name: impl Into>) -> Self { Self { kind: ErrorKind::ForbiddenName { path, name: name.into(), }, } } pub(crate) fn duplicate_type_name( name: Cow<'static, str>, first: Location<'static>, second: Location<'static>, ) -> Self { Self { kind: ErrorKind::DuplicateTypeName { name, first: format_location(first), second: format_location(second), }, } } pub(crate) fn read_dir(path: PathBuf, source: io::Error) -> Self { Self { kind: ErrorKind::ReadDir { path, source }, } } pub(crate) fn metadata(path: PathBuf, source: io::Error) -> Self { Self { kind: ErrorKind::Metadata { path, source }, } } pub(crate) fn remove_file(path: PathBuf, source: io::Error) -> Self { Self { kind: ErrorKind::RemoveFile { path, source }, } } pub(crate) fn remove_dir(path: PathBuf, source: io::Error) -> Self { Self { kind: ErrorKind::RemoveDir { path, source }, } } pub(crate) fn unsupported_opaque_reference(reference: OpaqueReference) -> Self { Self { kind: ErrorKind::UnsupportedOpaqueReference(reference), } } pub(crate) fn dangling_named_reference(reference: String) -> Self { Self { kind: ErrorKind::DanglingNamedReference { reference }, } } pub(crate) fn unable_to_export(layout: Layout) -> Self { Self { kind: ErrorKind::UnableToExport(layout), } } pub(crate) fn format( message: impl Into>, source: specta::FormatError, ) -> Self { Self { kind: ErrorKind::Framework { message: message.into(), source, }, } } } impl From for Error { fn from(error: io::Error) -> Self { Self { kind: ErrorKind::Io(error), } } } impl From for Error { fn from(source: std::fmt::Error) -> Self { Self { kind: ErrorKind::Framework { message: Cow::Borrowed("Formatting error"), source: Box::new(source), }, } } } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.kind { ErrorKind::BigIntForbidden { path } => write!( f, "Attempted to export {path:?} but Specta configuration forbids exporting BigInt types (i64, u64, i128, u128) because serializer compatibility is unknown. Configure `BigIntExportBehavior` to allow this." ), ErrorKind::InvalidName { path, name } => write!( f, "Attempted to export {path:?} but was unable to due to name {name:?} containing an invalid character. Try renaming it or using `#[specta(rename = \"new_name\")]`" ), ErrorKind::ForbiddenName { path, name } => write!( f, "Attempted to export {path:?} but was unable to due to name {name:?} being a reserved keyword in TypeScript. Try renaming it or using `#[specta(rename = \"new_name\")]`" ), ErrorKind::DuplicateTypeName { name, first, second, } => write!( f, "Detected multiple types with the same name: {name:?} at {first} and {second}" ), ErrorKind::Io(err) => write!(f, "IO error: {err}"), ErrorKind::ReadDir { path, source } => { write!(f, "Failed to read directory '{}': {source}", path.display()) } ErrorKind::Metadata { path, source } => { write!( f, "Failed to read metadata for '{}': {source}", path.display() ) } ErrorKind::RemoveFile { path, source } => { write!(f, "Failed to remove file '{}': {source}", path.display()) } ErrorKind::RemoveDir { path, source } => { write!( f, "Failed to remove directory '{}': {source}", path.display() ) } ErrorKind::UnsupportedOpaqueReference(reference) => write!( f, "Found unsupported opaque reference '{}'. It is not supported by the Zod exporter.", reference.type_name() ), ErrorKind::DanglingNamedReference { reference } => write!( f, "Found dangling named reference {reference}. The referenced type is missing from the resolved type collection." ), ErrorKind::Framework { message, source } => { let source = source.to_string(); if message.is_empty() && source.is_empty() { write!(f, "Framework error") } else if source.is_empty() { write!(f, "Framework error: {message}") } else { write!(f, "Framework error: {message}: {source}") } } ErrorKind::UnableToExport(layout) => { write!( f, "Unable to export layout {layout} with `Zod::export`. Use `Zod::export_to` or change layout." ) } } } } impl fmt::Debug for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(self, f) } } impl error::Error for Error { fn source(&self) -> Option<&(dyn error::Error + 'static)> { match &self.kind { ErrorKind::Io(error) => Some(error), ErrorKind::ReadDir { source, .. } | ErrorKind::Metadata { source, .. } | ErrorKind::RemoveFile { source, .. } | ErrorKind::RemoveDir { source, .. } => Some(source), ErrorKind::Framework { source, .. } => Some(source.as_ref()), _ => None, } } } fn format_location(location: Location<'static>) -> String { format!( "{}:{}:{}", location.file(), location.line(), location.column() ) } ================================================ FILE: specta-zod/src/lib.rs ================================================ //! [Zod](https://zod.dev) language exporter for [Specta](specta). //! //!
//! This crate is still in active development and is not yet ready for general purpose use! //!
//! #![cfg_attr(docsrs, feature(doc_cfg))] #![doc( html_logo_url = "https://github.com/specta-rs/specta/raw/main/.github/logo-128.png", html_favicon_url = "https://github.com/specta-rs/specta/raw/main/.github/logo-128.png" )] mod error; mod opaque; pub mod primitives; mod references; mod reserved_names; mod types; mod zod; pub use error::Error; pub use opaque::define; pub use types::{Any, Never, Unknown}; pub use zod::{BigIntExportBehavior, FrameworkExporter, Layout, Zod}; ================================================ FILE: specta-zod/src/opaque.rs ================================================ use std::borrow::Cow; use specta::datatype::Reference; #[derive(PartialEq, Eq, Hash)] pub(crate) struct Define(pub(crate) Cow<'static, str>); #[derive(PartialEq, Eq, Hash)] pub(crate) struct Any; #[derive(PartialEq, Eq, Hash)] pub(crate) struct Unknown; #[derive(PartialEq, Eq, Hash)] pub(crate) struct Never; /// Define a custom Zod expression which can be used as a `DataType::Reference`. /// /// This is an advanced feature which should be used with caution. pub fn define(raw: impl Into>) -> Reference { Reference::opaque(Define(raw.into())) } ================================================ FILE: specta-zod/src/primitives.rs ================================================ //! Primitives provide building blocks for Specta-based libraries. use std::{borrow::Cow, fmt::Write as _}; use specta::{ Types, datatype::{ DataType, Enum, Fields, GenericReference, List, Map, NamedDataType, NamedReference, NamedReferenceType, OpaqueReference, Primitive, Reference, Struct, Tuple, }, }; use crate::{ BigIntExportBehavior, Error, Layout, Zod, opaque, reserved_names::RESERVED_TYPE_NAMES, }; pub(crate) type TypeRenderStack = Vec<(Cow<'static, str>, Cow<'static, str>)>; fn named_reference_generics(r: &NamedReference) -> Result<&[(GenericReference, DataType)], Error> { match &r.inner { NamedReferenceType::Reference { generics, .. } => Ok(generics), NamedReferenceType::Inline { .. } => Ok(&[]), NamedReferenceType::Recursive => Err(Error::dangling_named_reference(format!( "recursive inline named reference {r:?}" ))), } } fn named_reference_ty<'a>(types: &'a Types, r: &'a NamedReference) -> Result<&'a DataType, Error> { match &r.inner { NamedReferenceType::Reference { .. } => types .get(r) .and_then(|ndt| ndt.ty.as_ref()) .ok_or_else(|| Error::dangling_named_reference(format!("{r:?}"))), NamedReferenceType::Inline { dt, .. } => Ok(dt), NamedReferenceType::Recursive => Err(Error::dangling_named_reference(format!( "recursive inline named reference {r:?}" ))), } } /// Generate a group of `export const XSchema = ...` declarations for named types. pub fn export<'a>( exporter: &dyn AsRef, types: &Types, ndts: impl Iterator, indent: &str, ) -> Result { let mut s = String::new(); let mut type_render_stack = TypeRenderStack::new(); export_internal( &mut s, exporter.as_ref(), types, ndts, indent, &mut type_render_stack, )?; Ok(s) } pub(crate) fn export_internal<'a>( s: &mut String, exporter: &Zod, types: &Types, ndts: impl Iterator, indent: &str, type_render_stack: &mut TypeRenderStack, ) -> Result<(), Error> { for (index, ndt) in ndts.enumerate() { if index != 0 { s.push('\n'); } export_single_internal(s, exporter, types, ndt, indent, type_render_stack)?; } Ok(()) } fn export_single_internal( s: &mut String, exporter: &Zod, types: &Types, ndt: &NamedDataType, indent: &str, type_render_stack: &mut TypeRenderStack, ) -> Result<(), Error> { let base_name = exported_type_name(exporter, ndt); let name_path = if ndt.module_path.is_empty() { ndt.name.to_string() } else { format!("{}::{}", ndt.module_path, ndt.name) }; validate_type_name(&base_name, name_path)?; let schema_name = format!("{base_name}Schema"); let Some(ty) = &ndt.ty else { return Ok(()); }; type_render_stack.push((ndt.module_path.clone(), ndt.name.clone())); let result = (|| { if ndt.generics.is_empty() { let mut schema_expr = String::new(); datatype( &mut schema_expr, exporter, types, ty, vec![ndt.name.clone()], &[], false, type_render_stack, )?; writeln!(s, "{indent}export const {schema_name} = {schema_expr};")?; writeln!( s, "{indent}export type {base_name} = z.infer;" )?; return Ok(()); } let generic_names = ndt .generics .iter() .map(|generic| generic.name.as_ref().to_string()) .collect::>(); let generic_params = generic_names .iter() .map(|name| format!("{name} extends z.ZodTypeAny")) .collect::>() .join(", "); let fn_params = generic_names.join(", "); let mut schema_expr = String::new(); datatype( &mut schema_expr, exporter, types, ty, vec![ndt.name.clone()], &[], false, type_render_stack, )?; writeln!( s, "{indent}export const {schema_name} = <{generic_params}>({fn_params}) => {schema_expr};" )?; let alias_params = generic_names.join(", "); let infer_args = generic_names .iter() .map(|name| format!("z.ZodType<{name}>")) .collect::>() .join(", "); writeln!( s, "{indent}export type {base_name}<{alias_params}> = z.infer>>;" )?; Ok(()) })(); type_render_stack.pop(); result } /// Generate an inline Zod expression for a [`DataType`]. /// /// If you are using a custom format such as `specta_serde::Format`, this helper does not apply /// datatype mapping automatically. Map both the full [`Types`] graph and any top-level /// [`DataType`] values before calling this helper. pub fn inline(exporter: &dyn AsRef, types: &Types, dt: &DataType) -> Result { let mut s = String::new(); let mut type_render_stack = TypeRenderStack::new(); datatype( &mut s, exporter.as_ref(), types, dt, vec![], &[], false, &mut type_render_stack, )?; Ok(s) } /// Generate a Zod expression for a [`Reference`]. /// /// If you are using a custom format such as `specta_serde::Format`, this helper does not apply /// datatype mapping automatically. pub fn reference(exporter: &dyn AsRef, types: &Types, r: &Reference) -> Result { let mut s = String::new(); let mut type_render_stack = TypeRenderStack::new(); reference_dt( &mut s, exporter.as_ref(), types, r, vec![], &[], &mut type_render_stack, )?; Ok(s) } pub(crate) fn datatype_with_inline_attr( s: &mut String, exporter: &Zod, types: &Types, dt: &DataType, location: Vec>, generics: &[(GenericReference, DataType)], inline: bool, type_render_stack: &mut TypeRenderStack, ) -> Result<(), Error> { datatype( s, exporter, types, dt, location, generics, inline, type_render_stack, ) } fn datatype( s: &mut String, exporter: &Zod, types: &Types, dt: &DataType, location: Vec>, generics: &[(GenericReference, DataType)], force_inline_ref: bool, type_render_stack: &mut TypeRenderStack, ) -> Result<(), Error> { match dt { DataType::Primitive(p) => s.push_str(primitive_dt(&exporter.bigint, p, location)?), DataType::List(l) => list_dt(s, exporter, types, l, location, generics, type_render_stack)?, DataType::Map(m) => map_dt(s, exporter, types, m, location, generics, type_render_stack)?, DataType::Nullable(def) => { let mut inner = String::new(); datatype( &mut inner, exporter, types, def, location, generics, force_inline_ref, type_render_stack, )?; write!(s, "{inner}.nullable()")?; } DataType::Struct(st) => struct_dt( s, exporter, types, st, location, generics, type_render_stack, )?, DataType::Enum(enm) => enum_dt( s, exporter, types, enm, location, generics, type_render_stack, )?, DataType::Tuple(tuple) => tuple_dt( s, exporter, types, tuple, location, generics, type_render_stack, )?, DataType::Reference(r) => { if force_inline_ref { match r { Reference::Named(named) => { let ty = named_reference_ty(types, named)?; let reference_generics = named_reference_generics(named)?; datatype( s, exporter, types, ty, location, reference_generics, false, type_render_stack, )?; } _ => { reference_dt(s, exporter, types, r, location, generics, type_render_stack)? } } } else { reference_dt(s, exporter, types, r, location, generics, type_render_stack)?; } } DataType::Generic(g) => generic_dt(s, g), DataType::Intersection(intersection) => { let mut parts = Vec::with_capacity(intersection.len()); for ty in intersection { let mut part = String::new(); datatype( &mut part, exporter, types, ty, location.clone(), generics, false, type_render_stack, )?; parts.push(part); } s.push_str(&parts.join(".and(")); for _ in 1..parts.len() { s.push(')'); } } } Ok(()) } fn primitive_dt( b: &BigIntExportBehavior, p: &Primitive, location: Vec>, ) -> Result<&'static str, Error> { use Primitive::*; Ok(match p { i8 | i16 | i32 | u8 | u16 | u32 | f16 | f32 | f64 | f128 => "z.number()", usize | isize | i64 | u64 | i128 | u128 => match b { BigIntExportBehavior::String => "z.string()", BigIntExportBehavior::Number => "z.number()", BigIntExportBehavior::BigInt => "z.bigint()", BigIntExportBehavior::Fail => return Err(Error::bigint_forbidden(location.join("."))), }, Primitive::bool => "z.boolean()", str | char => "z.string()", }) } fn list_dt( s: &mut String, exporter: &Zod, types: &Types, l: &List, location: Vec>, generics: &[(GenericReference, DataType)], type_render_stack: &mut TypeRenderStack, ) -> Result<(), Error> { let mut dt = String::new(); datatype( &mut dt, exporter, types, &l.ty, location, generics, false, type_render_stack, )?; if let Some(length) = l.length { s.push_str("z.tuple(["); for n in 0..length { if n != 0 { s.push_str(", "); } s.push_str(&dt); } s.push_str("])"); } else { write!(s, "z.array({dt})")?; } Ok(()) } fn map_dt( s: &mut String, exporter: &Zod, types: &Types, m: &Map, location: Vec>, generics: &[(GenericReference, DataType)], type_render_stack: &mut TypeRenderStack, ) -> Result<(), Error> { let mut key = String::new(); datatype( &mut key, exporter, types, m.key_ty(), location.clone(), generics, false, type_render_stack, )?; let mut value = String::new(); datatype( &mut value, exporter, types, m.value_ty(), location, generics, false, type_render_stack, )?; write!(s, "z.record({key}, {value})")?; Ok(()) } fn tuple_dt( s: &mut String, exporter: &Zod, types: &Types, t: &Tuple, location: Vec>, generics: &[(GenericReference, DataType)], type_render_stack: &mut TypeRenderStack, ) -> Result<(), Error> { match t.elements.as_slice() { [] => s.push_str("z.null()"), elements => { s.push_str("z.tuple(["); for (i, dt) in elements.iter().enumerate() { if i != 0 { s.push_str(", "); } datatype( s, exporter, types, dt, location.clone(), generics, false, type_render_stack, )?; } s.push_str("])"); } } Ok(()) } fn struct_dt( s: &mut String, exporter: &Zod, types: &Types, st: &Struct, location: Vec>, generics: &[(GenericReference, DataType)], type_render_stack: &mut TypeRenderStack, ) -> Result<(), Error> { match &st.fields { Fields::Unit => s.push_str("z.null()"), Fields::Unnamed(unnamed) => { let fields = unnamed .fields .iter() .filter_map(|field| field.ty.as_ref().map(|ty| (field, ty))) .collect::>(); match fields.as_slice() { [] => s.push_str("z.tuple([])"), [(field, ty)] if unnamed.fields.len() == 1 => { datatype_with_inline_attr( s, exporter, types, ty, location, generics, false, type_render_stack, )?; } fields => { s.push_str("z.tuple(["); for (i, (_field, ty)) in fields.iter().enumerate() { if i != 0 { s.push_str(", "); } datatype_with_inline_attr( s, exporter, types, ty, location.clone(), generics, false, type_render_stack, )?; } s.push_str("])"); } } } Fields::Named(named) => { let all_fields = named .fields .iter() .filter_map(|(name, field)| field.ty.as_ref().map(|ty| (name, field, ty))) .collect::>(); if all_fields.is_empty() { s.push_str("z.object({}).strict()"); return Ok(()); } let non_flattened = all_fields.iter().collect::>(); let mut schema = String::from("z.object({"); for (name, field, ty) in &non_flattened { let key = sanitise_key(name.as_ref()); write!(schema, "\n\t{key}: ")?; let mut value = String::new(); datatype_with_inline_attr( &mut value, exporter, types, ty, location.clone(), generics, false, type_render_stack, )?; if field.optional { write!(schema, "{value}.optional(),")?; } else { write!(schema, "{value},")?; } } if !non_flattened.is_empty() { schema.push('\n'); } schema.push_str("})"); s.push_str(&schema); } } Ok(()) } fn enum_dt( s: &mut String, exporter: &Zod, types: &Types, e: &Enum, location: Vec>, generics: &[(GenericReference, DataType)], type_render_stack: &mut TypeRenderStack, ) -> Result<(), Error> { let variants = e .variants .iter() .filter(|(_, variant)| !variant.skip) .map(|(name, variant)| { enum_variant_dt( exporter, types, name.as_ref(), variant, location.clone(), generics, type_render_stack, ) }) .collect::, _>>()?; let mut variants = variants.into_iter().flatten().collect::>(); if variants.is_empty() { s.push_str("z.never()"); return Ok(()); } variants.sort(); variants.dedup(); if variants.len() == 1 { s.push_str(&variants[0]); } else { write!(s, "z.union([{}])", variants.join(", "))?; } Ok(()) } fn enum_variant_dt( exporter: &Zod, types: &Types, name: &str, variant: &specta::datatype::Variant, location: Vec>, generics: &[(GenericReference, DataType)], type_render_stack: &mut TypeRenderStack, ) -> Result, Error> { match &variant.fields { Fields::Unit => Ok(Some(format!("z.literal(\"{}\")", escape_string(name)))), Fields::Named(named) => { if named.fields.iter().all(|(_, field)| field.ty.is_none()) { return Ok(Some("z.object({}).strict()".to_string())); } let mut schema = String::from("z.object({"); let mut has_field = false; let mut flattened_sections = Vec::new(); for (field_name, field) in &named.fields { let Some(ty) = field.ty.as_ref() else { continue; }; if false { let mut value = String::new(); datatype_with_inline_attr( &mut value, exporter, types, ty, location.clone(), generics, false, type_render_stack, )?; flattened_sections.push(value); continue; } has_field = true; let mut value = String::new(); datatype_with_inline_attr( &mut value, exporter, types, ty, location.clone(), generics, false, type_render_stack, )?; let key = sanitise_key(field_name); if field.optional { write!(schema, "\n\t{key}: {value}.optional(),")?; } else { write!(schema, "\n\t{key}: {value},")?; } } if has_field { schema.push('\n'); } schema.push_str("})"); if flattened_sections.is_empty() { return Ok(Some(schema)); } let mut sections = vec![schema]; sections.extend(flattened_sections); let mut out = String::new(); out.push_str(§ions.join(".and(")); for _ in 1..sections.len() { out.push(')'); } Ok(Some(out)) } Fields::Unnamed(unnamed) => { let fields = unnamed .fields .iter() .filter_map(|field| field.ty.as_ref().map(|ty| (field, ty))) .collect::>(); Ok(match fields.as_slice() { [] => { if unnamed.fields.is_empty() { Some("z.tuple([])".to_string()) } else { None } } [(field, ty)] if unnamed.fields.len() == 1 => { let mut out = String::new(); datatype_with_inline_attr( &mut out, exporter, types, ty, location, generics, false, type_render_stack, )?; Some(out) } fields => { let mut out = String::from("z.tuple(["); for (i, (_field, ty)) in fields.iter().enumerate() { if i != 0 { out.push_str(", "); } let mut item = String::new(); datatype_with_inline_attr( &mut item, exporter, types, ty, location.clone(), generics, false, type_render_stack, )?; out.push_str(&item); } out.push_str("])"); Some(out) } }) } } } fn reference_dt( s: &mut String, exporter: &Zod, types: &Types, r: &Reference, location: Vec>, generics: &[(GenericReference, DataType)], type_render_stack: &mut TypeRenderStack, ) -> Result<(), Error> { match r { Reference::Named(r) => { reference_named_dt(s, exporter, types, r, location, generics, type_render_stack) } Reference::Opaque(r) => reference_opaque_dt(s, r), } } fn generic_dt(s: &mut String, g: &GenericReference) { s.push_str(g.name()); } fn reference_opaque_dt(s: &mut String, r: &OpaqueReference) -> Result<(), Error> { if let Some(def) = r.downcast_ref::() { s.push_str(&def.0); return Ok(()); } if r.downcast_ref::().is_some() { s.push_str("z.any()"); return Ok(()); } if r.downcast_ref::().is_some() { s.push_str("z.unknown()"); return Ok(()); } if r.downcast_ref::().is_some() { s.push_str("z.never()"); return Ok(()); } Err(Error::unsupported_opaque_reference(r.clone())) } fn reference_named_dt( s: &mut String, exporter: &Zod, types: &Types, r: &NamedReference, location: Vec>, generics: &[(GenericReference, DataType)], type_render_stack: &mut TypeRenderStack, ) -> Result<(), Error> { let ndt = types .get(r) .ok_or_else(|| Error::dangling_named_reference(format!("{r:?}")))?; if matches!(r.inner, NamedReferenceType::Inline { .. }) { let ty = named_reference_ty(types, r)?; let reference_generics = named_reference_generics(r)?; return datatype( s, exporter, types, ty, location, reference_generics, false, type_render_stack, ); } crate::references::track_nr(r); let schema_name = match exporter.layout { Layout::FlatFile => format!("{}Schema", ndt.name), Layout::ModulePrefixedName => { let mut name = ndt.module_path.split("::").collect::>().join("_"); if !name.is_empty() { name.push('_'); } name.push_str(&ndt.name); name.push_str("Schema"); name } Layout::Files => { let current_module_path = crate::references::current_module_path().unwrap_or_default(); let base = format!("{}Schema", ndt.name); if ndt.module_path == current_module_path { base } else { format!("{}.{}", crate::zod::module_alias(&ndt.module_path), base) } } }; let should_lazy = type_render_stack .iter() .any(|(module, name)| module == &ndt.module_path && name == &ndt.name); let mut reference_expr = schema_name; let reference_generics = match &r.inner { NamedReferenceType::Recursive => &[], _ => named_reference_generics(r)?, }; if !reference_generics.is_empty() { let scoped_generics = generics .iter() .filter(|(parent_generic, _)| { !reference_generics .iter() .any(|(child_generic, _)| child_generic == parent_generic) }) .cloned() .collect::>(); reference_expr.push('('); for (i, (_, v)) in reference_generics.iter().enumerate() { if i != 0 { reference_expr.push_str(", "); } let mut generic_schema = String::new(); datatype( &mut generic_schema, exporter, types, v, vec![], &scoped_generics, false, type_render_stack, )?; reference_expr.push_str(&generic_schema); } reference_expr.push(')'); } if should_lazy { write!(s, "z.lazy(() => {reference_expr})")?; } else { s.push_str(&reference_expr); } Ok(()) } fn exported_type_name(exporter: &Zod, ndt: &NamedDataType) -> Cow<'static, str> { match exporter.layout { Layout::FlatFile | Layout::Files => ndt.name.clone(), Layout::ModulePrefixedName => { let mut s = ndt.module_path.split("::").collect::>().join("_"); if !s.is_empty() { s.push('_'); } s.push_str(&ndt.name); Cow::Owned(s) } } } fn validate_type_name(name: &str, path: String) -> Result<(), Error> { if RESERVED_TYPE_NAMES.contains(&name) { return Err(Error::forbidden_name(path, name.to_string())); } let mut chars = name.chars(); let Some(first) = chars.next() else { return Err(Error::invalid_name(path, name.to_string())); }; if !(first.is_ascii_alphabetic() || first == '_' || first == '$') { return Err(Error::invalid_name(path, name.to_string())); } if chars.any(|ch| !(ch.is_ascii_alphanumeric() || ch == '_' || ch == '$')) { return Err(Error::invalid_name(path, name.to_string())); } Ok(()) } fn sanitise_key(field_name: &str) -> String { if is_identifier(field_name) { field_name.to_string() } else { format!("\"{}\"", escape_string(field_name)) } } fn is_identifier(name: &str) -> bool { let mut chars = name.chars(); let Some(first) = chars.next() else { return false; }; (first.is_ascii_alphabetic() || first == '_' || first == '$') && chars.all(|ch| ch.is_ascii_alphanumeric() || ch == '_' || ch == '$') } fn escape_string(value: &str) -> Cow<'_, str> { if !value .chars() .any(|ch| ch == '"' || ch == '\\' || ch == '\n' || ch == '\r' || ch == '\t') { return Cow::Borrowed(value); } let mut escaped = String::with_capacity(value.len()); for ch in value.chars() { match ch { '"' => escaped.push_str(r#"\""#), '\\' => escaped.push_str(r#"\\"#), '\n' => escaped.push_str(r#"\n"#), '\r' => escaped.push_str(r#"\r"#), '\t' => escaped.push_str(r#"\t"#), _ => escaped.push(ch), } } Cow::Owned(escaped) } ================================================ FILE: specta-zod/src/references.rs ================================================ use std::{cell::RefCell, collections::HashSet}; use specta::datatype::NamedReference; thread_local! { static REFERENCED_TYPES: RefCell>>> = const { RefCell::new(None) }; static MODULE_PATH_CONTEXT: RefCell> = const { RefCell::new(Vec::new()) }; } pub(crate) fn with_module_path(module_path: &str, func: impl FnOnce() -> R) -> R { struct Guard; impl Drop for Guard { fn drop(&mut self) { MODULE_PATH_CONTEXT.with_borrow_mut(|ctx| { ctx.pop(); }); } } MODULE_PATH_CONTEXT.with_borrow_mut(|ctx| { ctx.push(module_path.to_string()); }); let guard = Guard; let result = func(); std::mem::forget(guard); MODULE_PATH_CONTEXT.with_borrow_mut(|ctx| { ctx.pop(); }); result } pub(crate) fn current_module_path() -> Option { MODULE_PATH_CONTEXT.with_borrow(|ctx| ctx.last().cloned()) } /// Collect all named references created in the closure body. pub fn collect_references(func: impl FnOnce() -> R) -> (R, HashSet) { struct Guard; impl Drop for Guard { fn drop(&mut self) { REFERENCED_TYPES.with_borrow_mut(|types| { if let Some(v) = types { if v.len() == 1 { *types = None; } else { v.pop(); } } }) } } REFERENCED_TYPES.with_borrow_mut(|v| { if let Some(v) = v { v.push(Default::default()); } else { *v = Some(vec![Default::default()]); } }); let guard = Guard; let result = func(); std::mem::forget(guard); ( result, REFERENCED_TYPES.with_borrow_mut(|types| { types .as_mut() .expect("REFERENCED_TYPES is unset but it should be set") .pop() .expect("REFERENCED_TYPES is missing a valid collection context") }), ) } pub(crate) fn track_nr(r: &NamedReference) { REFERENCED_TYPES.with_borrow_mut(|ctxs| { if let Some(ctxs) = ctxs { for ctx in ctxs { ctx.insert(r.clone()); } } }); } ================================================ FILE: specta-zod/src/reserved_names.rs ================================================ pub(crate) const RESERVED_TYPE_NAMES: &[&str] = &[ "break", "case", "catch", "class", "const", "continue", "debugger", "default", "delete", "do", "else", "enum", "export", "extends", "false", "finally", "for", "function", "if", "import", "in", "instanceof", "new", "null", "return", "super", "switch", "this", "throw", "true", "try", "typeof", "var", "void", "while", "with", "as", "implements", "interface", "let", "package", "private", "protected", "public", "static", "yield", "type", "from", "of", ]; ================================================ FILE: specta-zod/src/types.rs ================================================ use std::fmt::Debug; use specta::{ Type, Types, datatype::{DataType, Reference}, }; use crate::opaque; /// Cast a Rust type to `z.any()`. pub struct Any(T); impl Type for Any { fn definition(_: &mut Types) -> DataType { DataType::Reference(Reference::opaque(opaque::Any)) } } impl Debug for Any { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_tuple("Any").field(&self.0).finish() } } impl Clone for Any { fn clone(&self) -> Self { Self(self.0.clone()) } } impl Default for Any { fn default() -> Self { Self(T::default()) } } #[cfg(feature = "serde")] #[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl serde::Serialize for Any { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { T::serialize(&self.0, serializer) } } /// Cast a Rust type to `z.unknown()`. pub struct Unknown(T); impl Type for Unknown { fn definition(_: &mut Types) -> DataType { DataType::Reference(Reference::opaque(opaque::Unknown)) } } impl Debug for Unknown { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_tuple("Unknown").field(&self.0).finish() } } impl Clone for Unknown { fn clone(&self) -> Self { Self(self.0.clone()) } } impl Default for Unknown { fn default() -> Self { Self(T::default()) } } #[cfg(feature = "serde")] #[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl serde::Serialize for Unknown { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { T::serialize(&self.0, serializer) } } /// Cast a Rust type to `z.never()`. pub struct Never(T); impl Type for Never { fn definition(_: &mut Types) -> DataType { DataType::Reference(Reference::opaque(opaque::Never)) } } impl Debug for Never { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_tuple("Never").field(&self.0).finish() } } impl Clone for Never { fn clone(&self) -> Self { Self(self.0.clone()) } } impl Default for Never { fn default() -> Self { Self(T::default()) } } #[cfg(feature = "serde")] #[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl serde::Serialize for Never { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { T::serialize(&self.0, serializer) } } ================================================ FILE: specta-zod/src/zod.rs ================================================ use std::{ borrow::Cow, collections::{BTreeMap, BTreeSet, HashMap, HashSet}, fmt, ops::Deref, path::{Path, PathBuf}, sync::Arc, }; use specta::{ Format, Types, datatype::{DataType, Fields, NamedDataType, Reference}, }; use crate::{Error, primitives, references}; /// Allows configuring how Specta's Zod exporter will deal with BigInt types ([i64], [i128] etc). #[derive(Debug, Clone, Copy, Default, PartialEq, Eq)] pub enum BigIntExportBehavior { /// Export BigInt as a Zod string schema. String, /// Export BigInt as a Zod number schema. Number, /// Export BigInt as a Zod bigint schema. BigInt, /// Abort export on BigInt usage. #[default] Fail, } /// Allows configuring the format of generated output. #[derive(Debug, Clone, Copy, Default, PartialEq, Eq)] pub enum Layout { /// Flatten all types into one file with unmodified names. #[default] FlatFile, /// Flatten into one file with module prefixes added to each type name. ModulePrefixedName, /// Emit one file per Rust module path. Files, } impl fmt::Display for Layout { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{self:?}") } } #[derive(Clone)] #[allow(clippy::type_complexity)] struct RuntimeFn( Arc) -> Result, Error> + Send + Sync>, ); impl fmt::Debug for RuntimeFn { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "RuntimeFn({:p})", self.0) } } /// Zod language exporter. #[derive(Debug, Clone)] #[non_exhaustive] pub struct Zod { /// Custom header prepended to exported files. pub header: Cow<'static, str>, framework_runtime: Option, framework_prelude: Cow<'static, str>, /// Strategy for exporting Rust bigint-compatible primitives. pub bigint: BigIntExportBehavior, /// Output layout mode for generated Zod TypeScript. pub layout: Layout, } impl Default for Zod { fn default() -> Self { Self::new() } } impl Zod { /// Construct a new exporter with default options configured. pub fn new() -> Self { Self { header: Cow::Borrowed(""), framework_runtime: None, framework_prelude: Cow::Borrowed( "import { z } from \"zod\";\n// This file has been generated by Specta. Do not edit this file manually.", ), bigint: Default::default(), layout: Default::default(), } } /// Provide a prelude which is added to the start of all exported files. pub fn framework_prelude(mut self, prelude: impl Into>) -> Self { self.framework_prelude = prelude.into(); self } /// Add runtime code exported as part of the bindings. pub fn framework_runtime( mut self, builder: impl Fn(FrameworkExporter<'_>) -> Result, Error> + Send + Sync + 'static, ) -> Self { self.framework_runtime = Some(RuntimeFn(Arc::new(builder))); self } /// Configure a header for the file. pub fn header(mut self, header: impl Into>) -> Self { self.header = header.into(); self } /// Configure BigInt handling behaviour. pub fn bigint(mut self, bigint: BigIntExportBehavior) -> Self { self.bigint = bigint; self } /// Configure bindings layout. pub fn layout(mut self, layout: Layout) -> Self { self.layout = layout; self } /// Export files into a single string. pub fn export(&self, types: &Types, format: impl Format) -> Result { let exporter = self.clone(); let formatted_types = format_types(types, &format)?; let types = formatted_types.as_ref(); if let Layout::Files = exporter.layout { return Err(Error::unable_to_export(exporter.layout)); } let mut out = render_file_header(&exporter); let mut has_manually_exported_user_types = false; let mut runtime = Ok(Cow::default()); if let Some(framework_runtime) = &exporter.framework_runtime { runtime = (framework_runtime.0)(FrameworkExporter { exporter: &exporter, format: Some(&format), has_manually_exported_user_types: &mut has_manually_exported_user_types, files_root_types: "", types, }); } let runtime = runtime?; if !runtime.is_empty() { out.push('\n'); out.push_str(&runtime); out.push('\n'); } if !has_manually_exported_user_types { render_types(&mut out, &exporter, types, "")?; } Ok(out) } /// Export the types to a specific file/folder. pub fn export_to( &self, path: impl AsRef, types: &Types, format: impl Format, ) -> Result<(), Error> { let exporter = self.clone(); let formatted_types = format_types(types, &format)?; let types = formatted_types.as_ref(); let path = path.as_ref(); if exporter.layout != Layout::Files { let mut result = render_file_header(&exporter); let mut has_manually_exported_user_types = false; let mut runtime = Ok(Cow::default()); if let Some(framework_runtime) = &exporter.framework_runtime { runtime = (framework_runtime.0)(FrameworkExporter { exporter: &exporter, format: Some(&format), has_manually_exported_user_types: &mut has_manually_exported_user_types, files_root_types: "", types, }); } let runtime = runtime?; if !runtime.is_empty() { result.push('\n'); result.push_str(&runtime); result.push('\n'); } if !has_manually_exported_user_types { render_types(&mut result, &exporter, types, "")?; } if let Some(parent) = path.parent() { std::fs::create_dir_all(parent)?; } std::fs::write(path, result)?; return Ok(()); } fn export( exporter: &Zod, types: &Types, module: &mut Module, s: &mut String, path: &Path, files: &mut HashMap, ) -> Result { module.types.sort_by(|a, b| { a.name .cmp(&b.name) .then(a.module_path.cmp(&b.module_path)) .then(a.location.cmp(&b.location)) }); let (rendered_types_result, referenced_types) = references::with_module_path(module.module_path.as_ref(), || { references::collect_references(|| { let mut rendered = String::new(); let exports = render_flat_types( &mut rendered, exporter, types, module.types.iter().copied(), "", )?; Ok::<_, Error>((rendered, exports)) }) }); let (rendered_types, exports) = rendered_types_result?; let import_paths = referenced_types .into_iter() .filter_map(|r| { types .get(&r) .map(|ndt| ndt.module_path.as_ref().to_string()) }) .filter(|module_path| module_path != module.module_path.as_ref()) .collect::>(); if !import_paths.is_empty() { s.push('\n'); s.push_str(&module_import_block( module.module_path.as_ref(), &import_paths, )); } if !import_paths.is_empty() && !rendered_types.is_empty() { s.push('\n'); } s.push_str(&rendered_types); for (name, module) in &mut module.children { if module.types.is_empty() && module.children.is_empty() { continue; } let mut path = path.join(name); let mut out = render_file_header(exporter); let has_types = export(exporter, types, module, &mut out, &path, files)?; if has_types { path.set_extension("ts"); files.insert(path, out); } } Ok(!exports.is_empty()) } let mut files = HashMap::new(); let mut runtime_path = path.join("index"); runtime_path.set_extension("ts"); let mut root_types = String::new(); export( &exporter, types, &mut build_module_graph(types), &mut root_types, path, &mut files, )?; { let mut has_manually_exported_user_types = false; let mut runtime = Cow::default(); let mut runtime_references = HashSet::new(); if let Some(framework_runtime) = &exporter.framework_runtime { let (runtime_result, referenced_types) = references::with_module_path("", || { references::collect_references(|| { (framework_runtime.0)(FrameworkExporter { exporter: &exporter, format: Some(&format), has_manually_exported_user_types: &mut has_manually_exported_user_types, files_root_types: &root_types, types, }) }) }); runtime = runtime_result?; runtime_references = referenced_types; } let should_export_user_types = !has_manually_exported_user_types && !root_types.is_empty(); if !runtime.is_empty() || should_export_user_types { files.insert(runtime_path, { let mut out = render_file_header(&exporter); let mut body = String::new(); if !runtime.is_empty() { body.push_str(&runtime); } if should_export_user_types { if !body.is_empty() { body.push('\n'); } body.push_str(&root_types); } let import_paths = runtime_references .into_iter() .filter_map(|r| { types .get(&r) .map(|ndt| ndt.module_path.as_ref().to_string()) }) .filter(|module_path| !module_path.is_empty()) .collect::>(); if !import_paths.is_empty() { out.push('\n'); out.push_str(&module_import_block("", &import_paths)); } if !body.is_empty() { out.push('\n'); if !import_paths.is_empty() { out.push('\n'); } out.push_str(&body); } out }); } } match path.metadata() { Ok(meta) if !meta.is_dir() => std::fs::remove_file(path).or_else(|source| { if source.kind() == std::io::ErrorKind::NotFound { Ok(()) } else { Err(Error::remove_file(path.to_path_buf(), source)) } })?, Ok(_) => {} Err(err) if err.kind() == std::io::ErrorKind::NotFound => {} Err(source) => { return Err(Error::metadata(path.to_path_buf(), source)); } } for (path, content) in &files { path.parent().map(std::fs::create_dir_all).transpose()?; std::fs::write(path, content)?; } cleanup_stale_files(path, &files, self)?; Ok(()) } } fn format_types<'a>(types: &'a Types, format: &dyn Format) -> Result, Error> { Ok( match format .map_types(types) .map_err(|err| Error::format("type graph formatter failed", err))? { Cow::Borrowed(_) => Cow::Borrowed(types), Cow::Owned(types) => Cow::Owned(types), }, ) } fn map_datatype_format( format: Option<&dyn Format>, types: &Types, dt: &DataType, ) -> Result { let Some(format) = format else { return Ok(dt.clone()); }; let mapped = format .map_type(types, dt) .map_err(|err| Error::format("datatype formatter failed", err))?; match mapped { Cow::Borrowed(dt) => map_datatype_format_children(Some(format), types, dt.clone()), Cow::Owned(dt) => map_datatype_format_children(Some(format), types, dt), } } fn map_datatype_format_children( format: Option<&dyn Format>, types: &Types, mut dt: DataType, ) -> Result { match &mut dt { DataType::Primitive(_) => {} DataType::List(list) => { *list.ty = map_datatype_format(format, types, &list.ty)?; } DataType::Map(map) => { let key = map_datatype_format(format, types, map.key_ty())?; let value = map_datatype_format(format, types, map.value_ty())?; map.set_key_ty(key); map.set_value_ty(value); } DataType::Nullable(inner) => { **inner = map_datatype_format(format, types, inner)?; } DataType::Struct(strct) => map_datatype_fields(format, types, &mut strct.fields)?, DataType::Enum(enm) => { for (_, variant) in &mut enm.variants { map_datatype_fields(format, types, &mut variant.fields)?; } } DataType::Tuple(tuple) => { for element in &mut tuple.elements { *element = map_datatype_format(format, types, element)?; } } DataType::Intersection(intersection) => { for element in intersection { *element = map_datatype_format(format, types, element)?; } } DataType::Reference(Reference::Named(reference)) => { if let specta::datatype::NamedReferenceType::Reference { generics, .. } = &mut reference.inner { for (_, generic) in generics { *generic = map_datatype_format(format, types, generic)?; } } } DataType::Reference(Reference::Opaque(_)) | DataType::Generic(_) => {} } Ok(dt) } fn map_datatype_fields( format: Option<&dyn Format>, types: &Types, fields: &mut Fields, ) -> Result<(), Error> { match fields { Fields::Unit => {} Fields::Unnamed(unnamed) => { for field in &mut unnamed.fields { if let Some(ty) = field.ty.as_mut() { *ty = map_datatype_format(format, types, ty)?; } } } Fields::Named(named) => { for (_, field) in &mut named.fields { if let Some(ty) = field.ty.as_mut() { *ty = map_datatype_format(format, types, ty)?; } } } } Ok(()) } fn map_named_datatype_format( format: Option<&dyn Format>, types: &Types, ndt: &NamedDataType, ) -> Result { let mut mapped = ndt.clone(); mapped.ty = ndt .ty .as_ref() .map(|ty| map_datatype_format(format, types, ty)) .transpose()?; Ok(mapped) } impl AsRef for Zod { fn as_ref(&self) -> &Zod { self } } impl AsMut for Zod { fn as_mut(&mut self) -> &mut Zod { self } } /// Reference to the Zod exporter for framework callbacks. pub struct FrameworkExporter<'a> { exporter: &'a Zod, format: Option<&'a dyn Format>, has_manually_exported_user_types: &'a mut bool, files_root_types: &'a str, /// Collected types currently being exported. pub types: &'a Types, } impl fmt::Debug for FrameworkExporter<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.exporter.fmt(f) } } impl AsRef for FrameworkExporter<'_> { fn as_ref(&self) -> &Zod { self.exporter } } impl Deref for FrameworkExporter<'_> { type Target = Zod; fn deref(&self) -> &Self::Target { self.exporter } } impl FrameworkExporter<'_> { /// Render the types within [`Types`](specta::Types). pub fn render_types(&mut self) -> Result, Error> { let mut s = String::new(); render_types(&mut s, self.exporter, self.types, self.files_root_types)?; *self.has_manually_exported_user_types = true; Ok(Cow::Owned(s)) } /// [primitives::inline] pub fn inline(&self, dt: &DataType) -> Result { let mapped = map_datatype_format(self.format, self.types, dt)?; primitives::inline(self, self.types, &mapped) } /// [primitives::reference] pub fn reference(&self, r: &Reference) -> Result { let mapped = map_datatype_format(self.format, self.types, &DataType::Reference(r.clone()))?; match mapped { DataType::Reference(reference) => primitives::reference(self, self.types, &reference), dt => primitives::inline(self, self.types, &dt), } } /// [primitives::export] pub fn export<'a>( &self, ndts: impl Iterator, indent: &'a str, ) -> Result { let mapped = ndts .map(|ndt| map_named_datatype_format(self.format, self.types, ndt)) .collect::, _>>()?; primitives::export(self, self.types, mapped.iter(), indent) } } struct Module<'a> { types: Vec<&'a NamedDataType>, children: BTreeMap<&'a str, Module<'a>>, module_path: Cow<'static, str>, } fn build_module_graph(types: &Types) -> Module<'_> { types.into_unsorted_iter().fold( Module { types: Default::default(), children: Default::default(), module_path: Default::default(), }, |mut ns, ndt| { let path = &ndt.module_path; if path.is_empty() { ns.types.push(ndt); } else { let mut current = &mut ns; let mut current_path = String::new(); for segment in path.split("::") { if !current_path.is_empty() { current_path.push_str("::"); } current_path.push_str(segment); current = current.children.entry(segment).or_insert_with(|| Module { types: Default::default(), children: Default::default(), module_path: current_path.clone().into(), }); } current.types.push(ndt); } ns }, ) } fn render_file_header(exporter: &Zod) -> String { let mut out = exporter.header.to_string(); if !exporter.header.is_empty() { out.push('\n'); } out.push_str(&exporter.framework_prelude); if !exporter.framework_prelude.is_empty() { out.push('\n'); } out } fn render_types( s: &mut String, exporter: &Zod, types: &Types, files_user_types: &str, ) -> Result<(), Error> { match exporter.layout { Layout::FlatFile | Layout::ModulePrefixedName => { render_flat_types(s, exporter, types, types.into_sorted_iter(), "")?; } Layout::Files => { if !files_user_types.is_empty() { s.push_str(files_user_types); } } } Ok(()) } fn render_flat_types<'a>( s: &mut String, exporter: &Zod, types: &Types, ndts: impl ExactSizeIterator, indent: &str, ) -> Result>, Error> { let mut exports = HashMap::with_capacity(ndts.len()); let ndts = ndts .filter(|ndt| ndt.ty.is_some()) .map(|ndt| { let export_name = exported_type_name(exporter, ndt); if let Some(other) = exports.insert(export_name.to_string(), ndt.location) { return Err(Error::duplicate_type_name(export_name, ndt.location, other)); } Ok(ndt) }) .collect::, _>>()?; let mut type_render_stack = Vec::new(); primitives::export_internal( s, exporter, types, ndts.into_iter(), indent, &mut type_render_stack, )?; Ok(exports) } fn collect_existing_files(root: &Path) -> Result, Error> { if !root.exists() { return Ok(HashSet::new()); } let mut files = HashSet::new(); let entries = std::fs::read_dir(root).map_err(|source| Error::read_dir(root.to_path_buf(), source))?; for entry in entries { let entry = entry.map_err(|source| Error::read_dir(root.to_path_buf(), source))?; let path = entry.path(); let file_type = entry .file_type() .map_err(|source| Error::metadata(path.clone(), source))?; if file_type.is_symlink() { continue; } if file_type.is_dir() { files.extend(collect_existing_files(&path)?); } else if matches!(path.extension().and_then(|e| e.to_str()), Some("ts")) { files.insert(path); } } Ok(files) } fn is_generated_specta_file(path: &Path, exporter: &Zod) -> Result { match std::fs::read_to_string(path) { Ok(contents) => Ok((!exporter.framework_prelude.is_empty() && contents.contains(exporter.framework_prelude.as_ref())) || contents.contains("generated by Specta")), Err(err) if err.kind() == std::io::ErrorKind::InvalidData => Ok(false), Err(source) => Err(Error::from(source)), } } fn remove_empty_dirs(path: &Path, root: &Path) -> Result<(), Error> { let entries = std::fs::read_dir(path).map_err(|source| Error::read_dir(path.to_path_buf(), source))?; for entry in entries { let entry = entry.map_err(|source| Error::read_dir(path.to_path_buf(), source))?; let entry_path = entry.path(); let file_type = entry .file_type() .map_err(|source| Error::metadata(entry_path.clone(), source))?; if file_type.is_symlink() { continue; } if file_type.is_dir() { remove_empty_dirs(&entry_path, root)?; } } let is_empty = path .read_dir() .map_err(|source| Error::read_dir(path.to_path_buf(), source))? .next() .is_none(); if path != root && is_empty { match std::fs::remove_dir(path) { Ok(()) => {} Err(err) if err.kind() == std::io::ErrorKind::NotFound => {} Err(source) => { return Err(Error::remove_dir(path.to_path_buf(), source)); } } } Ok(()) } fn cleanup_stale_files( root: &Path, current_files: &HashMap, exporter: &Zod, ) -> Result<(), Error> { for path in collect_existing_files(root)? { if current_files.contains_key(&path) || !is_generated_specta_file(&path, exporter)? { continue; } std::fs::remove_file(&path).or_else(|source| { if source.kind() == std::io::ErrorKind::NotFound { Ok(()) } else { Err(Error::remove_file(path.clone(), source)) } })?; } remove_empty_dirs(root, root)?; Ok(()) } fn exported_type_name(exporter: &Zod, ndt: &NamedDataType) -> Cow<'static, str> { match exporter.layout { Layout::FlatFile | Layout::Files => ndt.name.clone(), Layout::ModulePrefixedName => { let mut s = ndt.module_path.split("::").collect::>().join("_"); if !s.is_empty() { s.push('_'); } s.push_str(&ndt.name); Cow::Owned(s) } } } pub(crate) fn module_alias(module_path: &str) -> String { if module_path.is_empty() { "$root".to_string() } else { module_path.split("::").collect::>().join("$") } } fn module_import_statement(from_module_path: &str, to_module_path: &str) -> String { format!( "import * as {} from \"{}\";", module_alias(to_module_path), module_import_path(from_module_path, to_module_path) ) } fn module_import_block(from_module_path: &str, import_paths: &BTreeSet) -> String { import_paths .iter() .map(|module_path| module_import_statement(from_module_path, module_path)) .collect::>() .join("\n") } fn module_import_path(from_module_path: &str, to_module_path: &str) -> String { fn module_file_segments(module_path: &str) -> Vec<&str> { if module_path.is_empty() { vec!["index"] } else { module_path.split("::").collect() } } let from_file_segments = module_file_segments(from_module_path); let from_dir_segments = &from_file_segments[..from_file_segments.len() - 1]; let to_file_segments = module_file_segments(to_module_path); let shared = from_dir_segments .iter() .zip(to_file_segments.iter()) .take_while(|(a, b)| a == b) .count(); let mut relative_parts = Vec::new(); relative_parts.extend(std::iter::repeat_n( "..", from_dir_segments.len().saturating_sub(shared), )); relative_parts.extend(to_file_segments.iter().skip(shared).copied()); if relative_parts .first() .is_none_or(|v| *v != "." && *v != "..") { relative_parts.insert(0, "."); } relative_parts.join("/") } ================================================ FILE: tests/Cargo.toml ================================================ [package] name = "specta-tests" version = "0.0.0" edition = "2024" publish = false autotests = false [[test]] name = "test" path = "tests/mod.rs" harness = true [dependencies] specta = { path = "../specta", features = ["function", "std", "derive", "serde_json", "serde_yaml", "toml", "chrono", "either", "error-stack", "ulid", "glam", "ordered-float", "heapless", "semver", "smol_str", "arrayvec", "smallvec", "geojson", "bson"] } specta-serde = { path = "../specta-serde" } specta-swift = { path = "../specta-swift" } specta-typescript = { path = "../specta-typescript" } specta-zod = { path = "../specta-zod" } specta-util = { path = "../specta-util", features = ["serde"] } # TODO: Remove `serde` feature serde = { version = "1.0.228", features = ["std", "derive"] } trybuild = "1.0.116" wasm-bindgen = "0.2.120" serde_json = "1.0.149" serde_yaml = "0.9.34" toml = "1.1.2" insta = "1.47.2" chrono = { version = "0.4", default-features = false, features = ["clock"] } either = { version = "1.15", default-features = false } ulid = { version = "1.2", default-features = false, features = [] } glam = { version = "0.32", default-features = false, features = ["std"] } ordered-float = { version = ">=3, <6", default-features = false } heapless = { version = ">=0.7, <0.10", default-features = false } semver = { version = "1", default-features = false } smol_str = { version = "0.3", default-features = false } arrayvec = { version = ">=0.6, <0.8", default-features = false } smallvec = { version = "1", default-features = false } geojson = { version = "1.0", default-features = false } tempfile = "3.27.0" thiserror = "2.0.18" error-stack = { version = "0.7", default-features = false } bson = { version = "3", default-features = false, features = ["compat-3-0-0"] } ================================================ FILE: tests/tests/bound.rs ================================================ use specta::{Type, Types}; use specta_typescript::Typescript; #[derive(Type)] #[specta(bound = "T: Clone + Type", collect = false)] struct CustomBound { value: T, } #[derive(Type)] #[specta(bound = "T: Clone + Type, U: std::fmt::Debug + Type", collect = false)] struct MultiBound { t: T, u: U, } #[derive(Type)] #[specta(bound = "T: Clone + std::fmt::Debug + Type", collect = false)] struct ComplexBound { value: T, } #[derive(Type)] #[specta(bound = "T: Type", collect = false)] struct ExistingWhere where T: Clone, { value: T, } #[derive(Type)] #[specta(bound = "T: Clone + Type", collect = false)] enum EnumWithBound { Variant(T), Other, } #[derive(Type)] #[specta(bound = "T: Type + 'static", collect = false)] struct LifetimeBound { value: T, } #[derive(Type)] #[specta(bound = "T: Clone + Type", collect = false)] struct RequiresClone { value: T, } #[test] fn custom_bound() { #[derive(Clone, Type)] #[specta(collect = false)] struct CloneAndType; let _: CustomBound = CustomBound { value: CloneAndType, }; } #[test] fn multi_bound() { #[derive(Clone, Debug, Type)] #[specta(collect = false)] struct AllTraits; let _: MultiBound = MultiBound { t: AllTraits, u: AllTraits, }; } #[test] fn complex_bound() { #[derive(Clone, Debug, Type)] #[specta(collect = false)] struct AllTraits; let _: ComplexBound = ComplexBound { value: AllTraits }; } #[test] fn existing_where() { #[derive(Clone, Type)] #[specta(collect = false)] struct BothTraits; let _: ExistingWhere = ExistingWhere { value: BothTraits }; } #[test] fn enum_bound() { #[derive(Clone, Type)] #[specta(collect = false)] struct CloneAndType; let _: EnumWithBound = EnumWithBound::Other; } #[test] fn lifetime_bound() { #[derive(Type)] #[specta(collect = false)] struct StaticType; let _: LifetimeBound = LifetimeBound { value: StaticType }; } #[test] fn requires_clone_bound() { #[derive(Clone, Type)] #[specta(collect = false)] struct CloneAndType; let _: RequiresClone = RequiresClone { value: CloneAndType, }; } #[test] fn associated_type_bound_issue_138() { // Regression test for https://github.com/specta-rs/specta/issues/138 trait MyTrait { type A: Type; } struct AssocIsI32; impl MyTrait for AssocIsI32 { type A = i32; } #[derive(Type)] #[specta(collect = false)] struct Demo { value: T::A, } let types = Types::default().register::>(); let output = Typescript::default() .export(&types, specta_serde::Format) .unwrap(); insta::assert_snapshot!("bound-associated-type-issue-138", output); } ================================================ FILE: tests/tests/errors.rs ================================================ // TODO: Maybe should this be merged into other tests??? use std::io; use specta::Type; use thiserror::Error; #[derive(Type, Error, Debug)] #[specta(collect = false)] pub enum MyError { #[error("data store disconnected")] Disconnect( #[specta(type = String)] #[from] io::Error, ), #[error("the data for key `{0}` is not available")] Redaction(String), #[error("invalid header (expected {expected:?}, found {found:?})")] InvalidHeader { expected: String, found: String }, #[error("unknown data store error")] Unknown, } ================================================ FILE: tests/tests/functions.rs ================================================ use std::fmt; use specta::{ Format as _, Type, Types, datatype::{DataType, Function}, function::{self, fn_datatype}, specta, }; use specta_typescript::{Typescript, primitives}; fn render_datatype(ts: &Typescript, types: &Types, dt: &DataType) -> String { // This is handled by Specta Typescript for you. let types = specta_serde::Format.map_types(types).unwrap(); let dt = specta_serde::Format.map_type(&types, dt).unwrap(); match &*dt { DataType::Reference(r) => primitives::reference(ts, &types, r).unwrap(), dt => primitives::inline(ts, &types, dt).unwrap(), } } /// Multiline /// Docs #[specta] fn a() {} #[specta] fn b(demo: String) {} #[specta] fn c(a: String, b: i32, c: bool) {} #[specta] fn d(demo: String) -> i32 { 42 } #[specta] fn e(window: T) {} // https://github.com/specta-rs/tauri-specta/issues/24 #[specta] fn f(mut demo: String) -> i32 { 42 } #[specta] fn g(x: std::string::String) {} macro_rules! special_string { () => { String }; } #[specta] fn h(demo: special_string!()) {} #[specta] fn i() -> Result { Ok(42) } #[specta] fn k() -> Result { Err(42.0) } #[derive(Type)] #[specta(collect = false)] pub struct Demo { pub demo: String, } #[specta] fn l(Demo { demo }: Demo, (a, b): (String, u32)) {} macro_rules! special_destructure { () => { Demo { demo } }; } #[specta] fn m(special_destructure!(): Demo) {} #[specta] async fn async_fn() {} /// Testing Doc Comment #[specta] fn with_docs() {} #[specta] pub fn public_function() {} mod nested { use super::*; #[specta] pub fn nested() {} } #[specta] fn raw(r#type: i32) {} // https://github.com/specta-rs/specta/issues/213 #[allow(non_snake_case)] #[specta(rename_all = "snake_case")] fn rename_all_fn(myArg: i32, anotherValue: String) {} #[allow(non_snake_case)] #[specta(rename = "totally_custom")] fn renamed_fn(myArg: i32) {} // TODO: Finish fixing these #[test] fn test_trailing_comma() { function::collect_functions![a]; function::collect_functions![a,]; function::collect_functions![a, b, c]; function::collect_functions![a, b, c,]; function::collect_functions![a, b, c, d, e::, f, g, h, i, k, nested::nested]; } #[test] fn test_function_exporting() { { let mut types = Types::default(); let def: Function = fn_datatype![a](&mut types); insta::assert_snapshot!(def.asyncness(), @"false"); insta::assert_snapshot!(def.name(), @"a"); insta::assert_snapshot!(def.args().len(), @"0"); insta::assert_snapshot!(format!("{:?}", def.result()), @"None"); } { let mut types = Types::default(); let def: Function = fn_datatype![b](&mut types); let ts = Typescript::new(); insta::assert_snapshot!(def.asyncness(), @"false"); insta::assert_snapshot!(def.name(), @"b"); insta::assert_snapshot!(def.args().len(), @"1"); insta::assert_snapshot!( render_datatype(&ts, &types, &def.args()[0].1), @"string" ); insta::assert_snapshot!(format!("{:?}", def.result()), @"None"); } { let mut types = Types::default(); let def: Function = fn_datatype![c](&mut types); let ts = Typescript::new(); insta::assert_snapshot!(def.asyncness(), @"false"); insta::assert_snapshot!(def.name(), @"c"); insta::assert_snapshot!(def.args().len(), @"3"); insta::assert_snapshot!( render_datatype(&ts, &types, &def.args()[0].1), @"string" ); insta::assert_snapshot!( render_datatype(&ts, &types, &def.args()[1].1), @"number" ); insta::assert_snapshot!( render_datatype(&ts, &types, &def.args()[2].1), @"boolean" ); insta::assert_snapshot!(format!("{:?}", def.result()), @"None"); } { let mut types = Types::default(); let def: Function = fn_datatype![d](&mut types); let ts = Typescript::new(); insta::assert_snapshot!(def.asyncness(), @"false"); insta::assert_snapshot!(def.name(), @"d"); insta::assert_snapshot!(def.args().len(), @"1"); insta::assert_snapshot!( render_datatype(&ts, &types, &def.args()[0].1), @"string" ); insta::assert_snapshot!( def.result() .map(|result| render_datatype(&ts, &types, result)) .as_deref() .unwrap_or("None"), @"number" ); } { let mut types = Types::default(); let def: Function = fn_datatype![e::](&mut types); let ts = Typescript::new(); insta::assert_snapshot!(def.asyncness(), @"false"); insta::assert_snapshot!(def.name(), @"e"); insta::assert_snapshot!(def.args().len(), @"1"); insta::assert_snapshot!( render_datatype(&ts, &types, &def.args()[0].1), @"boolean" ); insta::assert_snapshot!(format!("{:?}", def.result()), @"None"); } { let mut types = Types::default(); let def: Function = fn_datatype![f](&mut types); let ts = Typescript::new(); insta::assert_snapshot!(def.asyncness(), @"false"); insta::assert_snapshot!(def.name(), @"f"); insta::assert_snapshot!(def.args().len(), @"1"); insta::assert_snapshot!( render_datatype(&ts, &types, &def.args()[0].1), @"string" ); insta::assert_snapshot!( def.result() .map(|result| render_datatype(&ts, &types, result)) .as_deref() .unwrap_or("None"), @"number" ); } { let mut types = Types::default(); let def: specta::datatype::Function = fn_datatype![g](&mut types); let ts = Typescript::new(); insta::assert_snapshot!(def.asyncness(), @"false"); insta::assert_snapshot!(def.name(), @"g"); insta::assert_snapshot!(def.args().len(), @"1"); insta::assert_snapshot!( render_datatype(&ts, &types, &def.args()[0].1), @"string" ); insta::assert_snapshot!(format!("{:?}", def.result()), @"None"); } { let mut types = Types::default(); let def: specta::datatype::Function = fn_datatype![h](&mut types); let ts = Typescript::new(); insta::assert_snapshot!(def.asyncness(), @"false"); insta::assert_snapshot!(def.name(), @"h"); insta::assert_snapshot!(def.args().len(), @"1"); insta::assert_snapshot!( render_datatype(&ts, &types, &def.args()[0].1), @"string" ); insta::assert_snapshot!(format!("{:?}", def.result()), @"None"); } { let mut types = Types::default(); let def: Function = fn_datatype![i](&mut types); let ts = Typescript::new(); insta::assert_snapshot!(def.asyncness(), @"false"); insta::assert_snapshot!(def.name(), @"i"); insta::assert_snapshot!(def.args().len(), @"0"); insta::assert_snapshot!( def.result() .map(|result| render_datatype(&ts, &types, result)) .as_deref() .unwrap_or("None"), @"Result" ); } { let mut types = Types::default(); let def: Function = fn_datatype![k](&mut types); let ts = Typescript::new(); insta::assert_snapshot!(def.asyncness(), @"false"); insta::assert_snapshot!(def.name(), @"k"); insta::assert_snapshot!(def.args().len(), @"0"); insta::assert_snapshot!( def.result() .map(|result| render_datatype(&ts, &types, result)) .as_deref() .unwrap_or("None"), @"Result" ); } { let mut types = Types::default(); let def: Function = fn_datatype![l](&mut types); let ts = Typescript::new(); insta::assert_snapshot!(def.asyncness(), @"false"); insta::assert_snapshot!(def.name(), @"l"); insta::assert_snapshot!(def.args().len(), @"2"); insta::assert_snapshot!( render_datatype(&ts, &types, &def.args()[0].1), @"Demo" ); insta::assert_snapshot!( render_datatype(&ts, &types, &def.args()[1].1), @"[string, number]" ); insta::assert_snapshot!(format!("{:?}", def.result()), @"None"); } { let mut types = Types::default(); let def: Function = fn_datatype![m](&mut types); let ts = Typescript::new(); insta::assert_snapshot!(def.asyncness(), @"false"); insta::assert_snapshot!(def.name(), @"m"); insta::assert_snapshot!(def.args().len(), @"1"); insta::assert_snapshot!( render_datatype(&ts, &types, &def.args()[0].1), @"Demo" ); insta::assert_snapshot!(format!("{:?}", def.result()), @"None"); } { let mut types = Types::default(); let def: Function = fn_datatype![async_fn](&mut types); insta::assert_snapshot!(def.asyncness(), @"true"); insta::assert_snapshot!(def.name(), @"async_fn"); insta::assert_snapshot!(def.args().len(), @"0"); insta::assert_snapshot!(format!("{:?}", def.result()), @"None"); } { let mut types = Types::default(); let def: Function = fn_datatype![with_docs](&mut types); insta::assert_snapshot!(def.asyncness, @"false"); insta::assert_snapshot!(def.name, @"with_docs"); insta::assert_snapshot!(def.args.len(), @"0"); insta::assert_snapshot!(format!("{:?}", def.result), @"None"); insta::assert_snapshot!(def.docs, @" Testing Doc Comment"); } { let mut types = Types::default(); let def: Function = fn_datatype![raw](&mut types); insta::assert_snapshot!(def.args()[0].0, @"type"); } { let mut types = Types::default(); let def: Function = fn_datatype![rename_all_fn](&mut types); insta::assert_snapshot!(def.name, @"rename_all_fn"); insta::assert_snapshot!(def.args[0].0, @"my_arg"); insta::assert_snapshot!(def.args[1].0, @"another_value"); } { let mut types = Types::default(); let def: Function = fn_datatype![renamed_fn](&mut types); insta::assert_snapshot!(def.name, @"totally_custom"); insta::assert_snapshot!(def.args[0].0, @"myArg"); } } ================================================ FILE: tests/tests/jsdoc.rs ================================================ use std::{ path::Path, time::{Duration, SystemTime}, }; use specta::datatype::{DataType, Reference}; use specta::{Type, Types}; use specta_typescript::{JSDoc, Layout, primitives}; use tempfile::TempDir; use crate::fs_to_string; use crate::typescript::phase_collections; mod jsdoc_export_to_files_runtime_imports_types { use super::*; pub mod three { use super::*; #[derive(Type)] #[specta(collect = false)] pub struct Three { pub active: bool, } } pub mod two { use super::*; #[derive(Type)] #[specta(collect = false)] pub struct Two { pub value: String, } } pub mod one { use super::*; #[derive(Type)] #[specta(collect = false)] pub struct One { pub two: super::two::Two, pub three: super::three::Three, } } } #[test] fn export_to() { let temp = Path::new(env!("CARGO_MANIFEST_DIR")).join(".temp"); std::fs::create_dir_all(&temp).unwrap(); let temp = TempDir::new_in(temp).unwrap(); for layout in [ Layout::Files, Layout::FlatFile, Layout::ModulePrefixedName, Layout::Namespaces, ] { for (mode, format, _, types) in phase_collections() { let name = format!( "jsdoc-export-to-{}-{}", layout.to_string().to_lowercase(), mode ); let output = (|| { let path = temp.path().join(&name); JSDoc::default() .layout(layout) .export_to(&path, &types, format) .unwrap(); fs_to_string(&path).map_err(|err| err.to_string()) })() .unwrap(); insta::assert_snapshot!(name, output); } } temp.close().unwrap(); // TODO: Assert layouts error out with `export` method // TODO: Assert it errors if given the path to a file } #[test] fn primitives_export() { for (mode, format, dts, types) in phase_collections() { let types = format.map_types(&types).unwrap().into_owned(); let output = dts .iter() .filter_map(|(name, dt)| { let mut ndt = match dt { DataType::Reference(Reference::Named(r)) => types.get(r).unwrap().to_owned(), _ => return None, }; if let Some(ty) = &mut ndt.ty { *ty = format.map_type(&types, ty).unwrap().into_owned(); } Some( primitives::export(&JSDoc::default(), &types, [ndt].iter(), "") .map(|ty| format!("{name}: {ty}")), ) }) .collect::, _>>() .map(|exports| exports.join("\n")) .unwrap(); insta::assert_snapshot!(format!("export-{mode}"), output); } } #[test] fn primitives_export_many() { for (mode, format, dts, types) in phase_collections() { let types = format.map_types(&types).unwrap().into_owned(); let output = primitives::export( &JSDoc::default(), &types, dts.iter() .filter_map(|(_, ty)| match ty { DataType::Reference(Reference::Named(r)) => types.get(r).cloned(), _ => None, }) .map(|mut ndt| { if let Some(ty) = &mut ndt.ty { *ty = format.map_type(&types, ty).unwrap().into_owned(); } ndt }) .collect::>() .iter(), "", ) .unwrap(); insta::assert_snapshot!(format!("export-many-{mode}"), output); } } #[test] fn primitives_reference() { for (mode, format, dts, types) in phase_collections() { let types = format.map_types(&types).unwrap().into_owned(); let output = dts .iter() .filter_map(|(name, dt)| { let dt = format.map_type(&types, dt).unwrap().into_owned(); let reference = match dt { DataType::Reference(reference) => reference.clone(), _ => return None, }; Some( primitives::reference(&JSDoc::default(), &types, &reference) .map(|ty| format!("{name}: {ty}")), ) }) .collect::, _>>() .map(|exports| exports.join("\n")) .unwrap(); insta::assert_snapshot!(format!("reference-{mode}"), output); } } #[test] fn primitives_inline() { for (mode, format, dts, types) in phase_collections() { let types = format.map_types(&types).unwrap().into_owned(); let output = dts .iter() .map(|(name, dt)| { let dt = format.map_type(&types, dt).unwrap().into_owned(); primitives::inline(&JSDoc::default(), &types, &dt).map(|ty| format!("{name}: {ty}")) }) .collect::, _>>() .map(|exports| exports.join("\n")) .unwrap(); insta::assert_snapshot!(format!("inline-{mode}"), output); } } #[test] fn jsdoc_export_bigint_errors() { fn assert_bigint_error(failures: &mut Vec, name: &str) { let jsdoc = JSDoc::default(); let mut types = Types::default(); let dt = T::definition(&mut types); match primitives::inline(&jsdoc, &types, &dt) { Ok(ty) => failures.push(format!( "{name} [inline]: expected BigInt error, but export succeeded with '{ty}'" )), Err(err) if err .to_string() .contains("forbids exporting BigInt-style types") => {} Err(err) => failures.push(format!("{name} [inline]: unexpected error '{err}'")), } if types.is_empty() { return; } match jsdoc.export(&types, specta_serde::Format) { Ok(output) => failures.push(format!( "{name} [export]: expected BigInt error, but export succeeded with '{output}'" )), Err(err) if err .to_string() .contains("forbids exporting BigInt-style types") => {} Err(err) => failures.push(format!("{name} [export]: unexpected error '{err}'")), } } fn assert_inline_bigint_error(failures: &mut Vec, name: &str) { let jsdoc = JSDoc::default(); let mut types = Types::default(); let dt = T::definition(&mut types); match primitives::inline(&jsdoc, &types, &dt) { Ok(ty) => failures.push(format!( "{name} [inline]: expected BigInt error, but export succeeded with '{ty}'" )), Err(err) if err .to_string() .contains("forbids exporting BigInt-style types") => {} Err(err) => failures.push(format!("{name} [inline]: unexpected error '{err}'")), } } macro_rules! for_bigint_types { (T -> $s:expr) => {{ for_bigint_types!(usize, isize, i64, u64, i128, u128; $s); }}; ($($i:ty),+; $s:expr) => {{ $({ type T = $i; $s(stringify!($i)); })* }}; } #[derive(Type)] #[specta(collect = false)] struct StructWithSystemTime { // https://github.com/specta-rs/specta/issues/77 #[specta(inline)] value: SystemTime, } #[derive(Type)] #[specta(collect = false)] struct StructWithDuration { // https://github.com/specta-rs/specta/issues/77 #[specta(inline)] value: Duration, } #[derive(Type)] #[specta(collect = false)] struct StructWithBigInt { a: i128, } #[derive(Type)] #[specta(collect = false)] struct StructWithStructWithBigInt { #[specta(inline)] abc: StructWithBigInt, } #[derive(Type)] #[specta(collect = false)] struct StructWithStructWithStructWithBigInt { #[specta(inline)] field1: StructWithStructWithBigInt, } #[derive(Type)] #[specta(collect = false)] struct StructWithOptionWithStructWithBigInt { #[specta(inline)] optional_field: Option, } #[derive(Type)] #[specta(collect = false)] enum EnumWithStructWithStructWithBigInt { #[specta(inline)] A(StructWithStructWithBigInt), } #[derive(Type)] #[specta(collect = false)] enum EnumWithInlineStructWithBigInt { #[specta(inline)] B { a: i128 }, } let mut failures = Vec::new(); for_bigint_types!(T -> |name| { assert_bigint_error::(&mut failures, name); }); for (name, assert) in [ ( "StructWithSystemTime", assert_bigint_error:: as fn(&mut Vec, &str), ), ( "StructWithDuration", assert_bigint_error:: as fn(&mut Vec, &str), ), ( "StructWithBigInt", assert_bigint_error:: as fn(&mut Vec, &str), ), ( "StructWithStructWithBigInt", assert_bigint_error:: as fn(&mut Vec, &str), ), ( "StructWithStructWithStructWithBigInt", assert_bigint_error:: as fn(&mut Vec, &str), ), ( "StructWithOptionWithStructWithBigInt", assert_bigint_error:: as fn(&mut Vec, &str), ), ( "EnumWithStructWithStructWithBigInt", assert_bigint_error:: as fn(&mut Vec, &str), ), ( "EnumWithInlineStructWithBigInt", assert_bigint_error:: as fn(&mut Vec, &str), ), ] { assert(&mut failures, name); } assert_inline_bigint_error::(&mut failures, "SystemTime"); assert_inline_bigint_error::(&mut failures, "Duration"); assert!( failures.is_empty(), "Unexpected JSDoc BigInt export behavior:\n{}", failures.join("\n") ); } #[test] fn jsdoc_export_to_files_uses_jsdoc_import_typedefs() { let temp = Path::new(env!("CARGO_MANIFEST_DIR")).join(".temp"); std::fs::create_dir_all(&temp).unwrap(); let temp = TempDir::new_in(temp).unwrap(); let path = temp.path().join("jsdoc-export-to-files-both"); let types = Types::default() .register::() .register::() .register::(); JSDoc::default() .layout(Layout::Files) .export_to(&path, &types, specta_serde::Format) .unwrap(); let output = fs_to_string(&path).unwrap(); insta::assert_snapshot!("jsdoc-export-to-files-both", output); temp.close().unwrap(); } // TODO: Confirm different layouts // TODO: Unit test JSDoc and other languages // TODO: Ensure this is feature matching with the Typescript testing ================================================ FILE: tests/tests/layouts.rs ================================================ use std::path::Path; use specta::{ Type, Types, datatype::{DataType, NamedDataType, Primitive}, }; use specta_typescript::{Layout, Typescript}; use tempfile::TempDir; #[derive(Type)] struct Testing { a: testing::Testing, } #[derive(Type)] struct Another { bruh: String, } #[derive(Type)] struct MoreType { u: String, } mod testing { use super::*; #[derive(Type)] pub struct Testing { b: testing2::Testing, } pub mod testing2 { use super::*; #[derive(Type)] pub struct Testing { c: String, } } } #[test] fn duplicate_typenames_layouts() { let types = Types::default() .register::() .register::() .register::(); assert_error_contains( Typescript::default().export(&types, specta_serde::Format), "Detected multiple types", ); assert_error_contains( Typescript::default() .layout(Layout::FlatFile) .export(&types, specta_serde::Format), "Detected multiple types", ); let module_prefixed = Typescript::default() .layout(Layout::ModulePrefixedName) .export(&types, specta_serde::Format) .unwrap(); insta::assert_snapshot!("layouts-duplicate-module-prefixed", module_prefixed); let namespaces = Typescript::default() .layout(Layout::Namespaces) .export(&types, specta_serde::Format) .unwrap(); insta::assert_snapshot!("layouts-duplicate-namespaces", namespaces); assert_error_contains( Typescript::default() .layout(Layout::Files) .export(&types, specta_serde::Format), "Unable to export layout Files", ); let temp = temp_dir(); let path = temp.path().join("duplicate-layout"); Typescript::default() .layout(Layout::Files) .export_to(&path, &types, specta_serde::Format) .unwrap(); let output = crate::fs_to_string(&path).unwrap(); insta::assert_snapshot!("layouts-duplicate-files", output); } #[test] fn non_duplicate_typenames_layouts() { let types = Types::default() .register::() .register::(); let default_output = Typescript::default() .export(&types, specta_serde::Format) .unwrap(); insta::assert_snapshot!("layouts-non-duplicate-default", default_output); let flat = Typescript::default() .layout(Layout::FlatFile) .export(&types, specta_serde::Format) .unwrap(); insta::assert_snapshot!("layouts-non-duplicate-flat", flat); let module_prefixed = Typescript::default() .layout(Layout::ModulePrefixedName) .export(&types, specta_serde::Format) .unwrap(); insta::assert_snapshot!("layouts-non-duplicate-module-prefixed", module_prefixed); let namespaces = Typescript::default() .layout(Layout::Namespaces) .export(&types, specta_serde::Format) .unwrap(); insta::assert_snapshot!("layouts-non-duplicate-namespaces", namespaces); assert_error_contains( Typescript::default() .layout(Layout::Files) .export(&types, specta_serde::Format), "Unable to export layout Files", ); let temp = temp_dir(); let path = temp.path().join("no-duplicate-layout"); Typescript::default() .layout(Layout::Files) .export_to(&path, &types, specta_serde::Format) .unwrap(); let output = crate::fs_to_string(&path).unwrap(); insta::assert_snapshot!("layouts-non-duplicate-files", output); } #[test] fn empty_module_path_layouts() { let mut types = Types::default(); let mut testing = NamedDataType::new("testing", &mut types, |_, ndt| { ndt.ty = Some(DataType::Primitive(Primitive::i8)); }); testing.module_path = "".into(); let flat = Typescript::default() .layout(Layout::FlatFile) .export(&types, specta_serde::Format) .unwrap(); insta::assert_snapshot!("layouts-empty-module-path-flat", flat); let module_prefixed = Typescript::default() .layout(Layout::ModulePrefixedName) .export(&types, specta_serde::Format) .unwrap(); insta::assert_snapshot!("layouts-empty-module-path-module-prefixed", module_prefixed); let namespaces = Typescript::default() .layout(Layout::Namespaces) .export(&types, specta_serde::Format) .unwrap(); insta::assert_snapshot!("layouts-empty-module-path-namespaces", namespaces); let temp = temp_dir(); let path = temp.path().join("empty-module-path-layout"); Typescript::default() .layout(Layout::Files) .export_to(&path, &types, specta_serde::Format) .unwrap(); let output = crate::fs_to_string(Path::new(&path)).unwrap(); insta::assert_snapshot!("layouts-empty-module-path-files", output); } fn temp_dir() -> TempDir { let temp_root = Path::new(env!("CARGO_MANIFEST_DIR")).join(".temp"); std::fs::create_dir_all(&temp_root).unwrap(); TempDir::new_in(temp_root).unwrap() } fn assert_error_contains(result: Result, expected: &str) { let error = match result { Ok(_) => panic!("expected exporter to fail"), Err(error) => error, }; assert!( error.to_string().contains(expected), "error '{error}' did not contain '{expected}'" ); } ================================================ FILE: tests/tests/legacy_impls.rs ================================================ #![allow(deprecated)] use specta::{Type, Types}; use specta_typescript::Typescript; #[derive(Debug)] struct ErrorStackRootError; impl std::fmt::Display for ErrorStackRootError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_str("error stack root error") } } impl std::error::Error for ErrorStackRootError {} #[derive(Type)] struct LegacyImpls { ordered_f32: ordered_float::OrderedFloat, ordered_f64: ordered_float::OrderedFloat, heapless_vec: heapless::Vec, semver: semver::Version, smol: smol_str::SmolStr, array_vec: arrayvec::ArrayVec, array_string: arrayvec::ArrayString<16>, smallvec: smallvec::SmallVec<[i32; 8]>, toml_datetime: toml::value::Datetime, ulid: ulid::Ulid, chrono_naive_datetime: chrono::NaiveDateTime, chrono_naive_date: chrono::NaiveDate, chrono_naive_time: chrono::NaiveTime, chrono_duration: chrono::Duration, chrono_date: chrono::Date, chrono_datetime: chrono::DateTime, chrono_fixed_offset: chrono::FixedOffset, chrono_utc: chrono::Utc, chrono_local: chrono::Local, either: either::Either, error_stack_report: error_stack::Report, error_stack_multi_report: error_stack::Report<[ErrorStackRootError]>, glam_affine2: glam::Affine2, glam_affine3a: glam::Affine3A, glam_mat2: glam::Mat2, glam_mat3: glam::Mat3, glam_mat3a: glam::Mat3A, glam_mat4: glam::Mat4, glam_quat: glam::Quat, glam_vec2: glam::Vec2, glam_vec3: glam::Vec3, glam_vec3a: glam::Vec3A, glam_vec4: glam::Vec4, glam_daffine2: glam::DAffine2, glam_daffine3: glam::DAffine3, glam_dmat2: glam::DMat2, glam_dmat3: glam::DMat3, glam_dmat4: glam::DMat4, glam_dquat: glam::DQuat, glam_dvec2: glam::DVec2, glam_dvec3: glam::DVec3, glam_dvec4: glam::DVec4, glam_i8vec2: glam::I8Vec2, glam_i8vec3: glam::I8Vec3, glam_i8vec4: glam::I8Vec4, glam_u8vec2: glam::U8Vec2, glam_u8vec3: glam::U8Vec3, glam_u8vec4: glam::U8Vec4, glam_i16vec2: glam::I16Vec2, glam_i16vec3: glam::I16Vec3, glam_i16vec4: glam::I16Vec4, glam_u16vec2: glam::U16Vec2, glam_u16vec3: glam::U16Vec3, glam_u16vec4: glam::U16Vec4, glam_ivec2: glam::IVec2, glam_ivec3: glam::IVec3, glam_ivec4: glam::IVec4, glam_uvec2: glam::UVec2, glam_uvec3: glam::UVec3, glam_uvec4: glam::UVec4, glam_bvec2: glam::BVec2, glam_bvec3: glam::BVec3, glam_bvec4: glam::BVec4, } #[derive(Type)] struct LegacyImplWithBigints { serde_json_map: serde_json::Map, serde_json_value: serde_json::Value, serde_json_number: serde_json::Number, serde_yaml_mapping: serde_yaml::Mapping, serde_yaml_tagged: serde_yaml::value::TaggedValue, serde_yaml_value: serde_yaml::Value, serde_yaml_number: serde_yaml::Number, bson_document: bson::Document, bson_value: bson::Bson, toml_map: toml::map::Map, toml_value: toml::Value, glam_i64vec2: glam::I64Vec2, glam_i64vec3: glam::I64Vec3, glam_i64vec4: glam::I64Vec4, glam_u64vec2: glam::U64Vec2, glam_u64vec3: glam::U64Vec3, glam_u64vec4: glam::U64Vec4, glam_usizevec2: glam::USizeVec2, glam_usizevec3: glam::USizeVec3, glam_usizevec4: glam::USizeVec4, } #[test] fn legacy_impls() { insta::assert_snapshot!( "legacy_impls", Typescript::default() .export( &Types::default().register::(), specta_serde::Format ) .unwrap() ); } #[test] fn legacy_impl_bigint_errors() { let err = Typescript::default() .export( &Types::default().register::(), specta_serde::Format, ) .expect_err("legacy BigInt impls should fail TypeScript export"); assert!( err.to_string() .contains("forbids exporting BigInt-style types") || err .to_string() .contains("Detected multiple types with the same name"), "unexpected error: {err}" ); } #[test] fn legacy_impl_individual_bigint_errors() { fn assert_bigint_export_error(failures: &mut Vec, name: &str) { match Typescript::default().export(&Types::default().register::(), specta_serde::Format) { Ok(output) => failures.push(format!( "{name}: expected BigInt export error, but export succeeded with '{output}'" )), Err(err) if err .to_string() .contains("forbids exporting BigInt-style types") => {} Err(err) => failures.push(format!("{name}: unexpected error '{err}'")), } } fn assert_bigint_or_invalid_map_key_error(failures: &mut Vec, name: &str) { match Typescript::default().export(&Types::default().register::(), specta_serde::Format) { Ok(output) => failures.push(format!( "{name}: expected BigInt or invalid map key error, but export succeeded with '{output}'" )), Err(err) if err .to_string() .contains("forbids exporting BigInt-style types") => {} Err(err) if err .to_string() .contains("Invalid map key") => {} Err(err) => failures.push(format!("{name}: unexpected error '{err}'")), } } macro_rules! bigint_wrapper { ($name:ident, $ty:ty) => { #[derive(Type)] #[specta(collect = false)] struct $name { value: $ty, } }; } bigint_wrapper!(BsonDocumentBigint, bson::Document); bigint_wrapper!(BsonValueBigint, bson::Bson); bigint_wrapper!(SerdeJsonMapBigint, serde_json::Map); bigint_wrapper!(SerdeJsonValueBigint, serde_json::Value); bigint_wrapper!(SerdeJsonNumberBigint, serde_json::Number); bigint_wrapper!(SerdeYamlMappingBigint, serde_yaml::Mapping); bigint_wrapper!(SerdeYamlTaggedBigint, serde_yaml::value::TaggedValue); bigint_wrapper!(SerdeYamlValueBigint, serde_yaml::Value); bigint_wrapper!(SerdeYamlNumberBigint, serde_yaml::Number); bigint_wrapper!(TomlMapBigint, toml::map::Map); bigint_wrapper!(TomlValueBigint, toml::Value); bigint_wrapper!(GlamI64Vec2Bigint, glam::I64Vec2); bigint_wrapper!(GlamI64Vec3Bigint, glam::I64Vec3); bigint_wrapper!(GlamI64Vec4Bigint, glam::I64Vec4); bigint_wrapper!(GlamU64Vec2Bigint, glam::U64Vec2); bigint_wrapper!(GlamU64Vec3Bigint, glam::U64Vec3); bigint_wrapper!(GlamU64Vec4Bigint, glam::U64Vec4); bigint_wrapper!(GlamUSizeVec2Bigint, glam::USizeVec2); bigint_wrapper!(GlamUSizeVec3Bigint, glam::USizeVec3); bigint_wrapper!(GlamUSizeVec4Bigint, glam::USizeVec4); let mut failures = Vec::new(); for (name, assert) in [ ( "bson::Document", assert_bigint_export_error:: as fn(&mut Vec, &str), ), ( "bson::Bson", assert_bigint_export_error:: as fn(&mut Vec, &str), ), ( "serde_json::Map", assert_bigint_export_error:: as fn(&mut Vec, &str), ), ( "serde_json::Value", assert_bigint_export_error:: as fn(&mut Vec, &str), ), ( "serde_json::Number", assert_bigint_export_error:: as fn(&mut Vec, &str), ), ( "serde_yaml::Mapping", assert_bigint_or_invalid_map_key_error:: as fn(&mut Vec, &str), ), ( "serde_yaml::value::TaggedValue", assert_bigint_or_invalid_map_key_error:: as fn(&mut Vec, &str), ), ( "serde_yaml::Value", assert_bigint_or_invalid_map_key_error:: as fn(&mut Vec, &str), ), ( "serde_yaml::Number", assert_bigint_export_error:: as fn(&mut Vec, &str), ), ( "toml::map::Map", assert_bigint_export_error:: as fn(&mut Vec, &str), ), ( "toml::Value", assert_bigint_export_error:: as fn(&mut Vec, &str), ), ( "glam::I64Vec2", assert_bigint_export_error:: as fn(&mut Vec, &str), ), ( "glam::I64Vec3", assert_bigint_export_error:: as fn(&mut Vec, &str), ), ( "glam::I64Vec4", assert_bigint_export_error:: as fn(&mut Vec, &str), ), ( "glam::U64Vec2", assert_bigint_export_error:: as fn(&mut Vec, &str), ), ( "glam::U64Vec3", assert_bigint_export_error:: as fn(&mut Vec, &str), ), ( "glam::U64Vec4", assert_bigint_export_error:: as fn(&mut Vec, &str), ), ( "glam::USizeVec2", assert_bigint_export_error:: as fn(&mut Vec, &str), ), ( "glam::USizeVec3", assert_bigint_export_error:: as fn(&mut Vec, &str), ), ( "glam::USizeVec4", assert_bigint_export_error:: as fn(&mut Vec, &str), ), ] { assert(&mut failures, name); } assert!( failures.is_empty(), "Unexpected legacy impl BigInt export behavior:\n{}", failures.join("\n") ); } ================================================ FILE: tests/tests/macro/compile_error.rs ================================================ //! This file is run with the `trybuild` crate to assert compilation errors in the Specta macros. use specta::{Type, specta}; // Invalid inflection #[derive(Type)] #[specta(collect = false)] #[serde(rename_all = "camelCase123")] pub enum Demo2 {} // Specta doesn't support Trait objects #[derive(Type)] #[specta(collect = false)] pub struct Error { pub(crate) cause: Option>, } // Enums can only flatten if // at least one of their variants can flatten #[derive(Type)] #[specta(collect = false)] enum UnitExternal { Unit, } #[derive(Type)] #[specta(collect = false)] enum UnnamedMultiExternal { UnnamedMulti(String, String), } #[derive(Type)] #[specta(collect = false)] struct FlattenExternal { #[serde(flatten)] unit: UnitExternal, #[serde(flatten)] unnamed_multi: UnnamedMultiExternal, } #[derive(Type)] #[specta(collect = false)] #[serde(untagged)] enum UnnamedUntagged { Unnamed(String), } #[derive(Type)] #[specta(collect = false)] #[serde(untagged)] enum UnnamedMultiUntagged { Unnamed(String, String), } #[derive(Type)] #[specta(collect = false)] struct FlattenUntagged { #[serde(flatten)] unnamed: UnnamedUntagged, #[serde(flatten)] unnamed_multi: UnnamedMultiUntagged, } // Adjacent can always flatten #[derive(Type)] #[specta(collect = false)] #[serde(tag = "tag")] enum UnnamedInternal { Unnamed(String), } // Internal can't be used with unnamed multis #[derive(Type)] #[specta(collect = false)] struct FlattenInternal { #[serde(flatten)] unnamed: UnnamedInternal, } // Invalid attributes #[derive(Type)] #[specta(collect = false)] #[specta(noshot = true)] struct InvalidAttrs1; #[derive(Type)] #[specta(collect = false)] #[specta(noshot)] struct InvalidAttrs2; #[derive(Type)] #[specta(collect = false)] struct InvalidAttrs3 { #[specta(noshot = true)] a: String, } #[derive(Type)] #[specta(collect = false)] struct InvalidAttrs4 { #[specta(noshot)] a: String, } // Legacy `#[specta(...)]` migration errors #[derive(Type)] #[specta(collect = false)] #[specta(rename = "Renamed")] struct LegacyContainerRename; #[derive(Type)] #[specta(collect = false)] struct LegacyFieldRename { #[specta(rename = "renamed")] a: String, } #[derive(Type)] #[specta(collect = false)] enum LegacyVariantRename { #[specta(rename = "renamed")] A, } const INTERNAL_RENAME_KEY: &str = "renamed"; #[derive(Type)] #[specta(collect = false)] struct InternalRenameFromPath { #[specta(rename_from_path = INTERNAL_RENAME_KEY)] a: String, } #[derive(Type)] #[specta(collect = false)] #[specta(transparent)] pub enum TransparentEnum {} #[derive(Type)] #[specta(collect = false, type = String, transparent)] pub struct TransparentTypeOverrideConflict(String); #[derive(Type)] #[specta(collect = false)] #[specta] pub struct InvalidSpectaAttribute1; #[derive(Type)] #[specta(collect = false)] #[specta = "todo"] pub struct InvalidSpectaAttribute2; use wasm_bindgen::prelude::wasm_bindgen; #[wasm_bindgen] #[specta] pub fn testing() {} #[specta(rename_all = "camelCase123")] pub fn invalid_function_rename_all() {} // TODO: https://docs.rs/trybuild/latest/trybuild/#what-to-test ================================================ FILE: tests/tests/macro/compile_error.stderr ================================================ error: unsupported serde casing: `camelCase123` --> tests/macro/compile_error.rs:8:22 | 8 | #[serde(rename_all = "camelCase123")] | ^^^^^^^^^^^^^^ error: specta: Found unsupported container attribute 'noshot' --> tests/macro/compile_error.rs:86:10 | 86 | #[specta(noshot = true)] | ^^^^^^ error: specta: Found unsupported container attribute 'noshot' --> tests/macro/compile_error.rs:91:10 | 91 | #[specta(noshot)] | ^^^^^^ error: specta: Found unsupported field attribute 'noshot' --> tests/macro/compile_error.rs:97:14 | 97 | #[specta(noshot = true)] | ^^^^^^ error: specta: Found unsupported field attribute 'noshot' --> tests/macro/compile_error.rs:104:14 | 104 | #[specta(noshot)] | ^^^^^^ error: specta: `#[specta(rename ...)]` is no longer supported on containers. Use `#[serde(rename = "...")]` instead. --> tests/macro/compile_error.rs:111:10 | 111 | #[specta(rename = "Renamed")] | ^^^^^^ error: specta: `#[specta(rename ...)]` is no longer supported on fields. Use `#[serde(rename = "...")]` instead. --> tests/macro/compile_error.rs:117:14 | 117 | #[specta(rename = "renamed")] | ^^^^^^ error: expected `,` --> tests/macro/compile_error.rs:124:21 | 124 | #[specta(rename = "renamed")] | ^ error: specta: Found unsupported field attribute 'rename_from_path' --> tests/macro/compile_error.rs:133:14 | 133 | #[specta(rename_from_path = INTERNAL_RENAME_KEY)] | ^^^^^^^^^^^^^^^^ error: #[specta(transparent)] is not allowed on an enum --> tests/macro/compile_error.rs:140:5 | 140 | pub enum TransparentEnum {} | ^^^^ error: specta: `#[specta(type = ...)]` cannot be combined with `#[specta(transparent)]` --> tests/macro/compile_error.rs:144:12 | 144 | pub struct TransparentTypeOverrideConflict(String); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: specta: invalid formatted attribute --> tests/macro/compile_error.rs:148:3 | 148 | #[specta] | ^^^^^^ error: specta: invalid formatted attribute --> tests/macro/compile_error.rs:153:3 | 153 | #[specta = "todo"] | ^^^^^^ error: specta: You must apply the #[specta] macro before the #[wasm_bindgen] macro --> tests/macro/compile_error.rs:158:1 | 158 | #[wasm_bindgen] | ^^^^^^^^^^^^^^^ | = note: this error originates in the attribute macro `wasm_bindgen` (in Nightly builds, run with -Z macro-backtrace for more info) error: specta: unsupported rename rule. Expected one of lowercase, UPPERCASE, PascalCase, camelCase, snake_case, SCREAMING_SNAKE_CASE, kebab-case, SCREAMING-KEBAB-CASE --> tests/macro/compile_error.rs:162:23 | 162 | #[specta(rename_all = "camelCase123")] | ^^^^^^^^^^^^^^ error[E0255]: the name `__specta__fn__testing` is defined multiple times --> tests/macro/compile_error.rs:160:8 | 159 | #[specta] | --------- previous definition of the macro `__specta__fn__testing` here 160 | pub fn testing() {} | ^^^^^^^ `__specta__fn__testing` reimported here | = note: `__specta__fn__testing` must be defined only once in the macro namespace of this module error: cannot find attribute `serde` in this scope --> tests/macro/compile_error.rs:8:3 | 8 | #[serde(rename_all = "camelCase123")] | ^^^^^ | = note: `serde` is in scope, but it is a crate, not an attribute help: `serde` is an attribute that can be used by the derive macros `Deserialize` and `Serialize`, you might be missing a `derive` attribute | 9 + #[derive(Deserialize, Serialize)] 10 | pub enum Demo2 {} | error: cannot find attribute `serde` in this scope --> tests/macro/compile_error.rs:36:7 | 36 | #[serde(flatten)] | ^^^^^ | = note: `serde` is an attribute that can be used by the derive macros `Deserialize` and `Serialize`, you might be missing a `derive` attribute = note: `serde` is in scope, but it is a crate, not an attribute error: cannot find attribute `serde` in this scope --> tests/macro/compile_error.rs:38:7 | 38 | #[serde(flatten)] | ^^^^^ | = note: `serde` is an attribute that can be used by the derive macros `Deserialize` and `Serialize`, you might be missing a `derive` attribute = note: `serde` is in scope, but it is a crate, not an attribute error: cannot find attribute `serde` in this scope --> tests/macro/compile_error.rs:44:3 | 44 | #[serde(untagged)] | ^^^^^ | = note: `serde` is in scope, but it is a crate, not an attribute help: `serde` is an attribute that can be used by the derive macros `Deserialize` and `Serialize`, you might be missing a `derive` attribute | 45 + #[derive(Deserialize, Serialize)] 46 | enum UnnamedUntagged { | error: cannot find attribute `serde` in this scope --> tests/macro/compile_error.rs:51:3 | 51 | #[serde(untagged)] | ^^^^^ | = note: `serde` is in scope, but it is a crate, not an attribute help: `serde` is an attribute that can be used by the derive macros `Deserialize` and `Serialize`, you might be missing a `derive` attribute | 52 + #[derive(Deserialize, Serialize)] 53 | enum UnnamedMultiUntagged { | error: cannot find attribute `serde` in this scope --> tests/macro/compile_error.rs:59:7 | 59 | #[serde(flatten)] | ^^^^^ | = note: `serde` is an attribute that can be used by the derive macros `Deserialize` and `Serialize`, you might be missing a `derive` attribute = note: `serde` is in scope, but it is a crate, not an attribute error: cannot find attribute `serde` in this scope --> tests/macro/compile_error.rs:61:7 | 61 | #[serde(flatten)] | ^^^^^ | = note: `serde` is an attribute that can be used by the derive macros `Deserialize` and `Serialize`, you might be missing a `derive` attribute = note: `serde` is in scope, but it is a crate, not an attribute error: cannot find attribute `serde` in this scope --> tests/macro/compile_error.rs:69:3 | 69 | #[serde(tag = "tag")] | ^^^^^ | = note: `serde` is in scope, but it is a crate, not an attribute help: `serde` is an attribute that can be used by the derive macros `Deserialize` and `Serialize`, you might be missing a `derive` attribute | 70 + #[derive(Deserialize, Serialize)] 71 | enum UnnamedInternal { | error: cannot find attribute `serde` in this scope --> tests/macro/compile_error.rs:79:7 | 79 | #[serde(flatten)] | ^^^^^ | = note: `serde` is an attribute that can be used by the derive macros `Deserialize` and `Serialize`, you might be missing a `derive` attribute = note: `serde` is in scope, but it is a crate, not an attribute error[E0601]: `main` function not found in crate `$CRATE` --> tests/macro/compile_error.rs:163:40 | 163 | pub fn invalid_function_rename_all() {} | ^ consider adding a `main` function to `$DIR/tests/macro/compile_error.rs` error[E0277]: the trait `specta::Type` is not implemented for `dyn std::error::Error + Send + Sync` --> tests/macro/compile_error.rs:15:23 | 15 | pub(crate) cause: Option>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `dyn std::error::Error + Send + Sync` must implement `Type` | = help: the trait `specta::Type` is not implemented for `dyn std::error::Error + Send + Sync` = note: Depending on your use case, this can be fixed in multiple ways: - If your using an type defined in one of your own crates, ensure you have `#[derive(specta::Type)]` on it. - If your using a crate with official Specta support, enable the matching feature flag on the `specta` crate. - If your using an external crate without Specta support, you may need to wrap your type in a new-type wrapper. = help: the following other types implement trait `specta::Type`: &T () (T10, T11, T12, T13) (T11, T12, T13) (T12, T13) (T13,) (T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13) (T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13) and $N others = note: required for `Box` to implement `specta::Type` = note: 1 redundant requirement hidden = note: required for `Option>` to implement `specta::Type` ================================================ FILE: tests/tests/mod.rs ================================================ //! We register a single entrypoint so all tests are compiled into a single binary. #![allow(unused_parens, unused_variables, dead_code, unused_mut)] macro_rules! register { ($types:expr, $dts:expr; $($ty:ty),* $(,)?) => {{ $( { let ty = <$ty as specta::Type>::definition(&mut $types); $dts.push((stringify!($ty), ty)); } )* }}; } mod bound; mod errors; mod functions; mod jsdoc; mod layouts; mod legacy_impls; mod references; mod serde_conversions; mod serde_identifiers; mod serde_other; mod swift; mod types; mod typescript; mod utils; mod zod; pub use types::{types, types_phased}; pub use utils::fs_to_string; #[test] fn compile_errors() { let t = trybuild::TestCases::new(); t.compile_fail("tests/macro/compile_error.rs"); } ================================================ FILE: tests/tests/references.rs ================================================ use std::any::TypeId; use specta::{ Type, Types, datatype::{DataType, Reference}, }; #[derive(Type)] #[specta(collect = false)] struct GenericType(T); #[derive(Type)] #[specta(collect = false)] struct AnotherOne; #[test] fn references() { // Opaque references are compared by value assert_eq!(Reference::opaque(()), Reference::opaque(())); assert_eq!(Reference::opaque(true), Reference::opaque(true)); assert_ne!(Reference::opaque(true), Reference::opaque(false)); assert_ne!(Reference::opaque(42u32), Reference::opaque('a')); // Ensure opaque metadata can be extracted again { let r = match Reference::opaque(()) { Reference::Opaque(r) => r, _ => panic!("Expected an opaque reference"), }; assert_eq!(r.type_id(), TypeId::of::<()>()); assert_eq!(r.type_name(), "()"); assert_eq!(r.downcast_ref(), Some(&())); } let mut types = Types::default(); // Named references `PartialEq` are compared by type, generics, inline, // however `Reference::ty_eq` compares by just type. { let a = match GenericType::<()>::definition(&mut types) { DataType::Reference(r) => r, _ => panic!("Expected a reference type"), }; let b = match GenericType::<()>::definition(&mut types) { DataType::Reference(r) => r, _ => panic!("Expected a reference type"), }; assert_eq!(a, b); assert!(a.ty_eq(&b)); assert!(b.ty_eq(&a)); } { let a = match GenericType::<()>::definition(&mut types) { DataType::Reference(r) => r, _ => panic!("Expected a reference type"), }; let b = match GenericType::::definition(&mut types) { DataType::Reference(r) => r, _ => panic!("Expected a reference type"), }; assert_ne!(a, b); assert!(a.ty_eq(&b)); assert!(b.ty_eq(&a)); } { let a = match GenericType::<()>::definition(&mut types) { DataType::Reference(r) => r, _ => panic!("Expected a reference type"), }; let b = match AnotherOne::definition(&mut types) { DataType::Reference(r) => r, _ => panic!("Expected a reference type"), }; assert_ne!(a, b); assert!(!a.ty_eq(&b)); assert!(!b.ty_eq(&a)); } } ================================================ FILE: tests/tests/serde_conversions.rs ================================================ use serde::{Deserialize, Serialize}; use specta::{Type, Types}; use specta_typescript::Typescript; #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct Wire { value: i32, } #[derive(Clone, Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(into = "Wire")] struct IntoOnly { value: i32, } #[derive(Clone, Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(from = "Wire", into = "Wire")] struct Symmetric { value: i32, } #[derive(Clone, Type, Serialize, Deserialize)] #[specta(collect = false)] struct GenericWire { values: Vec, } #[derive(Clone, Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(try_from = "GenericWire")] struct GenericTryFrom { values: Vec, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct GenericParent { child: GenericTryFrom, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct Parent { child: IntoOnly, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct CustomCodecNoOverride { #[serde(with = "codec")] value: String, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct CustomCodecWithOverride { #[specta(type = String)] #[serde(with = "codec")] value: String, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct CustomCodecWithPhasedOverride { #[specta(type = specta_serde::Phased)] #[serde(with = "codec")] value: String, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct FieldOnlyPhasedOverride { #[specta(type = specta_serde::Phased)] value: String, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct SkipSerializingIfOnly { #[serde(skip_serializing_if = "Option::is_none")] value: Option, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct FieldPhaseSpecificRename { #[serde(rename(serialize = "serialized_value", deserialize = "deserialized_value"))] value: String, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] enum VariantCodecNoOverride { #[serde( serialize_with = "codec_variant::serialize", deserialize_with = "codec_variant::deserialize" )] A(String), } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] enum VariantCodecWithOverride { #[serde( serialize_with = "codec_variant::serialize", deserialize_with = "codec_variant::deserialize" )] #[specta(r#type = String)] A(String), } #[derive(Type, Deserialize)] #[specta(collect = false)] #[serde(variant_identifier)] enum VariantIdentifierValid { Alpha, Beta, } #[derive(Type, Deserialize)] #[specta(collect = false)] #[serde(field_identifier)] enum FieldIdentifierValid { Alpha, Beta, Other(String), } mod codec { use serde::{Deserialize, Deserializer, Serializer}; pub fn serialize(_value: &str, serializer: S) -> Result where S: Serializer, { serializer.serialize_str("codec") } pub fn deserialize<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, { String::deserialize(deserializer) } } mod codec_variant { use serde::{Deserialize, Deserializer, Serializer}; pub fn serialize(value: &str, serializer: S) -> Result where S: Serializer, { serializer.serialize_str(value) } pub fn deserialize<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, { String::deserialize(deserializer) } } impl From for Wire { fn from(value: IntoOnly) -> Self { Self { value: value.value } } } impl From for Wire { fn from(value: Symmetric) -> Self { Self { value: value.value } } } impl From for Symmetric { fn from(value: Wire) -> Self { Self { value: value.value } } } impl TryFrom> for GenericTryFrom { type Error = std::convert::Infallible; fn try_from(value: GenericWire) -> Result { Ok(Self { values: value.values, }) } } #[test] fn apply_rejects_asymmetric_container_conversion() { let err = Typescript::default() .export( &Types::default().register::(), specta_serde::Format, ) .expect_err("apply should reject asymmetric serde conversions"); assert!( err.to_string() .contains("Incompatible container conversion"), "unexpected error: {err}" ); } #[test] fn phases_format_splits_container_and_dependents_for_conversions() { let rendered = Typescript::default() .export( &Types::default().register::(), specta_serde::PhasesFormat, ) .expect("PhasesFormat should support asymmetric serde conversions"); insta::assert_snapshot!( "serde-conversions-format-phases-splits-container-and-dependents", rendered ); } #[test] fn apply_accepts_symmetric_container_conversion() { Typescript::default() .export( &Types::default().register::(), specta_serde::Format, ) .expect("apply should accept symmetric serde conversions"); } #[test] fn phases_format_accepts_generic_try_from_container_conversion() { let err = Typescript::default() .export( &Types::default().register::>(), specta_serde::Format, ) .expect_err("apply should reject deserialize-only container conversions"); assert!( err.to_string() .contains("Incompatible container conversion") ); Typescript::default() .export( &Types::default().register::>(), specta_serde::PhasesFormat, ) .expect("PhasesFormat should resolve nested generic references from container conversions"); } #[test] fn custom_codec_requires_explicit_override() { let err = Typescript::default() .export( &Types::default().register::(), specta_serde::Format, ) .expect_err("custom serde codecs should require #[specta(type = ...)]"); assert!(err.to_string().contains("Unsupported serde attribute")); Typescript::default() .export( &Types::default().register::(), specta_serde::Format, ) .expect("override should satisfy custom serde codecs"); } #[test] fn custom_codec_variant_requires_explicit_override() { let err = Typescript::default() .export( &Types::default().register::(), specta_serde::Format, ) .expect_err("variant custom serde codecs should require #[specta(type = ...)]"); assert!(err.to_string().contains("Unsupported serde attribute")); Typescript::default() .export( &Types::default().register::(), specta_serde::Format, ) .expect("variant override should satisfy custom serde codecs"); } #[test] fn phased_override_requires_phases_format() { let err = Typescript::default() .export( &Types::default().register::(), specta_serde::Format, ) .expect_err("apply should reject phased overrides"); assert!(err.to_string().contains("requires `PhasesFormat`")); Typescript::default() .export( &Types::default().register::(), specta_serde::PhasesFormat, ) .expect("PhasesFormat should accept phased overrides"); } #[test] fn field_only_phased_override_requires_phases_format() { let err = Typescript::default() .export( &Types::default().register::(), specta_serde::Format, ) .expect_err("apply should reject phased field overrides"); assert!(err.to_string().contains("requires `PhasesFormat`")); Typescript::default() .export( &Types::default().register::(), specta_serde::PhasesFormat, ) .expect("phased export should remove phased opaque references"); } #[test] fn phases_format_exports_field_only_phased_override() { let rendered = Typescript::default() .export( &Types::default().register::(), specta_serde::PhasesFormat, ) .expect("PhasesFormat should resolve phased overrides during export"); insta::assert_snapshot!( "serde-conversions-format-phases-exports-field-only-phased-override", rendered ); } #[test] fn skip_serializing_if_requires_phases() { let err = Typescript::default() .export( &Types::default().register::(), specta_serde::Format, ) .expect_err("skip_serializing_if should require PhasesFormat"); assert!(err.to_string().contains("skip_serializing_if")); Typescript::default() .export( &Types::default().register::(), specta_serde::PhasesFormat, ) .expect("PhasesFormat should accept skip_serializing_if"); } #[test] fn field_phase_specific_rename_requires_phases() { let err = Typescript::default() .export( &Types::default().register::(), specta_serde::Format, ) .expect_err("field-level phase-specific renames should require PhasesFormat"); assert!(err.to_string().contains("Incompatible field rename")); Typescript::default() .export( &Types::default().register::(), specta_serde::PhasesFormat, ) .expect("PhasesFormat should accept field-level phase-specific renames"); } #[test] fn identifier_enums_require_phases() { let err = Typescript::default() .export( &Types::default().register::(), specta_serde::Format, ) .expect_err("identifier enums should require PhasesFormat"); assert!( err.to_string() .contains("identifier enums require `PhasesFormat`") ); Typescript::default() .export( &Types::default().register::(), specta_serde::PhasesFormat, ) .expect("valid variant_identifier enum should pass in PhasesFormat"); Typescript::default() .export( &Types::default().register::(), specta_serde::PhasesFormat, ) .expect("valid field_identifier enum should pass in PhasesFormat"); } ================================================ FILE: tests/tests/serde_identifiers.rs ================================================ use serde::Deserialize; use specta::{Type, Types}; use specta_typescript::Typescript; #[derive(Type, Deserialize)] #[specta(collect = false)] #[serde(variant_identifier, rename_all = "snake_case")] enum VariantIdentifier { HttpStatus, #[serde(alias = "legacy")] LegacyName, } #[derive(Type, Deserialize)] #[specta(collect = false)] #[serde(field_identifier, rename_all = "snake_case")] enum FieldIdentifier { FirstName, LastName, Other(bool), } #[test] fn identifier_apply_requires_phases() { let err = Typescript::default() .export( &Types::default().register::(), specta_serde::Format, ) .expect_err("variant_identifier should require PhasesFormat"); assert!( err.to_string() .contains("identifier enums require `PhasesFormat`") ); let err = Typescript::default() .export( &Types::default().register::(), specta_serde::Format, ) .expect_err("field_identifier should require PhasesFormat"); assert!( err.to_string() .contains("identifier enums require `PhasesFormat`") ); } #[test] fn identifier_phases_format_exports_deserialize_union() { let variant_ts = Typescript::default() .export( &Types::default().register::(), specta_serde::PhasesFormat, ) .expect("typescript export should succeed"); insta::assert_snapshot!("serde-identifiers-variant-typescript", variant_ts); let field_ts = Typescript::default() .export( &Types::default().register::(), specta_serde::PhasesFormat, ) .expect("typescript export should succeed"); insta::assert_snapshot!("serde-identifiers-field-typescript", field_ts); } ================================================ FILE: tests/tests/serde_other.rs ================================================ // Regression test for https://github.com/specta-rs/specta/issues/131 use serde::Deserialize; use specta::{Type, Types}; use specta_typescript::Typescript; #[derive(Type, Deserialize)] #[specta(collect = false)] #[serde(tag = "kind")] enum InternalOther { #[serde(rename = "known")] Known, #[serde(other)] Other, } #[derive(Type, Deserialize)] #[specta(collect = false)] #[serde(tag = "kind", content = "data")] enum AdjacentOther { #[serde(rename = "known")] Known(String), #[serde(other)] Other, } #[test] fn serde_other_requires_phases_format() { let err = Typescript::default() .export( &Types::default().register::(), specta_serde::Format, ) .expect_err("#[serde(other)] should require PhasesFormat"); assert!( err.to_string() .contains("`#[serde(other)]` requires `PhasesFormat`") ); } #[test] fn serde_other_internal_tag_widens_deserialize_tag_to_string() { let ts = Typescript::default() .export( &Types::default().register::(), specta_serde::PhasesFormat, ) .expect("typescript export should succeed"); insta::assert_snapshot!("serde-other-internal-tag-typescript", ts); } #[test] fn serde_other_adjacent_tag_widens_deserialize_tag_to_string() { let ts = Typescript::default() .export( &Types::default().register::(), specta_serde::PhasesFormat, ) .expect("typescript export should succeed"); insta::assert_snapshot!("serde-other-adjacent-tag-typescript", ts); } ================================================ FILE: tests/tests/snapshots/test__bound__bound-associated-type-issue-138.snap ================================================ --- source: tests/tests/bound.rs expression: output --- // This file has been generated by Specta. Do not edit this file manually. export type Demo = { value: number, }; ================================================ FILE: tests/tests/snapshots/test__jsdoc__export-many-raw.snap ================================================ --- source: tests/tests/jsdoc.rs expression: output --- /** * @typedef {{ * start: T, * end: T, * }} Range * @property {T} start * @property {T} end * * @typedef {{ * start: T, * end: T, * }} RangeInclusive * @property {T} start * @property {T} end * * @typedef {{ * ok: T, * err: E, * }} Result * @property {T} ok * @property {E} err * * @typedef {null} Unit1 * * @typedef {Record} Unit2 * * @typedef {[]} Unit3 * * @typedef {null} Unit4 * @property {null} "0" * * @typedef {"A"} Unit5 * @property {"A"} A * * @typedef {[]} Unit6 * @property {[]} A * * @typedef {Record} Unit7 * @property {Record} A * * @typedef {{ * a: number, * b: string, * c: [number, string, number], * d: string[], * e: string | null, * }} SimpleStruct * @property {number} a * @property {string} b * @property {[number, string, number]} c * @property {string[]} d * @property {string | null} e * * @typedef {number} TupleStruct1 * @property {number} "0" * * @typedef {[number, boolean, string]} TupleStruct3 * @property {number} "0" * @property {boolean} "1" * @property {string} "2" * * @typedef {"Unit" | number | [number, number] | { a: number }} TestEnum * @property {"Unit"} Unit * @property {number} Single * @property {[number, number]} Multiple * @property {{ a: number }} Struct * * @typedef {TestEnum} RefStruct * @property {TestEnum} "0" * * @typedef {{ * inline_this: { * ref_struct: SimpleStruct, * val: number, * }, * dont_inline_this: RefStruct, * }} InlinerStruct * @property {{ * ref_struct: SimpleStruct, * val: number, * }} inline_this * @property {RefStruct} dont_inline_this * * @typedef {{ * arg: T, * }} GenericStruct * @property {T} arg * * @typedef {{ * arg: T, * }} GenericStruct * @property {T} arg * * @typedef {{ * outer: string, * inner: FlattenEnum, * }} FlattenEnumStruct * @property {string} outer * @property {FlattenEnum} inner * * @typedef {{ * overriden_field: string, * }} OverridenStruct * @property {string} overriden_field * * @typedef {{ [key in number]: string }} HasGenericAlias * @property {{ [key in number]: string }} "0" * * @typedef {string | number | { a: string; b: number }} EnumMacroAttributes * @property {string} A * @property {number} B * @property {number} C * @property {{ a: string; b: number }} D * * @typedef {{ * a: string, * }} InlineEnumField * @property {{ * a: string, * }} A * * @typedef {{ * optional_field: { * a: string, * } | null, * }} InlineOptionalType * @property {{ * a: string, * } | null} optional_field * * @typedef {"OneWord" | "TwoWords"} Rename * @property {"OneWord"} OneWord * @property {"TwoWords"} TwoWords * * @typedef {TransparentTypeInner} TransparentType * @property {TransparentTypeInner} "0" * * @typedef {null} TransparentType2 * @property {null} "0" * * @typedef {string} TransparentTypeWithOverride * @property {string} "0" * * @typedef {{ * a: Partial<{ [key in BasicEnum]: number }>, * }} EnumReferenceRecordKey * @property {Partial<{ [key in BasicEnum]: number }>} a * * @typedef {{ * id: string, * result: NestedEnum, * }} FlattenOnNestedEnum * @property {string} id * @property {NestedEnum} result * * @typedef {Record} MyEmptyInput * * @typedef {string} ExtraBracketsInTupleVariant * @property {string} A * * @typedef {string} ExtraBracketsInUnnamedStruct * @property {string} "0" * * @typedef {{ * demo: [string, boolean], * }} InlineTuple * @property {[string, boolean]} demo * * @typedef {{ * demo: [{ * demo: [string, boolean], * }, boolean], * }} InlineTuple2 * @property {[{ * demo: [string, boolean], * }, boolean]} demo * * @typedef {never | string} SkippedFieldWithinVariant * @property {never} A * @property {string} B * * @typedef {{ * test_ing: string, * }} KebabCase * @property {string} test_ing * * @typedef {{ * default_unity_arguments: string[], * }} Issue281 * @property {string[]} default_unity_arguments * * @typedef {{ * borrowed: T[], * owned: T[], * }} LifetimeGenericStruct * @property {T[]} borrowed * @property {T[]} owned * * @typedef {T} LifetimeGenericEnum * @property {T} Borrowed * @property {T} Owned * * @typedef {{ * odata_context: string, * }} RenameWithWeirdCharsField * @property {string} odata_context * * @typedef {string} RenameWithWeirdCharsVariant * @property {string} A * * @typedef {{ * empty: string, * quote: string, * backslash: string, * newline: string, * line_separator: string, * paragraph_separator: string, * }} RenamedFieldKeys * @property {string} empty * @property {string} quote * @property {string} backslash * @property {string} newline * @property {string} line_separator * @property {string} paragraph_separator * * @typedef {never} RenamedVariantWithSkippedPayload * @property {never} A * * @typedef {never} Type * * @typedef {{ * a: GenericType, * }} ActualType * @property {GenericType} a * * @typedef {{ * string_ident: string, * u32_ident: number, * path: string, * tuple: [string, number], * }} SpectaTypeOverride * @property {string} string_ident * @property {number} u32_ident * @property {string} path * @property {[string, number]} tuple * * @typedef {string} ContainerTypeOverrideStruct * * @typedef {string} ContainerTypeOverrideEnum * * @typedef {string} ContainerTypeOverrideGeneric * * @typedef {T} ContainerTypeOverrideToGeneric * * @typedef {[string, number]} ContainerTypeOverrideTuple * * @typedef {[T, string]} ContainerTypeOverrideTupleGeneric * * @typedef {{ * cause: null, * }} InvalidToValidType * @property {null} cause * * @typedef {string} TupleStruct * @property {string} "0" * * @typedef {string} TupleStructWithRep * @property {string} "0" * * @typedef {T} GenericTupleStruct * @property {T} "0" * * @typedef {string} BracedStruct * @property {string} "0" * * @typedef {{ * a: string, * }} Struct * @property {string} a * * @typedef {{ * a: string, * }} Struct2 * @property {string} a * * @typedef {"A" | "B"} Enum * @property {"A"} A * @property {"B"} B * * @typedef {"A" | "B" | { enum_field: null }} Enum2 * @property {"A"} A * @property {"B"} B * @property {{ enum_field: null }} D * * @typedef {{ a: string }} Enum3 * @property {{ a: string }} A * * @typedef {{ * a: number, * b: number, * }} StructRenameAllUppercase * @property {number} a * @property {number} b * * @typedef {{ * b: number, * }} RenameSerdeSpecialChar * @property {number} b * * @typedef {"HelloWorld" | "VariantB" | "TestingWords"} EnumRenameAllUppercase * @property {"HelloWorld"} HelloWorld * @property {"VariantB"} VariantB * @property {"TestingWords"} TestingWords * * @typedef {{ * demo: Recursive, * }} Recursive * @property {Recursive} demo * * @typedef {{ * demo: { [key in string]: RecursiveMapValue }, * }} RecursiveMapValue * @property {{ [key in string]: RecursiveMapValue }} demo * * @typedef {RecursiveInline} RecursiveTransparent * @property {RecursiveInline} "0" * * @typedef {{ demo: RecursiveInEnum }} RecursiveInEnum * @property {{ demo: RecursiveInEnum }} A * * @typedef {string | null} NonOptional * @property {string | null} "0" * * @typedef {string | null} OptionalOnNamedField * @property {string | null} ["0"] * * @typedef {{ * b: string | null, * }} OptionalOnTransparentNamedField * @property {string | null} b * * @typedef {string | null | { a: string | null } | { a?: string | null }} OptionalInEnum * @property {string | null} A * @property {{ a: string | null }} B * @property {{ a?: string | null }} C * * @typedef {string | number | { id: string } | [string, boolean]} UntaggedVariants * @property {string} A * @property {number} B * @property {number} C * @property {{ id: string }} D * @property {[string, boolean]} E * * @typedef {string | [number, string] | number} UntaggedVariantsWithoutValue * @property {string} A * @property {[number, string]} B * @property {number} C * * @typedef {null | number} UntaggedVariantsWithDuplicateBranches * @property {null} A * @property {number} B * @property {null} C * * @typedef {{ [key in string]: null }} Regular * @property {{ [key in string]: null }} "0" * * @typedef {{ [key in MaybeValidKey]: null }} ValidMaybeValidKey * @property {{ [key in MaybeValidKey]: null }} "0" * * @typedef {{ [key in MaybeValidKey>]: null }} ValidMaybeValidKeyNested * @property {{ [key in MaybeValidKey>]: null }} "0" * * @typedef {string} MacroStruct * @property {string} "0" * * @typedef {{ * demo: string, * }} MacroStruct2 * @property {string} demo * * @typedef {string | { demo2: string }} MacroEnum * @property {string} Demo * @property {{ demo2: string }} Demo2 * * @deprecated * @typedef {{ * a: number, * }} DeprecatedType * @property {number} a * * @deprecated Look at you big man using a deprecation message * @typedef {{ * a: number, * }} DeprecatedTypeWithMsg * @property {number} a * * @deprecated Look at you big man using a deprecation message * @typedef {{ * a: number, * }} DeprecatedTypeWithMsg2 * @property {number} a * * @typedef {{ * a: number, * /** * * @deprecated * */ * b: string, * /** * * @deprecated This field is cringe! * */ * c: string, * /** * * @deprecated This field is cringe! * */ * d: string, * }} DeprecatedFields * @property {number} a * @property {string} b - @deprecated * @property {string} c - @deprecated This field is cringe! * @property {string} d - @deprecated This field is cringe! * * @typedef {[ * /** * * @deprecated * */ * string, * /** * * @deprecated Nope * */ * string, * /** * * @deprecated Nope * */ * number]} DeprecatedTupleVariant * @property {string} "0" - @deprecated * @property {string} "1" - @deprecated Nope * @property {number} "2" - @deprecated Nope * * @typedef { * /** * * @deprecated * */ * "A" | * /** * * @deprecated Nope * */ * "B" | * /** * * @deprecated Nope * */ * "C"} DeprecatedEnumVariants * @property { * /** * * @deprecated * */ * "A"} A - @deprecated * @property { * /** * * @deprecated Nope * */ * "B"} B - @deprecated Nope * @property { * /** * * @deprecated Nope * */ * "C"} C - @deprecated Nope * * Some triple-slash comment * Some more triple-slash comment * * @typedef {{ * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * }} CommentedStruct * @property {number} a - Some triple-slash comment Some more triple-slash comment * * Some triple-slash comment * Some more triple-slash comment * * @typedef { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * number | * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number }} CommentedEnum * @property { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * number} A - Some triple-slash comment Some more triple-slash comment * @property { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number }} B - Some triple-slash comment Some more triple-slash comment * * Some single-line comment * * @typedef { * /** Some single-line comment */ * number | * /** Some single-line comment */ * { * /** Some single-line comment */ * a: number }} SingleLineComment * @property { * /** Some single-line comment */ * number} A - Some single-line comment * @property { * /** Some single-line comment */ * { * /** Some single-line comment */ * a: number }} B - Some single-line comment * * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b * * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b * * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b * * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b * * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b * * @typedef {{ * field: Demo, * }} AGenericStruct * @property {Demo} field * * @typedef {{ * a: B, * b: { * b: number, * }, * c: B, * d: { * flattened: number, * }, * e: { * generic_flattened: number, * }, * }} A * @property {B} a * @property {{ * b: number, * }} b * @property {B} c * @property {{ * flattened: number, * }} d * @property {{ * generic_flattened: number, * }} e * * @typedef {{ * a: ToBeFlattened, * b: ToBeFlattened, * }} DoubleFlattened * @property {ToBeFlattened} a * @property {ToBeFlattened} b * * @typedef {{ * c: Inner, * }} FlattenedInner * @property {Inner} c * * @typedef {{ * b: BoxedInner, * }} BoxFlattened * @property {BoxedInner} b * * @typedef {{ * c: { * a: number, * }, * }} BoxInline * @property {{ * a: number, * }} c * * @typedef {{ * a: string, * }} First * @property {string} a * * @typedef {{ * a: number, * }} Second * @property {number} a * * @typedef {{ * a: First, * b: { [key in string]: string }, * c: First, * }} Third * @property {First} a * @property {{ [key in string]: string }} b * @property {First} c * * @typedef {{ * a: First, * b: { * a: string, * }, * }} Fourth * @property {First} a * @property {{ * a: string, * }} b * * @typedef {{ * a: First, * b: { * a: string, * }, * }} TagOnStructWithInline * @property {First} a * @property {{ * a: string, * }} b * * @typedef {{ * a: First, * b: First, * }} Sixth * @property {First} a * @property {First} b * * @typedef {{ * a: First, * b: Second, * }} Seventh * @property {First} a * @property {Second} b * * @typedef {string | "B"} Eight * @property {string} A * @property {"B"} B * * @typedef {string | "B" | { * a: string, * } | First} Ninth * @property {string} A * @property {"B"} B * @property {{ * a: string, * }} C * @property {First} D * * @typedef {string | "B" | { * a: string, * } | First} Tenth * @property {string} A * @property {"B"} B * @property {{ * a: string, * }} C * @property {First} D * * @typedef {{ inner: First }} MyEnumTagged * @property {{ inner: First }} Variant * * @typedef {{ inner: First }} MyEnumExternal * @property {{ inner: First }} Variant * * @typedef {{ inner: First }} MyEnumAdjacent * @property {{ inner: First }} Variant * * @typedef {{ inner: First }} MyEnumUntagged * @property {{ inner: First }} Variant * * @typedef {Record} EmptyStruct * * @typedef {Record} EmptyStructWithTag * * @typedef {"A" | { id: string; method: string } | string} AdjacentlyTagged * @property {"A"} A * @property {{ id: string; method: string }} B * @property {string} C * * @typedef {({ project_name: string }) & { progress?: never; status?: never } | { project_name: string; status: string; progress: number }} LoadProjectEvent * @property {{ project_name: string }} Started * @property {{ project_name: string; status: string; progress: number }} ProgressTest * @property {{ project_name: string }} Finished * * @typedef {"A" | { id: string; method: string } | string} ExternallyTagged * @property {"A"} A * @property {{ id: string; method: string }} B * @property {string} C * * @typedef {({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }} Issue221External * @property {{ a: string }} A * @property {{ b: string }} B * * @typedef {{ [key in string]: string }} InternallyTaggedD * @property {{ [key in string]: string }} A * * @typedef {null} InternallyTaggedE * @property {null} A * * @typedef {InternallyTaggedFInner} InternallyTaggedF * @property {InternallyTaggedFInner} A * * @typedef {InternallyTaggedHInner} InternallyTaggedH * @property {InternallyTaggedHInner} A * * @typedef {"A" | "B"} InternallyTaggedL * @property {"A" | "B"} A * * @typedef {"A" | "B"} InternallyTaggedM * @property {"A" | "B"} A * * @typedef {{ * field: string, * }} StructWithAlias * @property {string} field * * @typedef {{ * field: string, * }} StructWithMultipleAliases * @property {string} field * * @typedef {{ * field: string, * }} StructWithAliasAndRename * @property {string} field * * @typedef {"Variant" | "Other"} EnumWithVariantAlias * @property {"Variant"} Variant * @property {"Other"} Other * * @typedef {"Variant" | "Other"} EnumWithMultipleVariantAliases * @property {"Variant"} Variant * @property {"Other"} Other * * @typedef {"Variant" | "Other"} EnumWithVariantAliasAndRename * @property {"Variant"} Variant * @property {"Other"} Other * * @typedef {({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }} InternallyTaggedWithAlias * @property {{ field: string }} A * @property {{ other: number }} B * * @typedef {({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }} AdjacentlyTaggedWithAlias * @property {{ field: string }} A * @property {{ other: number }} B * * @typedef {({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }} UntaggedWithAlias * @property {{ field: string }} A * @property {{ other: number }} B * * @typedef {({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }} Issue221UntaggedSafe * @property {{ a: string }} A * @property {{ b: string }} B * * @typedef {({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never }} Issue221UntaggedMixed * @property {{ a: string }} A * @property {{ b: string }} B * @property {{ values: { [key in string]: string } }} Unsafe * * @typedef {never} EmptyEnum * * @typedef {never} EmptyEnumTagged * * @typedef {never} EmptyEnumTaggedWContent * * @typedef {never} EmptyEnumUntagged * * @typedef {Record} SkipOnlyField * * @typedef {{ * b: number, * }} SkipField * @property {number} b * * @typedef {string} SkipVariant * @property {string} A * * @typedef {never | [number]} SkipUnnamedFieldInVariant * @property {never} A * @property {[number]} B * * @typedef {Record | { b: number }} SkipNamedFieldInVariant * @property {Record} A * @property {{ b: number }} B * * @typedef {null} TransparentWithSkip * @property {null} "0" * * @typedef {string} TransparentWithSkip2 * @property {string} "0" * * @typedef {string} TransparentWithSkip3 * @property {string} "0" * * @typedef {string} SkipVariant2 * @property {string} A * * @typedef {{ a: string }} SkipVariant3 * @property {{ a: string }} A * * @typedef {{ * a: number, * }} SkipStructFields * @property {number} a * * @typedef {{ * a: number, * }} SpectaSkipNonTypeField * @property {number} a * * @typedef {{ * a: number, * b: number, * }} FlattenA * @property {number} a * @property {number} b * * @typedef {{ * a: FlattenA, * c: number, * }} FlattenB * @property {FlattenA} a * @property {number} c * * @typedef {{ * a: FlattenA, * c: number, * }} FlattenC * @property {FlattenA} a * @property {number} c * * @typedef {{ * a: FlattenA, * c: number, * }} FlattenD * @property {FlattenA} a * @property {number} c * * @typedef {{ * b: { * a: FlattenA, * c: number, * }, * d: number, * }} FlattenE * @property {{ * a: FlattenA, * c: number, * }} b * @property {number} d * * @typedef {{ * b: { * a: FlattenA, * c: number, * }, * d: number, * }} FlattenF * @property {{ * a: FlattenA, * c: number, * }} b * @property {number} d * * @typedef {{ * b: FlattenB, * d: number, * }} FlattenG * @property {FlattenB} b * @property {number} d * * @typedef {[number[], [number[], number[]], [number[], number[], number[]]]} TupleNested * @property {number[]} "0" * @property {[number[], number[]]} "1" * @property {[number[], number[], number[]]} "2" * * @typedef {{ * value: T, * values: T[], * }} Generic1 * @property {T} value * @property {T[]} values * * @typedef {{ * value: T, * values: T[], * }} GenericAutoBound * @property {T} value * @property {T[]} values * * @typedef {{ * value: T, * values: T[], * }} GenericAutoBound2 * @property {T} value * @property {T[]} values * * @typedef {{ * foo: Generic1, * bar: Generic1[], * baz: { [key in string]: Generic1 }, * }} Container1 * @property {Generic1} foo * @property {Generic1[]} bar * @property {{ [key in string]: Generic1 }} baz * * @typedef {A | [B, B, B] | C[] | A[][][] | { a: A; b: B; c: C } | number[] | number | number[][]} Generic2 * @property {A} A * @property {[B, B, B]} B * @property {C[]} C * @property {A[][][]} D * @property {{ a: A; b: B; c: C }} E * @property {number[]} X * @property {number} Y * @property {number[][]} Z * * @typedef {T[][]} GenericNewType1 * @property {T[][]} "0" * * @typedef {[T, T[], T[][]]} GenericTuple * @property {T} "0" * @property {T[]} "1" * @property {T[][]} "2" * * @typedef {{ * a: T, * b: [T, T], * c: [T, [T, T]], * d: [T, T, T], * e: [([T, T]), ([T, T]), ([T, T])], * f: T[], * g: T[][], * h: ([([T, T]), ([T, T]), ([T, T])])[], * }} GenericStruct2 * @property {T} a * @property {[T, T]} b * @property {[T, [T, T]]} c * @property {[T, T, T]} d * @property {[([T, T]), ([T, T]), ([T, T])]} e * @property {T[]} f * @property {T[][]} g * @property {([([T, T]), ([T, T]), ([T, T])])[]} h * * @typedef {{ * t: T, * }} InlineFlattenGenericsG * @property {T} t * * @typedef {{ * g: InlineFlattenGenericsG, * gi: { * t: string, * }, * t: InlineFlattenGenericsG, * }} InlineFlattenGenerics * @property {InlineFlattenGenericsG} g * @property {{ * t: string, * }} gi * @property {InlineFlattenGenericsG} t * * @typedef {{ * value: T, * }} GenericDefault * @property {T} value * * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second * * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second * * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second * * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second * * @typedef {{ * value: T, * }} GenericDefaultSkipped * @property {T} value * * @typedef {{ * value: number, * }} GenericDefaultSkippedNonType * @property {number} value * * @typedef {{ * pair: Pair, * }} GenericParameterOrderPreserved * @property {Pair} pair * * @typedef {{ * data: [number], * a: [number, number], * d: [number, number], * }} ConstGenericInNonConstContainer * @property {[number]} data * @property {[number, number]} a * @property {[number, number]} d * * @typedef {{ * data: number[], * a: number[], * d: [number, number], * }} ConstGenericInConstContainer * @property {number[]} data * @property {number[]} a * @property {[number, number]} d * * @typedef {{ * a: NamedConstGeneric, * b: NamedConstGeneric, * d: [number, number], * }} NamedConstGenericContainer * @property {NamedConstGeneric} a * @property {NamedConstGeneric} b * @property {[number, number]} d * * @typedef {{ * b: { * data: [number, number], * a: [number, number], * d: [number, number, number], * }, * c: { * data: [number, number, number], * a: [number, number], * d: [number, number, number], * }, * d: [number, number], * }} InlineConstGenericContainer * @property {{ * data: [number, number], * a: [number, number], * d: [number, number, number], * }} b * @property {{ * data: [number, number, number], * a: [number, number], * d: [number, number, number], * }} c * @property {[number, number]} d * * @typedef {{ * b: { * data: [number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }, * c: { * data: [number, number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }, * d: [number, number], * }} InlineRecursiveConstGenericContainer * @property {{ * data: [number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }} b * @property {{ * data: [number, number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }} c * @property {[number, number]} d * * @typedef {never} TestCollectionRegister * * @typedef {never} TestCollectionRegister */ ================================================ FILE: tests/tests/snapshots/test__jsdoc__export-many-serde.snap ================================================ --- source: tests/tests/jsdoc.rs expression: output --- /** * @typedef {{ * start: T, * end: T, * }} Range * @property {T} start * @property {T} end * * @typedef {{ * start: T, * end: T, * }} RangeInclusive * @property {T} start * @property {T} end * * @typedef {{ * ok: T, * err: E, * }} Result * @property {T} ok * @property {E} err * * @typedef {null} Unit1 * * @typedef {Record} Unit2 * * @typedef {[]} Unit3 * * @typedef {null} Unit4 * @property {null} "0" * * @typedef {"A"} Unit5 * @property {"A"} A * * @typedef {{ A: null }} Unit6 * @property {{ A: null }} A * * @typedef {{ A: Record }} Unit7 * @property {{ A: Record }} A * * @typedef {{ * a: number, * b: string, * c: [number, string, number], * d: string[], * e: string | null, * }} SimpleStruct * @property {number} a * @property {string} b * @property {[number, string, number]} c * @property {string[]} d * @property {string | null} e * * @typedef {number} TupleStruct1 * @property {number} "0" * * @typedef {[number, boolean, string]} TupleStruct3 * @property {number} "0" * @property {boolean} "1" * @property {string} "2" * * @typedef {"Unit" | ({ Single: number }) & { Multiple?: never; Struct?: never } | ({ Multiple: [number, number] }) & { Single?: never; Struct?: never } | ({ Struct: { * a: number, * } }) & { Multiple?: never; Single?: never }} TestEnum * @property {"Unit"} Unit * @property {{ Single: number }} Single * @property {{ Multiple: [number, number] }} Multiple * @property {{ Struct: { * a: number, * } }} Struct * * @typedef {TestEnum} RefStruct * @property {TestEnum} "0" * * @typedef {{ * inline_this: { * ref_struct: SimpleStruct, * val: number, * }, * dont_inline_this: RefStruct, * }} InlinerStruct * @property {{ * ref_struct: SimpleStruct, * val: number, * }} inline_this * @property {RefStruct} dont_inline_this * * @typedef {{ * arg: T, * }} GenericStruct * @property {T} arg * * @typedef {{ * arg: T, * }} GenericStruct * @property {T} arg * * @typedef {{ * outer: string, * } & FlattenEnum} FlattenEnumStruct * @property {string} outer * * @typedef {{ * overriden_field: string, * }} OverridenStruct * @property {string} overriden_field * * @typedef {{ [key in number]: string }} HasGenericAlias * @property {{ [key in number]: string }} "0" * * @typedef {({ A: string }) & { D?: never; bbb?: never; cccc?: never } | ({ bbb: number }) & { A?: never; D?: never; cccc?: never } | ({ cccc: number }) & { A?: never; D?: never; bbb?: never } | ({ D: { * a: string, * bbbbbb: number, * } }) & { A?: never; bbb?: never; cccc?: never }} EnumMacroAttributes * @property {{ A: string }} A * @property {{ bbb: number }} bbb * @property {{ cccc: number }} cccc * @property {{ D: { * a: string, * bbbbbb: number, * } }} D * * @typedef {{ A: { * a: string, * } }} InlineEnumField * @property {{ A: { * a: string, * } }} A * * @typedef {{ * optional_field: { * a: string, * } | null, * }} InlineOptionalType * @property {{ * a: string, * } | null} optional_field * * @typedef {"OneWord" | "Two words"} Rename * @property {"OneWord"} OneWord * @property {"Two words"} "Two words" * * @typedef {TransparentTypeInner} TransparentType * @property {TransparentTypeInner} "0" * * @typedef {null} TransparentType2 * @property {null} "0" * * @typedef {string} TransparentTypeWithOverride * @property {string} "0" * * @typedef {{ * a: Partial<{ [key in BasicEnum]: number }>, * }} EnumReferenceRecordKey * @property {Partial<{ [key in BasicEnum]: number }>} a * * @typedef {{ * id: string, * } & NestedEnum} FlattenOnNestedEnum * @property {string} id * * @typedef {Record} MyEmptyInput * * @typedef {{ A: string }} ExtraBracketsInTupleVariant * @property {{ A: string }} A * * @typedef {string} ExtraBracketsInUnnamedStruct * @property {string} "0" * * @typedef {{ * demo: [string, boolean], * }} InlineTuple * @property {[string, boolean]} demo * * @typedef {{ * demo: [{ * demo: [string, boolean], * }, boolean], * }} InlineTuple2 * @property {[{ * demo: [string, boolean], * }, boolean]} demo * * @typedef {{ type: "A" } | { type: "B"; data: string }} SkippedFieldWithinVariant * @property {{ type: "A" }} A * @property {{ type: "B"; data: string }} B * * @typedef {{ * "test-ing": string, * }} KebabCase * @property {string} "test-ing" * * @typedef {{ * default_unity_arguments: string[], * }} Issue281 * @property {string[]} default_unity_arguments * * @typedef {{ * borrowed: T[], * owned: T[], * }} LifetimeGenericStruct * @property {T[]} borrowed * @property {T[]} owned * * @typedef {({ Borrowed: T }) & { Owned?: never } | ({ Owned: T }) & { Borrowed?: never }} LifetimeGenericEnum * @property {{ Borrowed: T }} Borrowed * @property {{ Owned: T }} Owned * * @typedef {{ * "@odata.context": string, * }} RenameWithWeirdCharsField * @property {string} "@odata.context" * * @typedef {{ "@odata.context": string }} RenameWithWeirdCharsVariant * @property {{ "@odata.context": string }} "@odata.context" * * @typedef {{ * "": string, * "a\"b": string, * "a\\b": string, * "line\nbreak": string, * "line\u2028break": string, * "line\u2029break": string, * }} RenamedFieldKeys * @property {string} "" * @property {string} "a\"b" * @property {string} "a\\b" * @property {string} "line\nbreak" * @property {string} "line\u2028break" * @property {string} "line\u2029break" * * @typedef {"a-b"} RenamedVariantWithSkippedPayload * @property {"a-b"} "a-b" * * @typedef {never} Type * * @typedef {{ * a: GenericType, * }} ActualType * @property {GenericType} a * * @typedef {{ * string_ident: string, * u32_ident: number, * path: string, * tuple: [string, number], * }} SpectaTypeOverride * @property {string} string_ident * @property {number} u32_ident * @property {string} path * @property {[string, number]} tuple * * @typedef {string} ContainerTypeOverrideStruct * * @typedef {string} ContainerTypeOverrideEnum * * @typedef {string} ContainerTypeOverrideGeneric * * @typedef {T} ContainerTypeOverrideToGeneric * * @typedef {[string, number]} ContainerTypeOverrideTuple * * @typedef {[T, string]} ContainerTypeOverrideTupleGeneric * * @typedef {{ * cause: null, * }} InvalidToValidType * @property {null} cause * * @typedef {string} TupleStruct * @property {string} "0" * * @typedef {string} TupleStructWithRep * @property {string} "0" * * @typedef {T} GenericTupleStruct * @property {T} "0" * * @typedef {string} BracedStruct * @property {string} "0" * * @typedef {{ * t: "StructNew", * a: string, * }} StructNew * @property {"StructNew"} t * @property {string} a * * @typedef {{ * b: string, * }} Struct2 * @property {string} b * * @typedef {{ t: "A" } | { t: "B" }} Enum * @property {{ t: "A" }} A * @property {{ t: "B" }} B * * @typedef {{ t: "C" } | { t: "B" } | { t: "D"; enumField: null }} Enum2 * @property {{ t: "C" }} C * @property {{ t: "B" }} B * @property {{ t: "D"; enumField: null }} D * * @typedef {{ t: "A"; b: string }} Enum3 * @property {{ t: "A"; b: string }} A * * @typedef {{ * A: number, * B: number, * }} StructRenameAllUppercase * @property {number} A * @property {number} B * * @typedef {{ * "a/b": number, * }} RenameSerdeSpecialChar * @property {number} "a/b" * * @typedef {"HELLOWORLD" | "VARIANTB" | "TESTINGWORDS"} EnumRenameAllUppercase * @property {"HELLOWORLD"} HELLOWORLD * @property {"VARIANTB"} VARIANTB * @property {"TESTINGWORDS"} TESTINGWORDS * * @typedef {{ * demo: Recursive, * }} Recursive * @property {Recursive} demo * * @typedef {{ * demo: { [key in string]: RecursiveMapValue }, * }} RecursiveMapValue * @property {{ [key in string]: RecursiveMapValue }} demo * * @typedef {RecursiveInline} RecursiveTransparent * @property {RecursiveInline} "0" * * @typedef {{ A: { * demo: RecursiveInEnum, * } }} RecursiveInEnum * @property {{ A: { * demo: RecursiveInEnum, * } }} A * * @typedef {string | null} NonOptional * @property {string | null} "0" * * @typedef {string | null} OptionalOnNamedField * @property {string | null} ["0"] * * @typedef {{ * b: string | null, * }} OptionalOnTransparentNamedField * @property {string | null} b * * @typedef {({ A?: string | null }) & { B?: never; C?: never } | ({ B: { * a: string | null, * } }) & { A?: never; C?: never } | ({ C: { * a?: string | null, * } }) & { A?: never; B?: never }} OptionalInEnum * @property {{ A?: string | null }} A * @property {{ B: { * a: string | null, * } }} B * @property {{ C: { * a?: string | null, * } }} C * * @typedef {string | number | { id: string } | [string, boolean]} UntaggedVariants * @property {string} A * @property {number} B * @property {number} C * @property {{ id: string }} D * @property {[string, boolean]} E * * @typedef {string | [number, string] | number} UntaggedVariantsWithoutValue * @property {string} A * @property {[number, string]} B * @property {number} C * * @typedef {null | number} UntaggedVariantsWithDuplicateBranches * @property {null} A * @property {number} B * @property {null} C * * @typedef {{ [key in string]: null }} Regular * @property {{ [key in string]: null }} "0" * * @typedef {{ [key in MaybeValidKey]: null }} ValidMaybeValidKey * @property {{ [key in MaybeValidKey]: null }} "0" * * @typedef {{ [key in MaybeValidKey>]: null }} ValidMaybeValidKeyNested * @property {{ [key in MaybeValidKey>]: null }} "0" * * @typedef {string} MacroStruct * @property {string} "0" * * @typedef {{ * demo: string, * }} MacroStruct2 * @property {string} demo * * @typedef {({ Demo: string }) & { Demo2?: never } | ({ Demo2: { * demo2: string, * } }) & { Demo?: never }} MacroEnum * @property {{ Demo: string }} Demo * @property {{ Demo2: { * demo2: string, * } }} Demo2 * * @deprecated * @typedef {{ * a: number, * }} DeprecatedType * @property {number} a * * @deprecated Look at you big man using a deprecation message * @typedef {{ * a: number, * }} DeprecatedTypeWithMsg * @property {number} a * * @deprecated Look at you big man using a deprecation message * @typedef {{ * a: number, * }} DeprecatedTypeWithMsg2 * @property {number} a * * @typedef {{ * a: number, * /** * * @deprecated * */ * b: string, * /** * * @deprecated This field is cringe! * */ * c: string, * /** * * @deprecated This field is cringe! * */ * d: string, * }} DeprecatedFields * @property {number} a * @property {string} b - @deprecated * @property {string} c - @deprecated This field is cringe! * @property {string} d - @deprecated This field is cringe! * * @typedef {[ * /** * * @deprecated * */ * string, * /** * * @deprecated Nope * */ * string, * /** * * @deprecated Nope * */ * number]} DeprecatedTupleVariant * @property {string} "0" - @deprecated * @property {string} "1" - @deprecated Nope * @property {number} "2" - @deprecated Nope * * @typedef { * /** * * @deprecated * */ * "A" | * /** * * @deprecated Nope * */ * "B" | * /** * * @deprecated Nope * */ * "C"} DeprecatedEnumVariants * @property { * /** * * @deprecated * */ * "A"} A - @deprecated * @property { * /** * * @deprecated Nope * */ * "B"} B - @deprecated Nope * @property { * /** * * @deprecated Nope * */ * "C"} C - @deprecated Nope * * Some triple-slash comment * Some more triple-slash comment * * @typedef {{ * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * }} CommentedStruct * @property {number} a - Some triple-slash comment Some more triple-slash comment * * Some triple-slash comment * Some more triple-slash comment * * @typedef { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * ({ A: number }) & { B?: never } | * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * ({ B: { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * } }) & { A?: never }} CommentedEnum * @property { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * { A: number }} A - Some triple-slash comment Some more triple-slash comment * @property { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * { B: { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * } }} B - Some triple-slash comment Some more triple-slash comment * * Some single-line comment * * @typedef { * /** Some single-line comment */ * ({ A: number }) & { B?: never } | * /** Some single-line comment */ * ({ B: { * /** Some single-line comment */ * a: number, * } }) & { A?: never }} SingleLineComment * @property { * /** Some single-line comment */ * { A: number }} A - Some single-line comment * @property { * /** Some single-line comment */ * { B: { * /** Some single-line comment */ * a: number, * } }} B - Some single-line comment * * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b * * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b * * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b * * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b * * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b * * @typedef {{ * field: Demo, * }} AGenericStruct * @property {Demo} field * * @typedef {{ * a: B, * b: { * b: number, * }, * c: B, * d: { * flattened: number, * }, * e: { * generic_flattened: number, * }, * }} A * @property {B} a * @property {{ * b: number, * }} b * @property {B} c * @property {{ * flattened: number, * }} d * @property {{ * generic_flattened: number, * }} e * * @typedef {{ * a: ToBeFlattened, * b: ToBeFlattened, * }} DoubleFlattened * @property {ToBeFlattened} a * @property {ToBeFlattened} b * * @typedef {Inner} FlattenedInner * * @typedef {BoxedInner} BoxFlattened * * @typedef {{ * c: { * a: number, * }, * }} BoxInline * @property {{ * a: number, * }} c * * @typedef {{ * a: string, * }} First * @property {string} a * * @typedef {{ * a: number, * }} Second * @property {number} a * * @typedef {{ * b: { [key in string]: string }, * c: First, * } & First} Third * @property {{ [key in string]: string }} b * @property {First} c * * @typedef {{ * a: First, * b: { * a: string, * }, * }} Fourth * @property {First} a * @property {{ * a: string, * }} b * * @typedef {{ * type: "TagOnStructWithInline", * a: First, * b: { * a: string, * }, * }} TagOnStructWithInline * @property {"TagOnStructWithInline"} type * @property {First} a * @property {{ * a: string, * }} b * * @typedef {{ * a: First, * b: First, * }} Sixth * @property {First} a * @property {First} b * * @typedef {{ * a: First, * b: Second, * }} Seventh * @property {First} a * @property {Second} b * * @typedef {{ A: string } | "B"} Eight * @property {{ A: string }} A * @property {"B"} B * * @typedef {{ t: "A"; c: string } | { t: "B" } | { t: "C"; c: { * a: string, * } } | { t: "D"; c: First }} Ninth * @property {{ t: "A"; c: string }} A * @property {{ t: "B" }} B * @property {{ t: "C"; c: { * a: string, * } }} C * @property {{ t: "D"; c: First }} D * * @typedef {string | "B" | { * a: string, * } | First} Tenth * @property {string} A * @property {"B"} B * @property {{ * a: string, * }} C * @property {First} D * * @typedef {{ type: "Variant"; inner: First }} MyEnumTagged * @property {{ type: "Variant"; inner: First }} Variant * * @typedef {{ Variant: { * inner: First, * } }} MyEnumExternal * @property {{ Variant: { * inner: First, * } }} Variant * * @typedef {{ t: "Variant"; c: { * inner: First, * } }} MyEnumAdjacent * @property {{ t: "Variant"; c: { * inner: First, * } }} Variant * * @typedef {{ inner: First }} MyEnumUntagged * @property {{ inner: First }} Variant * * @typedef {Record} EmptyStruct * * @typedef {{ * a: "EmptyStructWithTag", * }} EmptyStructWithTag * @property {"EmptyStructWithTag"} a * * @typedef {{ t: "A" } | { t: "B"; c: { * id: string, * method: string, * } } | { t: "C"; c: string }} AdjacentlyTagged * @property {{ t: "A" }} A * @property {{ t: "B"; c: { * id: string, * method: string, * } }} B * @property {{ t: "C"; c: string }} C * * @typedef {{ event: "started"; data: { * projectName: string, * } } | { event: "progressTest"; data: { * projectName: string, * status: string, * progress: number, * } } | { event: "finished"; data: { * projectName: string, * } }} LoadProjectEvent * @property {{ event: "started"; data: { * projectName: string, * } }} started * @property {{ event: "progressTest"; data: { * projectName: string, * status: string, * progress: number, * } }} progressTest * @property {{ event: "finished"; data: { * projectName: string, * } }} finished * * @typedef {"A" | ({ B: { * id: string, * method: string, * } }) & { C?: never } | ({ C: string }) & { B?: never }} ExternallyTagged * @property {"A"} A * @property {{ B: { * id: string, * method: string, * } }} B * @property {{ C: string }} C * * @typedef {({ A: { * a: string, * } }) & { B?: never } | ({ B: { * b: string, * } }) & { A?: never }} Issue221External * @property {{ A: { * a: string, * } }} A * @property {{ B: { * b: string, * } }} B * * @typedef {{ * type: "A", * } & { [key in string]: string }} InternallyTaggedD * @property {{ * type: "A", * } & { [key in string]: string }} A * * @typedef {{ type: "A" }} InternallyTaggedE * @property {{ type: "A" }} A * * @typedef {{ type: "A" }} InternallyTaggedF * @property {{ type: "A" }} A * * @typedef {{ type: "A" }} InternallyTaggedH * @property {{ type: "A" }} A * * @typedef {{ * type: "A", * } & { type: "A" } | { type: "B" }} InternallyTaggedL * @property {{ * type: "A", * } & { type: "A" } | { type: "B" }} A * * @typedef {{ type: "A" }} InternallyTaggedM * @property {{ type: "A" }} A * * @typedef {{ * field: string, * }} StructWithAlias * @property {string} field * * @typedef {{ * field: string, * }} StructWithMultipleAliases * @property {string} field * * @typedef {{ * renamed_field: string, * }} StructWithAliasAndRename * @property {string} renamed_field * * @typedef {"Variant" | "Other"} EnumWithVariantAlias * @property {"Variant"} Variant * @property {"Other"} Other * * @typedef {"Variant" | "Other"} EnumWithMultipleVariantAliases * @property {"Variant"} Variant * @property {"Other"} Other * * @typedef {"renamed_variant" | "Other"} EnumWithVariantAliasAndRename * @property {"renamed_variant"} renamed_variant * @property {"Other"} Other * * @typedef {{ type: "A"; field: string } | { type: "B"; other: number }} InternallyTaggedWithAlias * @property {{ type: "A"; field: string }} A * @property {{ type: "B"; other: number }} B * * @typedef {{ type: "A"; data: { * field: string, * } } | { type: "B"; data: { * other: number, * } }} AdjacentlyTaggedWithAlias * @property {{ type: "A"; data: { * field: string, * } }} A * @property {{ type: "B"; data: { * other: number, * } }} B * * @typedef {({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }} UntaggedWithAlias * @property {{ field: string }} A * @property {{ other: number }} B * * @typedef {({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }} Issue221UntaggedSafe * @property {{ a: string }} A * @property {{ b: string }} B * * @typedef {({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never }} Issue221UntaggedMixed * @property {{ a: string }} A * @property {{ b: string }} B * @property {{ values: { [key in string]: string } }} Unsafe * * @typedef {never} EmptyEnum * * @typedef {never} EmptyEnumTagged * * @typedef {never} EmptyEnumTaggedWContent * * @typedef {never} EmptyEnumUntagged * * @typedef {Record} SkipOnlyField * * @typedef {{ * b: number, * }} SkipField * @property {number} b * * @typedef {{ A: string }} SkipVariant * @property {{ A: string }} A * * @typedef {"A" | { B: [number] }} SkipUnnamedFieldInVariant * @property {"A"} A * @property {{ B: [number] }} B * * @typedef {({ A: Record }) & { B?: never } | ({ B: { * b: number, * } }) & { A?: never }} SkipNamedFieldInVariant * @property {{ A: Record }} A * @property {{ B: { * b: number, * } }} B * * @typedef {null} TransparentWithSkip * @property {null} "0" * * @typedef {string} TransparentWithSkip2 * @property {string} "0" * * @typedef {string} TransparentWithSkip3 * @property {string} "0" * * @typedef {{ tag: "A"; data: string }} SkipVariant2 * @property {{ tag: "A"; data: string }} A * * @typedef {{ A: { * a: string, * } }} SkipVariant3 * @property {{ A: { * a: string, * } }} A * * @typedef {{ * a: number, * }} SkipStructFields * @property {number} a * * @typedef {{ * a: number, * }} SpectaSkipNonTypeField * @property {number} a * * @typedef {{ * a: number, * b: number, * }} FlattenA * @property {number} a * @property {number} b * * @typedef {{ * c: number, * } & FlattenA} FlattenB * @property {number} c * * @typedef {{ * c: number, * } & FlattenA} FlattenC * @property {number} c * * @typedef {{ * a: FlattenA, * c: number, * }} FlattenD * @property {FlattenA} a * @property {number} c * * @typedef {{ * b: ({ * c: number, * }) & (FlattenA), * d: number, * }} FlattenE * @property {({ * c: number, * }) & (FlattenA)} b * @property {number} d * * @typedef {{ * b: ({ * c: number, * }) & (FlattenA), * d: number, * }} FlattenF * @property {({ * c: number, * }) & (FlattenA)} b * @property {number} d * * @typedef {{ * b: FlattenB, * d: number, * }} FlattenG * @property {FlattenB} b * @property {number} d * * @typedef {[number[], [number[], number[]], [number[], number[], number[]]]} TupleNested * @property {number[]} "0" * @property {[number[], number[]]} "1" * @property {[number[], number[], number[]]} "2" * * @typedef {{ * value: T, * values: T[], * }} Generic1 * @property {T} value * @property {T[]} values * * @typedef {{ * value: T, * values: T[], * }} GenericAutoBound * @property {T} value * @property {T[]} values * * @typedef {{ * value: T, * values: T[], * }} GenericAutoBound2 * @property {T} value * @property {T[]} values * * @typedef {{ * foo: Generic1, * bar: Generic1[], * baz: { [key in string]: Generic1 }, * }} Container1 * @property {Generic1} foo * @property {Generic1[]} bar * @property {{ [key in string]: Generic1 }} baz * * @typedef {({ A: A }) & { B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ B: [B, B, B] }) & { A?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ C: C[] }) & { A?: never; B?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ D: A[][][] }) & { A?: never; B?: never; C?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ E: { * a: A, * b: B, * c: C, * } }) & { A?: never; B?: never; C?: never; D?: never; X?: never; Y?: never; Z?: never } | ({ X: number[] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; Y?: never; Z?: never } | ({ Y: number }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Z?: never } | ({ Z: number[][] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never }} Generic2 * @property {{ A: A }} A * @property {{ B: [B, B, B] }} B * @property {{ C: C[] }} C * @property {{ D: A[][][] }} D * @property {{ E: { * a: A, * b: B, * c: C, * } }} E * @property {{ X: number[] }} X * @property {{ Y: number }} Y * @property {{ Z: number[][] }} Z * * @typedef {T[][]} GenericNewType1 * @property {T[][]} "0" * * @typedef {[T, T[], T[][]]} GenericTuple * @property {T} "0" * @property {T[]} "1" * @property {T[][]} "2" * * @typedef {{ * a: T, * b: [T, T], * c: [T, [T, T]], * d: [T, T, T], * e: [([T, T]), ([T, T]), ([T, T])], * f: T[], * g: T[][], * h: ([([T, T]), ([T, T]), ([T, T])])[], * }} GenericStruct2 * @property {T} a * @property {[T, T]} b * @property {[T, [T, T]]} c * @property {[T, T, T]} d * @property {[([T, T]), ([T, T]), ([T, T])]} e * @property {T[]} f * @property {T[][]} g * @property {([([T, T]), ([T, T]), ([T, T])])[]} h * * @typedef {{ * t: T, * }} InlineFlattenGenericsG * @property {T} t * * @typedef {{ * g: InlineFlattenGenericsG, * gi: { * t: string, * }, * } & InlineFlattenGenericsG} InlineFlattenGenerics * @property {InlineFlattenGenericsG} g * @property {{ * t: string, * }} gi * * @typedef {{ * value: T, * }} GenericDefault * @property {T} value * * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second * * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second * * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second * * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second * * @typedef {{ * value: T, * }} GenericDefaultSkipped * @property {T} value * * @typedef {{ * value: number, * }} GenericDefaultSkippedNonType * @property {number} value * * @typedef {{ * pair: Pair, * }} GenericParameterOrderPreserved * @property {Pair} pair * * @typedef {{ * data: [number], * a: [number, number], * d: [number, number], * }} ConstGenericInNonConstContainer * @property {[number]} data * @property {[number, number]} a * @property {[number, number]} d * * @typedef {{ * data: number[], * a: number[], * d: [number, number], * }} ConstGenericInConstContainer * @property {number[]} data * @property {number[]} a * @property {[number, number]} d * * @typedef {{ * a: NamedConstGeneric, * b: NamedConstGeneric, * d: [number, number], * }} NamedConstGenericContainer * @property {NamedConstGeneric} a * @property {NamedConstGeneric} b * @property {[number, number]} d * * @typedef {{ * b: { * data: [number, number], * a: [number, number], * d: [number, number, number], * }, * c: { * data: [number, number, number], * a: [number, number], * d: [number, number, number], * }, * d: [number, number], * }} InlineConstGenericContainer * @property {{ * data: [number, number], * a: [number, number], * d: [number, number, number], * }} b * @property {{ * data: [number, number, number], * a: [number, number], * d: [number, number, number], * }} c * @property {[number, number]} d * * @typedef {{ * b: { * data: [number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }, * c: { * data: [number, number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }, * d: [number, number], * }} InlineRecursiveConstGenericContainer * @property {{ * data: [number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }} b * @property {{ * data: [number, number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }} c * @property {[number, number]} d * * @typedef {never} TestCollectionRegister * * @typedef {never} TestCollectionRegister */ ================================================ FILE: tests/tests/snapshots/test__jsdoc__export-many-serde_phases.snap ================================================ --- source: tests/tests/jsdoc.rs expression: output --- /** * https://github.com/specta-rs/specta/issues/374 * * @typedef {Issue374_Serialize | Issue374_Deserialize} Issue374 * @property {Issue374_Serialize} Serialize * @property {Issue374_Deserialize} Deserialize * * @typedef {Optional_Serialize | Optional_Deserialize} Optional * @property {Optional_Serialize} Serialize * @property {Optional_Deserialize} Deserialize * * @typedef {StructPhaseSpecificRenameSerialize | StructPhaseSpecificRenameDeserialize} StructPhaseSpecificRename * @property {StructPhaseSpecificRenameSerialize} Serialize * @property {StructPhaseSpecificRenameDeserialize} Deserialize * * @typedef {{ * start: T, * end: T, * }} Range * @property {T} start * @property {T} end * * @typedef {{ * start: T, * end: T, * }} RangeInclusive * @property {T} start * @property {T} end * * @typedef {{ * ok: T, * err: E, * }} Result * @property {T} ok * @property {E} err * * @typedef {null} Unit1 * * @typedef {Record} Unit2 * * @typedef {[]} Unit3 * * @typedef {null} Unit4 * @property {null} "0" * * @typedef {"A"} Unit5 * @property {"A"} A * * @typedef {{ A: null }} Unit6 * @property {{ A: null }} A * * @typedef {{ A: Record }} Unit7 * @property {{ A: Record }} A * * @typedef {{ * a: number, * b: string, * c: [number, string, number], * d: string[], * e: string | null, * }} SimpleStruct * @property {number} a * @property {string} b * @property {[number, string, number]} c * @property {string[]} d * @property {string | null} e * * @typedef {number} TupleStruct1 * @property {number} "0" * * @typedef {[number, boolean, string]} TupleStruct3 * @property {number} "0" * @property {boolean} "1" * @property {string} "2" * * @typedef {"Unit" | ({ Single: number }) & { Multiple?: never; Struct?: never } | ({ Multiple: [number, number] }) & { Single?: never; Struct?: never } | ({ Struct: { * a: number, * } }) & { Multiple?: never; Single?: never }} TestEnum * @property {"Unit"} Unit * @property {{ Single: number }} Single * @property {{ Multiple: [number, number] }} Multiple * @property {{ Struct: { * a: number, * } }} Struct * * @typedef {TestEnum} RefStruct * @property {TestEnum} "0" * * @typedef {{ * inline_this: { * ref_struct: SimpleStruct, * val: number, * }, * dont_inline_this: RefStruct, * }} InlinerStruct * @property {{ * ref_struct: SimpleStruct, * val: number, * }} inline_this * @property {RefStruct} dont_inline_this * * @typedef {{ * arg: T, * }} GenericStruct * @property {T} arg * * @typedef {{ * arg: T, * }} GenericStruct * @property {T} arg * * @typedef {{ * outer: string, * } & FlattenEnum} FlattenEnumStruct * @property {string} outer * * @typedef {{ * overriden_field: string, * }} OverridenStruct * @property {string} overriden_field * * @typedef {{ [key in number]: string }} HasGenericAlias * @property {{ [key in number]: string }} "0" * * @typedef {({ A: string }) & { D?: never; bbb?: never; cccc?: never } | ({ bbb: number }) & { A?: never; D?: never; cccc?: never } | ({ cccc: number }) & { A?: never; D?: never; bbb?: never } | ({ D: { * a: string, * bbbbbb: number, * } }) & { A?: never; bbb?: never; cccc?: never }} EnumMacroAttributes * @property {{ A: string }} A * @property {{ bbb: number }} bbb * @property {{ cccc: number }} cccc * @property {{ D: { * a: string, * bbbbbb: number, * } }} D * * @typedef {{ A: { * a: string, * } }} InlineEnumField * @property {{ A: { * a: string, * } }} A * * @typedef {{ * optional_field: { * a: string, * } | null, * }} InlineOptionalType * @property {{ * a: string, * } | null} optional_field * * @typedef {"OneWord" | "Two words"} Rename * @property {"OneWord"} OneWord * @property {"Two words"} "Two words" * * @typedef {TransparentTypeInner} TransparentType * @property {TransparentTypeInner} "0" * * @typedef {null} TransparentType2 * @property {null} "0" * * @typedef {string} TransparentTypeWithOverride * @property {string} "0" * * @typedef {{ * a: Partial<{ [key in BasicEnum]: number }>, * }} EnumReferenceRecordKey * @property {Partial<{ [key in BasicEnum]: number }>} a * * @typedef {{ * id: string, * } & NestedEnum} FlattenOnNestedEnum * @property {string} id * * @typedef {Record} MyEmptyInput * * @typedef {{ A: string }} ExtraBracketsInTupleVariant * @property {{ A: string }} A * * @typedef {string} ExtraBracketsInUnnamedStruct * @property {string} "0" * * @typedef {{ * demo: [string, boolean], * }} InlineTuple * @property {[string, boolean]} demo * * @typedef {{ * demo: [{ * demo: [string, boolean], * }, boolean], * }} InlineTuple2 * @property {[{ * demo: [string, boolean], * }, boolean]} demo * * @typedef {{ type: "A" } | { type: "B"; data: string }} SkippedFieldWithinVariant * @property {{ type: "A" }} A * @property {{ type: "B"; data: string }} B * * @typedef {{ * "test-ing": string, * }} KebabCase * @property {string} "test-ing" * * @typedef {{ * default_unity_arguments: string[], * }} Issue281 * @property {string[]} default_unity_arguments * * @typedef {{ * borrowed: T[], * owned: T[], * }} LifetimeGenericStruct * @property {T[]} borrowed * @property {T[]} owned * * @typedef {({ Borrowed: T }) & { Owned?: never } | ({ Owned: T }) & { Borrowed?: never }} LifetimeGenericEnum * @property {{ Borrowed: T }} Borrowed * @property {{ Owned: T }} Owned * * @typedef {{ * "@odata.context": string, * }} RenameWithWeirdCharsField * @property {string} "@odata.context" * * @typedef {{ "@odata.context": string }} RenameWithWeirdCharsVariant * @property {{ "@odata.context": string }} "@odata.context" * * @typedef {{ * "": string, * "a\"b": string, * "a\\b": string, * "line\nbreak": string, * "line\u2028break": string, * "line\u2029break": string, * }} RenamedFieldKeys * @property {string} "" * @property {string} "a\"b" * @property {string} "a\\b" * @property {string} "line\nbreak" * @property {string} "line\u2028break" * @property {string} "line\u2029break" * * @typedef {"a-b"} RenamedVariantWithSkippedPayload * @property {"a-b"} "a-b" * * @typedef {never} Type * * @typedef {{ * a: GenericType, * }} ActualType * @property {GenericType} a * * @typedef {{ * string_ident: string, * u32_ident: number, * path: string, * tuple: [string, number], * }} SpectaTypeOverride * @property {string} string_ident * @property {number} u32_ident * @property {string} path * @property {[string, number]} tuple * * @typedef {string} ContainerTypeOverrideStruct * * @typedef {string} ContainerTypeOverrideEnum * * @typedef {string} ContainerTypeOverrideGeneric * * @typedef {T} ContainerTypeOverrideToGeneric * * @typedef {[string, number]} ContainerTypeOverrideTuple * * @typedef {[T, string]} ContainerTypeOverrideTupleGeneric * * @typedef {{ * cause: null, * }} InvalidToValidType * @property {null} cause * * @typedef {string} TupleStruct * @property {string} "0" * * @typedef {string} TupleStructWithRep * @property {string} "0" * * @typedef {T} GenericTupleStruct * @property {T} "0" * * @typedef {string} BracedStruct * @property {string} "0" * * @typedef {{ * t: "StructNew", * a: string, * }} StructNew * @property {"StructNew"} t * @property {string} a * * @typedef {{ * b: string, * }} Struct2 * @property {string} b * * @typedef {{ t: "A" } | { t: "B" }} Enum * @property {{ t: "A" }} A * @property {{ t: "B" }} B * * @typedef {{ t: "C" } | { t: "B" } | { t: "D"; enumField: null }} Enum2 * @property {{ t: "C" }} C * @property {{ t: "B" }} B * @property {{ t: "D"; enumField: null }} D * * @typedef {{ t: "A"; b: string }} Enum3 * @property {{ t: "A"; b: string }} A * * @typedef {{ * A: number, * B: number, * }} StructRenameAllUppercase * @property {number} A * @property {number} B * * @typedef {{ * "a/b": number, * }} RenameSerdeSpecialChar * @property {number} "a/b" * * @typedef {"HELLOWORLD" | "VARIANTB" | "TESTINGWORDS"} EnumRenameAllUppercase * @property {"HELLOWORLD"} HELLOWORLD * @property {"VARIANTB"} VARIANTB * @property {"TESTINGWORDS"} TESTINGWORDS * * @typedef {{ * demo: Recursive, * }} Recursive * @property {Recursive} demo * * @typedef {{ * demo: { [key in string]: RecursiveMapValue }, * }} RecursiveMapValue * @property {{ [key in string]: RecursiveMapValue }} demo * * @typedef {RecursiveInline} RecursiveTransparent * @property {RecursiveInline} "0" * * @typedef {{ A: { * demo: RecursiveInEnum, * } }} RecursiveInEnum * @property {{ A: { * demo: RecursiveInEnum, * } }} A * * @typedef {string | null} NonOptional * @property {string | null} "0" * * @typedef {string | null} OptionalOnNamedField * @property {string | null} ["0"] * * @typedef {{ * b: string | null, * }} OptionalOnTransparentNamedField * @property {string | null} b * * @typedef {({ A?: string | null }) & { B?: never; C?: never } | ({ B: { * a: string | null, * } }) & { A?: never; C?: never } | ({ C: { * a?: string | null, * } }) & { A?: never; B?: never }} OptionalInEnum * @property {{ A?: string | null }} A * @property {{ B: { * a: string | null, * } }} B * @property {{ C: { * a?: string | null, * } }} C * * @typedef {string | number | { id: string } | [string, boolean]} UntaggedVariants * @property {string} A * @property {number} B * @property {number} C * @property {{ id: string }} D * @property {[string, boolean]} E * * @typedef {string | [number, string] | number} UntaggedVariantsWithoutValue * @property {string} A * @property {[number, string]} B * @property {number} C * * @typedef {null | number} UntaggedVariantsWithDuplicateBranches * @property {null} A * @property {number} B * @property {null} C * * @typedef {{ [key in string]: null }} Regular * @property {{ [key in string]: null }} "0" * * @typedef {{ [key in MaybeValidKey]: null }} ValidMaybeValidKey * @property {{ [key in MaybeValidKey]: null }} "0" * * @typedef {{ [key in MaybeValidKey>]: null }} ValidMaybeValidKeyNested * @property {{ [key in MaybeValidKey>]: null }} "0" * * @typedef {string} MacroStruct * @property {string} "0" * * @typedef {{ * demo: string, * }} MacroStruct2 * @property {string} demo * * @typedef {({ Demo: string }) & { Demo2?: never } | ({ Demo2: { * demo2: string, * } }) & { Demo?: never }} MacroEnum * @property {{ Demo: string }} Demo * @property {{ Demo2: { * demo2: string, * } }} Demo2 * * @deprecated * @typedef {{ * a: number, * }} DeprecatedType * @property {number} a * * @deprecated Look at you big man using a deprecation message * @typedef {{ * a: number, * }} DeprecatedTypeWithMsg * @property {number} a * * @deprecated Look at you big man using a deprecation message * @typedef {{ * a: number, * }} DeprecatedTypeWithMsg2 * @property {number} a * * @typedef {{ * a: number, * /** * * @deprecated * */ * b: string, * /** * * @deprecated This field is cringe! * */ * c: string, * /** * * @deprecated This field is cringe! * */ * d: string, * }} DeprecatedFields * @property {number} a * @property {string} b - @deprecated * @property {string} c - @deprecated This field is cringe! * @property {string} d - @deprecated This field is cringe! * * @typedef {[ * /** * * @deprecated * */ * string, * /** * * @deprecated Nope * */ * string, * /** * * @deprecated Nope * */ * number]} DeprecatedTupleVariant * @property {string} "0" - @deprecated * @property {string} "1" - @deprecated Nope * @property {number} "2" - @deprecated Nope * * @typedef { * /** * * @deprecated * */ * "A" | * /** * * @deprecated Nope * */ * "B" | * /** * * @deprecated Nope * */ * "C"} DeprecatedEnumVariants * @property { * /** * * @deprecated * */ * "A"} A - @deprecated * @property { * /** * * @deprecated Nope * */ * "B"} B - @deprecated Nope * @property { * /** * * @deprecated Nope * */ * "C"} C - @deprecated Nope * * Some triple-slash comment * Some more triple-slash comment * * @typedef {{ * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * }} CommentedStruct * @property {number} a - Some triple-slash comment Some more triple-slash comment * * Some triple-slash comment * Some more triple-slash comment * * @typedef { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * ({ A: number }) & { B?: never } | * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * ({ B: { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * } }) & { A?: never }} CommentedEnum * @property { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * { A: number }} A - Some triple-slash comment Some more triple-slash comment * @property { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * { B: { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * } }} B - Some triple-slash comment Some more triple-slash comment * * Some single-line comment * * @typedef { * /** Some single-line comment */ * ({ A: number }) & { B?: never } | * /** Some single-line comment */ * ({ B: { * /** Some single-line comment */ * a: number, * } }) & { A?: never }} SingleLineComment * @property { * /** Some single-line comment */ * { A: number }} A - Some single-line comment * @property { * /** Some single-line comment */ * { B: { * /** Some single-line comment */ * a: number, * } }} B - Some single-line comment * * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b * * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b * * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b * * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b * * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b * * @typedef {{ * field: Demo, * }} AGenericStruct * @property {Demo} field * * @typedef {{ * a: B, * b: { * b: number, * }, * c: B, * d: { * flattened: number, * }, * e: { * generic_flattened: number, * }, * }} A * @property {B} a * @property {{ * b: number, * }} b * @property {B} c * @property {{ * flattened: number, * }} d * @property {{ * generic_flattened: number, * }} e * * @typedef {{ * a: ToBeFlattened, * b: ToBeFlattened, * }} DoubleFlattened * @property {ToBeFlattened} a * @property {ToBeFlattened} b * * @typedef {Inner} FlattenedInner * * @typedef {BoxedInner} BoxFlattened * * @typedef {{ * c: { * a: number, * }, * }} BoxInline * @property {{ * a: number, * }} c * * @typedef {{ * a: string, * }} First * @property {string} a * * @typedef {{ * a: number, * }} Second * @property {number} a * * @typedef {{ * b: { [key in string]: string }, * c: First, * } & First} Third * @property {{ [key in string]: string }} b * @property {First} c * * @typedef {{ * a: First, * b: { * a: string, * }, * }} Fourth * @property {First} a * @property {{ * a: string, * }} b * * @typedef {{ * type: "TagOnStructWithInline", * a: First, * b: { * a: string, * }, * }} TagOnStructWithInline * @property {"TagOnStructWithInline"} type * @property {First} a * @property {{ * a: string, * }} b * * @typedef {{ * a: First, * b: First, * }} Sixth * @property {First} a * @property {First} b * * @typedef {{ * a: First, * b: Second, * }} Seventh * @property {First} a * @property {Second} b * * @typedef {{ A: string } | "B"} Eight * @property {{ A: string }} A * @property {"B"} B * * @typedef {{ t: "A"; c: string } | { t: "B" } | { t: "C"; c: { * a: string, * } } | { t: "D"; c: First }} Ninth * @property {{ t: "A"; c: string }} A * @property {{ t: "B" }} B * @property {{ t: "C"; c: { * a: string, * } }} C * @property {{ t: "D"; c: First }} D * * @typedef {string | "B" | { * a: string, * } | First} Tenth * @property {string} A * @property {"B"} B * @property {{ * a: string, * }} C * @property {First} D * * @typedef {{ type: "Variant"; inner: First }} MyEnumTagged * @property {{ type: "Variant"; inner: First }} Variant * * @typedef {{ Variant: { * inner: First, * } }} MyEnumExternal * @property {{ Variant: { * inner: First, * } }} Variant * * @typedef {{ t: "Variant"; c: { * inner: First, * } }} MyEnumAdjacent * @property {{ t: "Variant"; c: { * inner: First, * } }} Variant * * @typedef {{ inner: First }} MyEnumUntagged * @property {{ inner: First }} Variant * * @typedef {Record} EmptyStruct * * @typedef {{ * a: "EmptyStructWithTag", * }} EmptyStructWithTag * @property {"EmptyStructWithTag"} a * * @typedef {{ t: "A" } | { t: "B"; c: { * id: string, * method: string, * } } | { t: "C"; c: string }} AdjacentlyTagged * @property {{ t: "A" }} A * @property {{ t: "B"; c: { * id: string, * method: string, * } }} B * @property {{ t: "C"; c: string }} C * * @typedef {{ event: "started"; data: { * projectName: string, * } } | { event: "progressTest"; data: { * projectName: string, * status: string, * progress: number, * } } | { event: "finished"; data: { * projectName: string, * } }} LoadProjectEvent * @property {{ event: "started"; data: { * projectName: string, * } }} started * @property {{ event: "progressTest"; data: { * projectName: string, * status: string, * progress: number, * } }} progressTest * @property {{ event: "finished"; data: { * projectName: string, * } }} finished * * @typedef {"A" | ({ B: { * id: string, * method: string, * } }) & { C?: never } | ({ C: string }) & { B?: never }} ExternallyTagged * @property {"A"} A * @property {{ B: { * id: string, * method: string, * } }} B * @property {{ C: string }} C * * @typedef {({ A: { * a: string, * } }) & { B?: never } | ({ B: { * b: string, * } }) & { A?: never }} Issue221External * @property {{ A: { * a: string, * } }} A * @property {{ B: { * b: string, * } }} B * * @typedef {{ * type: "A", * } & { [key in string]: string }} InternallyTaggedD * @property {{ * type: "A", * } & { [key in string]: string }} A * * @typedef {{ type: "A" }} InternallyTaggedE * @property {{ type: "A" }} A * * @typedef {{ type: "A" }} InternallyTaggedF * @property {{ type: "A" }} A * * @typedef {{ type: "A" }} InternallyTaggedH * @property {{ type: "A" }} A * * @typedef {{ * type: "A", * } & { type: "A" } | { type: "B" }} InternallyTaggedL * @property {{ * type: "A", * } & { type: "A" } | { type: "B" }} A * * @typedef {{ type: "A" }} InternallyTaggedM * @property {{ type: "A" }} A * * @typedef {{ * field: string, * }} StructWithAlias * @property {string} field * * @typedef {{ * field: string, * }} StructWithMultipleAliases * @property {string} field * * @typedef {{ * renamed_field: string, * }} StructWithAliasAndRename * @property {string} renamed_field * * @typedef {"Variant" | "Other"} EnumWithVariantAlias * @property {"Variant"} Variant * @property {"Other"} Other * * @typedef {"Variant" | "Other"} EnumWithMultipleVariantAliases * @property {"Variant"} Variant * @property {"Other"} Other * * @typedef {"renamed_variant" | "Other"} EnumWithVariantAliasAndRename * @property {"renamed_variant"} renamed_variant * @property {"Other"} Other * * @typedef {{ type: "A"; field: string } | { type: "B"; other: number }} InternallyTaggedWithAlias * @property {{ type: "A"; field: string }} A * @property {{ type: "B"; other: number }} B * * @typedef {{ type: "A"; data: { * field: string, * } } | { type: "B"; data: { * other: number, * } }} AdjacentlyTaggedWithAlias * @property {{ type: "A"; data: { * field: string, * } }} A * @property {{ type: "B"; data: { * other: number, * } }} B * * @typedef {({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }} UntaggedWithAlias * @property {{ field: string }} A * @property {{ other: number }} B * * @typedef {({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }} Issue221UntaggedSafe * @property {{ a: string }} A * @property {{ b: string }} B * * @typedef {({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never }} Issue221UntaggedMixed * @property {{ a: string }} A * @property {{ b: string }} B * @property {{ values: { [key in string]: string } }} Unsafe * * @typedef {never} EmptyEnum * * @typedef {never} EmptyEnumTagged * * @typedef {never} EmptyEnumTaggedWContent * * @typedef {never} EmptyEnumUntagged * * @typedef {Record} SkipOnlyField * * @typedef {{ * b: number, * }} SkipField * @property {number} b * * @typedef {{ A: string }} SkipVariant * @property {{ A: string }} A * * @typedef {"A" | { B: [number] }} SkipUnnamedFieldInVariant * @property {"A"} A * @property {{ B: [number] }} B * * @typedef {({ A: Record }) & { B?: never } | ({ B: { * b: number, * } }) & { A?: never }} SkipNamedFieldInVariant * @property {{ A: Record }} A * @property {{ B: { * b: number, * } }} B * * @typedef {null} TransparentWithSkip * @property {null} "0" * * @typedef {string} TransparentWithSkip2 * @property {string} "0" * * @typedef {string} TransparentWithSkip3 * @property {string} "0" * * @typedef {{ tag: "A"; data: string }} SkipVariant2 * @property {{ tag: "A"; data: string }} A * * @typedef {{ A: { * a: string, * } }} SkipVariant3 * @property {{ A: { * a: string, * } }} A * * @typedef {{ * a: number, * }} SkipStructFields * @property {number} a * * @typedef {{ * a: number, * }} SpectaSkipNonTypeField * @property {number} a * * @typedef {{ * a: number, * b: number, * }} FlattenA * @property {number} a * @property {number} b * * @typedef {{ * c: number, * } & FlattenA} FlattenB * @property {number} c * * @typedef {{ * c: number, * } & FlattenA} FlattenC * @property {number} c * * @typedef {{ * a: FlattenA, * c: number, * }} FlattenD * @property {FlattenA} a * @property {number} c * * @typedef {{ * b: ({ * c: number, * }) & (FlattenA), * d: number, * }} FlattenE * @property {({ * c: number, * }) & (FlattenA)} b * @property {number} d * * @typedef {{ * b: ({ * c: number, * }) & (FlattenA), * d: number, * }} FlattenF * @property {({ * c: number, * }) & (FlattenA)} b * @property {number} d * * @typedef {{ * b: FlattenB, * d: number, * }} FlattenG * @property {FlattenB} b * @property {number} d * * @typedef {[number[], [number[], number[]], [number[], number[], number[]]]} TupleNested * @property {number[]} "0" * @property {[number[], number[]]} "1" * @property {[number[], number[], number[]]} "2" * * @typedef {{ * value: T, * values: T[], * }} Generic1 * @property {T} value * @property {T[]} values * * @typedef {{ * value: T, * values: T[], * }} GenericAutoBound * @property {T} value * @property {T[]} values * * @typedef {{ * value: T, * values: T[], * }} GenericAutoBound2 * @property {T} value * @property {T[]} values * * @typedef {{ * foo: Generic1, * bar: Generic1[], * baz: { [key in string]: Generic1 }, * }} Container1 * @property {Generic1} foo * @property {Generic1[]} bar * @property {{ [key in string]: Generic1 }} baz * * @typedef {({ A: A }) & { B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ B: [B, B, B] }) & { A?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ C: C[] }) & { A?: never; B?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ D: A[][][] }) & { A?: never; B?: never; C?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ E: { * a: A, * b: B, * c: C, * } }) & { A?: never; B?: never; C?: never; D?: never; X?: never; Y?: never; Z?: never } | ({ X: number[] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; Y?: never; Z?: never } | ({ Y: number }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Z?: never } | ({ Z: number[][] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never }} Generic2 * @property {{ A: A }} A * @property {{ B: [B, B, B] }} B * @property {{ C: C[] }} C * @property {{ D: A[][][] }} D * @property {{ E: { * a: A, * b: B, * c: C, * } }} E * @property {{ X: number[] }} X * @property {{ Y: number }} Y * @property {{ Z: number[][] }} Z * * @typedef {T[][]} GenericNewType1 * @property {T[][]} "0" * * @typedef {[T, T[], T[][]]} GenericTuple * @property {T} "0" * @property {T[]} "1" * @property {T[][]} "2" * * @typedef {{ * a: T, * b: [T, T], * c: [T, [T, T]], * d: [T, T, T], * e: [([T, T]), ([T, T]), ([T, T])], * f: T[], * g: T[][], * h: ([([T, T]), ([T, T]), ([T, T])])[], * }} GenericStruct2 * @property {T} a * @property {[T, T]} b * @property {[T, [T, T]]} c * @property {[T, T, T]} d * @property {[([T, T]), ([T, T]), ([T, T])]} e * @property {T[]} f * @property {T[][]} g * @property {([([T, T]), ([T, T]), ([T, T])])[]} h * * @typedef {{ * t: T, * }} InlineFlattenGenericsG * @property {T} t * * @typedef {{ * g: InlineFlattenGenericsG, * gi: { * t: string, * }, * } & InlineFlattenGenericsG} InlineFlattenGenerics * @property {InlineFlattenGenericsG} g * @property {{ * t: string, * }} gi * * @typedef {{ * value: T, * }} GenericDefault * @property {T} value * * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second * * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second * * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second * * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second * * @typedef {{ * value: T, * }} GenericDefaultSkipped * @property {T} value * * @typedef {{ * value: number, * }} GenericDefaultSkippedNonType * @property {number} value * * @typedef {{ * pair: Pair, * }} GenericParameterOrderPreserved * @property {Pair} pair * * @typedef {{ * data: [number], * a: [number, number], * d: [number, number], * }} ConstGenericInNonConstContainer * @property {[number]} data * @property {[number, number]} a * @property {[number, number]} d * * @typedef {{ * data: number[], * a: number[], * d: [number, number], * }} ConstGenericInConstContainer * @property {number[]} data * @property {number[]} a * @property {[number, number]} d * * @typedef {{ * a: NamedConstGeneric, * b: NamedConstGeneric, * d: [number, number], * }} NamedConstGenericContainer * @property {NamedConstGeneric} a * @property {NamedConstGeneric} b * @property {[number, number]} d * * @typedef {{ * b: { * data: [number, number], * a: [number, number], * d: [number, number, number], * }, * c: { * data: [number, number, number], * a: [number, number], * d: [number, number, number], * }, * d: [number, number], * }} InlineConstGenericContainer * @property {{ * data: [number, number], * a: [number, number], * d: [number, number, number], * }} b * @property {{ * data: [number, number, number], * a: [number, number], * d: [number, number, number], * }} c * @property {[number, number]} d * * @typedef {{ * b: { * data: [number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }, * c: { * data: [number, number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }, * d: [number, number], * }} InlineRecursiveConstGenericContainer * @property {{ * data: [number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }} b * @property {{ * data: [number, number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }} c * @property {[number, number]} d * * @typedef {never} TestCollectionRegister * * @typedef {never} TestCollectionRegister */ ================================================ FILE: tests/tests/snapshots/test__jsdoc__export-raw.snap ================================================ --- source: tests/tests/jsdoc.rs expression: output --- Range: /** * @typedef {{ * start: T, * end: T, * }} Range * @property {T} start * @property {T} end */ RangeInclusive: /** * @typedef {{ * start: T, * end: T, * }} RangeInclusive * @property {T} start * @property {T} end */ String: PathBuf: IpAddr: Ipv4Addr: Ipv6Addr: SocketAddr: SocketAddrV4: SocketAddrV6: Cow<'static, str>: Cow<'static, i32>: Vec: Vec: Result: /** * @typedef {{ * ok: T, * err: E, * }} Result * @property {T} ok * @property {E} err */ Vec>>: PhantomData<()>: PhantomData: Infallible: Unit1: /** * @typedef {null} Unit1 */ Unit2: /** * @typedef {Record} Unit2 */ Unit3: /** * @typedef {[]} Unit3 */ Unit4: /** * @typedef {null} Unit4 * @property {null} "0" */ Unit5: /** * @typedef {"A"} Unit5 * @property {"A"} A */ Unit6: /** * @typedef {[]} Unit6 * @property {[]} A */ Unit7: /** * @typedef {Record} Unit7 * @property {Record} A */ SimpleStruct: /** * @typedef {{ * a: number, * b: string, * c: [number, string, number], * d: string[], * e: string | null, * }} SimpleStruct * @property {number} a * @property {string} b * @property {[number, string, number]} c * @property {string[]} d * @property {string | null} e */ TupleStruct1: /** * @typedef {number} TupleStruct1 * @property {number} "0" */ TupleStruct3: /** * @typedef {[number, boolean, string]} TupleStruct3 * @property {number} "0" * @property {boolean} "1" * @property {string} "2" */ TestEnum: /** * @typedef {"Unit" | number | [number, number] | { a: number }} TestEnum * @property {"Unit"} Unit * @property {number} Single * @property {[number, number]} Multiple * @property {{ a: number }} Struct */ RefStruct: /** * @typedef {TestEnum} RefStruct * @property {TestEnum} "0" */ InlinerStruct: /** * @typedef {{ * inline_this: { * ref_struct: SimpleStruct, * val: number, * }, * dont_inline_this: RefStruct, * }} InlinerStruct * @property {{ * ref_struct: SimpleStruct, * val: number, * }} inline_this * @property {RefStruct} dont_inline_this */ GenericStruct: /** * @typedef {{ * arg: T, * }} GenericStruct * @property {T} arg */ GenericStruct: /** * @typedef {{ * arg: T, * }} GenericStruct * @property {T} arg */ FlattenEnumStruct: /** * @typedef {{ * outer: string, * inner: FlattenEnum, * }} FlattenEnumStruct * @property {string} outer * @property {FlattenEnum} inner */ OverridenStruct: /** * @typedef {{ * overriden_field: string, * }} OverridenStruct * @property {string} overriden_field */ HasGenericAlias: /** * @typedef {{ [key in number]: string }} HasGenericAlias * @property {{ [key in number]: string }} "0" */ EnumMacroAttributes: /** * @typedef {string | number | { a: string; b: number }} EnumMacroAttributes * @property {string} A * @property {number} B * @property {number} C * @property {{ a: string; b: number }} D */ InlineEnumField: /** * @typedef {{ * a: string, * }} InlineEnumField * @property {{ * a: string, * }} A */ InlineOptionalType: /** * @typedef {{ * optional_field: { * a: string, * } | null, * }} InlineOptionalType * @property {{ * a: string, * } | null} optional_field */ Rename: /** * @typedef {"OneWord" | "TwoWords"} Rename * @property {"OneWord"} OneWord * @property {"TwoWords"} TwoWords */ TransparentType: /** * @typedef {TransparentTypeInner} TransparentType * @property {TransparentTypeInner} "0" */ TransparentType2: /** * @typedef {null} TransparentType2 * @property {null} "0" */ TransparentTypeWithOverride: /** * @typedef {string} TransparentTypeWithOverride * @property {string} "0" */ HashMap: HashMap: Vec: EnumReferenceRecordKey: /** * @typedef {{ * a: Partial<{ [key in BasicEnum]: number }>, * }} EnumReferenceRecordKey * @property {Partial<{ [key in BasicEnum]: number }>} a */ FlattenOnNestedEnum: /** * @typedef {{ * id: string, * result: NestedEnum, * }} FlattenOnNestedEnum * @property {string} id * @property {NestedEnum} result */ MyEmptyInput: /** * @typedef {Record} MyEmptyInput */ (String): ExtraBracketsInTupleVariant: /** * @typedef {string} ExtraBracketsInTupleVariant * @property {string} A */ ExtraBracketsInUnnamedStruct: /** * @typedef {string} ExtraBracketsInUnnamedStruct * @property {string} "0" */ Vec: InlineTuple: /** * @typedef {{ * demo: [string, boolean], * }} InlineTuple * @property {[string, boolean]} demo */ InlineTuple2: /** * @typedef {{ * demo: [{ * demo: [string, boolean], * }, boolean], * }} InlineTuple2 * @property {[{ * demo: [string, boolean], * }, boolean]} demo */ Box: Box: SkippedFieldWithinVariant: /** * @typedef {never | string} SkippedFieldWithinVariant * @property {never} A * @property {string} B */ KebabCase: /** * @typedef {{ * test_ing: string, * }} KebabCase * @property {string} test_ing */ Issue281<'_>: /** * @typedef {{ * default_unity_arguments: string[], * }} Issue281 * @property {string[]} default_unity_arguments */ LifetimeGenericStruct<'_, i32>: /** * @typedef {{ * borrowed: T[], * owned: T[], * }} LifetimeGenericStruct * @property {T[]} borrowed * @property {T[]} owned */ LifetimeGenericEnum<'_, i32>: /** * @typedef {T} LifetimeGenericEnum * @property {T} Borrowed * @property {T} Owned */ RenameWithWeirdCharsField: /** * @typedef {{ * odata_context: string, * }} RenameWithWeirdCharsField * @property {string} odata_context */ RenameWithWeirdCharsVariant: /** * @typedef {string} RenameWithWeirdCharsVariant * @property {string} A */ RenamedFieldKeys: /** * @typedef {{ * empty: string, * quote: string, * backslash: string, * newline: string, * line_separator: string, * paragraph_separator: string, * }} RenamedFieldKeys * @property {string} empty * @property {string} quote * @property {string} backslash * @property {string} newline * @property {string} line_separator * @property {string} paragraph_separator */ RenamedVariantWithSkippedPayload: /** * @typedef {never} RenamedVariantWithSkippedPayload * @property {never} A */ type_type::Type: /** * @typedef {never} Type */ ActualType: /** * @typedef {{ * a: GenericType, * }} ActualType * @property {GenericType} a */ SpectaTypeOverride: /** * @typedef {{ * string_ident: string, * u32_ident: number, * path: string, * tuple: [string, number], * }} SpectaTypeOverride * @property {string} string_ident * @property {number} u32_ident * @property {string} path * @property {[string, number]} tuple */ ContainerTypeOverrideStruct: /** * @typedef {string} ContainerTypeOverrideStruct */ ContainerTypeOverrideEnum: /** * @typedef {string} ContainerTypeOverrideEnum */ ContainerTypeOverrideGeneric>: /** * @typedef {string} ContainerTypeOverrideGeneric */ ContainerTypeOverrideToGeneric: /** * @typedef {T} ContainerTypeOverrideToGeneric */ ContainerTypeOverrideTuple: /** * @typedef {[string, number]} ContainerTypeOverrideTuple */ ContainerTypeOverrideTupleGeneric: /** * @typedef {[T, string]} ContainerTypeOverrideTupleGeneric */ InvalidToValidType: /** * @typedef {{ * cause: null, * }} InvalidToValidType * @property {null} cause */ TupleStruct: /** * @typedef {string} TupleStruct * @property {string} "0" */ TupleStructWithRep: /** * @typedef {string} TupleStructWithRep * @property {string} "0" */ GenericTupleStruct: /** * @typedef {T} GenericTupleStruct * @property {T} "0" */ BracedStruct: /** * @typedef {string} BracedStruct * @property {string} "0" */ Struct: /** * @typedef {{ * a: string, * }} Struct * @property {string} a */ Struct2: /** * @typedef {{ * a: string, * }} Struct2 * @property {string} a */ Enum: /** * @typedef {"A" | "B"} Enum * @property {"A"} A * @property {"B"} B */ Enum2: /** * @typedef {"A" | "B" | { enum_field: null }} Enum2 * @property {"A"} A * @property {"B"} B * @property {{ enum_field: null }} D */ Enum3: /** * @typedef {{ a: string }} Enum3 * @property {{ a: string }} A */ StructRenameAllUppercase: /** * @typedef {{ * a: number, * b: number, * }} StructRenameAllUppercase * @property {number} a * @property {number} b */ RenameSerdeSpecialChar: /** * @typedef {{ * b: number, * }} RenameSerdeSpecialChar * @property {number} b */ EnumRenameAllUppercase: /** * @typedef {"HelloWorld" | "VariantB" | "TestingWords"} EnumRenameAllUppercase * @property {"HelloWorld"} HelloWorld * @property {"VariantB"} VariantB * @property {"TestingWords"} TestingWords */ Recursive: /** * @typedef {{ * demo: Recursive, * }} Recursive * @property {Recursive} demo */ RecursiveMapValue: /** * @typedef {{ * demo: { [key in string]: RecursiveMapValue }, * }} RecursiveMapValue * @property {{ [key in string]: RecursiveMapValue }} demo */ RecursiveTransparent: /** * @typedef {RecursiveInline} RecursiveTransparent * @property {RecursiveInline} "0" */ RecursiveInEnum: /** * @typedef {{ demo: RecursiveInEnum }} RecursiveInEnum * @property {{ demo: RecursiveInEnum }} A */ NonOptional: /** * @typedef {string | null} NonOptional * @property {string | null} "0" */ OptionalOnNamedField: /** * @typedef {string | null} OptionalOnNamedField * @property {string | null} ["0"] */ OptionalOnTransparentNamedField: /** * @typedef {{ * b: string | null, * }} OptionalOnTransparentNamedField * @property {string | null} b */ OptionalInEnum: /** * @typedef {string | null | { a: string | null } | { a?: string | null }} OptionalInEnum * @property {string | null} A * @property {{ a: string | null }} B * @property {{ a?: string | null }} C */ UntaggedVariants: /** * @typedef {string | number | { id: string } | [string, boolean]} UntaggedVariants * @property {string} A * @property {number} B * @property {number} C * @property {{ id: string }} D * @property {[string, boolean]} E */ UntaggedVariantsWithoutValue: /** * @typedef {string | [number, string] | number} UntaggedVariantsWithoutValue * @property {string} A * @property {[number, string]} B * @property {number} C */ UntaggedVariantsWithDuplicateBranches: /** * @typedef {null | number} UntaggedVariantsWithDuplicateBranches * @property {null} A * @property {number} B * @property {null} C */ HashMap: Regular: /** * @typedef {{ [key in string]: null }} Regular * @property {{ [key in string]: null }} "0" */ HashMap: HashMap: HashMap: HashMap: ValidMaybeValidKey: /** * @typedef {{ [key in MaybeValidKey]: null }} ValidMaybeValidKey * @property {{ [key in MaybeValidKey]: null }} "0" */ ValidMaybeValidKeyNested: /** * @typedef {{ [key in MaybeValidKey>]: null }} ValidMaybeValidKeyNested * @property {{ [key in MaybeValidKey>]: null }} "0" */ MacroStruct: /** * @typedef {string} MacroStruct * @property {string} "0" */ MacroStruct2: /** * @typedef {{ * demo: string, * }} MacroStruct2 * @property {string} demo */ MacroEnum: /** * @typedef {string | { demo2: string }} MacroEnum * @property {string} Demo * @property {{ demo2: string }} Demo2 */ DeprecatedType: /** * @deprecated * @typedef {{ * a: number, * }} DeprecatedType * @property {number} a */ DeprecatedTypeWithMsg: /** * @deprecated Look at you big man using a deprecation message * @typedef {{ * a: number, * }} DeprecatedTypeWithMsg * @property {number} a */ DeprecatedTypeWithMsg2: /** * @deprecated Look at you big man using a deprecation message * @typedef {{ * a: number, * }} DeprecatedTypeWithMsg2 * @property {number} a */ DeprecatedFields: /** * @typedef {{ * a: number, * /** * * @deprecated * */ * b: string, * /** * * @deprecated This field is cringe! * */ * c: string, * /** * * @deprecated This field is cringe! * */ * d: string, * }} DeprecatedFields * @property {number} a * @property {string} b - @deprecated * @property {string} c - @deprecated This field is cringe! * @property {string} d - @deprecated This field is cringe! */ DeprecatedTupleVariant: /** * @typedef {[ * /** * * @deprecated * */ * string, * /** * * @deprecated Nope * */ * string, * /** * * @deprecated Nope * */ * number]} DeprecatedTupleVariant * @property {string} "0" - @deprecated * @property {string} "1" - @deprecated Nope * @property {number} "2" - @deprecated Nope */ DeprecatedEnumVariants: /** * @typedef { * /** * * @deprecated * */ * "A" | * /** * * @deprecated Nope * */ * "B" | * /** * * @deprecated Nope * */ * "C"} DeprecatedEnumVariants * @property { * /** * * @deprecated * */ * "A"} A - @deprecated * @property { * /** * * @deprecated Nope * */ * "B"} B - @deprecated Nope * @property { * /** * * @deprecated Nope * */ * "C"} C - @deprecated Nope */ CommentedStruct: /** * Some triple-slash comment * Some more triple-slash comment * * @typedef {{ * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * }} CommentedStruct * @property {number} a - Some triple-slash comment Some more triple-slash comment */ CommentedEnum: /** * Some triple-slash comment * Some more triple-slash comment * * @typedef { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * number | * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number }} CommentedEnum * @property { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * number} A - Some triple-slash comment Some more triple-slash comment * @property { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number }} B - Some triple-slash comment Some more triple-slash comment */ SingleLineComment: /** * Some single-line comment * * @typedef { * /** Some single-line comment */ * number | * /** Some single-line comment */ * { * /** Some single-line comment */ * a: number }} SingleLineComment * @property { * /** Some single-line comment */ * number} A - Some single-line comment * @property { * /** Some single-line comment */ * { * /** Some single-line comment */ * a: number }} B - Some single-line comment */ NonGeneric: /** * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b */ HalfGenericA: /** * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b */ HalfGenericB: /** * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b */ FullGeneric: /** * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b */ Another: /** * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b */ MapA: MapB: MapC: AGenericStruct: /** * @typedef {{ * field: Demo, * }} AGenericStruct * @property {Demo} field */ A: /** * @typedef {{ * a: B, * b: { * b: number, * }, * c: B, * d: { * flattened: number, * }, * e: { * generic_flattened: number, * }, * }} A * @property {B} a * @property {{ * b: number, * }} b * @property {B} c * @property {{ * flattened: number, * }} d * @property {{ * generic_flattened: number, * }} e */ DoubleFlattened: /** * @typedef {{ * a: ToBeFlattened, * b: ToBeFlattened, * }} DoubleFlattened * @property {ToBeFlattened} a * @property {ToBeFlattened} b */ FlattenedInner: /** * @typedef {{ * c: Inner, * }} FlattenedInner * @property {Inner} c */ BoxFlattened: /** * @typedef {{ * b: BoxedInner, * }} BoxFlattened * @property {BoxedInner} b */ BoxInline: /** * @typedef {{ * c: { * a: number, * }, * }} BoxInline * @property {{ * a: number, * }} c */ First: /** * @typedef {{ * a: string, * }} First * @property {string} a */ Second: /** * @typedef {{ * a: number, * }} Second * @property {number} a */ Third: /** * @typedef {{ * a: First, * b: { [key in string]: string }, * c: First, * }} Third * @property {First} a * @property {{ [key in string]: string }} b * @property {First} c */ Fourth: /** * @typedef {{ * a: First, * b: { * a: string, * }, * }} Fourth * @property {First} a * @property {{ * a: string, * }} b */ TagOnStructWithInline: /** * @typedef {{ * a: First, * b: { * a: string, * }, * }} TagOnStructWithInline * @property {First} a * @property {{ * a: string, * }} b */ Sixth: /** * @typedef {{ * a: First, * b: First, * }} Sixth * @property {First} a * @property {First} b */ Seventh: /** * @typedef {{ * a: First, * b: Second, * }} Seventh * @property {First} a * @property {Second} b */ Eight: /** * @typedef {string | "B"} Eight * @property {string} A * @property {"B"} B */ Ninth: /** * @typedef {string | "B" | { * a: string, * } | First} Ninth * @property {string} A * @property {"B"} B * @property {{ * a: string, * }} C * @property {First} D */ Tenth: /** * @typedef {string | "B" | { * a: string, * } | First} Tenth * @property {string} A * @property {"B"} B * @property {{ * a: string, * }} C * @property {First} D */ MyEnumTagged: /** * @typedef {{ inner: First }} MyEnumTagged * @property {{ inner: First }} Variant */ MyEnumExternal: /** * @typedef {{ inner: First }} MyEnumExternal * @property {{ inner: First }} Variant */ MyEnumAdjacent: /** * @typedef {{ inner: First }} MyEnumAdjacent * @property {{ inner: First }} Variant */ MyEnumUntagged: /** * @typedef {{ inner: First }} MyEnumUntagged * @property {{ inner: First }} Variant */ EmptyStruct: /** * @typedef {Record} EmptyStruct */ EmptyStructWithTag: /** * @typedef {Record} EmptyStructWithTag */ AdjacentlyTagged: /** * @typedef {"A" | { id: string; method: string } | string} AdjacentlyTagged * @property {"A"} A * @property {{ id: string; method: string }} B * @property {string} C */ LoadProjectEvent: /** * @typedef {({ project_name: string }) & { progress?: never; status?: never } | { project_name: string; status: string; progress: number }} LoadProjectEvent * @property {{ project_name: string }} Started * @property {{ project_name: string; status: string; progress: number }} ProgressTest * @property {{ project_name: string }} Finished */ ExternallyTagged: /** * @typedef {"A" | { id: string; method: string } | string} ExternallyTagged * @property {"A"} A * @property {{ id: string; method: string }} B * @property {string} C */ Issue221External: /** * @typedef {({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }} Issue221External * @property {{ a: string }} A * @property {{ b: string }} B */ InternallyTaggedD: /** * @typedef {{ [key in string]: string }} InternallyTaggedD * @property {{ [key in string]: string }} A */ InternallyTaggedE: /** * @typedef {null} InternallyTaggedE * @property {null} A */ InternallyTaggedF: /** * @typedef {InternallyTaggedFInner} InternallyTaggedF * @property {InternallyTaggedFInner} A */ InternallyTaggedH: /** * @typedef {InternallyTaggedHInner} InternallyTaggedH * @property {InternallyTaggedHInner} A */ InternallyTaggedL: /** * @typedef {"A" | "B"} InternallyTaggedL * @property {"A" | "B"} A */ InternallyTaggedM: /** * @typedef {"A" | "B"} InternallyTaggedM * @property {"A" | "B"} A */ StructWithAlias: /** * @typedef {{ * field: string, * }} StructWithAlias * @property {string} field */ StructWithMultipleAliases: /** * @typedef {{ * field: string, * }} StructWithMultipleAliases * @property {string} field */ StructWithAliasAndRename: /** * @typedef {{ * field: string, * }} StructWithAliasAndRename * @property {string} field */ EnumWithVariantAlias: /** * @typedef {"Variant" | "Other"} EnumWithVariantAlias * @property {"Variant"} Variant * @property {"Other"} Other */ EnumWithMultipleVariantAliases: /** * @typedef {"Variant" | "Other"} EnumWithMultipleVariantAliases * @property {"Variant"} Variant * @property {"Other"} Other */ EnumWithVariantAliasAndRename: /** * @typedef {"Variant" | "Other"} EnumWithVariantAliasAndRename * @property {"Variant"} Variant * @property {"Other"} Other */ InternallyTaggedWithAlias: /** * @typedef {({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }} InternallyTaggedWithAlias * @property {{ field: string }} A * @property {{ other: number }} B */ AdjacentlyTaggedWithAlias: /** * @typedef {({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }} AdjacentlyTaggedWithAlias * @property {{ field: string }} A * @property {{ other: number }} B */ UntaggedWithAlias: /** * @typedef {({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }} UntaggedWithAlias * @property {{ field: string }} A * @property {{ other: number }} B */ Issue221UntaggedSafe: /** * @typedef {({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }} Issue221UntaggedSafe * @property {{ a: string }} A * @property {{ b: string }} B */ Issue221UntaggedMixed: /** * @typedef {({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never }} Issue221UntaggedMixed * @property {{ a: string }} A * @property {{ b: string }} B * @property {{ values: { [key in string]: string } }} Unsafe */ EmptyEnum: /** * @typedef {never} EmptyEnum */ EmptyEnumTagged: /** * @typedef {never} EmptyEnumTagged */ EmptyEnumTaggedWContent: /** * @typedef {never} EmptyEnumTaggedWContent */ EmptyEnumUntagged: /** * @typedef {never} EmptyEnumUntagged */ SkipOnlyField: /** * @typedef {Record} SkipOnlyField */ SkipField: /** * @typedef {{ * b: number, * }} SkipField * @property {number} b */ SkipVariant: /** * @typedef {string} SkipVariant * @property {string} A */ SkipUnnamedFieldInVariant: /** * @typedef {never | [number]} SkipUnnamedFieldInVariant * @property {never} A * @property {[number]} B */ SkipNamedFieldInVariant: /** * @typedef {Record | { b: number }} SkipNamedFieldInVariant * @property {Record} A * @property {{ b: number }} B */ TransparentWithSkip: /** * @typedef {null} TransparentWithSkip * @property {null} "0" */ TransparentWithSkip2: /** * @typedef {string} TransparentWithSkip2 * @property {string} "0" */ TransparentWithSkip3: /** * @typedef {string} TransparentWithSkip3 * @property {string} "0" */ SkipVariant2: /** * @typedef {string} SkipVariant2 * @property {string} A */ SkipVariant3: /** * @typedef {{ a: string }} SkipVariant3 * @property {{ a: string }} A */ SkipStructFields: /** * @typedef {{ * a: number, * }} SkipStructFields * @property {number} a */ SpectaSkipNonTypeField: /** * @typedef {{ * a: number, * }} SpectaSkipNonTypeField * @property {number} a */ FlattenA: /** * @typedef {{ * a: number, * b: number, * }} FlattenA * @property {number} a * @property {number} b */ FlattenB: /** * @typedef {{ * a: FlattenA, * c: number, * }} FlattenB * @property {FlattenA} a * @property {number} c */ FlattenC: /** * @typedef {{ * a: FlattenA, * c: number, * }} FlattenC * @property {FlattenA} a * @property {number} c */ FlattenD: /** * @typedef {{ * a: FlattenA, * c: number, * }} FlattenD * @property {FlattenA} a * @property {number} c */ FlattenE: /** * @typedef {{ * b: { * a: FlattenA, * c: number, * }, * d: number, * }} FlattenE * @property {{ * a: FlattenA, * c: number, * }} b * @property {number} d */ FlattenF: /** * @typedef {{ * b: { * a: FlattenA, * c: number, * }, * d: number, * }} FlattenF * @property {{ * a: FlattenA, * c: number, * }} b * @property {number} d */ FlattenG: /** * @typedef {{ * b: FlattenB, * d: number, * }} FlattenG * @property {FlattenB} b * @property {number} d */ TupleNested: /** * @typedef {[number[], [number[], number[]], [number[], number[], number[]]]} TupleNested * @property {number[]} "0" * @property {[number[], number[]]} "1" * @property {[number[], number[], number[]]} "2" */ Generic1<()>: /** * @typedef {{ * value: T, * values: T[], * }} Generic1 * @property {T} value * @property {T[]} values */ GenericAutoBound<()>: /** * @typedef {{ * value: T, * values: T[], * }} GenericAutoBound * @property {T} value * @property {T[]} values */ GenericAutoBound2<()>: /** * @typedef {{ * value: T, * values: T[], * }} GenericAutoBound2 * @property {T} value * @property {T[]} values */ Container1: /** * @typedef {{ * foo: Generic1, * bar: Generic1[], * baz: { [key in string]: Generic1 }, * }} Container1 * @property {Generic1} foo * @property {Generic1[]} bar * @property {{ [key in string]: Generic1 }} baz */ Generic2<(), String, i32>: /** * @typedef {A | [B, B, B] | C[] | A[][][] | { a: A; b: B; c: C } | number[] | number | number[][]} Generic2 * @property {A} A * @property {[B, B, B]} B * @property {C[]} C * @property {A[][][]} D * @property {{ a: A; b: B; c: C }} E * @property {number[]} X * @property {number} Y * @property {number[][]} Z */ GenericNewType1<()>: /** * @typedef {T[][]} GenericNewType1 * @property {T[][]} "0" */ GenericTuple<()>: /** * @typedef {[T, T[], T[][]]} GenericTuple * @property {T} "0" * @property {T[]} "1" * @property {T[][]} "2" */ GenericStruct2<()>: /** * @typedef {{ * a: T, * b: [T, T], * c: [T, [T, T]], * d: [T, T, T], * e: [([T, T]), ([T, T]), ([T, T])], * f: T[], * g: T[][], * h: ([([T, T]), ([T, T]), ([T, T])])[], * }} GenericStruct2 * @property {T} a * @property {[T, T]} b * @property {[T, [T, T]]} c * @property {[T, T, T]} d * @property {[([T, T]), ([T, T]), ([T, T])]} e * @property {T[]} f * @property {T[][]} g * @property {([([T, T]), ([T, T]), ([T, T])])[]} h */ InlineGenericNewtype: InlineGenericNested: InlineFlattenGenericsG<()>: /** * @typedef {{ * t: T, * }} InlineFlattenGenericsG * @property {T} t */ InlineFlattenGenerics: /** * @typedef {{ * g: InlineFlattenGenericsG, * gi: { * t: string, * }, * t: InlineFlattenGenericsG, * }} InlineFlattenGenerics * @property {InlineFlattenGenericsG} g * @property {{ * t: string, * }} gi * @property {InlineFlattenGenericsG} t */ GenericDefault: /** * @typedef {{ * value: T, * }} GenericDefault * @property {T} value */ ChainedGenericDefault: /** * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second */ ChainedGenericDefault: /** * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second */ ChainedGenericDefault: /** * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second */ ChainedGenericDefault: /** * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second */ GenericDefaultSkipped: /** * @typedef {{ * value: T, * }} GenericDefaultSkipped * @property {T} value */ GenericDefaultSkippedNonType: /** * @typedef {{ * value: number, * }} GenericDefaultSkippedNonType * @property {number} value */ GenericParameterOrderPreserved: /** * @typedef {{ * pair: Pair, * }} GenericParameterOrderPreserved * @property {Pair} pair */ ConstGenericInNonConstContainer: /** * @typedef {{ * data: [number], * a: [number, number], * d: [number, number], * }} ConstGenericInNonConstContainer * @property {[number]} data * @property {[number, number]} a * @property {[number, number]} d */ ConstGenericInConstContainer: /** * @typedef {{ * data: number[], * a: number[], * d: [number, number], * }} ConstGenericInConstContainer * @property {number[]} data * @property {number[]} a * @property {[number, number]} d */ NamedConstGenericContainer: /** * @typedef {{ * a: NamedConstGeneric, * b: NamedConstGeneric, * d: [number, number], * }} NamedConstGenericContainer * @property {NamedConstGeneric} a * @property {NamedConstGeneric} b * @property {[number, number]} d */ InlineConstGenericContainer: /** * @typedef {{ * b: { * data: [number, number], * a: [number, number], * d: [number, number, number], * }, * c: { * data: [number, number, number], * a: [number, number], * d: [number, number, number], * }, * d: [number, number], * }} InlineConstGenericContainer * @property {{ * data: [number, number], * a: [number, number], * d: [number, number, number], * }} b * @property {{ * data: [number, number, number], * a: [number, number], * d: [number, number, number], * }} c * @property {[number, number]} d */ InlineRecursiveConstGenericContainer: /** * @typedef {{ * b: { * data: [number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }, * c: { * data: [number, number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }, * d: [number, number], * }} InlineRecursiveConstGenericContainer * @property {{ * data: [number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }} b * @property {{ * data: [number, number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }} c * @property {[number, number]} d */ TestCollectionRegister: /** * @typedef {never} TestCollectionRegister */ TestCollectionRegister: /** * @typedef {never} TestCollectionRegister */ ================================================ FILE: tests/tests/snapshots/test__jsdoc__export-serde.snap ================================================ --- source: tests/tests/jsdoc.rs expression: output --- Range: /** * @typedef {{ * start: T, * end: T, * }} Range * @property {T} start * @property {T} end */ RangeInclusive: /** * @typedef {{ * start: T, * end: T, * }} RangeInclusive * @property {T} start * @property {T} end */ String: PathBuf: IpAddr: Ipv4Addr: Ipv6Addr: SocketAddr: SocketAddrV4: SocketAddrV6: Cow<'static, str>: Cow<'static, i32>: Vec: Vec: Result: /** * @typedef {{ * ok: T, * err: E, * }} Result * @property {T} ok * @property {E} err */ Vec>>: PhantomData<()>: PhantomData: Infallible: Unit1: /** * @typedef {null} Unit1 */ Unit2: /** * @typedef {Record} Unit2 */ Unit3: /** * @typedef {[]} Unit3 */ Unit4: /** * @typedef {null} Unit4 * @property {null} "0" */ Unit5: /** * @typedef {"A"} Unit5 * @property {"A"} A */ Unit6: /** * @typedef {{ A: null }} Unit6 * @property {{ A: null }} A */ Unit7: /** * @typedef {{ A: Record }} Unit7 * @property {{ A: Record }} A */ SimpleStruct: /** * @typedef {{ * a: number, * b: string, * c: [number, string, number], * d: string[], * e: string | null, * }} SimpleStruct * @property {number} a * @property {string} b * @property {[number, string, number]} c * @property {string[]} d * @property {string | null} e */ TupleStruct1: /** * @typedef {number} TupleStruct1 * @property {number} "0" */ TupleStruct3: /** * @typedef {[number, boolean, string]} TupleStruct3 * @property {number} "0" * @property {boolean} "1" * @property {string} "2" */ TestEnum: /** * @typedef {"Unit" | ({ Single: number }) & { Multiple?: never; Struct?: never } | ({ Multiple: [number, number] }) & { Single?: never; Struct?: never } | ({ Struct: { * a: number, * } }) & { Multiple?: never; Single?: never }} TestEnum * @property {"Unit"} Unit * @property {{ Single: number }} Single * @property {{ Multiple: [number, number] }} Multiple * @property {{ Struct: { * a: number, * } }} Struct */ RefStruct: /** * @typedef {TestEnum} RefStruct * @property {TestEnum} "0" */ InlinerStruct: /** * @typedef {{ * inline_this: { * ref_struct: SimpleStruct, * val: number, * }, * dont_inline_this: RefStruct, * }} InlinerStruct * @property {{ * ref_struct: SimpleStruct, * val: number, * }} inline_this * @property {RefStruct} dont_inline_this */ GenericStruct: /** * @typedef {{ * arg: T, * }} GenericStruct * @property {T} arg */ GenericStruct: /** * @typedef {{ * arg: T, * }} GenericStruct * @property {T} arg */ FlattenEnumStruct: /** * @typedef {{ * outer: string, * } & FlattenEnum} FlattenEnumStruct * @property {string} outer */ OverridenStruct: /** * @typedef {{ * overriden_field: string, * }} OverridenStruct * @property {string} overriden_field */ HasGenericAlias: /** * @typedef {{ [key in number]: string }} HasGenericAlias * @property {{ [key in number]: string }} "0" */ EnumMacroAttributes: /** * @typedef {({ A: string }) & { D?: never; bbb?: never; cccc?: never } | ({ bbb: number }) & { A?: never; D?: never; cccc?: never } | ({ cccc: number }) & { A?: never; D?: never; bbb?: never } | ({ D: { * a: string, * bbbbbb: number, * } }) & { A?: never; bbb?: never; cccc?: never }} EnumMacroAttributes * @property {{ A: string }} A * @property {{ bbb: number }} bbb * @property {{ cccc: number }} cccc * @property {{ D: { * a: string, * bbbbbb: number, * } }} D */ InlineEnumField: /** * @typedef {{ A: { * a: string, * } }} InlineEnumField * @property {{ A: { * a: string, * } }} A */ InlineOptionalType: /** * @typedef {{ * optional_field: { * a: string, * } | null, * }} InlineOptionalType * @property {{ * a: string, * } | null} optional_field */ Rename: /** * @typedef {"OneWord" | "Two words"} Rename * @property {"OneWord"} OneWord * @property {"Two words"} "Two words" */ TransparentType: /** * @typedef {TransparentTypeInner} TransparentType * @property {TransparentTypeInner} "0" */ TransparentType2: /** * @typedef {null} TransparentType2 * @property {null} "0" */ TransparentTypeWithOverride: /** * @typedef {string} TransparentTypeWithOverride * @property {string} "0" */ HashMap: HashMap: Vec: EnumReferenceRecordKey: /** * @typedef {{ * a: Partial<{ [key in BasicEnum]: number }>, * }} EnumReferenceRecordKey * @property {Partial<{ [key in BasicEnum]: number }>} a */ FlattenOnNestedEnum: /** * @typedef {{ * id: string, * } & NestedEnum} FlattenOnNestedEnum * @property {string} id */ MyEmptyInput: /** * @typedef {Record} MyEmptyInput */ (String): ExtraBracketsInTupleVariant: /** * @typedef {{ A: string }} ExtraBracketsInTupleVariant * @property {{ A: string }} A */ ExtraBracketsInUnnamedStruct: /** * @typedef {string} ExtraBracketsInUnnamedStruct * @property {string} "0" */ Vec: InlineTuple: /** * @typedef {{ * demo: [string, boolean], * }} InlineTuple * @property {[string, boolean]} demo */ InlineTuple2: /** * @typedef {{ * demo: [{ * demo: [string, boolean], * }, boolean], * }} InlineTuple2 * @property {[{ * demo: [string, boolean], * }, boolean]} demo */ Box: Box: SkippedFieldWithinVariant: /** * @typedef {{ type: "A" } | { type: "B"; data: string }} SkippedFieldWithinVariant * @property {{ type: "A" }} A * @property {{ type: "B"; data: string }} B */ KebabCase: /** * @typedef {{ * "test-ing": string, * }} KebabCase * @property {string} "test-ing" */ Issue281<'_>: /** * @typedef {{ * default_unity_arguments: string[], * }} Issue281 * @property {string[]} default_unity_arguments */ LifetimeGenericStruct<'_, i32>: /** * @typedef {{ * borrowed: T[], * owned: T[], * }} LifetimeGenericStruct * @property {T[]} borrowed * @property {T[]} owned */ LifetimeGenericEnum<'_, i32>: /** * @typedef {({ Borrowed: T }) & { Owned?: never } | ({ Owned: T }) & { Borrowed?: never }} LifetimeGenericEnum * @property {{ Borrowed: T }} Borrowed * @property {{ Owned: T }} Owned */ RenameWithWeirdCharsField: /** * @typedef {{ * "@odata.context": string, * }} RenameWithWeirdCharsField * @property {string} "@odata.context" */ RenameWithWeirdCharsVariant: /** * @typedef {{ "@odata.context": string }} RenameWithWeirdCharsVariant * @property {{ "@odata.context": string }} "@odata.context" */ RenamedFieldKeys: /** * @typedef {{ * "": string, * "a\"b": string, * "a\\b": string, * "line\nbreak": string, * "line\u2028break": string, * "line\u2029break": string, * }} RenamedFieldKeys * @property {string} "" * @property {string} "a\"b" * @property {string} "a\\b" * @property {string} "line\nbreak" * @property {string} "line\u2028break" * @property {string} "line\u2029break" */ RenamedVariantWithSkippedPayload: /** * @typedef {"a-b"} RenamedVariantWithSkippedPayload * @property {"a-b"} "a-b" */ type_type::Type: /** * @typedef {never} Type */ ActualType: /** * @typedef {{ * a: GenericType, * }} ActualType * @property {GenericType} a */ SpectaTypeOverride: /** * @typedef {{ * string_ident: string, * u32_ident: number, * path: string, * tuple: [string, number], * }} SpectaTypeOverride * @property {string} string_ident * @property {number} u32_ident * @property {string} path * @property {[string, number]} tuple */ ContainerTypeOverrideStruct: /** * @typedef {string} ContainerTypeOverrideStruct */ ContainerTypeOverrideEnum: /** * @typedef {string} ContainerTypeOverrideEnum */ ContainerTypeOverrideGeneric>: /** * @typedef {string} ContainerTypeOverrideGeneric */ ContainerTypeOverrideToGeneric: /** * @typedef {T} ContainerTypeOverrideToGeneric */ ContainerTypeOverrideTuple: /** * @typedef {[string, number]} ContainerTypeOverrideTuple */ ContainerTypeOverrideTupleGeneric: /** * @typedef {[T, string]} ContainerTypeOverrideTupleGeneric */ InvalidToValidType: /** * @typedef {{ * cause: null, * }} InvalidToValidType * @property {null} cause */ TupleStruct: /** * @typedef {string} TupleStruct * @property {string} "0" */ TupleStructWithRep: /** * @typedef {string} TupleStructWithRep * @property {string} "0" */ GenericTupleStruct: /** * @typedef {T} GenericTupleStruct * @property {T} "0" */ BracedStruct: /** * @typedef {string} BracedStruct * @property {string} "0" */ Struct: /** * @typedef {{ * t: "StructNew", * a: string, * }} StructNew * @property {"StructNew"} t * @property {string} a */ Struct2: /** * @typedef {{ * b: string, * }} Struct2 * @property {string} b */ Enum: /** * @typedef {{ t: "A" } | { t: "B" }} Enum * @property {{ t: "A" }} A * @property {{ t: "B" }} B */ Enum2: /** * @typedef {{ t: "C" } | { t: "B" } | { t: "D"; enumField: null }} Enum2 * @property {{ t: "C" }} C * @property {{ t: "B" }} B * @property {{ t: "D"; enumField: null }} D */ Enum3: /** * @typedef {{ t: "A"; b: string }} Enum3 * @property {{ t: "A"; b: string }} A */ StructRenameAllUppercase: /** * @typedef {{ * A: number, * B: number, * }} StructRenameAllUppercase * @property {number} A * @property {number} B */ RenameSerdeSpecialChar: /** * @typedef {{ * "a/b": number, * }} RenameSerdeSpecialChar * @property {number} "a/b" */ EnumRenameAllUppercase: /** * @typedef {"HELLOWORLD" | "VARIANTB" | "TESTINGWORDS"} EnumRenameAllUppercase * @property {"HELLOWORLD"} HELLOWORLD * @property {"VARIANTB"} VARIANTB * @property {"TESTINGWORDS"} TESTINGWORDS */ Recursive: /** * @typedef {{ * demo: Recursive, * }} Recursive * @property {Recursive} demo */ RecursiveMapValue: /** * @typedef {{ * demo: { [key in string]: RecursiveMapValue }, * }} RecursiveMapValue * @property {{ [key in string]: RecursiveMapValue }} demo */ RecursiveTransparent: /** * @typedef {RecursiveInline} RecursiveTransparent * @property {RecursiveInline} "0" */ RecursiveInEnum: /** * @typedef {{ A: { * demo: RecursiveInEnum, * } }} RecursiveInEnum * @property {{ A: { * demo: RecursiveInEnum, * } }} A */ NonOptional: /** * @typedef {string | null} NonOptional * @property {string | null} "0" */ OptionalOnNamedField: /** * @typedef {string | null} OptionalOnNamedField * @property {string | null} ["0"] */ OptionalOnTransparentNamedField: /** * @typedef {{ * b: string | null, * }} OptionalOnTransparentNamedField * @property {string | null} b */ OptionalInEnum: /** * @typedef {({ A?: string | null }) & { B?: never; C?: never } | ({ B: { * a: string | null, * } }) & { A?: never; C?: never } | ({ C: { * a?: string | null, * } }) & { A?: never; B?: never }} OptionalInEnum * @property {{ A?: string | null }} A * @property {{ B: { * a: string | null, * } }} B * @property {{ C: { * a?: string | null, * } }} C */ UntaggedVariants: /** * @typedef {string | number | { id: string } | [string, boolean]} UntaggedVariants * @property {string} A * @property {number} B * @property {number} C * @property {{ id: string }} D * @property {[string, boolean]} E */ UntaggedVariantsWithoutValue: /** * @typedef {string | [number, string] | number} UntaggedVariantsWithoutValue * @property {string} A * @property {[number, string]} B * @property {number} C */ UntaggedVariantsWithDuplicateBranches: /** * @typedef {null | number} UntaggedVariantsWithDuplicateBranches * @property {null} A * @property {number} B * @property {null} C */ HashMap: Regular: /** * @typedef {{ [key in string]: null }} Regular * @property {{ [key in string]: null }} "0" */ HashMap: HashMap: HashMap: HashMap: ValidMaybeValidKey: /** * @typedef {{ [key in MaybeValidKey]: null }} ValidMaybeValidKey * @property {{ [key in MaybeValidKey]: null }} "0" */ ValidMaybeValidKeyNested: /** * @typedef {{ [key in MaybeValidKey>]: null }} ValidMaybeValidKeyNested * @property {{ [key in MaybeValidKey>]: null }} "0" */ MacroStruct: /** * @typedef {string} MacroStruct * @property {string} "0" */ MacroStruct2: /** * @typedef {{ * demo: string, * }} MacroStruct2 * @property {string} demo */ MacroEnum: /** * @typedef {({ Demo: string }) & { Demo2?: never } | ({ Demo2: { * demo2: string, * } }) & { Demo?: never }} MacroEnum * @property {{ Demo: string }} Demo * @property {{ Demo2: { * demo2: string, * } }} Demo2 */ DeprecatedType: /** * @deprecated * @typedef {{ * a: number, * }} DeprecatedType * @property {number} a */ DeprecatedTypeWithMsg: /** * @deprecated Look at you big man using a deprecation message * @typedef {{ * a: number, * }} DeprecatedTypeWithMsg * @property {number} a */ DeprecatedTypeWithMsg2: /** * @deprecated Look at you big man using a deprecation message * @typedef {{ * a: number, * }} DeprecatedTypeWithMsg2 * @property {number} a */ DeprecatedFields: /** * @typedef {{ * a: number, * /** * * @deprecated * */ * b: string, * /** * * @deprecated This field is cringe! * */ * c: string, * /** * * @deprecated This field is cringe! * */ * d: string, * }} DeprecatedFields * @property {number} a * @property {string} b - @deprecated * @property {string} c - @deprecated This field is cringe! * @property {string} d - @deprecated This field is cringe! */ DeprecatedTupleVariant: /** * @typedef {[ * /** * * @deprecated * */ * string, * /** * * @deprecated Nope * */ * string, * /** * * @deprecated Nope * */ * number]} DeprecatedTupleVariant * @property {string} "0" - @deprecated * @property {string} "1" - @deprecated Nope * @property {number} "2" - @deprecated Nope */ DeprecatedEnumVariants: /** * @typedef { * /** * * @deprecated * */ * "A" | * /** * * @deprecated Nope * */ * "B" | * /** * * @deprecated Nope * */ * "C"} DeprecatedEnumVariants * @property { * /** * * @deprecated * */ * "A"} A - @deprecated * @property { * /** * * @deprecated Nope * */ * "B"} B - @deprecated Nope * @property { * /** * * @deprecated Nope * */ * "C"} C - @deprecated Nope */ CommentedStruct: /** * Some triple-slash comment * Some more triple-slash comment * * @typedef {{ * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * }} CommentedStruct * @property {number} a - Some triple-slash comment Some more triple-slash comment */ CommentedEnum: /** * Some triple-slash comment * Some more triple-slash comment * * @typedef { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * ({ A: number }) & { B?: never } | * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * ({ B: { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * } }) & { A?: never }} CommentedEnum * @property { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * { A: number }} A - Some triple-slash comment Some more triple-slash comment * @property { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * { B: { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * } }} B - Some triple-slash comment Some more triple-slash comment */ SingleLineComment: /** * Some single-line comment * * @typedef { * /** Some single-line comment */ * ({ A: number }) & { B?: never } | * /** Some single-line comment */ * ({ B: { * /** Some single-line comment */ * a: number, * } }) & { A?: never }} SingleLineComment * @property { * /** Some single-line comment */ * { A: number }} A - Some single-line comment * @property { * /** Some single-line comment */ * { B: { * /** Some single-line comment */ * a: number, * } }} B - Some single-line comment */ NonGeneric: /** * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b */ HalfGenericA: /** * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b */ HalfGenericB: /** * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b */ FullGeneric: /** * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b */ Another: /** * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b */ MapA: MapB: MapC: AGenericStruct: /** * @typedef {{ * field: Demo, * }} AGenericStruct * @property {Demo} field */ A: /** * @typedef {{ * a: B, * b: { * b: number, * }, * c: B, * d: { * flattened: number, * }, * e: { * generic_flattened: number, * }, * }} A * @property {B} a * @property {{ * b: number, * }} b * @property {B} c * @property {{ * flattened: number, * }} d * @property {{ * generic_flattened: number, * }} e */ DoubleFlattened: /** * @typedef {{ * a: ToBeFlattened, * b: ToBeFlattened, * }} DoubleFlattened * @property {ToBeFlattened} a * @property {ToBeFlattened} b */ FlattenedInner: /** * @typedef {Inner} FlattenedInner */ BoxFlattened: /** * @typedef {BoxedInner} BoxFlattened */ BoxInline: /** * @typedef {{ * c: { * a: number, * }, * }} BoxInline * @property {{ * a: number, * }} c */ First: /** * @typedef {{ * a: string, * }} First * @property {string} a */ Second: /** * @typedef {{ * a: number, * }} Second * @property {number} a */ Third: /** * @typedef {{ * b: { [key in string]: string }, * c: First, * } & First} Third * @property {{ [key in string]: string }} b * @property {First} c */ Fourth: /** * @typedef {{ * a: First, * b: { * a: string, * }, * }} Fourth * @property {First} a * @property {{ * a: string, * }} b */ TagOnStructWithInline: /** * @typedef {{ * type: "TagOnStructWithInline", * a: First, * b: { * a: string, * }, * }} TagOnStructWithInline * @property {"TagOnStructWithInline"} type * @property {First} a * @property {{ * a: string, * }} b */ Sixth: /** * @typedef {{ * a: First, * b: First, * }} Sixth * @property {First} a * @property {First} b */ Seventh: /** * @typedef {{ * a: First, * b: Second, * }} Seventh * @property {First} a * @property {Second} b */ Eight: /** * @typedef {{ A: string } | "B"} Eight * @property {{ A: string }} A * @property {"B"} B */ Ninth: /** * @typedef {{ t: "A"; c: string } | { t: "B" } | { t: "C"; c: { * a: string, * } } | { t: "D"; c: First }} Ninth * @property {{ t: "A"; c: string }} A * @property {{ t: "B" }} B * @property {{ t: "C"; c: { * a: string, * } }} C * @property {{ t: "D"; c: First }} D */ Tenth: /** * @typedef {string | "B" | { * a: string, * } | First} Tenth * @property {string} A * @property {"B"} B * @property {{ * a: string, * }} C * @property {First} D */ MyEnumTagged: /** * @typedef {{ type: "Variant"; inner: First }} MyEnumTagged * @property {{ type: "Variant"; inner: First }} Variant */ MyEnumExternal: /** * @typedef {{ Variant: { * inner: First, * } }} MyEnumExternal * @property {{ Variant: { * inner: First, * } }} Variant */ MyEnumAdjacent: /** * @typedef {{ t: "Variant"; c: { * inner: First, * } }} MyEnumAdjacent * @property {{ t: "Variant"; c: { * inner: First, * } }} Variant */ MyEnumUntagged: /** * @typedef {{ inner: First }} MyEnumUntagged * @property {{ inner: First }} Variant */ EmptyStruct: /** * @typedef {Record} EmptyStruct */ EmptyStructWithTag: /** * @typedef {{ * a: "EmptyStructWithTag", * }} EmptyStructWithTag * @property {"EmptyStructWithTag"} a */ AdjacentlyTagged: /** * @typedef {{ t: "A" } | { t: "B"; c: { * id: string, * method: string, * } } | { t: "C"; c: string }} AdjacentlyTagged * @property {{ t: "A" }} A * @property {{ t: "B"; c: { * id: string, * method: string, * } }} B * @property {{ t: "C"; c: string }} C */ LoadProjectEvent: /** * @typedef {{ event: "started"; data: { * projectName: string, * } } | { event: "progressTest"; data: { * projectName: string, * status: string, * progress: number, * } } | { event: "finished"; data: { * projectName: string, * } }} LoadProjectEvent * @property {{ event: "started"; data: { * projectName: string, * } }} started * @property {{ event: "progressTest"; data: { * projectName: string, * status: string, * progress: number, * } }} progressTest * @property {{ event: "finished"; data: { * projectName: string, * } }} finished */ ExternallyTagged: /** * @typedef {"A" | ({ B: { * id: string, * method: string, * } }) & { C?: never } | ({ C: string }) & { B?: never }} ExternallyTagged * @property {"A"} A * @property {{ B: { * id: string, * method: string, * } }} B * @property {{ C: string }} C */ Issue221External: /** * @typedef {({ A: { * a: string, * } }) & { B?: never } | ({ B: { * b: string, * } }) & { A?: never }} Issue221External * @property {{ A: { * a: string, * } }} A * @property {{ B: { * b: string, * } }} B */ InternallyTaggedD: /** * @typedef {{ * type: "A", * } & { [key in string]: string }} InternallyTaggedD * @property {{ * type: "A", * } & { [key in string]: string }} A */ InternallyTaggedE: /** * @typedef {{ type: "A" }} InternallyTaggedE * @property {{ type: "A" }} A */ InternallyTaggedF: /** * @typedef {{ type: "A" }} InternallyTaggedF * @property {{ type: "A" }} A */ InternallyTaggedH: /** * @typedef {{ type: "A" }} InternallyTaggedH * @property {{ type: "A" }} A */ InternallyTaggedL: /** * @typedef {{ * type: "A", * } & { type: "A" } | { type: "B" }} InternallyTaggedL * @property {{ * type: "A", * } & { type: "A" } | { type: "B" }} A */ InternallyTaggedM: /** * @typedef {{ type: "A" }} InternallyTaggedM * @property {{ type: "A" }} A */ StructWithAlias: /** * @typedef {{ * field: string, * }} StructWithAlias * @property {string} field */ StructWithMultipleAliases: /** * @typedef {{ * field: string, * }} StructWithMultipleAliases * @property {string} field */ StructWithAliasAndRename: /** * @typedef {{ * renamed_field: string, * }} StructWithAliasAndRename * @property {string} renamed_field */ EnumWithVariantAlias: /** * @typedef {"Variant" | "Other"} EnumWithVariantAlias * @property {"Variant"} Variant * @property {"Other"} Other */ EnumWithMultipleVariantAliases: /** * @typedef {"Variant" | "Other"} EnumWithMultipleVariantAliases * @property {"Variant"} Variant * @property {"Other"} Other */ EnumWithVariantAliasAndRename: /** * @typedef {"renamed_variant" | "Other"} EnumWithVariantAliasAndRename * @property {"renamed_variant"} renamed_variant * @property {"Other"} Other */ InternallyTaggedWithAlias: /** * @typedef {{ type: "A"; field: string } | { type: "B"; other: number }} InternallyTaggedWithAlias * @property {{ type: "A"; field: string }} A * @property {{ type: "B"; other: number }} B */ AdjacentlyTaggedWithAlias: /** * @typedef {{ type: "A"; data: { * field: string, * } } | { type: "B"; data: { * other: number, * } }} AdjacentlyTaggedWithAlias * @property {{ type: "A"; data: { * field: string, * } }} A * @property {{ type: "B"; data: { * other: number, * } }} B */ UntaggedWithAlias: /** * @typedef {({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }} UntaggedWithAlias * @property {{ field: string }} A * @property {{ other: number }} B */ Issue221UntaggedSafe: /** * @typedef {({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }} Issue221UntaggedSafe * @property {{ a: string }} A * @property {{ b: string }} B */ Issue221UntaggedMixed: /** * @typedef {({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never }} Issue221UntaggedMixed * @property {{ a: string }} A * @property {{ b: string }} B * @property {{ values: { [key in string]: string } }} Unsafe */ EmptyEnum: /** * @typedef {never} EmptyEnum */ EmptyEnumTagged: /** * @typedef {never} EmptyEnumTagged */ EmptyEnumTaggedWContent: /** * @typedef {never} EmptyEnumTaggedWContent */ EmptyEnumUntagged: /** * @typedef {never} EmptyEnumUntagged */ SkipOnlyField: /** * @typedef {Record} SkipOnlyField */ SkipField: /** * @typedef {{ * b: number, * }} SkipField * @property {number} b */ SkipVariant: /** * @typedef {{ A: string }} SkipVariant * @property {{ A: string }} A */ SkipUnnamedFieldInVariant: /** * @typedef {"A" | { B: [number] }} SkipUnnamedFieldInVariant * @property {"A"} A * @property {{ B: [number] }} B */ SkipNamedFieldInVariant: /** * @typedef {({ A: Record }) & { B?: never } | ({ B: { * b: number, * } }) & { A?: never }} SkipNamedFieldInVariant * @property {{ A: Record }} A * @property {{ B: { * b: number, * } }} B */ TransparentWithSkip: /** * @typedef {null} TransparentWithSkip * @property {null} "0" */ TransparentWithSkip2: /** * @typedef {string} TransparentWithSkip2 * @property {string} "0" */ TransparentWithSkip3: /** * @typedef {string} TransparentWithSkip3 * @property {string} "0" */ SkipVariant2: /** * @typedef {{ tag: "A"; data: string }} SkipVariant2 * @property {{ tag: "A"; data: string }} A */ SkipVariant3: /** * @typedef {{ A: { * a: string, * } }} SkipVariant3 * @property {{ A: { * a: string, * } }} A */ SkipStructFields: /** * @typedef {{ * a: number, * }} SkipStructFields * @property {number} a */ SpectaSkipNonTypeField: /** * @typedef {{ * a: number, * }} SpectaSkipNonTypeField * @property {number} a */ FlattenA: /** * @typedef {{ * a: number, * b: number, * }} FlattenA * @property {number} a * @property {number} b */ FlattenB: /** * @typedef {{ * c: number, * } & FlattenA} FlattenB * @property {number} c */ FlattenC: /** * @typedef {{ * c: number, * } & FlattenA} FlattenC * @property {number} c */ FlattenD: /** * @typedef {{ * a: FlattenA, * c: number, * }} FlattenD * @property {FlattenA} a * @property {number} c */ FlattenE: /** * @typedef {{ * b: ({ * c: number, * }) & (FlattenA), * d: number, * }} FlattenE * @property {({ * c: number, * }) & (FlattenA)} b * @property {number} d */ FlattenF: /** * @typedef {{ * b: ({ * c: number, * }) & (FlattenA), * d: number, * }} FlattenF * @property {({ * c: number, * }) & (FlattenA)} b * @property {number} d */ FlattenG: /** * @typedef {{ * b: FlattenB, * d: number, * }} FlattenG * @property {FlattenB} b * @property {number} d */ TupleNested: /** * @typedef {[number[], [number[], number[]], [number[], number[], number[]]]} TupleNested * @property {number[]} "0" * @property {[number[], number[]]} "1" * @property {[number[], number[], number[]]} "2" */ Generic1<()>: /** * @typedef {{ * value: T, * values: T[], * }} Generic1 * @property {T} value * @property {T[]} values */ GenericAutoBound<()>: /** * @typedef {{ * value: T, * values: T[], * }} GenericAutoBound * @property {T} value * @property {T[]} values */ GenericAutoBound2<()>: /** * @typedef {{ * value: T, * values: T[], * }} GenericAutoBound2 * @property {T} value * @property {T[]} values */ Container1: /** * @typedef {{ * foo: Generic1, * bar: Generic1[], * baz: { [key in string]: Generic1 }, * }} Container1 * @property {Generic1} foo * @property {Generic1[]} bar * @property {{ [key in string]: Generic1 }} baz */ Generic2<(), String, i32>: /** * @typedef {({ A: A }) & { B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ B: [B, B, B] }) & { A?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ C: C[] }) & { A?: never; B?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ D: A[][][] }) & { A?: never; B?: never; C?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ E: { * a: A, * b: B, * c: C, * } }) & { A?: never; B?: never; C?: never; D?: never; X?: never; Y?: never; Z?: never } | ({ X: number[] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; Y?: never; Z?: never } | ({ Y: number }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Z?: never } | ({ Z: number[][] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never }} Generic2 * @property {{ A: A }} A * @property {{ B: [B, B, B] }} B * @property {{ C: C[] }} C * @property {{ D: A[][][] }} D * @property {{ E: { * a: A, * b: B, * c: C, * } }} E * @property {{ X: number[] }} X * @property {{ Y: number }} Y * @property {{ Z: number[][] }} Z */ GenericNewType1<()>: /** * @typedef {T[][]} GenericNewType1 * @property {T[][]} "0" */ GenericTuple<()>: /** * @typedef {[T, T[], T[][]]} GenericTuple * @property {T} "0" * @property {T[]} "1" * @property {T[][]} "2" */ GenericStruct2<()>: /** * @typedef {{ * a: T, * b: [T, T], * c: [T, [T, T]], * d: [T, T, T], * e: [([T, T]), ([T, T]), ([T, T])], * f: T[], * g: T[][], * h: ([([T, T]), ([T, T]), ([T, T])])[], * }} GenericStruct2 * @property {T} a * @property {[T, T]} b * @property {[T, [T, T]]} c * @property {[T, T, T]} d * @property {[([T, T]), ([T, T]), ([T, T])]} e * @property {T[]} f * @property {T[][]} g * @property {([([T, T]), ([T, T]), ([T, T])])[]} h */ InlineGenericNewtype: InlineGenericNested: InlineFlattenGenericsG<()>: /** * @typedef {{ * t: T, * }} InlineFlattenGenericsG * @property {T} t */ InlineFlattenGenerics: /** * @typedef {{ * g: InlineFlattenGenericsG, * gi: { * t: string, * }, * } & InlineFlattenGenericsG} InlineFlattenGenerics * @property {InlineFlattenGenericsG} g * @property {{ * t: string, * }} gi */ GenericDefault: /** * @typedef {{ * value: T, * }} GenericDefault * @property {T} value */ ChainedGenericDefault: /** * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second */ ChainedGenericDefault: /** * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second */ ChainedGenericDefault: /** * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second */ ChainedGenericDefault: /** * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second */ GenericDefaultSkipped: /** * @typedef {{ * value: T, * }} GenericDefaultSkipped * @property {T} value */ GenericDefaultSkippedNonType: /** * @typedef {{ * value: number, * }} GenericDefaultSkippedNonType * @property {number} value */ GenericParameterOrderPreserved: /** * @typedef {{ * pair: Pair, * }} GenericParameterOrderPreserved * @property {Pair} pair */ ConstGenericInNonConstContainer: /** * @typedef {{ * data: [number], * a: [number, number], * d: [number, number], * }} ConstGenericInNonConstContainer * @property {[number]} data * @property {[number, number]} a * @property {[number, number]} d */ ConstGenericInConstContainer: /** * @typedef {{ * data: number[], * a: number[], * d: [number, number], * }} ConstGenericInConstContainer * @property {number[]} data * @property {number[]} a * @property {[number, number]} d */ NamedConstGenericContainer: /** * @typedef {{ * a: NamedConstGeneric, * b: NamedConstGeneric, * d: [number, number], * }} NamedConstGenericContainer * @property {NamedConstGeneric} a * @property {NamedConstGeneric} b * @property {[number, number]} d */ InlineConstGenericContainer: /** * @typedef {{ * b: { * data: [number, number], * a: [number, number], * d: [number, number, number], * }, * c: { * data: [number, number, number], * a: [number, number], * d: [number, number, number], * }, * d: [number, number], * }} InlineConstGenericContainer * @property {{ * data: [number, number], * a: [number, number], * d: [number, number, number], * }} b * @property {{ * data: [number, number, number], * a: [number, number], * d: [number, number, number], * }} c * @property {[number, number]} d */ InlineRecursiveConstGenericContainer: /** * @typedef {{ * b: { * data: [number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }, * c: { * data: [number, number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }, * d: [number, number], * }} InlineRecursiveConstGenericContainer * @property {{ * data: [number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }} b * @property {{ * data: [number, number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }} c * @property {[number, number]} d */ TestCollectionRegister: /** * @typedef {never} TestCollectionRegister */ TestCollectionRegister: /** * @typedef {never} TestCollectionRegister */ ================================================ FILE: tests/tests/snapshots/test__jsdoc__export-serde_phases.snap ================================================ --- source: tests/tests/jsdoc.rs expression: output --- Issue374: /** * https://github.com/specta-rs/specta/issues/374 * * @typedef {Issue374_Serialize | Issue374_Deserialize} Issue374 * @property {Issue374_Serialize} Serialize * @property {Issue374_Deserialize} Deserialize */ Optional: /** * @typedef {Optional_Serialize | Optional_Deserialize} Optional * @property {Optional_Serialize} Serialize * @property {Optional_Deserialize} Deserialize */ StructPhaseSpecificRename: /** * @typedef {StructPhaseSpecificRenameSerialize | StructPhaseSpecificRenameDeserialize} StructPhaseSpecificRename * @property {StructPhaseSpecificRenameSerialize} Serialize * @property {StructPhaseSpecificRenameDeserialize} Deserialize */ Range: /** * @typedef {{ * start: T, * end: T, * }} Range * @property {T} start * @property {T} end */ RangeInclusive: /** * @typedef {{ * start: T, * end: T, * }} RangeInclusive * @property {T} start * @property {T} end */ String: PathBuf: IpAddr: Ipv4Addr: Ipv6Addr: SocketAddr: SocketAddrV4: SocketAddrV6: Cow<'static, str>: Cow<'static, i32>: Vec: Vec: Result: /** * @typedef {{ * ok: T, * err: E, * }} Result * @property {T} ok * @property {E} err */ Vec>>: PhantomData<()>: PhantomData: Infallible: Unit1: /** * @typedef {null} Unit1 */ Unit2: /** * @typedef {Record} Unit2 */ Unit3: /** * @typedef {[]} Unit3 */ Unit4: /** * @typedef {null} Unit4 * @property {null} "0" */ Unit5: /** * @typedef {"A"} Unit5 * @property {"A"} A */ Unit6: /** * @typedef {{ A: null }} Unit6 * @property {{ A: null }} A */ Unit7: /** * @typedef {{ A: Record }} Unit7 * @property {{ A: Record }} A */ SimpleStruct: /** * @typedef {{ * a: number, * b: string, * c: [number, string, number], * d: string[], * e: string | null, * }} SimpleStruct * @property {number} a * @property {string} b * @property {[number, string, number]} c * @property {string[]} d * @property {string | null} e */ TupleStruct1: /** * @typedef {number} TupleStruct1 * @property {number} "0" */ TupleStruct3: /** * @typedef {[number, boolean, string]} TupleStruct3 * @property {number} "0" * @property {boolean} "1" * @property {string} "2" */ TestEnum: /** * @typedef {"Unit" | ({ Single: number }) & { Multiple?: never; Struct?: never } | ({ Multiple: [number, number] }) & { Single?: never; Struct?: never } | ({ Struct: { * a: number, * } }) & { Multiple?: never; Single?: never }} TestEnum * @property {"Unit"} Unit * @property {{ Single: number }} Single * @property {{ Multiple: [number, number] }} Multiple * @property {{ Struct: { * a: number, * } }} Struct */ RefStruct: /** * @typedef {TestEnum} RefStruct * @property {TestEnum} "0" */ InlinerStruct: /** * @typedef {{ * inline_this: { * ref_struct: SimpleStruct, * val: number, * }, * dont_inline_this: RefStruct, * }} InlinerStruct * @property {{ * ref_struct: SimpleStruct, * val: number, * }} inline_this * @property {RefStruct} dont_inline_this */ GenericStruct: /** * @typedef {{ * arg: T, * }} GenericStruct * @property {T} arg */ GenericStruct: /** * @typedef {{ * arg: T, * }} GenericStruct * @property {T} arg */ FlattenEnumStruct: /** * @typedef {{ * outer: string, * } & FlattenEnum} FlattenEnumStruct * @property {string} outer */ OverridenStruct: /** * @typedef {{ * overriden_field: string, * }} OverridenStruct * @property {string} overriden_field */ HasGenericAlias: /** * @typedef {{ [key in number]: string }} HasGenericAlias * @property {{ [key in number]: string }} "0" */ EnumMacroAttributes: /** * @typedef {({ A: string }) & { D?: never; bbb?: never; cccc?: never } | ({ bbb: number }) & { A?: never; D?: never; cccc?: never } | ({ cccc: number }) & { A?: never; D?: never; bbb?: never } | ({ D: { * a: string, * bbbbbb: number, * } }) & { A?: never; bbb?: never; cccc?: never }} EnumMacroAttributes * @property {{ A: string }} A * @property {{ bbb: number }} bbb * @property {{ cccc: number }} cccc * @property {{ D: { * a: string, * bbbbbb: number, * } }} D */ InlineEnumField: /** * @typedef {{ A: { * a: string, * } }} InlineEnumField * @property {{ A: { * a: string, * } }} A */ InlineOptionalType: /** * @typedef {{ * optional_field: { * a: string, * } | null, * }} InlineOptionalType * @property {{ * a: string, * } | null} optional_field */ Rename: /** * @typedef {"OneWord" | "Two words"} Rename * @property {"OneWord"} OneWord * @property {"Two words"} "Two words" */ TransparentType: /** * @typedef {TransparentTypeInner} TransparentType * @property {TransparentTypeInner} "0" */ TransparentType2: /** * @typedef {null} TransparentType2 * @property {null} "0" */ TransparentTypeWithOverride: /** * @typedef {string} TransparentTypeWithOverride * @property {string} "0" */ HashMap: HashMap: Vec: EnumReferenceRecordKey: /** * @typedef {{ * a: Partial<{ [key in BasicEnum]: number }>, * }} EnumReferenceRecordKey * @property {Partial<{ [key in BasicEnum]: number }>} a */ FlattenOnNestedEnum: /** * @typedef {{ * id: string, * } & NestedEnum} FlattenOnNestedEnum * @property {string} id */ MyEmptyInput: /** * @typedef {Record} MyEmptyInput */ (String): ExtraBracketsInTupleVariant: /** * @typedef {{ A: string }} ExtraBracketsInTupleVariant * @property {{ A: string }} A */ ExtraBracketsInUnnamedStruct: /** * @typedef {string} ExtraBracketsInUnnamedStruct * @property {string} "0" */ Vec: InlineTuple: /** * @typedef {{ * demo: [string, boolean], * }} InlineTuple * @property {[string, boolean]} demo */ InlineTuple2: /** * @typedef {{ * demo: [{ * demo: [string, boolean], * }, boolean], * }} InlineTuple2 * @property {[{ * demo: [string, boolean], * }, boolean]} demo */ Box: Box: SkippedFieldWithinVariant: /** * @typedef {{ type: "A" } | { type: "B"; data: string }} SkippedFieldWithinVariant * @property {{ type: "A" }} A * @property {{ type: "B"; data: string }} B */ KebabCase: /** * @typedef {{ * "test-ing": string, * }} KebabCase * @property {string} "test-ing" */ Issue281<'_>: /** * @typedef {{ * default_unity_arguments: string[], * }} Issue281 * @property {string[]} default_unity_arguments */ LifetimeGenericStruct<'_, i32>: /** * @typedef {{ * borrowed: T[], * owned: T[], * }} LifetimeGenericStruct * @property {T[]} borrowed * @property {T[]} owned */ LifetimeGenericEnum<'_, i32>: /** * @typedef {({ Borrowed: T }) & { Owned?: never } | ({ Owned: T }) & { Borrowed?: never }} LifetimeGenericEnum * @property {{ Borrowed: T }} Borrowed * @property {{ Owned: T }} Owned */ RenameWithWeirdCharsField: /** * @typedef {{ * "@odata.context": string, * }} RenameWithWeirdCharsField * @property {string} "@odata.context" */ RenameWithWeirdCharsVariant: /** * @typedef {{ "@odata.context": string }} RenameWithWeirdCharsVariant * @property {{ "@odata.context": string }} "@odata.context" */ RenamedFieldKeys: /** * @typedef {{ * "": string, * "a\"b": string, * "a\\b": string, * "line\nbreak": string, * "line\u2028break": string, * "line\u2029break": string, * }} RenamedFieldKeys * @property {string} "" * @property {string} "a\"b" * @property {string} "a\\b" * @property {string} "line\nbreak" * @property {string} "line\u2028break" * @property {string} "line\u2029break" */ RenamedVariantWithSkippedPayload: /** * @typedef {"a-b"} RenamedVariantWithSkippedPayload * @property {"a-b"} "a-b" */ type_type::Type: /** * @typedef {never} Type */ ActualType: /** * @typedef {{ * a: GenericType, * }} ActualType * @property {GenericType} a */ SpectaTypeOverride: /** * @typedef {{ * string_ident: string, * u32_ident: number, * path: string, * tuple: [string, number], * }} SpectaTypeOverride * @property {string} string_ident * @property {number} u32_ident * @property {string} path * @property {[string, number]} tuple */ ContainerTypeOverrideStruct: /** * @typedef {string} ContainerTypeOverrideStruct */ ContainerTypeOverrideEnum: /** * @typedef {string} ContainerTypeOverrideEnum */ ContainerTypeOverrideGeneric>: /** * @typedef {string} ContainerTypeOverrideGeneric */ ContainerTypeOverrideToGeneric: /** * @typedef {T} ContainerTypeOverrideToGeneric */ ContainerTypeOverrideTuple: /** * @typedef {[string, number]} ContainerTypeOverrideTuple */ ContainerTypeOverrideTupleGeneric: /** * @typedef {[T, string]} ContainerTypeOverrideTupleGeneric */ InvalidToValidType: /** * @typedef {{ * cause: null, * }} InvalidToValidType * @property {null} cause */ TupleStruct: /** * @typedef {string} TupleStruct * @property {string} "0" */ TupleStructWithRep: /** * @typedef {string} TupleStructWithRep * @property {string} "0" */ GenericTupleStruct: /** * @typedef {T} GenericTupleStruct * @property {T} "0" */ BracedStruct: /** * @typedef {string} BracedStruct * @property {string} "0" */ Struct: /** * @typedef {{ * t: "StructNew", * a: string, * }} StructNew * @property {"StructNew"} t * @property {string} a */ Struct2: /** * @typedef {{ * b: string, * }} Struct2 * @property {string} b */ Enum: /** * @typedef {{ t: "A" } | { t: "B" }} Enum * @property {{ t: "A" }} A * @property {{ t: "B" }} B */ Enum2: /** * @typedef {{ t: "C" } | { t: "B" } | { t: "D"; enumField: null }} Enum2 * @property {{ t: "C" }} C * @property {{ t: "B" }} B * @property {{ t: "D"; enumField: null }} D */ Enum3: /** * @typedef {{ t: "A"; b: string }} Enum3 * @property {{ t: "A"; b: string }} A */ StructRenameAllUppercase: /** * @typedef {{ * A: number, * B: number, * }} StructRenameAllUppercase * @property {number} A * @property {number} B */ RenameSerdeSpecialChar: /** * @typedef {{ * "a/b": number, * }} RenameSerdeSpecialChar * @property {number} "a/b" */ EnumRenameAllUppercase: /** * @typedef {"HELLOWORLD" | "VARIANTB" | "TESTINGWORDS"} EnumRenameAllUppercase * @property {"HELLOWORLD"} HELLOWORLD * @property {"VARIANTB"} VARIANTB * @property {"TESTINGWORDS"} TESTINGWORDS */ Recursive: /** * @typedef {{ * demo: Recursive, * }} Recursive * @property {Recursive} demo */ RecursiveMapValue: /** * @typedef {{ * demo: { [key in string]: RecursiveMapValue }, * }} RecursiveMapValue * @property {{ [key in string]: RecursiveMapValue }} demo */ RecursiveTransparent: /** * @typedef {RecursiveInline} RecursiveTransparent * @property {RecursiveInline} "0" */ RecursiveInEnum: /** * @typedef {{ A: { * demo: RecursiveInEnum, * } }} RecursiveInEnum * @property {{ A: { * demo: RecursiveInEnum, * } }} A */ NonOptional: /** * @typedef {string | null} NonOptional * @property {string | null} "0" */ OptionalOnNamedField: /** * @typedef {string | null} OptionalOnNamedField * @property {string | null} ["0"] */ OptionalOnTransparentNamedField: /** * @typedef {{ * b: string | null, * }} OptionalOnTransparentNamedField * @property {string | null} b */ OptionalInEnum: /** * @typedef {({ A?: string | null }) & { B?: never; C?: never } | ({ B: { * a: string | null, * } }) & { A?: never; C?: never } | ({ C: { * a?: string | null, * } }) & { A?: never; B?: never }} OptionalInEnum * @property {{ A?: string | null }} A * @property {{ B: { * a: string | null, * } }} B * @property {{ C: { * a?: string | null, * } }} C */ UntaggedVariants: /** * @typedef {string | number | { id: string } | [string, boolean]} UntaggedVariants * @property {string} A * @property {number} B * @property {number} C * @property {{ id: string }} D * @property {[string, boolean]} E */ UntaggedVariantsWithoutValue: /** * @typedef {string | [number, string] | number} UntaggedVariantsWithoutValue * @property {string} A * @property {[number, string]} B * @property {number} C */ UntaggedVariantsWithDuplicateBranches: /** * @typedef {null | number} UntaggedVariantsWithDuplicateBranches * @property {null} A * @property {number} B * @property {null} C */ HashMap: Regular: /** * @typedef {{ [key in string]: null }} Regular * @property {{ [key in string]: null }} "0" */ HashMap: HashMap: HashMap: HashMap: ValidMaybeValidKey: /** * @typedef {{ [key in MaybeValidKey]: null }} ValidMaybeValidKey * @property {{ [key in MaybeValidKey]: null }} "0" */ ValidMaybeValidKeyNested: /** * @typedef {{ [key in MaybeValidKey>]: null }} ValidMaybeValidKeyNested * @property {{ [key in MaybeValidKey>]: null }} "0" */ MacroStruct: /** * @typedef {string} MacroStruct * @property {string} "0" */ MacroStruct2: /** * @typedef {{ * demo: string, * }} MacroStruct2 * @property {string} demo */ MacroEnum: /** * @typedef {({ Demo: string }) & { Demo2?: never } | ({ Demo2: { * demo2: string, * } }) & { Demo?: never }} MacroEnum * @property {{ Demo: string }} Demo * @property {{ Demo2: { * demo2: string, * } }} Demo2 */ DeprecatedType: /** * @deprecated * @typedef {{ * a: number, * }} DeprecatedType * @property {number} a */ DeprecatedTypeWithMsg: /** * @deprecated Look at you big man using a deprecation message * @typedef {{ * a: number, * }} DeprecatedTypeWithMsg * @property {number} a */ DeprecatedTypeWithMsg2: /** * @deprecated Look at you big man using a deprecation message * @typedef {{ * a: number, * }} DeprecatedTypeWithMsg2 * @property {number} a */ DeprecatedFields: /** * @typedef {{ * a: number, * /** * * @deprecated * */ * b: string, * /** * * @deprecated This field is cringe! * */ * c: string, * /** * * @deprecated This field is cringe! * */ * d: string, * }} DeprecatedFields * @property {number} a * @property {string} b - @deprecated * @property {string} c - @deprecated This field is cringe! * @property {string} d - @deprecated This field is cringe! */ DeprecatedTupleVariant: /** * @typedef {[ * /** * * @deprecated * */ * string, * /** * * @deprecated Nope * */ * string, * /** * * @deprecated Nope * */ * number]} DeprecatedTupleVariant * @property {string} "0" - @deprecated * @property {string} "1" - @deprecated Nope * @property {number} "2" - @deprecated Nope */ DeprecatedEnumVariants: /** * @typedef { * /** * * @deprecated * */ * "A" | * /** * * @deprecated Nope * */ * "B" | * /** * * @deprecated Nope * */ * "C"} DeprecatedEnumVariants * @property { * /** * * @deprecated * */ * "A"} A - @deprecated * @property { * /** * * @deprecated Nope * */ * "B"} B - @deprecated Nope * @property { * /** * * @deprecated Nope * */ * "C"} C - @deprecated Nope */ CommentedStruct: /** * Some triple-slash comment * Some more triple-slash comment * * @typedef {{ * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * }} CommentedStruct * @property {number} a - Some triple-slash comment Some more triple-slash comment */ CommentedEnum: /** * Some triple-slash comment * Some more triple-slash comment * * @typedef { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * ({ A: number }) & { B?: never } | * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * ({ B: { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * } }) & { A?: never }} CommentedEnum * @property { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * { A: number }} A - Some triple-slash comment Some more triple-slash comment * @property { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * { B: { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * } }} B - Some triple-slash comment Some more triple-slash comment */ SingleLineComment: /** * Some single-line comment * * @typedef { * /** Some single-line comment */ * ({ A: number }) & { B?: never } | * /** Some single-line comment */ * ({ B: { * /** Some single-line comment */ * a: number, * } }) & { A?: never }} SingleLineComment * @property { * /** Some single-line comment */ * { A: number }} A - Some single-line comment * @property { * /** Some single-line comment */ * { B: { * /** Some single-line comment */ * a: number, * } }} B - Some single-line comment */ NonGeneric: /** * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b */ HalfGenericA: /** * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b */ HalfGenericB: /** * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b */ FullGeneric: /** * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b */ Another: /** * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b */ MapA: MapB: MapC: AGenericStruct: /** * @typedef {{ * field: Demo, * }} AGenericStruct * @property {Demo} field */ A: /** * @typedef {{ * a: B, * b: { * b: number, * }, * c: B, * d: { * flattened: number, * }, * e: { * generic_flattened: number, * }, * }} A * @property {B} a * @property {{ * b: number, * }} b * @property {B} c * @property {{ * flattened: number, * }} d * @property {{ * generic_flattened: number, * }} e */ DoubleFlattened: /** * @typedef {{ * a: ToBeFlattened, * b: ToBeFlattened, * }} DoubleFlattened * @property {ToBeFlattened} a * @property {ToBeFlattened} b */ FlattenedInner: /** * @typedef {Inner} FlattenedInner */ BoxFlattened: /** * @typedef {BoxedInner} BoxFlattened */ BoxInline: /** * @typedef {{ * c: { * a: number, * }, * }} BoxInline * @property {{ * a: number, * }} c */ First: /** * @typedef {{ * a: string, * }} First * @property {string} a */ Second: /** * @typedef {{ * a: number, * }} Second * @property {number} a */ Third: /** * @typedef {{ * b: { [key in string]: string }, * c: First, * } & First} Third * @property {{ [key in string]: string }} b * @property {First} c */ Fourth: /** * @typedef {{ * a: First, * b: { * a: string, * }, * }} Fourth * @property {First} a * @property {{ * a: string, * }} b */ TagOnStructWithInline: /** * @typedef {{ * type: "TagOnStructWithInline", * a: First, * b: { * a: string, * }, * }} TagOnStructWithInline * @property {"TagOnStructWithInline"} type * @property {First} a * @property {{ * a: string, * }} b */ Sixth: /** * @typedef {{ * a: First, * b: First, * }} Sixth * @property {First} a * @property {First} b */ Seventh: /** * @typedef {{ * a: First, * b: Second, * }} Seventh * @property {First} a * @property {Second} b */ Eight: /** * @typedef {{ A: string } | "B"} Eight * @property {{ A: string }} A * @property {"B"} B */ Ninth: /** * @typedef {{ t: "A"; c: string } | { t: "B" } | { t: "C"; c: { * a: string, * } } | { t: "D"; c: First }} Ninth * @property {{ t: "A"; c: string }} A * @property {{ t: "B" }} B * @property {{ t: "C"; c: { * a: string, * } }} C * @property {{ t: "D"; c: First }} D */ Tenth: /** * @typedef {string | "B" | { * a: string, * } | First} Tenth * @property {string} A * @property {"B"} B * @property {{ * a: string, * }} C * @property {First} D */ MyEnumTagged: /** * @typedef {{ type: "Variant"; inner: First }} MyEnumTagged * @property {{ type: "Variant"; inner: First }} Variant */ MyEnumExternal: /** * @typedef {{ Variant: { * inner: First, * } }} MyEnumExternal * @property {{ Variant: { * inner: First, * } }} Variant */ MyEnumAdjacent: /** * @typedef {{ t: "Variant"; c: { * inner: First, * } }} MyEnumAdjacent * @property {{ t: "Variant"; c: { * inner: First, * } }} Variant */ MyEnumUntagged: /** * @typedef {{ inner: First }} MyEnumUntagged * @property {{ inner: First }} Variant */ EmptyStruct: /** * @typedef {Record} EmptyStruct */ EmptyStructWithTag: /** * @typedef {{ * a: "EmptyStructWithTag", * }} EmptyStructWithTag * @property {"EmptyStructWithTag"} a */ AdjacentlyTagged: /** * @typedef {{ t: "A" } | { t: "B"; c: { * id: string, * method: string, * } } | { t: "C"; c: string }} AdjacentlyTagged * @property {{ t: "A" }} A * @property {{ t: "B"; c: { * id: string, * method: string, * } }} B * @property {{ t: "C"; c: string }} C */ LoadProjectEvent: /** * @typedef {{ event: "started"; data: { * projectName: string, * } } | { event: "progressTest"; data: { * projectName: string, * status: string, * progress: number, * } } | { event: "finished"; data: { * projectName: string, * } }} LoadProjectEvent * @property {{ event: "started"; data: { * projectName: string, * } }} started * @property {{ event: "progressTest"; data: { * projectName: string, * status: string, * progress: number, * } }} progressTest * @property {{ event: "finished"; data: { * projectName: string, * } }} finished */ ExternallyTagged: /** * @typedef {"A" | ({ B: { * id: string, * method: string, * } }) & { C?: never } | ({ C: string }) & { B?: never }} ExternallyTagged * @property {"A"} A * @property {{ B: { * id: string, * method: string, * } }} B * @property {{ C: string }} C */ Issue221External: /** * @typedef {({ A: { * a: string, * } }) & { B?: never } | ({ B: { * b: string, * } }) & { A?: never }} Issue221External * @property {{ A: { * a: string, * } }} A * @property {{ B: { * b: string, * } }} B */ InternallyTaggedD: /** * @typedef {{ * type: "A", * } & { [key in string]: string }} InternallyTaggedD * @property {{ * type: "A", * } & { [key in string]: string }} A */ InternallyTaggedE: /** * @typedef {{ type: "A" }} InternallyTaggedE * @property {{ type: "A" }} A */ InternallyTaggedF: /** * @typedef {{ type: "A" }} InternallyTaggedF * @property {{ type: "A" }} A */ InternallyTaggedH: /** * @typedef {{ type: "A" }} InternallyTaggedH * @property {{ type: "A" }} A */ InternallyTaggedL: /** * @typedef {{ * type: "A", * } & { type: "A" } | { type: "B" }} InternallyTaggedL * @property {{ * type: "A", * } & { type: "A" } | { type: "B" }} A */ InternallyTaggedM: /** * @typedef {{ type: "A" }} InternallyTaggedM * @property {{ type: "A" }} A */ StructWithAlias: /** * @typedef {{ * field: string, * }} StructWithAlias * @property {string} field */ StructWithMultipleAliases: /** * @typedef {{ * field: string, * }} StructWithMultipleAliases * @property {string} field */ StructWithAliasAndRename: /** * @typedef {{ * renamed_field: string, * }} StructWithAliasAndRename * @property {string} renamed_field */ EnumWithVariantAlias: /** * @typedef {"Variant" | "Other"} EnumWithVariantAlias * @property {"Variant"} Variant * @property {"Other"} Other */ EnumWithMultipleVariantAliases: /** * @typedef {"Variant" | "Other"} EnumWithMultipleVariantAliases * @property {"Variant"} Variant * @property {"Other"} Other */ EnumWithVariantAliasAndRename: /** * @typedef {"renamed_variant" | "Other"} EnumWithVariantAliasAndRename * @property {"renamed_variant"} renamed_variant * @property {"Other"} Other */ InternallyTaggedWithAlias: /** * @typedef {{ type: "A"; field: string } | { type: "B"; other: number }} InternallyTaggedWithAlias * @property {{ type: "A"; field: string }} A * @property {{ type: "B"; other: number }} B */ AdjacentlyTaggedWithAlias: /** * @typedef {{ type: "A"; data: { * field: string, * } } | { type: "B"; data: { * other: number, * } }} AdjacentlyTaggedWithAlias * @property {{ type: "A"; data: { * field: string, * } }} A * @property {{ type: "B"; data: { * other: number, * } }} B */ UntaggedWithAlias: /** * @typedef {({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }} UntaggedWithAlias * @property {{ field: string }} A * @property {{ other: number }} B */ Issue221UntaggedSafe: /** * @typedef {({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }} Issue221UntaggedSafe * @property {{ a: string }} A * @property {{ b: string }} B */ Issue221UntaggedMixed: /** * @typedef {({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never }} Issue221UntaggedMixed * @property {{ a: string }} A * @property {{ b: string }} B * @property {{ values: { [key in string]: string } }} Unsafe */ EmptyEnum: /** * @typedef {never} EmptyEnum */ EmptyEnumTagged: /** * @typedef {never} EmptyEnumTagged */ EmptyEnumTaggedWContent: /** * @typedef {never} EmptyEnumTaggedWContent */ EmptyEnumUntagged: /** * @typedef {never} EmptyEnumUntagged */ SkipOnlyField: /** * @typedef {Record} SkipOnlyField */ SkipField: /** * @typedef {{ * b: number, * }} SkipField * @property {number} b */ SkipVariant: /** * @typedef {{ A: string }} SkipVariant * @property {{ A: string }} A */ SkipUnnamedFieldInVariant: /** * @typedef {"A" | { B: [number] }} SkipUnnamedFieldInVariant * @property {"A"} A * @property {{ B: [number] }} B */ SkipNamedFieldInVariant: /** * @typedef {({ A: Record }) & { B?: never } | ({ B: { * b: number, * } }) & { A?: never }} SkipNamedFieldInVariant * @property {{ A: Record }} A * @property {{ B: { * b: number, * } }} B */ TransparentWithSkip: /** * @typedef {null} TransparentWithSkip * @property {null} "0" */ TransparentWithSkip2: /** * @typedef {string} TransparentWithSkip2 * @property {string} "0" */ TransparentWithSkip3: /** * @typedef {string} TransparentWithSkip3 * @property {string} "0" */ SkipVariant2: /** * @typedef {{ tag: "A"; data: string }} SkipVariant2 * @property {{ tag: "A"; data: string }} A */ SkipVariant3: /** * @typedef {{ A: { * a: string, * } }} SkipVariant3 * @property {{ A: { * a: string, * } }} A */ SkipStructFields: /** * @typedef {{ * a: number, * }} SkipStructFields * @property {number} a */ SpectaSkipNonTypeField: /** * @typedef {{ * a: number, * }} SpectaSkipNonTypeField * @property {number} a */ FlattenA: /** * @typedef {{ * a: number, * b: number, * }} FlattenA * @property {number} a * @property {number} b */ FlattenB: /** * @typedef {{ * c: number, * } & FlattenA} FlattenB * @property {number} c */ FlattenC: /** * @typedef {{ * c: number, * } & FlattenA} FlattenC * @property {number} c */ FlattenD: /** * @typedef {{ * a: FlattenA, * c: number, * }} FlattenD * @property {FlattenA} a * @property {number} c */ FlattenE: /** * @typedef {{ * b: ({ * c: number, * }) & (FlattenA), * d: number, * }} FlattenE * @property {({ * c: number, * }) & (FlattenA)} b * @property {number} d */ FlattenF: /** * @typedef {{ * b: ({ * c: number, * }) & (FlattenA), * d: number, * }} FlattenF * @property {({ * c: number, * }) & (FlattenA)} b * @property {number} d */ FlattenG: /** * @typedef {{ * b: FlattenB, * d: number, * }} FlattenG * @property {FlattenB} b * @property {number} d */ TupleNested: /** * @typedef {[number[], [number[], number[]], [number[], number[], number[]]]} TupleNested * @property {number[]} "0" * @property {[number[], number[]]} "1" * @property {[number[], number[], number[]]} "2" */ Generic1<()>: /** * @typedef {{ * value: T, * values: T[], * }} Generic1 * @property {T} value * @property {T[]} values */ GenericAutoBound<()>: /** * @typedef {{ * value: T, * values: T[], * }} GenericAutoBound * @property {T} value * @property {T[]} values */ GenericAutoBound2<()>: /** * @typedef {{ * value: T, * values: T[], * }} GenericAutoBound2 * @property {T} value * @property {T[]} values */ Container1: /** * @typedef {{ * foo: Generic1, * bar: Generic1[], * baz: { [key in string]: Generic1 }, * }} Container1 * @property {Generic1} foo * @property {Generic1[]} bar * @property {{ [key in string]: Generic1 }} baz */ Generic2<(), String, i32>: /** * @typedef {({ A: A }) & { B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ B: [B, B, B] }) & { A?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ C: C[] }) & { A?: never; B?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ D: A[][][] }) & { A?: never; B?: never; C?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ E: { * a: A, * b: B, * c: C, * } }) & { A?: never; B?: never; C?: never; D?: never; X?: never; Y?: never; Z?: never } | ({ X: number[] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; Y?: never; Z?: never } | ({ Y: number }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Z?: never } | ({ Z: number[][] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never }} Generic2 * @property {{ A: A }} A * @property {{ B: [B, B, B] }} B * @property {{ C: C[] }} C * @property {{ D: A[][][] }} D * @property {{ E: { * a: A, * b: B, * c: C, * } }} E * @property {{ X: number[] }} X * @property {{ Y: number }} Y * @property {{ Z: number[][] }} Z */ GenericNewType1<()>: /** * @typedef {T[][]} GenericNewType1 * @property {T[][]} "0" */ GenericTuple<()>: /** * @typedef {[T, T[], T[][]]} GenericTuple * @property {T} "0" * @property {T[]} "1" * @property {T[][]} "2" */ GenericStruct2<()>: /** * @typedef {{ * a: T, * b: [T, T], * c: [T, [T, T]], * d: [T, T, T], * e: [([T, T]), ([T, T]), ([T, T])], * f: T[], * g: T[][], * h: ([([T, T]), ([T, T]), ([T, T])])[], * }} GenericStruct2 * @property {T} a * @property {[T, T]} b * @property {[T, [T, T]]} c * @property {[T, T, T]} d * @property {[([T, T]), ([T, T]), ([T, T])]} e * @property {T[]} f * @property {T[][]} g * @property {([([T, T]), ([T, T]), ([T, T])])[]} h */ InlineGenericNewtype: InlineGenericNested: InlineFlattenGenericsG<()>: /** * @typedef {{ * t: T, * }} InlineFlattenGenericsG * @property {T} t */ InlineFlattenGenerics: /** * @typedef {{ * g: InlineFlattenGenericsG, * gi: { * t: string, * }, * } & InlineFlattenGenericsG} InlineFlattenGenerics * @property {InlineFlattenGenericsG} g * @property {{ * t: string, * }} gi */ GenericDefault: /** * @typedef {{ * value: T, * }} GenericDefault * @property {T} value */ ChainedGenericDefault: /** * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second */ ChainedGenericDefault: /** * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second */ ChainedGenericDefault: /** * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second */ ChainedGenericDefault: /** * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second */ GenericDefaultSkipped: /** * @typedef {{ * value: T, * }} GenericDefaultSkipped * @property {T} value */ GenericDefaultSkippedNonType: /** * @typedef {{ * value: number, * }} GenericDefaultSkippedNonType * @property {number} value */ GenericParameterOrderPreserved: /** * @typedef {{ * pair: Pair, * }} GenericParameterOrderPreserved * @property {Pair} pair */ ConstGenericInNonConstContainer: /** * @typedef {{ * data: [number], * a: [number, number], * d: [number, number], * }} ConstGenericInNonConstContainer * @property {[number]} data * @property {[number, number]} a * @property {[number, number]} d */ ConstGenericInConstContainer: /** * @typedef {{ * data: number[], * a: number[], * d: [number, number], * }} ConstGenericInConstContainer * @property {number[]} data * @property {number[]} a * @property {[number, number]} d */ NamedConstGenericContainer: /** * @typedef {{ * a: NamedConstGeneric, * b: NamedConstGeneric, * d: [number, number], * }} NamedConstGenericContainer * @property {NamedConstGeneric} a * @property {NamedConstGeneric} b * @property {[number, number]} d */ InlineConstGenericContainer: /** * @typedef {{ * b: { * data: [number, number], * a: [number, number], * d: [number, number, number], * }, * c: { * data: [number, number, number], * a: [number, number], * d: [number, number, number], * }, * d: [number, number], * }} InlineConstGenericContainer * @property {{ * data: [number, number], * a: [number, number], * d: [number, number, number], * }} b * @property {{ * data: [number, number, number], * a: [number, number], * d: [number, number, number], * }} c * @property {[number, number]} d */ InlineRecursiveConstGenericContainer: /** * @typedef {{ * b: { * data: [number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }, * c: { * data: [number, number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }, * d: [number, number], * }} InlineRecursiveConstGenericContainer * @property {{ * data: [number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }} b * @property {{ * data: [number, number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }} c * @property {[number, number]} d */ TestCollectionRegister: /** * @typedef {never} TestCollectionRegister */ TestCollectionRegister: /** * @typedef {never} TestCollectionRegister */ ================================================ FILE: tests/tests/snapshots/test__jsdoc__inline-raw.snap ================================================ --- source: tests/tests/jsdoc.rs expression: output --- i8: number i16: number i32: number u8: number u16: number u32: number f32: number f64: number bool: boolean char: string Range: { start: T, end: T, } RangeInclusive: { start: T, end: T, } (): null (String, i32): [string, number] (String, i32, bool): [string, number, boolean] ((String, i32), (bool, char, bool), ()): [[string, number], [boolean, string, boolean], null] (bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool): [boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean] (Vec, Vec): [number[], boolean[]] String: string PathBuf: string IpAddr: string Ipv4Addr: string Ipv6Addr: string SocketAddr: string SocketAddrV4: string SocketAddrV6: string Cow<'static, str>: string Cow<'static, i32>: number &'static str: string &'static bool: boolean &'static i32: number Vec: number[] &'static [i32]: number[] &'static [i32; 3]: [number, number, number] [i32; 3]: [number, number, number] Vec: MyEnum[] &'static [MyEnum]: MyEnum[] &'static [MyEnum; 6]: [MyEnum, MyEnum, MyEnum, MyEnum, MyEnum, MyEnum] [MyEnum; 2]: [MyEnum, MyEnum] &'static [i32; 1]: [number] &'static [i32; 0]: [] Option: number | null Option<()>: null Option>: number[] | null Result: { ok: T, err: E, } Vec>>: (number | null)[] Option>>: number[] | null [Vec; 3]: [string[], string[], string[]] Option>: string | null Option>>: string | null PhantomData<()>: null PhantomData: null Infallible: never Unit1: null Unit2: Record Unit3: [] Unit4: null Unit5: "A" Unit6: [] Unit7: Record SimpleStruct: { a: number, b: string, c: [number, string, number], d: string[], e: string | null, } TupleStruct1: number TupleStruct3: [number, boolean, string] TestEnum: "Unit" | number | [number, number] | { a: number } RefStruct: TestEnum InlinerStruct: { inline_this: { ref_struct: SimpleStruct, val: number, }, dont_inline_this: RefStruct, } GenericStruct: { arg: T, } GenericStruct: { arg: T, } FlattenEnumStruct: { outer: string, inner: FlattenEnum, } OverridenStruct: { overriden_field: string, } HasGenericAlias: { [key in number]: string } EnumMacroAttributes: string | number | { a: string; b: number } InlineEnumField: { a: string, } InlineOptionalType: { optional_field: { a: string, } | null, } Rename: "OneWord" | "TwoWords" TransparentType: TransparentTypeInner TransparentType2: null TransparentTypeWithOverride: string [Option; 3]: [(number | null), (number | null), (number | null)] HashMap: Partial<{ [key in BasicEnum]: null }> HashMap: Partial<{ [key in BasicEnum]: number }> Option>>>: number | null Vec: PlaceholderInnerField[] EnumReferenceRecordKey: { a: Partial<{ [key in BasicEnum]: number }>, } FlattenOnNestedEnum: { id: string, result: NestedEnum, } MyEmptyInput: Record (String): string (String,): [string] ExtraBracketsInTupleVariant: string ExtraBracketsInUnnamedStruct: string Vec: MyEnum[] InlineTuple: { demo: [string, boolean], } InlineTuple2: { demo: [{ demo: [string, boolean], }, boolean], } Box: string Box: string SkippedFieldWithinVariant: never | string KebabCase: { test_ing: string, } &[&str]: string[] Issue281<'_>: { default_unity_arguments: string[], } LifetimeGenericStruct<'_, i32>: { borrowed: T[], owned: T[], } LifetimeGenericEnum<'_, i32>: T RenameWithWeirdCharsField: { odata_context: string, } RenameWithWeirdCharsVariant: string RenamedFieldKeys: { empty: string, quote: string, backslash: string, newline: string, line_separator: string, paragraph_separator: string, } RenamedVariantWithSkippedPayload: never type_type::Type: never ActualType: { a: GenericType, } SpectaTypeOverride: { string_ident: string, u32_ident: number, path: string, tuple: [string, number], } ContainerTypeOverrideStruct: string ContainerTypeOverrideEnum: string ContainerTypeOverrideGeneric>: string ContainerTypeOverrideToGeneric: T ContainerTypeOverrideTuple: [string, number] ContainerTypeOverrideTupleGeneric: [T, string] InvalidToValidType: { cause: null, } TupleStruct: string TupleStructWithRep: string GenericTupleStruct: T BracedStruct: string Struct: { a: string, } Struct2: { a: string, } Enum: "A" | "B" Enum2: "A" | "B" | { enum_field: null } Enum3: { a: string } StructRenameAllUppercase: { a: number, b: number, } RenameSerdeSpecialChar: { b: number, } EnumRenameAllUppercase: "HelloWorld" | "VariantB" | "TestingWords" Recursive: { demo: Recursive, } RecursiveMapValue: { demo: { [key in string]: RecursiveMapValue }, } RecursiveTransparent: RecursiveInline RecursiveInEnum: { demo: RecursiveInEnum } NonOptional: string | null OptionalOnNamedField: string | null OptionalOnTransparentNamedField: { b: string | null, } OptionalInEnum: string | null | { a: string | null } | { a?: string | null } UntaggedVariants: string | number | { id: string } | [string, boolean] UntaggedVariantsWithoutValue: string | [number, string] | number UntaggedVariantsWithDuplicateBranches: null | number HashMap: { [key in string]: null } Regular: { [key in string]: null } HashMap: { [key in never]: null } HashMap: { [key in TransparentStruct]: null } HashMap: Partial<{ [key in UnitVariants]: null }> HashMap: Partial<{ [key in UntaggedVariantsKey]: null }> ValidMaybeValidKey: { [key in MaybeValidKey]: null } ValidMaybeValidKeyNested: { [key in MaybeValidKey>]: null } MacroStruct: string MacroStruct2: { demo: string, } MacroEnum: string | { demo2: string } DeprecatedType: { a: number, } DeprecatedTypeWithMsg: { a: number, } DeprecatedTypeWithMsg2: { a: number, } DeprecatedFields: { a: number, /** * @deprecated */ b: string, /** * @deprecated This field is cringe! */ c: string, /** * @deprecated This field is cringe! */ d: string, } DeprecatedTupleVariant: [ /** * @deprecated */ string, /** * @deprecated Nope */ string, /** * @deprecated Nope */ number] DeprecatedEnumVariants: /** * @deprecated */ "A" | /** * @deprecated Nope */ "B" | /** * @deprecated Nope */ "C" CommentedStruct: { /** * Some triple-slash comment * Some more triple-slash comment */ a: number, } CommentedEnum: /** * Some triple-slash comment * Some more triple-slash comment */ number | /** * Some triple-slash comment * Some more triple-slash comment */ { /** * Some triple-slash comment * Some more triple-slash comment */ a: number } SingleLineComment: /** Some single-line comment */ number | /** Some single-line comment */ { /** Some single-line comment */ a: number } NonGeneric: { a: A, b: B, } HalfGenericA: { a: A, b: B, } HalfGenericB: { a: A, b: B, } FullGeneric: { a: A, b: B, } Another: { a: A, b: B, } MapA: { [key in string]: number } MapB: { [key in number]: string } MapC: { [key in string]: AGenericStruct } AGenericStruct: { field: { a: A, b: B, }, } A: { a: B, b: { b: number, }, c: B, d: { flattened: number, }, e: { generic_flattened: number, }, } DoubleFlattened: { a: ToBeFlattened, b: ToBeFlattened, } FlattenedInner: { c: Inner, } BoxFlattened: { b: BoxedInner, } BoxInline: { c: { a: number, }, } First: { a: string, } Second: { a: number, } Third: { a: First, b: { [key in string]: string }, c: First, } Fourth: { a: First, b: { a: string, }, } TagOnStructWithInline: { a: First, b: { a: string, }, } Sixth: { a: First, b: First, } Seventh: { a: First, b: Second, } Eight: string | "B" Ninth: string | "B" | { a: string, } | First Tenth: string | "B" | { a: string, } | First MyEnumTagged: { inner: First } MyEnumExternal: { inner: First } MyEnumAdjacent: { inner: First } MyEnumUntagged: { inner: First } EmptyStruct: Record EmptyStructWithTag: Record AdjacentlyTagged: "A" | { id: string; method: string } | string LoadProjectEvent: ({ project_name: string }) & { progress?: never; status?: never } | { project_name: string; status: string; progress: number } ExternallyTagged: "A" | { id: string; method: string } | string Issue221External: ({ a: string }) & { b?: never } | ({ b: string }) & { a?: never } InternallyTaggedD: { [key in string]: string } InternallyTaggedE: null InternallyTaggedF: InternallyTaggedFInner InternallyTaggedH: InternallyTaggedHInner InternallyTaggedL: "A" | "B" InternallyTaggedM: "A" | "B" StructWithAlias: { field: string, } StructWithMultipleAliases: { field: string, } StructWithAliasAndRename: { field: string, } EnumWithVariantAlias: "Variant" | "Other" EnumWithMultipleVariantAliases: "Variant" | "Other" EnumWithVariantAliasAndRename: "Variant" | "Other" InternallyTaggedWithAlias: ({ field: string }) & { other?: never } | ({ other: number }) & { field?: never } AdjacentlyTaggedWithAlias: ({ field: string }) & { other?: never } | ({ other: number }) & { field?: never } UntaggedWithAlias: ({ field: string }) & { other?: never } | ({ other: number }) & { field?: never } Issue221UntaggedSafe: ({ a: string }) & { b?: never } | ({ b: string }) & { a?: never } Issue221UntaggedMixed: ({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never } EmptyEnum: never EmptyEnumTagged: never EmptyEnumTaggedWContent: never EmptyEnumUntagged: never SkipOnlyField: Record SkipField: { b: number, } SkipVariant: string SkipUnnamedFieldInVariant: never | [number] SkipNamedFieldInVariant: Record | { b: number } TransparentWithSkip: null TransparentWithSkip2: string TransparentWithSkip3: string SkipVariant2: string SkipVariant3: { a: string } SkipStructFields: { a: number, } SpectaSkipNonTypeField: { a: number, } FlattenA: { a: number, b: number, } FlattenB: { a: FlattenA, c: number, } FlattenC: { a: FlattenA, c: number, } FlattenD: { a: FlattenA, c: number, } FlattenE: { b: { a: FlattenA, c: number, }, d: number, } FlattenF: { b: { a: FlattenA, c: number, }, d: number, } FlattenG: { b: FlattenB, d: number, } TupleNested: [number[], [number[], number[]], [number[], number[], number[]]] Generic1<()>: { value: T, values: T[], } GenericAutoBound<()>: { value: T, values: T[], } GenericAutoBound2<()>: { value: T, values: T[], } Container1: { foo: Generic1, bar: Generic1[], baz: { [key in string]: Generic1 }, } Generic2<(), String, i32>: A | [B, B, B] | C[] | A[][][] | { a: A; b: B; c: C } | number[] | number | number[][] GenericNewType1<()>: T[][] GenericTuple<()>: [T, T[], T[][]] GenericStruct2<()>: { a: T, b: [T, T], c: [T, [T, T]], d: [T, T, T], e: [([T, T]), ([T, T]), ([T, T])], f: T[], g: T[][], h: ([([T, T]), ([T, T]), ([T, T])])[], } InlineGenericNewtype: string InlineGenericNested: [string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | string | { value: string }] InlineFlattenGenericsG<()>: { t: T, } InlineFlattenGenerics: { g: InlineFlattenGenericsG, gi: { t: string, }, t: InlineFlattenGenericsG, } GenericDefault: { value: T, } ChainedGenericDefault: { first: T, second: U, } ChainedGenericDefault: { first: T, second: U, } ChainedGenericDefault: { first: T, second: U, } ChainedGenericDefault: { first: T, second: U, } GenericDefaultSkipped: { value: T, } GenericDefaultSkippedNonType: { value: number, } GenericParameterOrderPreserved: { pair: Pair, } ConstGenericInNonConstContainer: { data: [number], a: [number, number], d: [number, number], } ConstGenericInConstContainer: { data: number[], a: number[], d: [number, number], } NamedConstGenericContainer: { a: NamedConstGeneric, b: NamedConstGeneric, d: [number, number], } InlineConstGenericContainer: { b: { data: [number, number], a: [number, number], d: [number, number, number], }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], }, d: [number, number], } InlineRecursiveConstGenericContainer: { b: { data: [number, number], a: [number, number], d: [number, number, number], e: InlineRecursiveConstGeneric, }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], e: InlineRecursiveConstGeneric, }, d: [number, number], } TestCollectionRegister: never TestCollectionRegister: never specta_typescript::Any: any specta_typescript::Any: any specta_typescript::Unknown: unknown specta_typescript::Unknown: unknown specta_typescript::Never: never specta_typescript::Never: never ================================================ FILE: tests/tests/snapshots/test__jsdoc__inline-serde.snap ================================================ --- source: tests/tests/jsdoc.rs expression: output --- i8: number i16: number i32: number u8: number u16: number u32: number f32: number f64: number bool: boolean char: string Range: { start: T, end: T, } RangeInclusive: { start: T, end: T, } (): null (String, i32): [string, number] (String, i32, bool): [string, number, boolean] ((String, i32), (bool, char, bool), ()): [[string, number], [boolean, string, boolean], null] (bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool): [boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean] (Vec, Vec): [number[], boolean[]] String: string PathBuf: string IpAddr: string Ipv4Addr: string Ipv6Addr: string SocketAddr: string SocketAddrV4: string SocketAddrV6: string Cow<'static, str>: string Cow<'static, i32>: number &'static str: string &'static bool: boolean &'static i32: number Vec: number[] &'static [i32]: number[] &'static [i32; 3]: [number, number, number] [i32; 3]: [number, number, number] Vec: MyEnum[] &'static [MyEnum]: MyEnum[] &'static [MyEnum; 6]: [MyEnum, MyEnum, MyEnum, MyEnum, MyEnum, MyEnum] [MyEnum; 2]: [MyEnum, MyEnum] &'static [i32; 1]: [number] &'static [i32; 0]: [] Option: number | null Option<()>: null Option>: number[] | null Result: { ok: T, err: E, } Vec>>: (number | null)[] Option>>: number[] | null [Vec; 3]: [string[], string[], string[]] Option>: string | null Option>>: string | null PhantomData<()>: null PhantomData: null Infallible: never Unit1: null Unit2: Record Unit3: [] Unit4: null Unit5: "A" Unit6: { A: null } Unit7: { A: Record } SimpleStruct: { a: number, b: string, c: [number, string, number], d: string[], e: string | null, } TupleStruct1: number TupleStruct3: [number, boolean, string] TestEnum: "Unit" | ({ Single: number }) & { Multiple?: never; Struct?: never } | ({ Multiple: [number, number] }) & { Single?: never; Struct?: never } | ({ Struct: { a: number, } }) & { Multiple?: never; Single?: never } RefStruct: TestEnum InlinerStruct: { inline_this: { ref_struct: SimpleStruct, val: number, }, dont_inline_this: RefStruct, } GenericStruct: { arg: T, } GenericStruct: { arg: T, } FlattenEnumStruct: ({ outer: string, }) & (FlattenEnum) OverridenStruct: { overriden_field: string, } HasGenericAlias: { [key in number]: string } EnumMacroAttributes: ({ A: string }) & { D?: never; bbb?: never; cccc?: never } | ({ bbb: number }) & { A?: never; D?: never; cccc?: never } | ({ cccc: number }) & { A?: never; D?: never; bbb?: never } | ({ D: { a: string, bbbbbb: number, } }) & { A?: never; bbb?: never; cccc?: never } InlineEnumField: { A: { a: string, } } InlineOptionalType: { optional_field: { a: string, } | null, } Rename: "OneWord" | "Two words" TransparentType: TransparentTypeInner TransparentType2: null TransparentTypeWithOverride: string [Option; 3]: [(number | null), (number | null), (number | null)] HashMap: Partial<{ [key in BasicEnum]: null }> HashMap: Partial<{ [key in BasicEnum]: number }> Option>>>: number | null Vec: PlaceholderInnerField[] EnumReferenceRecordKey: { a: Partial<{ [key in BasicEnum]: number }>, } FlattenOnNestedEnum: ({ id: string, }) & (NestedEnum) MyEmptyInput: Record (String): string (String,): [string] ExtraBracketsInTupleVariant: { A: string } ExtraBracketsInUnnamedStruct: string Vec: MyEnum[] InlineTuple: { demo: [string, boolean], } InlineTuple2: { demo: [{ demo: [string, boolean], }, boolean], } Box: string Box: string SkippedFieldWithinVariant: { type: "A" } | { type: "B"; data: string } KebabCase: { "test-ing": string, } &[&str]: string[] Issue281<'_>: { default_unity_arguments: string[], } LifetimeGenericStruct<'_, i32>: { borrowed: T[], owned: T[], } LifetimeGenericEnum<'_, i32>: ({ Borrowed: T }) & { Owned?: never } | ({ Owned: T }) & { Borrowed?: never } RenameWithWeirdCharsField: { "@odata.context": string, } RenameWithWeirdCharsVariant: { "@odata.context": string } RenamedFieldKeys: { "": string, "a\"b": string, "a\\b": string, "line\nbreak": string, "line\u2028break": string, "line\u2029break": string, } RenamedVariantWithSkippedPayload: "a-b" type_type::Type: never ActualType: { a: GenericType, } SpectaTypeOverride: { string_ident: string, u32_ident: number, path: string, tuple: [string, number], } ContainerTypeOverrideStruct: string ContainerTypeOverrideEnum: string ContainerTypeOverrideGeneric>: string ContainerTypeOverrideToGeneric: T ContainerTypeOverrideTuple: [string, number] ContainerTypeOverrideTupleGeneric: [T, string] InvalidToValidType: { cause: null, } TupleStruct: string TupleStructWithRep: string GenericTupleStruct: T BracedStruct: string Struct: { t: "StructNew", a: string, } Struct2: { b: string, } Enum: { t: "A" } | { t: "B" } Enum2: { t: "C" } | { t: "B" } | { t: "D"; enumField: null } Enum3: { t: "A"; b: string } StructRenameAllUppercase: { A: number, B: number, } RenameSerdeSpecialChar: { "a/b": number, } EnumRenameAllUppercase: "HELLOWORLD" | "VARIANTB" | "TESTINGWORDS" Recursive: { demo: Recursive, } RecursiveMapValue: { demo: { [key in string]: RecursiveMapValue }, } RecursiveTransparent: RecursiveInline RecursiveInEnum: { A: { demo: RecursiveInEnum, } } NonOptional: string | null OptionalOnNamedField: string | null OptionalOnTransparentNamedField: { b: string | null, } OptionalInEnum: ({ A?: string | null }) & { B?: never; C?: never } | ({ B: { a: string | null, } }) & { A?: never; C?: never } | ({ C: { a?: string | null, } }) & { A?: never; B?: never } UntaggedVariants: string | number | { id: string } | [string, boolean] UntaggedVariantsWithoutValue: string | [number, string] | number UntaggedVariantsWithDuplicateBranches: null | number HashMap: { [key in string]: null } Regular: { [key in string]: null } HashMap: { [key in never]: null } HashMap: { [key in TransparentStruct]: null } HashMap: Partial<{ [key in UnitVariants]: null }> HashMap: Partial<{ [key in UntaggedVariantsKey]: null }> ValidMaybeValidKey: { [key in MaybeValidKey]: null } ValidMaybeValidKeyNested: { [key in MaybeValidKey>]: null } MacroStruct: string MacroStruct2: { demo: string, } MacroEnum: ({ Demo: string }) & { Demo2?: never } | ({ Demo2: { demo2: string, } }) & { Demo?: never } DeprecatedType: { a: number, } DeprecatedTypeWithMsg: { a: number, } DeprecatedTypeWithMsg2: { a: number, } DeprecatedFields: { a: number, /** * @deprecated */ b: string, /** * @deprecated This field is cringe! */ c: string, /** * @deprecated This field is cringe! */ d: string, } DeprecatedTupleVariant: [ /** * @deprecated */ string, /** * @deprecated Nope */ string, /** * @deprecated Nope */ number] DeprecatedEnumVariants: /** * @deprecated */ "A" | /** * @deprecated Nope */ "B" | /** * @deprecated Nope */ "C" CommentedStruct: { /** * Some triple-slash comment * Some more triple-slash comment */ a: number, } CommentedEnum: /** * Some triple-slash comment * Some more triple-slash comment */ ({ A: number }) & { B?: never } | /** * Some triple-slash comment * Some more triple-slash comment */ ({ B: { /** * Some triple-slash comment * Some more triple-slash comment */ a: number, } }) & { A?: never } SingleLineComment: /** Some single-line comment */ ({ A: number }) & { B?: never } | /** Some single-line comment */ ({ B: { /** Some single-line comment */ a: number, } }) & { A?: never } NonGeneric: { a: A, b: B, } HalfGenericA: { a: A, b: B, } HalfGenericB: { a: A, b: B, } FullGeneric: { a: A, b: B, } Another: { a: A, b: B, } MapA: { [key in string]: number } MapB: { [key in number]: string } MapC: { [key in string]: AGenericStruct } AGenericStruct: { field: { a: A, b: B, }, } A: { a: B, b: { b: number, }, c: B, d: { flattened: number, }, e: { generic_flattened: number, }, } DoubleFlattened: { a: ToBeFlattened, b: ToBeFlattened, } FlattenedInner: (Inner) BoxFlattened: (BoxedInner) BoxInline: { c: { a: number, }, } First: { a: string, } Second: { a: number, } Third: ({ b: { [key in string]: string }, c: First, }) & (First) Fourth: { a: First, b: { a: string, }, } TagOnStructWithInline: { type: "TagOnStructWithInline", a: First, b: { a: string, }, } Sixth: { a: First, b: First, } Seventh: { a: First, b: Second, } Eight: { A: string } | "B" Ninth: { t: "A"; c: string } | { t: "B" } | { t: "C"; c: { a: string, } } | { t: "D"; c: First } Tenth: string | "B" | { a: string, } | First MyEnumTagged: { type: "Variant"; inner: First } MyEnumExternal: { Variant: { inner: First, } } MyEnumAdjacent: { t: "Variant"; c: { inner: First, } } MyEnumUntagged: { inner: First } EmptyStruct: Record EmptyStructWithTag: { a: "EmptyStructWithTag", } AdjacentlyTagged: { t: "A" } | { t: "B"; c: { id: string, method: string, } } | { t: "C"; c: string } LoadProjectEvent: { event: "started"; data: { projectName: string, } } | { event: "progressTest"; data: { projectName: string, status: string, progress: number, } } | { event: "finished"; data: { projectName: string, } } ExternallyTagged: "A" | ({ B: { id: string, method: string, } }) & { C?: never } | ({ C: string }) & { B?: never } Issue221External: ({ A: { a: string, } }) & { B?: never } | ({ B: { b: string, } }) & { A?: never } InternallyTaggedD: { type: "A", } & { [key in string]: string } InternallyTaggedE: { type: "A" } InternallyTaggedF: { type: "A" } InternallyTaggedH: { type: "A" } InternallyTaggedL: { type: "A", } & { type: "A" } | { type: "B" } InternallyTaggedM: { type: "A" } StructWithAlias: { field: string, } StructWithMultipleAliases: { field: string, } StructWithAliasAndRename: { renamed_field: string, } EnumWithVariantAlias: "Variant" | "Other" EnumWithMultipleVariantAliases: "Variant" | "Other" EnumWithVariantAliasAndRename: "renamed_variant" | "Other" InternallyTaggedWithAlias: { type: "A"; field: string } | { type: "B"; other: number } AdjacentlyTaggedWithAlias: { type: "A"; data: { field: string, } } | { type: "B"; data: { other: number, } } UntaggedWithAlias: ({ field: string }) & { other?: never } | ({ other: number }) & { field?: never } Issue221UntaggedSafe: ({ a: string }) & { b?: never } | ({ b: string }) & { a?: never } Issue221UntaggedMixed: ({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never } EmptyEnum: never EmptyEnumTagged: never EmptyEnumTaggedWContent: never EmptyEnumUntagged: never SkipOnlyField: Record SkipField: { b: number, } SkipVariant: { A: string } SkipUnnamedFieldInVariant: "A" | { B: [number] } SkipNamedFieldInVariant: ({ A: Record }) & { B?: never } | ({ B: { b: number, } }) & { A?: never } TransparentWithSkip: null TransparentWithSkip2: string TransparentWithSkip3: string SkipVariant2: { tag: "A"; data: string } SkipVariant3: { A: { a: string, } } SkipStructFields: { a: number, } SpectaSkipNonTypeField: { a: number, } FlattenA: { a: number, b: number, } FlattenB: ({ c: number, }) & (FlattenA) FlattenC: ({ c: number, }) & (FlattenA) FlattenD: { a: FlattenA, c: number, } FlattenE: { b: ({ c: number, }) & (FlattenA), d: number, } FlattenF: { b: ({ c: number, }) & (FlattenA), d: number, } FlattenG: { b: FlattenB, d: number, } TupleNested: [number[], [number[], number[]], [number[], number[], number[]]] Generic1<()>: { value: T, values: T[], } GenericAutoBound<()>: { value: T, values: T[], } GenericAutoBound2<()>: { value: T, values: T[], } Container1: { foo: Generic1, bar: Generic1[], baz: { [key in string]: Generic1 }, } Generic2<(), String, i32>: ({ A: A }) & { B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ B: [B, B, B] }) & { A?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ C: C[] }) & { A?: never; B?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ D: A[][][] }) & { A?: never; B?: never; C?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ E: { a: A, b: B, c: C, } }) & { A?: never; B?: never; C?: never; D?: never; X?: never; Y?: never; Z?: never } | ({ X: number[] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; Y?: never; Z?: never } | ({ Y: number }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Z?: never } | ({ Z: number[][] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never } GenericNewType1<()>: T[][] GenericTuple<()>: [T, T[], T[][]] GenericStruct2<()>: { a: T, b: [T, T], c: [T, [T, T]], d: [T, T, T], e: [([T, T]), ([T, T]), ([T, T])], f: T[], g: T[][], h: ([([T, T]), ([T, T]), ([T, T])])[], } InlineGenericNewtype: string InlineGenericNested: [string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | ({ Unnamed: string }) & { Named?: never } | ({ Named: { value: string, } }) & { Unnamed?: never }] InlineFlattenGenericsG<()>: { t: T, } InlineFlattenGenerics: ({ g: InlineFlattenGenericsG, gi: { t: string, }, }) & (InlineFlattenGenericsG) GenericDefault: { value: T, } ChainedGenericDefault: { first: T, second: U, } ChainedGenericDefault: { first: T, second: U, } ChainedGenericDefault: { first: T, second: U, } ChainedGenericDefault: { first: T, second: U, } GenericDefaultSkipped: { value: T, } GenericDefaultSkippedNonType: { value: number, } GenericParameterOrderPreserved: { pair: Pair, } ConstGenericInNonConstContainer: { data: [number], a: [number, number], d: [number, number], } ConstGenericInConstContainer: { data: number[], a: number[], d: [number, number], } NamedConstGenericContainer: { a: NamedConstGeneric, b: NamedConstGeneric, d: [number, number], } InlineConstGenericContainer: { b: { data: [number, number], a: [number, number], d: [number, number, number], }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], }, d: [number, number], } InlineRecursiveConstGenericContainer: { b: { data: [number, number], a: [number, number], d: [number, number, number], e: InlineRecursiveConstGeneric, }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], e: InlineRecursiveConstGeneric, }, d: [number, number], } TestCollectionRegister: never TestCollectionRegister: never specta_typescript::Any: any specta_typescript::Any: any specta_typescript::Unknown: unknown specta_typescript::Unknown: unknown specta_typescript::Never: never specta_typescript::Never: never ================================================ FILE: tests/tests/snapshots/test__jsdoc__inline-serde_phases.snap ================================================ --- source: tests/tests/jsdoc.rs expression: output --- Issue374: { foo?: boolean, bar?: boolean, } Optional: { a: number | null, b?: number | null, c?: string | null, d: boolean, } StructPhaseSpecificRename: { kind: "StructPhaseSpecificRenameSerialize", ser: string, } i8: number i16: number i32: number u8: number u16: number u32: number f32: number f64: number bool: boolean char: string Range: { start: T, end: T, } RangeInclusive: { start: T, end: T, } (): null (String, i32): [string, number] (String, i32, bool): [string, number, boolean] ((String, i32), (bool, char, bool), ()): [[string, number], [boolean, string, boolean], null] (bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool): [boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean] (Vec, Vec): [number[], boolean[]] String: string PathBuf: string IpAddr: string Ipv4Addr: string Ipv6Addr: string SocketAddr: string SocketAddrV4: string SocketAddrV6: string Cow<'static, str>: string Cow<'static, i32>: number &'static str: string &'static bool: boolean &'static i32: number Vec: number[] &'static [i32]: number[] &'static [i32; 3]: [number, number, number] [i32; 3]: [number, number, number] Vec: MyEnum[] &'static [MyEnum]: MyEnum[] &'static [MyEnum; 6]: [MyEnum, MyEnum, MyEnum, MyEnum, MyEnum, MyEnum] [MyEnum; 2]: [MyEnum, MyEnum] &'static [i32; 1]: [number] &'static [i32; 0]: [] Option: number | null Option<()>: null Option>: number[] | null Result: { ok: T, err: E, } Vec>>: (number | null)[] Option>>: number[] | null [Vec; 3]: [string[], string[], string[]] Option>: string | null Option>>: string | null PhantomData<()>: null PhantomData: null Infallible: never Unit1: null Unit2: Record Unit3: [] Unit4: null Unit5: "A" Unit6: { A: null } Unit7: { A: Record } SimpleStruct: { a: number, b: string, c: [number, string, number], d: string[], e: string | null, } TupleStruct1: number TupleStruct3: [number, boolean, string] TestEnum: "Unit" | ({ Single: number }) & { Multiple?: never; Struct?: never } | ({ Multiple: [number, number] }) & { Single?: never; Struct?: never } | ({ Struct: { a: number, } }) & { Multiple?: never; Single?: never } RefStruct: TestEnum InlinerStruct: { inline_this: { ref_struct: SimpleStruct, val: number, }, dont_inline_this: RefStruct, } GenericStruct: { arg: T, } GenericStruct: { arg: T, } FlattenEnumStruct: ({ outer: string, }) & (FlattenEnum) OverridenStruct: { overriden_field: string, } HasGenericAlias: { [key in number]: string } EnumMacroAttributes: ({ A: string }) & { D?: never; bbb?: never; cccc?: never } | ({ bbb: number }) & { A?: never; D?: never; cccc?: never } | ({ cccc: number }) & { A?: never; D?: never; bbb?: never } | ({ D: { a: string, bbbbbb: number, } }) & { A?: never; bbb?: never; cccc?: never } InlineEnumField: { A: { a: string, } } InlineOptionalType: { optional_field: { a: string, } | null, } Rename: "OneWord" | "Two words" TransparentType: TransparentTypeInner TransparentType2: null TransparentTypeWithOverride: string [Option; 3]: [(number | null), (number | null), (number | null)] HashMap: Partial<{ [key in BasicEnum]: null }> HashMap: Partial<{ [key in BasicEnum]: number }> Option>>>: number | null Vec: PlaceholderInnerField[] EnumReferenceRecordKey: { a: Partial<{ [key in BasicEnum]: number }>, } FlattenOnNestedEnum: ({ id: string, }) & (NestedEnum) MyEmptyInput: Record (String): string (String,): [string] ExtraBracketsInTupleVariant: { A: string } ExtraBracketsInUnnamedStruct: string Vec: MyEnum[] InlineTuple: { demo: [string, boolean], } InlineTuple2: { demo: [{ demo: [string, boolean], }, boolean], } Box: string Box: string SkippedFieldWithinVariant: { type: "A" } | { type: "B"; data: string } KebabCase: { "test-ing": string, } &[&str]: string[] Issue281<'_>: { default_unity_arguments: string[], } LifetimeGenericStruct<'_, i32>: { borrowed: T[], owned: T[], } LifetimeGenericEnum<'_, i32>: ({ Borrowed: T }) & { Owned?: never } | ({ Owned: T }) & { Borrowed?: never } RenameWithWeirdCharsField: { "@odata.context": string, } RenameWithWeirdCharsVariant: { "@odata.context": string } RenamedFieldKeys: { "": string, "a\"b": string, "a\\b": string, "line\nbreak": string, "line\u2028break": string, "line\u2029break": string, } RenamedVariantWithSkippedPayload: "a-b" type_type::Type: never ActualType: { a: GenericType, } SpectaTypeOverride: { string_ident: string, u32_ident: number, path: string, tuple: [string, number], } ContainerTypeOverrideStruct: string ContainerTypeOverrideEnum: string ContainerTypeOverrideGeneric>: string ContainerTypeOverrideToGeneric: T ContainerTypeOverrideTuple: [string, number] ContainerTypeOverrideTupleGeneric: [T, string] InvalidToValidType: { cause: null, } TupleStruct: string TupleStructWithRep: string GenericTupleStruct: T BracedStruct: string Struct: { t: "StructNew", a: string, } Struct2: { b: string, } Enum: { t: "A" } | { t: "B" } Enum2: { t: "C" } | { t: "B" } | { t: "D"; enumField: null } Enum3: { t: "A"; b: string } StructRenameAllUppercase: { A: number, B: number, } RenameSerdeSpecialChar: { "a/b": number, } EnumRenameAllUppercase: "HELLOWORLD" | "VARIANTB" | "TESTINGWORDS" Recursive: { demo: Recursive, } RecursiveMapValue: { demo: { [key in string]: RecursiveMapValue }, } RecursiveTransparent: RecursiveInline RecursiveInEnum: { A: { demo: RecursiveInEnum, } } NonOptional: string | null OptionalOnNamedField: string | null OptionalOnTransparentNamedField: { b: string | null, } OptionalInEnum: ({ A?: string | null }) & { B?: never; C?: never } | ({ B: { a: string | null, } }) & { A?: never; C?: never } | ({ C: { a?: string | null, } }) & { A?: never; B?: never } UntaggedVariants: string | number | { id: string } | [string, boolean] UntaggedVariantsWithoutValue: string | [number, string] | number UntaggedVariantsWithDuplicateBranches: null | number HashMap: { [key in string]: null } Regular: { [key in string]: null } HashMap: { [key in never]: null } HashMap: { [key in TransparentStruct]: null } HashMap: Partial<{ [key in UnitVariants]: null }> HashMap: Partial<{ [key in UntaggedVariantsKey]: null }> ValidMaybeValidKey: { [key in MaybeValidKey]: null } ValidMaybeValidKeyNested: { [key in MaybeValidKey>]: null } MacroStruct: string MacroStruct2: { demo: string, } MacroEnum: ({ Demo: string }) & { Demo2?: never } | ({ Demo2: { demo2: string, } }) & { Demo?: never } DeprecatedType: { a: number, } DeprecatedTypeWithMsg: { a: number, } DeprecatedTypeWithMsg2: { a: number, } DeprecatedFields: { a: number, /** * @deprecated */ b: string, /** * @deprecated This field is cringe! */ c: string, /** * @deprecated This field is cringe! */ d: string, } DeprecatedTupleVariant: [ /** * @deprecated */ string, /** * @deprecated Nope */ string, /** * @deprecated Nope */ number] DeprecatedEnumVariants: /** * @deprecated */ "A" | /** * @deprecated Nope */ "B" | /** * @deprecated Nope */ "C" CommentedStruct: { /** * Some triple-slash comment * Some more triple-slash comment */ a: number, } CommentedEnum: /** * Some triple-slash comment * Some more triple-slash comment */ ({ A: number }) & { B?: never } | /** * Some triple-slash comment * Some more triple-slash comment */ ({ B: { /** * Some triple-slash comment * Some more triple-slash comment */ a: number, } }) & { A?: never } SingleLineComment: /** Some single-line comment */ ({ A: number }) & { B?: never } | /** Some single-line comment */ ({ B: { /** Some single-line comment */ a: number, } }) & { A?: never } NonGeneric: { a: A, b: B, } HalfGenericA: { a: A, b: B, } HalfGenericB: { a: A, b: B, } FullGeneric: { a: A, b: B, } Another: { a: A, b: B, } MapA: { [key in string]: number } MapB: { [key in number]: string } MapC: { [key in string]: AGenericStruct } AGenericStruct: { field: { a: A, b: B, }, } A: { a: B, b: { b: number, }, c: B, d: { flattened: number, }, e: { generic_flattened: number, }, } DoubleFlattened: { a: ToBeFlattened, b: ToBeFlattened, } FlattenedInner: (Inner) BoxFlattened: (BoxedInner) BoxInline: { c: { a: number, }, } First: { a: string, } Second: { a: number, } Third: ({ b: { [key in string]: string }, c: First, }) & (First) Fourth: { a: First, b: { a: string, }, } TagOnStructWithInline: { type: "TagOnStructWithInline", a: First, b: { a: string, }, } Sixth: { a: First, b: First, } Seventh: { a: First, b: Second, } Eight: { A: string } | "B" Ninth: { t: "A"; c: string } | { t: "B" } | { t: "C"; c: { a: string, } } | { t: "D"; c: First } Tenth: string | "B" | { a: string, } | First MyEnumTagged: { type: "Variant"; inner: First } MyEnumExternal: { Variant: { inner: First, } } MyEnumAdjacent: { t: "Variant"; c: { inner: First, } } MyEnumUntagged: { inner: First } EmptyStruct: Record EmptyStructWithTag: { a: "EmptyStructWithTag", } AdjacentlyTagged: { t: "A" } | { t: "B"; c: { id: string, method: string, } } | { t: "C"; c: string } LoadProjectEvent: { event: "started"; data: { projectName: string, } } | { event: "progressTest"; data: { projectName: string, status: string, progress: number, } } | { event: "finished"; data: { projectName: string, } } ExternallyTagged: "A" | ({ B: { id: string, method: string, } }) & { C?: never } | ({ C: string }) & { B?: never } Issue221External: ({ A: { a: string, } }) & { B?: never } | ({ B: { b: string, } }) & { A?: never } InternallyTaggedD: { type: "A", } & { [key in string]: string } InternallyTaggedE: { type: "A" } InternallyTaggedF: { type: "A" } InternallyTaggedH: { type: "A" } InternallyTaggedL: { type: "A", } & { type: "A" } | { type: "B" } InternallyTaggedM: { type: "A" } StructWithAlias: { field: string, } StructWithMultipleAliases: { field: string, } StructWithAliasAndRename: { renamed_field: string, } EnumWithVariantAlias: "Variant" | "Other" EnumWithMultipleVariantAliases: "Variant" | "Other" EnumWithVariantAliasAndRename: "renamed_variant" | "Other" InternallyTaggedWithAlias: { type: "A"; field: string } | { type: "B"; other: number } AdjacentlyTaggedWithAlias: { type: "A"; data: { field: string, } } | { type: "B"; data: { other: number, } } UntaggedWithAlias: ({ field: string }) & { other?: never } | ({ other: number }) & { field?: never } Issue221UntaggedSafe: ({ a: string }) & { b?: never } | ({ b: string }) & { a?: never } Issue221UntaggedMixed: ({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never } EmptyEnum: never EmptyEnumTagged: never EmptyEnumTaggedWContent: never EmptyEnumUntagged: never SkipOnlyField: Record SkipField: { b: number, } SkipVariant: { A: string } SkipUnnamedFieldInVariant: "A" | { B: [number] } SkipNamedFieldInVariant: ({ A: Record }) & { B?: never } | ({ B: { b: number, } }) & { A?: never } TransparentWithSkip: null TransparentWithSkip2: string TransparentWithSkip3: string SkipVariant2: { tag: "A"; data: string } SkipVariant3: { A: { a: string, } } SkipStructFields: { a: number, } SpectaSkipNonTypeField: { a: number, } FlattenA: { a: number, b: number, } FlattenB: ({ c: number, }) & (FlattenA) FlattenC: ({ c: number, }) & (FlattenA) FlattenD: { a: FlattenA, c: number, } FlattenE: { b: ({ c: number, }) & (FlattenA), d: number, } FlattenF: { b: ({ c: number, }) & (FlattenA), d: number, } FlattenG: { b: FlattenB, d: number, } TupleNested: [number[], [number[], number[]], [number[], number[], number[]]] Generic1<()>: { value: T, values: T[], } GenericAutoBound<()>: { value: T, values: T[], } GenericAutoBound2<()>: { value: T, values: T[], } Container1: { foo: Generic1, bar: Generic1[], baz: { [key in string]: Generic1 }, } Generic2<(), String, i32>: ({ A: A }) & { B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ B: [B, B, B] }) & { A?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ C: C[] }) & { A?: never; B?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ D: A[][][] }) & { A?: never; B?: never; C?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ E: { a: A, b: B, c: C, } }) & { A?: never; B?: never; C?: never; D?: never; X?: never; Y?: never; Z?: never } | ({ X: number[] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; Y?: never; Z?: never } | ({ Y: number }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Z?: never } | ({ Z: number[][] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never } GenericNewType1<()>: T[][] GenericTuple<()>: [T, T[], T[][]] GenericStruct2<()>: { a: T, b: [T, T], c: [T, [T, T]], d: [T, T, T], e: [([T, T]), ([T, T]), ([T, T])], f: T[], g: T[][], h: ([([T, T]), ([T, T]), ([T, T])])[], } InlineGenericNewtype: string InlineGenericNested: [string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | ({ Unnamed: string }) & { Named?: never } | ({ Named: { value: string, } }) & { Unnamed?: never }] InlineFlattenGenericsG<()>: { t: T, } InlineFlattenGenerics: ({ g: InlineFlattenGenericsG, gi: { t: string, }, }) & (InlineFlattenGenericsG) GenericDefault: { value: T, } ChainedGenericDefault: { first: T, second: U, } ChainedGenericDefault: { first: T, second: U, } ChainedGenericDefault: { first: T, second: U, } ChainedGenericDefault: { first: T, second: U, } GenericDefaultSkipped: { value: T, } GenericDefaultSkippedNonType: { value: number, } GenericParameterOrderPreserved: { pair: Pair, } ConstGenericInNonConstContainer: { data: [number], a: [number, number], d: [number, number], } ConstGenericInConstContainer: { data: number[], a: number[], d: [number, number], } NamedConstGenericContainer: { a: NamedConstGeneric, b: NamedConstGeneric, d: [number, number], } InlineConstGenericContainer: { b: { data: [number, number], a: [number, number], d: [number, number, number], }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], }, d: [number, number], } InlineRecursiveConstGenericContainer: { b: { data: [number, number], a: [number, number], d: [number, number, number], e: InlineRecursiveConstGeneric, }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], e: InlineRecursiveConstGeneric, }, d: [number, number], } TestCollectionRegister: never TestCollectionRegister: never specta_typescript::Any: any specta_typescript::Any: any specta_typescript::Unknown: unknown specta_typescript::Unknown: unknown specta_typescript::Never: never specta_typescript::Never: never ================================================ FILE: tests/tests/snapshots/test__jsdoc__jsdoc-export-to-files-both.snap ================================================ --- source: tests/tests/jsdoc.rs expression: output --- test/ jsdoc/ jsdoc_export_to_files_runtime_imports_types/ one.js (621 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. /** * @typedef {import("./three")} test$jsdoc$jsdoc_export_to_files_runtime_imports_types$three * @typedef {import("./two")} test$jsdoc$jsdoc_export_to_files_runtime_imports_types$two */ /** * @typedef {{ * two: test$jsdoc$jsdoc_export_to_files_runtime_imports_types$two.Two, * three: test$jsdoc$jsdoc_export_to_files_runtime_imports_types$three.Three, * }} One * @property {test$jsdoc$jsdoc_export_to_files_runtime_imports_types$two.Two} two * @property {test$jsdoc$jsdoc_export_to_files_runtime_imports_types$three.Three} three */ ════════════════════════════════════════ three.js (161 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. /** * @typedef {{ * active: boolean, * }} Three * @property {boolean} active */ ════════════════════════════════════════ two.js (155 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. /** * @typedef {{ * value: string, * }} Two * @property {string} value */ ════════════════════════════════════════ ================================================ FILE: tests/tests/snapshots/test__jsdoc__jsdoc-export-to-files-raw.snap ================================================ --- source: tests/tests/jsdoc.rs expression: output --- std/ ops.js (295 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. /** * @typedef {{ * start: T, * end: T, * }} Range * @property {T} start * @property {T} end * * @typedef {{ * start: T, * end: T, * }} RangeInclusive * @property {T} start * @property {T} end */ ════════════════════════════════════════ result.js (181 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. /** * @typedef {{ * ok: T, * err: E, * }} Result * @property {T} ok * @property {E} err */ ════════════════════════════════════════ test/ types/ type_type.js (108 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. /** * @typedef {never} Type */ ════════════════════════════════════════ types.js (26962 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. /** * @typedef {{ * a: B, * b: { * b: number, * }, * c: B, * d: { * flattened: number, * }, * e: { * generic_flattened: number, * }, * }} A * @property {B} a * @property {{ * b: number, * }} b * @property {B} c * @property {{ * flattened: number, * }} d * @property {{ * generic_flattened: number, * }} e * * @typedef {{ * field: Demo, * }} AGenericStruct * @property {Demo} field * * @typedef {{ * a: GenericType, * }} ActualType * @property {GenericType} a * * @typedef {"A" | { id: string; method: string } | string} AdjacentlyTagged * @property {"A"} A * @property {{ id: string; method: string }} B * @property {string} C * * @typedef {({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }} AdjacentlyTaggedWithAlias * @property {{ field: string }} A * @property {{ other: number }} B * * @typedef {{ * b: number, * }} B * @property {number} b * * @typedef {"A" | "B"} BasicEnum * @property {"A"} A * @property {"B"} B * * @typedef {{ * b: BoxedInner, * }} BoxFlattened * @property {BoxedInner} b * * @typedef {{ * c: { * a: number, * }, * }} BoxInline * @property {{ * a: number, * }} c * * @typedef {{ * a: number, * }} BoxedInner * @property {number} a * * @typedef {string} BracedStruct * @property {string} "0" * * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second * * Some triple-slash comment * Some more triple-slash comment * * @typedef { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * number | * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number }} CommentedEnum * @property { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * number} A - Some triple-slash comment Some more triple-slash comment * @property { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number }} B - Some triple-slash comment Some more triple-slash comment * * Some triple-slash comment * Some more triple-slash comment * * @typedef {{ * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * }} CommentedStruct * @property {number} a - Some triple-slash comment Some more triple-slash comment * * @typedef {{ * data: number[], * a: number[], * d: [number, number], * }} ConstGenericInConstContainer * @property {number[]} data * @property {number[]} a * @property {[number, number]} d * * @typedef {{ * data: [number], * a: [number, number], * d: [number, number], * }} ConstGenericInNonConstContainer * @property {[number]} data * @property {[number, number]} a * @property {[number, number]} d * * @typedef {{ * foo: Generic1, * bar: Generic1[], * baz: { [key in string]: Generic1 }, * }} Container1 * @property {Generic1} foo * @property {Generic1[]} bar * @property {{ [key in string]: Generic1 }} baz * * @typedef {string} ContainerTypeOverrideEnum * * @typedef {string} ContainerTypeOverrideGeneric * * @typedef {string} ContainerTypeOverrideStruct * * @typedef {T} ContainerTypeOverrideToGeneric * * @typedef {[string, number]} ContainerTypeOverrideTuple * * @typedef {[T, string]} ContainerTypeOverrideTupleGeneric * * @typedef {{ * flattened: number, * }} D * @property {number} flattened * * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b * * @typedef { * /** * * @deprecated * */ * "A" | * /** * * @deprecated Nope * */ * "B" | * /** * * @deprecated Nope * */ * "C"} DeprecatedEnumVariants * @property { * /** * * @deprecated * */ * "A"} A - @deprecated * @property { * /** * * @deprecated Nope * */ * "B"} B - @deprecated Nope * @property { * /** * * @deprecated Nope * */ * "C"} C - @deprecated Nope * * @typedef {{ * a: number, * /** * * @deprecated * */ * b: string, * /** * * @deprecated This field is cringe! * */ * c: string, * /** * * @deprecated This field is cringe! * */ * d: string, * }} DeprecatedFields * @property {number} a * @property {string} b - @deprecated * @property {string} c - @deprecated This field is cringe! * @property {string} d - @deprecated This field is cringe! * * @typedef {[ * /** * * @deprecated * */ * string, * /** * * @deprecated Nope * */ * string, * /** * * @deprecated Nope * */ * number]} DeprecatedTupleVariant * @property {string} "0" - @deprecated * @property {string} "1" - @deprecated Nope * @property {number} "2" - @deprecated Nope * * @deprecated * @typedef {{ * a: number, * }} DeprecatedType * @property {number} a * * @deprecated Look at you big man using a deprecation message * @typedef {{ * a: number, * }} DeprecatedTypeWithMsg * @property {number} a * * @deprecated Look at you big man using a deprecation message * @typedef {{ * a: number, * }} DeprecatedTypeWithMsg2 * @property {number} a * * @typedef {{ * a: ToBeFlattened, * b: ToBeFlattened, * }} DoubleFlattened * @property {ToBeFlattened} a * @property {ToBeFlattened} b * * @typedef {string | "B"} Eight * @property {string} A * @property {"B"} B * * @typedef {never} EmptyEnum * * @typedef {never} EmptyEnumTagged * * @typedef {never} EmptyEnumTaggedWContent * * @typedef {never} EmptyEnumUntagged * * @typedef {Record} EmptyStruct * * @typedef {Record} EmptyStructWithTag * * @typedef {"A" | "B"} Enum * @property {"A"} A * @property {"B"} B * * @typedef {"A" | "B" | { enum_field: null }} Enum2 * @property {"A"} A * @property {"B"} B * @property {{ enum_field: null }} D * * @typedef {{ a: string }} Enum3 * @property {{ a: string }} A * * @typedef {string | number | { a: string; b: number }} EnumMacroAttributes * @property {string} A * @property {number} B * @property {number} C * @property {{ a: string; b: number }} D * * @typedef {{ * a: Partial<{ [key in BasicEnum]: number }>, * }} EnumReferenceRecordKey * @property {Partial<{ [key in BasicEnum]: number }>} a * * @typedef {"HelloWorld" | "VariantB" | "TestingWords"} EnumRenameAllUppercase * @property {"HelloWorld"} HelloWorld * @property {"VariantB"} VariantB * @property {"TestingWords"} TestingWords * * @typedef {"Variant" | "Other"} EnumWithMultipleVariantAliases * @property {"Variant"} Variant * @property {"Other"} Other * * @typedef {"Variant" | "Other"} EnumWithVariantAlias * @property {"Variant"} Variant * @property {"Other"} Other * * @typedef {"Variant" | "Other"} EnumWithVariantAliasAndRename * @property {"Variant"} Variant * @property {"Other"} Other * * @typedef {"A" | { id: string; method: string } | string} ExternallyTagged * @property {"A"} A * @property {{ id: string; method: string }} B * @property {string} C * * @typedef {string} ExtraBracketsInTupleVariant * @property {string} A * * @typedef {string} ExtraBracketsInUnnamedStruct * @property {string} "0" * * @typedef {{ * a: string, * }} First * @property {string} a * * @typedef {{ * a: number, * b: number, * }} FlattenA * @property {number} a * @property {number} b * * @typedef {{ * a: FlattenA, * c: number, * }} FlattenB * @property {FlattenA} a * @property {number} c * * @typedef {{ * a: FlattenA, * c: number, * }} FlattenC * @property {FlattenA} a * @property {number} c * * @typedef {{ * a: FlattenA, * c: number, * }} FlattenD * @property {FlattenA} a * @property {number} c * * @typedef {{ * b: { * a: FlattenA, * c: number, * }, * d: number, * }} FlattenE * @property {{ * a: FlattenA, * c: number, * }} b * @property {number} d * * @typedef {"One" | "Two" | "Three"} FlattenEnum * @property {"One"} One * @property {"Two"} Two * @property {"Three"} Three * * @typedef {{ * outer: string, * inner: FlattenEnum, * }} FlattenEnumStruct * @property {string} outer * @property {FlattenEnum} inner * * @typedef {{ * b: { * a: FlattenA, * c: number, * }, * d: number, * }} FlattenF * @property {{ * a: FlattenA, * c: number, * }} b * @property {number} d * * @typedef {{ * b: FlattenB, * d: number, * }} FlattenG * @property {FlattenB} b * @property {number} d * * @typedef {{ * id: string, * result: NestedEnum, * }} FlattenOnNestedEnum * @property {string} id * @property {NestedEnum} result * * @typedef {{ * c: Inner, * }} FlattenedInner * @property {Inner} c * * @typedef {{ * a: First, * b: { * a: string, * }, * }} Fourth * @property {First} a * @property {{ * a: string, * }} b * * @typedef {{ * value: T, * values: T[], * }} Generic1 * @property {T} value * @property {T[]} values * * @typedef {A | [B, B, B] | C[] | A[][][] | { a: A; b: B; c: C } | number[] | number | number[][]} Generic2 * @property {A} A * @property {[B, B, B]} B * @property {C[]} C * @property {A[][][]} D * @property {{ a: A; b: B; c: C }} E * @property {number[]} X * @property {number} Y * @property {number[][]} Z * * @typedef {{ * value: T, * values: T[], * }} GenericAutoBound * @property {T} value * @property {T[]} values * * @typedef {{ * value: T, * values: T[], * }} GenericAutoBound2 * @property {T} value * @property {T[]} values * * @typedef {{ * value: T, * }} GenericDefault * @property {T} value * * @typedef {{ * value: T, * }} GenericDefaultSkipped * @property {T} value * * @typedef {{ * value: number, * }} GenericDefaultSkippedNonType * @property {number} value * * @typedef {{ * generic_flattened: T, * }} GenericFlattened * @property {T} generic_flattened * * @typedef {T[][]} GenericNewType1 * @property {T[][]} "0" * * @typedef {{ * pair: Pair, * }} GenericParameterOrderPreserved * @property {Pair} pair * * @typedef {{ * arg: T, * }} GenericStruct * @property {T} arg * * @typedef {{ * a: T, * b: [T, T], * c: [T, [T, T]], * d: [T, T, T], * e: [([T, T]), ([T, T]), ([T, T])], * f: T[], * g: T[][], * h: ([([T, T]), ([T, T]), ([T, T])])[], * }} GenericStruct2 * @property {T} a * @property {[T, T]} b * @property {[T, [T, T]]} c * @property {[T, T, T]} d * @property {[([T, T]), ([T, T]), ([T, T])]} e * @property {T[]} f * @property {T[][]} g * @property {([([T, T]), ([T, T]), ([T, T])])[]} h * * @typedef {[T, T[], T[][]]} GenericTuple * @property {T} "0" * @property {T[]} "1" * @property {T[][]} "2" * * @typedef {T} GenericTupleStruct * @property {T} "0" * * @typedef {"Undefined" | T} GenericType * @property {"Undefined"} Undefined * @property {T} Value * * @typedef {{ [key in number]: string }} HasGenericAlias * @property {{ [key in number]: string }} "0" * * @typedef {{ * b: { * data: [number, number], * a: [number, number], * d: [number, number, number], * }, * c: { * data: [number, number, number], * a: [number, number], * d: [number, number, number], * }, * d: [number, number], * }} InlineConstGenericContainer * @property {{ * data: [number, number], * a: [number, number], * d: [number, number, number], * }} b * @property {{ * data: [number, number, number], * a: [number, number], * d: [number, number, number], * }} c * @property {[number, number]} d * * @typedef {{ * a: string, * }} InlineEnumField * @property {{ * a: string, * }} A * * @typedef {{ * g: InlineFlattenGenericsG, * gi: { * t: string, * }, * t: InlineFlattenGenericsG, * }} InlineFlattenGenerics * @property {InlineFlattenGenericsG} g * @property {{ * t: string, * }} gi * @property {InlineFlattenGenericsG} t * * @typedef {{ * t: T, * }} InlineFlattenGenericsG * @property {T} t * * @typedef {{ * optional_field: { * a: string, * } | null, * }} InlineOptionalType * @property {{ * a: string, * } | null} optional_field * * @typedef {{ * data: number[], * a: number[], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }} InlineRecursiveConstGeneric * @property {number[]} data * @property {number[]} a * @property {[number, number, number]} d * @property {InlineRecursiveConstGeneric} e * * @typedef {{ * b: { * data: [number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }, * c: { * data: [number, number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }, * d: [number, number], * }} InlineRecursiveConstGenericContainer * @property {{ * data: [number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }} b * @property {{ * data: [number, number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }} c * @property {[number, number]} d * * @typedef {{ * ref_struct: SimpleStruct, * val: number, * }} InlineStruct * @property {SimpleStruct} ref_struct * @property {number} val * * @typedef {{ * demo: [string, boolean], * }} InlineTuple * @property {[string, boolean]} demo * * @typedef {{ * demo: [{ * demo: [string, boolean], * }, boolean], * }} InlineTuple2 * @property {[{ * demo: [string, boolean], * }, boolean]} demo * * @typedef {{ * inline_this: { * ref_struct: SimpleStruct, * val: number, * }, * dont_inline_this: RefStruct, * }} InlinerStruct * @property {{ * ref_struct: SimpleStruct, * val: number, * }} inline_this * @property {RefStruct} dont_inline_this * * @typedef {{ * a: number, * b: FlattenedInner, * }} Inner * @property {number} a * @property {FlattenedInner} b * * @typedef {{ [key in string]: string }} InternallyTaggedD * @property {{ [key in string]: string }} A * * @typedef {null} InternallyTaggedE * @property {null} A * * @typedef {InternallyTaggedFInner} InternallyTaggedF * @property {InternallyTaggedFInner} A * * @typedef {null} InternallyTaggedFInner * @property {null} A * * @typedef {InternallyTaggedHInner} InternallyTaggedH * @property {InternallyTaggedHInner} A * * @typedef {null} InternallyTaggedHInner * @property {null} "0" * * @typedef {"A" | "B"} InternallyTaggedL * @property {"A" | "B"} A * * @typedef {"A" | "B"} InternallyTaggedLInner * @property {"A"} A * @property {"B"} B * * @typedef {"A" | "B"} InternallyTaggedM * @property {"A" | "B"} A * * @typedef {"A" | "B"} InternallyTaggedMInner * @property {"A"} A * @property {"B"} B * * @typedef {({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }} InternallyTaggedWithAlias * @property {{ field: string }} A * @property {{ other: number }} B * * @typedef {{ * cause: null, * }} InvalidToValidType * @property {null} cause * * @typedef {({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }} Issue221External * @property {{ a: string }} A * @property {{ b: string }} B * * @typedef {({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never }} Issue221UntaggedMixed * @property {{ a: string }} A * @property {{ b: string }} B * @property {{ values: { [key in string]: string } }} Unsafe * * @typedef {({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }} Issue221UntaggedSafe * @property {{ a: string }} A * @property {{ b: string }} B * * @typedef {{ * default_unity_arguments: string[], * }} Issue281 * @property {string[]} default_unity_arguments * * @typedef {{ * test_ing: string, * }} KebabCase * @property {string} test_ing * * @typedef {T} LifetimeGenericEnum * @property {T} Borrowed * @property {T} Owned * * @typedef {{ * borrowed: T[], * owned: T[], * }} LifetimeGenericStruct * @property {T[]} borrowed * @property {T[]} owned * * @typedef {({ project_name: string }) & { progress?: never; status?: never } | { project_name: string; status: string; progress: number }} LoadProjectEvent * @property {{ project_name: string }} Started * @property {{ project_name: string; status: string; progress: number }} ProgressTest * @property {{ project_name: string }} Finished * * @typedef {string | { demo2: string }} MacroEnum * @property {string} Demo * @property {{ demo2: string }} Demo2 * * @typedef {string} MacroStruct * @property {string} "0" * * @typedef {{ * demo: string, * }} MacroStruct2 * @property {string} demo * * @typedef {T} MaybeValidKey * @property {T} "0" * * @typedef {Record} MyEmptyInput * * @typedef {string | number} MyEnum * @property {string} A * @property {number} B * * @typedef {{ inner: First }} MyEnumAdjacent * @property {{ inner: First }} Variant * * @typedef {{ inner: First }} MyEnumExternal * @property {{ inner: First }} Variant * * @typedef {{ inner: First }} MyEnumTagged * @property {{ inner: First }} Variant * * @typedef {{ inner: First }} MyEnumUntagged * @property {{ inner: First }} Variant * * @typedef {{ * data: number[], * a: number[], * d: [number, number], * }} NamedConstGeneric * @property {number[]} data * @property {number[]} a * @property {[number, number]} d * * @typedef {{ * a: NamedConstGeneric, * b: NamedConstGeneric, * d: [number, number], * }} NamedConstGenericContainer * @property {NamedConstGeneric} a * @property {NamedConstGeneric} b * @property {[number, number]} d * * @typedef {string | number} NestedEnum * @property {string} A * @property {number} B * * @typedef {string | "B" | { * a: string, * } | First} Ninth * @property {string} A * @property {"B"} B * @property {{ * a: string, * }} C * @property {First} D * * @typedef {string | null} NonOptional * @property {string | null} "0" * * @typedef {string | null | { a: string | null } | { a?: string | null }} OptionalInEnum * @property {string | null} A * @property {{ a: string | null }} B * @property {{ a?: string | null }} C * * @typedef {string | null} OptionalOnNamedField * @property {string | null} ["0"] * * @typedef {{ * b: string | null, * }} OptionalOnTransparentNamedField * @property {string | null} b * * @typedef {{ * overriden_field: string, * }} OverridenStruct * @property {string} overriden_field * * @typedef {{ * first: Z, * second: A, * }} Pair * @property {Z} first * @property {A} second * * @typedef {{ * a: string, * }} PlaceholderInnerField * @property {string} a * * @typedef {{ * demo: Recursive, * }} Recursive * @property {Recursive} demo * * @typedef {{ demo: RecursiveInEnum }} RecursiveInEnum * @property {{ demo: RecursiveInEnum }} A * * @typedef {{ * demo: RecursiveInline, * }} RecursiveInline * @property {RecursiveInline} demo * * @typedef {{ * demo: { [key in string]: RecursiveMapValue }, * }} RecursiveMapValue * @property {{ [key in string]: RecursiveMapValue }} demo * * @typedef {RecursiveInline} RecursiveTransparent * @property {RecursiveInline} "0" * * @typedef {TestEnum} RefStruct * @property {TestEnum} "0" * * @typedef {{ [key in string]: null }} Regular * @property {{ [key in string]: null }} "0" * * @typedef {"OneWord" | "TwoWords"} Rename * @property {"OneWord"} OneWord * @property {"TwoWords"} TwoWords * * @typedef {{ * b: number, * }} RenameSerdeSpecialChar * @property {number} b * * @typedef {{ * odata_context: string, * }} RenameWithWeirdCharsField * @property {string} odata_context * * @typedef {string} RenameWithWeirdCharsVariant * @property {string} A * * @typedef {{ * empty: string, * quote: string, * backslash: string, * newline: string, * line_separator: string, * paragraph_separator: string, * }} RenamedFieldKeys * @property {string} empty * @property {string} quote * @property {string} backslash * @property {string} newline * @property {string} line_separator * @property {string} paragraph_separator * * @typedef {never} RenamedVariantWithSkippedPayload * @property {never} A * * @typedef {{ * a: number, * }} Second * @property {number} a * * @typedef {{ * a: First, * b: Second, * }} Seventh * @property {First} a * @property {Second} b * * @typedef {{ * a: number, * b: string, * c: [number, string, number], * d: string[], * e: string | null, * }} SimpleStruct * @property {number} a * @property {string} b * @property {[number, string, number]} c * @property {string[]} d * @property {string | null} e * * Some single-line comment * * @typedef { * /** Some single-line comment */ * number | * /** Some single-line comment */ * { * /** Some single-line comment */ * a: number }} SingleLineComment * @property { * /** Some single-line comment */ * number} A - Some single-line comment * @property { * /** Some single-line comment */ * { * /** Some single-line comment */ * a: number }} B - Some single-line comment * * @typedef {{ * a: First, * b: First, * }} Sixth * @property {First} a * @property {First} b * * @typedef {{ * b: number, * }} SkipField * @property {number} b * * @typedef {Record | { b: number }} SkipNamedFieldInVariant * @property {Record} A * @property {{ b: number }} B * * @typedef {Record} SkipOnlyField * * @typedef {{ * a: number, * }} SkipStructFields * @property {number} a * * @typedef {never | [number]} SkipUnnamedFieldInVariant * @property {never} A * @property {[number]} B * * @typedef {string} SkipVariant * @property {string} A * * @typedef {string} SkipVariant2 * @property {string} A * * @typedef {{ a: string }} SkipVariant3 * @property {{ a: string }} A * * @typedef {never | string} SkippedFieldWithinVariant * @property {never} A * @property {string} B * * @typedef {{ * a: number, * }} SpectaSkipNonTypeField * @property {number} a * * @typedef {{ * string_ident: string, * u32_ident: number, * path: string, * tuple: [string, number], * }} SpectaTypeOverride * @property {string} string_ident * @property {number} u32_ident * @property {string} path * @property {[string, number]} tuple * * @typedef {{ * a: string, * }} Struct * @property {string} a * * @typedef {{ * a: string, * }} Struct2 * @property {string} a * * @typedef {{ * a: number, * b: number, * }} StructRenameAllUppercase * @property {number} a * @property {number} b * * @typedef {{ * field: string, * }} StructWithAlias * @property {string} field * * @typedef {{ * field: string, * }} StructWithAliasAndRename * @property {string} field * * @typedef {{ * field: string, * }} StructWithMultipleAliases * @property {string} field * * @typedef {{ * a: First, * b: { * a: string, * }, * }} TagOnStructWithInline * @property {First} a * @property {{ * a: string, * }} b * * @typedef {string | "B" | { * a: string, * } | First} Tenth * @property {string} A * @property {"B"} B * @property {{ * a: string, * }} C * @property {First} D * * @typedef {never} TestCollectionRegister * * @typedef {"Unit" | number | [number, number] | { a: number }} TestEnum * @property {"Unit"} Unit * @property {number} Single * @property {[number, number]} Multiple * @property {{ a: number }} Struct * * @typedef {{ * a: First, * b: { [key in string]: string }, * c: First, * }} Third * @property {First} a * @property {{ [key in string]: string }} b * @property {First} c * * @typedef {{ * a: string, * }} ToBeFlattened * @property {string} a * * @typedef {string} TransparentStruct * @property {string} "0" * * @typedef {TransparentTypeInner} TransparentType * @property {TransparentTypeInner} "0" * * @typedef {null} TransparentType2 * @property {null} "0" * * @typedef {{ * inner: string, * }} TransparentTypeInner * @property {string} inner * * @typedef {string} TransparentTypeWithOverride * @property {string} "0" * * @typedef {null} TransparentWithSkip * @property {null} "0" * * @typedef {string} TransparentWithSkip2 * @property {string} "0" * * @typedef {string} TransparentWithSkip3 * @property {string} "0" * * @typedef {[number[], [number[], number[]], [number[], number[], number[]]]} TupleNested * @property {number[]} "0" * @property {[number[], number[]]} "1" * @property {[number[], number[], number[]]} "2" * * @typedef {string} TupleStruct * @property {string} "0" * * @typedef {number} TupleStruct1 * @property {number} "0" * * @typedef {[number, boolean, string]} TupleStruct3 * @property {number} "0" * @property {boolean} "1" * @property {string} "2" * * @typedef {string} TupleStructWithRep * @property {string} "0" * * @typedef {null} Unit1 * * @typedef {Record} Unit2 * * @typedef {[]} Unit3 * * @typedef {null} Unit4 * @property {null} "0" * * @typedef {"A"} Unit5 * @property {"A"} A * * @typedef {[]} Unit6 * @property {[]} A * * @typedef {Record} Unit7 * @property {Record} A * * @typedef {"A" | "B" | "C"} UnitVariants * @property {"A"} A * @property {"B"} B * @property {"C"} C * * @typedef {string | number | { id: string } | [string, boolean]} UntaggedVariants * @property {string} A * @property {number} B * @property {number} C * @property {{ id: string }} D * @property {[string, boolean]} E * * @typedef {string | number} UntaggedVariantsKey * @property {string} A * @property {number} B * @property {number} C * * @typedef {null | number} UntaggedVariantsWithDuplicateBranches * @property {null} A * @property {number} B * @property {null} C * * @typedef {string | [number, string] | number} UntaggedVariantsWithoutValue * @property {string} A * @property {[number, string]} B * @property {number} C * * @typedef {({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }} UntaggedWithAlias * @property {{ field: string }} A * @property {{ other: number }} B * * @typedef {{ [key in MaybeValidKey]: null }} ValidMaybeValidKey * @property {{ [key in MaybeValidKey]: null }} "0" * * @typedef {{ [key in MaybeValidKey>]: null }} ValidMaybeValidKeyNested * @property {{ [key in MaybeValidKey>]: null }} "0" */ ════════════════════════════════════════ tests/ tests/ types.js (29296 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. /** * @typedef {import("../../std/ops")} std$ops * @typedef {import("../../std/result")} std$result * @typedef {import("../../test/types")} test$types * @typedef {import("../../test/types/type_type")} test$types$type_type */ /** * @typedef {{ * i8: number, * i16: number, * i32: number, * u8: number, * u16: number, * u32: number, * f32: number, * f64: number, * bool: boolean, * char: string, * "Range": std$ops.Range, * "RangeInclusive": std$ops.RangeInclusive, * "()": null, * "(String, i32)": [string, number], * "(String, i32, bool)": [string, number, boolean], * "((String, i32), (bool, char, bool), ())": [[string, number], [boolean, string, boolean], null], * "(bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool)": [boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean], * "(Vec, Vec)": [number[], boolean[]], * String: string, * PathBuf: string, * IpAddr: string, * Ipv4Addr: string, * Ipv6Addr: string, * SocketAddr: string, * SocketAddrV4: string, * SocketAddrV6: string, * "Cow<'static, str>": string, * "Cow<'static, i32>": number, * "&'static str": string, * "&'static bool": boolean, * "&'static i32": number, * "Vec": number[], * "&'static [i32]": number[], * "&'static [i32; 3]": [number, number, number], * "[i32; 3]": [number, number, number], * "Vec": test$types.MyEnum[], * "&'static [MyEnum]": test$types.MyEnum[], * "&'static [MyEnum; 6]": [test$types.MyEnum, test$types.MyEnum, test$types.MyEnum, test$types.MyEnum, test$types.MyEnum, test$types.MyEnum], * "[MyEnum; 2]": [test$types.MyEnum, test$types.MyEnum], * "&'static [i32; 1]": [number], * "&'static [i32; 0]": [], * "Option": number | null, * "Option<()>": null, * "Option>": number[] | null, * "Result": std$result.Result, * "Vec>>": (number | null)[], * "Option>>": number[] | null, * "[Vec; 3]": [string[], string[], string[]], * "Option>": string | null, * "Option>>": string | null, * "PhantomData<()>": null, * "PhantomData": null, * Infallible: never, * Unit1: test$types.Unit1, * Unit2: test$types.Unit2, * Unit3: test$types.Unit3, * Unit4: test$types.Unit4, * Unit5: test$types.Unit5, * Unit6: test$types.Unit6, * Unit7: test$types.Unit7, * SimpleStruct: test$types.SimpleStruct, * TupleStruct1: test$types.TupleStruct1, * TupleStruct3: test$types.TupleStruct3, * TestEnum: test$types.TestEnum, * RefStruct: test$types.RefStruct, * InlinerStruct: test$types.InlinerStruct, * "GenericStruct": test$types.GenericStruct, * "GenericStruct": test$types.GenericStruct, * FlattenEnumStruct: test$types.FlattenEnumStruct, * OverridenStruct: test$types.OverridenStruct, * HasGenericAlias: test$types.HasGenericAlias, * EnumMacroAttributes: test$types.EnumMacroAttributes, * InlineEnumField: test$types.InlineEnumField, * InlineOptionalType: test$types.InlineOptionalType, * Rename: test$types.Rename, * TransparentType: test$types.TransparentType, * TransparentType2: test$types.TransparentType2, * TransparentTypeWithOverride: test$types.TransparentTypeWithOverride, * "[Option; 3]": [(number | null), (number | null), (number | null)], * "HashMap": Partial<{ [key in test$types.BasicEnum]: null }>, * "HashMap": Partial<{ [key in test$types.BasicEnum]: number }>, * "Option>>>": number | null, * "Vec": test$types.PlaceholderInnerField[], * EnumReferenceRecordKey: test$types.EnumReferenceRecordKey, * FlattenOnNestedEnum: test$types.FlattenOnNestedEnum, * MyEmptyInput: test$types.MyEmptyInput, * "(String)": string, * "(String,)": [string], * ExtraBracketsInTupleVariant: test$types.ExtraBracketsInTupleVariant, * ExtraBracketsInUnnamedStruct: test$types.ExtraBracketsInUnnamedStruct, * "Vec": test$types.MyEnum[], * InlineTuple: test$types.InlineTuple, * InlineTuple2: test$types.InlineTuple2, * "Box": string, * "Box": string, * SkippedFieldWithinVariant: test$types.SkippedFieldWithinVariant, * KebabCase: test$types.KebabCase, * "&[&str]": string[], * "Issue281<'_>": test$types.Issue281, * "LifetimeGenericStruct<'_, i32>": test$types.LifetimeGenericStruct, * "LifetimeGenericEnum<'_, i32>": test$types.LifetimeGenericEnum, * RenameWithWeirdCharsField: test$types.RenameWithWeirdCharsField, * RenameWithWeirdCharsVariant: test$types.RenameWithWeirdCharsVariant, * RenamedFieldKeys: test$types.RenamedFieldKeys, * RenamedVariantWithSkippedPayload: test$types.RenamedVariantWithSkippedPayload, * "type_type::Type": test$types$type_type.Type, * ActualType: test$types.ActualType, * SpectaTypeOverride: test$types.SpectaTypeOverride, * ContainerTypeOverrideStruct: test$types.ContainerTypeOverrideStruct, * ContainerTypeOverrideEnum: test$types.ContainerTypeOverrideEnum, * "ContainerTypeOverrideGeneric>": test$types.ContainerTypeOverrideGeneric, * "ContainerTypeOverrideToGeneric": test$types.ContainerTypeOverrideToGeneric, * ContainerTypeOverrideTuple: test$types.ContainerTypeOverrideTuple, * "ContainerTypeOverrideTupleGeneric": test$types.ContainerTypeOverrideTupleGeneric, * InvalidToValidType: test$types.InvalidToValidType, * TupleStruct: test$types.TupleStruct, * TupleStructWithRep: test$types.TupleStructWithRep, * "GenericTupleStruct": test$types.GenericTupleStruct, * BracedStruct: test$types.BracedStruct, * Struct: test$types.Struct, * Struct2: test$types.Struct2, * Enum: test$types.Enum, * Enum2: test$types.Enum2, * Enum3: test$types.Enum3, * StructRenameAllUppercase: test$types.StructRenameAllUppercase, * RenameSerdeSpecialChar: test$types.RenameSerdeSpecialChar, * EnumRenameAllUppercase: test$types.EnumRenameAllUppercase, * Recursive: test$types.Recursive, * RecursiveMapValue: test$types.RecursiveMapValue, * RecursiveTransparent: test$types.RecursiveTransparent, * RecursiveInEnum: test$types.RecursiveInEnum, * NonOptional: test$types.NonOptional, * OptionalOnNamedField: test$types.OptionalOnNamedField, * OptionalOnTransparentNamedField: test$types.OptionalOnTransparentNamedField, * OptionalInEnum: test$types.OptionalInEnum, * UntaggedVariants: test$types.UntaggedVariants, * UntaggedVariantsWithoutValue: test$types.UntaggedVariantsWithoutValue, * UntaggedVariantsWithDuplicateBranches: test$types.UntaggedVariantsWithDuplicateBranches, * "HashMap": { [key in string]: null }, * Regular: test$types.Regular, * "HashMap": { [key in never]: null }, * "HashMap": { [key in test$types.TransparentStruct]: null }, * "HashMap": Partial<{ [key in test$types.UnitVariants]: null }>, * "HashMap": Partial<{ [key in test$types.UntaggedVariantsKey]: null }>, * ValidMaybeValidKey: test$types.ValidMaybeValidKey, * ValidMaybeValidKeyNested: test$types.ValidMaybeValidKeyNested, * MacroStruct: test$types.MacroStruct, * MacroStruct2: test$types.MacroStruct2, * MacroEnum: test$types.MacroEnum, * DeprecatedType: test$types.DeprecatedType, * DeprecatedTypeWithMsg: test$types.DeprecatedTypeWithMsg, * DeprecatedTypeWithMsg2: test$types.DeprecatedTypeWithMsg2, * DeprecatedFields: test$types.DeprecatedFields, * DeprecatedTupleVariant: test$types.DeprecatedTupleVariant, * DeprecatedEnumVariants: test$types.DeprecatedEnumVariants, * CommentedStruct: test$types.CommentedStruct, * CommentedEnum: test$types.CommentedEnum, * SingleLineComment: test$types.SingleLineComment, * NonGeneric: test$types.Demo, * "HalfGenericA": test$types.Demo, * "HalfGenericB": test$types.Demo, * "FullGeneric": test$types.Demo, * "Another": test$types.Demo, * "MapA": { [key in string]: number }, * "MapB": { [key in number]: string }, * "MapC": { [key in string]: test$types.AGenericStruct }, * "AGenericStruct": test$types.AGenericStruct, * A: test$types.A, * DoubleFlattened: test$types.DoubleFlattened, * FlattenedInner: test$types.FlattenedInner, * BoxFlattened: test$types.BoxFlattened, * BoxInline: test$types.BoxInline, * First: test$types.First, * Second: test$types.Second, * Third: test$types.Third, * Fourth: test$types.Fourth, * TagOnStructWithInline: test$types.TagOnStructWithInline, * Sixth: test$types.Sixth, * Seventh: test$types.Seventh, * Eight: test$types.Eight, * Ninth: test$types.Ninth, * Tenth: test$types.Tenth, * MyEnumTagged: test$types.MyEnumTagged, * MyEnumExternal: test$types.MyEnumExternal, * MyEnumAdjacent: test$types.MyEnumAdjacent, * MyEnumUntagged: test$types.MyEnumUntagged, * EmptyStruct: test$types.EmptyStruct, * EmptyStructWithTag: test$types.EmptyStructWithTag, * AdjacentlyTagged: test$types.AdjacentlyTagged, * LoadProjectEvent: test$types.LoadProjectEvent, * ExternallyTagged: test$types.ExternallyTagged, * Issue221External: test$types.Issue221External, * InternallyTaggedD: test$types.InternallyTaggedD, * InternallyTaggedE: test$types.InternallyTaggedE, * InternallyTaggedF: test$types.InternallyTaggedF, * InternallyTaggedH: test$types.InternallyTaggedH, * InternallyTaggedL: test$types.InternallyTaggedL, * InternallyTaggedM: test$types.InternallyTaggedM, * StructWithAlias: test$types.StructWithAlias, * StructWithMultipleAliases: test$types.StructWithMultipleAliases, * StructWithAliasAndRename: test$types.StructWithAliasAndRename, * EnumWithVariantAlias: test$types.EnumWithVariantAlias, * EnumWithMultipleVariantAliases: test$types.EnumWithMultipleVariantAliases, * EnumWithVariantAliasAndRename: test$types.EnumWithVariantAliasAndRename, * InternallyTaggedWithAlias: test$types.InternallyTaggedWithAlias, * AdjacentlyTaggedWithAlias: test$types.AdjacentlyTaggedWithAlias, * UntaggedWithAlias: test$types.UntaggedWithAlias, * Issue221UntaggedSafe: test$types.Issue221UntaggedSafe, * Issue221UntaggedMixed: test$types.Issue221UntaggedMixed, * EmptyEnum: test$types.EmptyEnum, * EmptyEnumTagged: test$types.EmptyEnumTagged, * EmptyEnumTaggedWContent: test$types.EmptyEnumTaggedWContent, * EmptyEnumUntagged: test$types.EmptyEnumUntagged, * SkipOnlyField: test$types.SkipOnlyField, * SkipField: test$types.SkipField, * SkipVariant: test$types.SkipVariant, * SkipUnnamedFieldInVariant: test$types.SkipUnnamedFieldInVariant, * SkipNamedFieldInVariant: test$types.SkipNamedFieldInVariant, * TransparentWithSkip: test$types.TransparentWithSkip, * TransparentWithSkip2: test$types.TransparentWithSkip2, * TransparentWithSkip3: test$types.TransparentWithSkip3, * SkipVariant2: test$types.SkipVariant2, * SkipVariant3: test$types.SkipVariant3, * SkipStructFields: test$types.SkipStructFields, * SpectaSkipNonTypeField: test$types.SpectaSkipNonTypeField, * FlattenA: test$types.FlattenA, * FlattenB: test$types.FlattenB, * FlattenC: test$types.FlattenC, * FlattenD: test$types.FlattenD, * FlattenE: test$types.FlattenE, * FlattenF: test$types.FlattenF, * FlattenG: test$types.FlattenG, * TupleNested: test$types.TupleNested, * "Generic1<()>": test$types.Generic1, * "GenericAutoBound<()>": test$types.GenericAutoBound, * "GenericAutoBound2<()>": test$types.GenericAutoBound2, * Container1: test$types.Container1, * "Generic2<(), String, i32>": test$types.Generic2, * "GenericNewType1<()>": test$types.GenericNewType1, * "GenericTuple<()>": test$types.GenericTuple, * "GenericStruct2<()>": test$types.GenericStruct2, * "InlineGenericNewtype": string, * "InlineGenericNested": [string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | string | { value: string }], * "InlineFlattenGenericsG<()>": test$types.InlineFlattenGenericsG, * InlineFlattenGenerics: test$types.InlineFlattenGenerics, * GenericDefault: test$types.GenericDefault, * ChainedGenericDefault: test$types.ChainedGenericDefault, * "ChainedGenericDefault": test$types.ChainedGenericDefault, * "ChainedGenericDefault": test$types.ChainedGenericDefault, * "ChainedGenericDefault": test$types.ChainedGenericDefault, * GenericDefaultSkipped: test$types.GenericDefaultSkipped, * GenericDefaultSkippedNonType: test$types.GenericDefaultSkippedNonType, * GenericParameterOrderPreserved: test$types.GenericParameterOrderPreserved, * ConstGenericInNonConstContainer: test$types.ConstGenericInNonConstContainer, * ConstGenericInConstContainer: test$types.ConstGenericInConstContainer, * NamedConstGenericContainer: test$types.NamedConstGenericContainer, * InlineConstGenericContainer: test$types.InlineConstGenericContainer, * InlineRecursiveConstGenericContainer: test$types.InlineRecursiveConstGenericContainer, * TestCollectionRegister: test$types.TestCollectionRegister, * TestCollectionRegister: test$types.TestCollectionRegister, * }} Primitives * @property {number} i8 * @property {number} i16 * @property {number} i32 * @property {number} u8 * @property {number} u16 * @property {number} u32 * @property {number} f32 * @property {number} f64 * @property {boolean} bool * @property {string} char * @property {std$ops.Range} "Range" * @property {std$ops.RangeInclusive} "RangeInclusive" * @property {null} "()" * @property {[string, number]} "(String, i32)" * @property {[string, number, boolean]} "(String, i32, bool)" * @property {[[string, number], [boolean, string, boolean], null]} "((String, i32), (bool, char, bool), ())" * @property {[boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean]} "(bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool)" * @property {[number[], boolean[]]} "(Vec, Vec)" * @property {string} String * @property {string} PathBuf * @property {string} IpAddr * @property {string} Ipv4Addr * @property {string} Ipv6Addr * @property {string} SocketAddr * @property {string} SocketAddrV4 * @property {string} SocketAddrV6 * @property {string} "Cow<'static, str>" * @property {number} "Cow<'static, i32>" * @property {string} "&'static str" * @property {boolean} "&'static bool" * @property {number} "&'static i32" * @property {number[]} "Vec" * @property {number[]} "&'static [i32]" * @property {[number, number, number]} "&'static [i32; 3]" * @property {[number, number, number]} "[i32; 3]" * @property {test$types.MyEnum[]} "Vec" * @property {test$types.MyEnum[]} "&'static [MyEnum]" * @property {[test$types.MyEnum, test$types.MyEnum, test$types.MyEnum, test$types.MyEnum, test$types.MyEnum, test$types.MyEnum]} "&'static [MyEnum; 6]" * @property {[test$types.MyEnum, test$types.MyEnum]} "[MyEnum; 2]" * @property {[number]} "&'static [i32; 1]" * @property {[]} "&'static [i32; 0]" * @property {number | null} "Option" * @property {null} "Option<()>" * @property {number[] | null} "Option>" * @property {std$result.Result} "Result" * @property {(number | null)[]} "Vec>>" * @property {number[] | null} "Option>>" * @property {[string[], string[], string[]]} "[Vec; 3]" * @property {string | null} "Option>" * @property {string | null} "Option>>" * @property {null} "PhantomData<()>" * @property {null} "PhantomData" * @property {never} Infallible * @property {test$types.Unit1} Unit1 * @property {test$types.Unit2} Unit2 * @property {test$types.Unit3} Unit3 * @property {test$types.Unit4} Unit4 * @property {test$types.Unit5} Unit5 * @property {test$types.Unit6} Unit6 * @property {test$types.Unit7} Unit7 * @property {test$types.SimpleStruct} SimpleStruct * @property {test$types.TupleStruct1} TupleStruct1 * @property {test$types.TupleStruct3} TupleStruct3 * @property {test$types.TestEnum} TestEnum * @property {test$types.RefStruct} RefStruct * @property {test$types.InlinerStruct} InlinerStruct * @property {test$types.GenericStruct} "GenericStruct" * @property {test$types.GenericStruct} "GenericStruct" * @property {test$types.FlattenEnumStruct} FlattenEnumStruct * @property {test$types.OverridenStruct} OverridenStruct * @property {test$types.HasGenericAlias} HasGenericAlias * @property {test$types.EnumMacroAttributes} EnumMacroAttributes * @property {test$types.InlineEnumField} InlineEnumField * @property {test$types.InlineOptionalType} InlineOptionalType * @property {test$types.Rename} Rename * @property {test$types.TransparentType} TransparentType * @property {test$types.TransparentType2} TransparentType2 * @property {test$types.TransparentTypeWithOverride} TransparentTypeWithOverride * @property {[(number | null), (number | null), (number | null)]} "[Option; 3]" * @property {Partial<{ [key in test$types.BasicEnum]: null }>} "HashMap" * @property {Partial<{ [key in test$types.BasicEnum]: number }>} "HashMap" * @property {number | null} "Option>>>" * @property {test$types.PlaceholderInnerField[]} "Vec" * @property {test$types.EnumReferenceRecordKey} EnumReferenceRecordKey * @property {test$types.FlattenOnNestedEnum} FlattenOnNestedEnum * @property {test$types.MyEmptyInput} MyEmptyInput * @property {string} "(String)" * @property {[string]} "(String,)" * @property {test$types.ExtraBracketsInTupleVariant} ExtraBracketsInTupleVariant * @property {test$types.ExtraBracketsInUnnamedStruct} ExtraBracketsInUnnamedStruct * @property {test$types.MyEnum[]} "Vec" * @property {test$types.InlineTuple} InlineTuple * @property {test$types.InlineTuple2} InlineTuple2 * @property {string} "Box" * @property {string} "Box" * @property {test$types.SkippedFieldWithinVariant} SkippedFieldWithinVariant * @property {test$types.KebabCase} KebabCase * @property {string[]} "&[&str]" * @property {test$types.Issue281} "Issue281<'_>" * @property {test$types.LifetimeGenericStruct} "LifetimeGenericStruct<'_, i32>" * @property {test$types.LifetimeGenericEnum} "LifetimeGenericEnum<'_, i32>" * @property {test$types.RenameWithWeirdCharsField} RenameWithWeirdCharsField * @property {test$types.RenameWithWeirdCharsVariant} RenameWithWeirdCharsVariant * @property {test$types.RenamedFieldKeys} RenamedFieldKeys * @property {test$types.RenamedVariantWithSkippedPayload} RenamedVariantWithSkippedPayload * @property {test$types$type_type.Type} "type_type::Type" * @property {test$types.ActualType} ActualType * @property {test$types.SpectaTypeOverride} SpectaTypeOverride * @property {test$types.ContainerTypeOverrideStruct} ContainerTypeOverrideStruct * @property {test$types.ContainerTypeOverrideEnum} ContainerTypeOverrideEnum * @property {test$types.ContainerTypeOverrideGeneric} "ContainerTypeOverrideGeneric>" * @property {test$types.ContainerTypeOverrideToGeneric} "ContainerTypeOverrideToGeneric" * @property {test$types.ContainerTypeOverrideTuple} ContainerTypeOverrideTuple * @property {test$types.ContainerTypeOverrideTupleGeneric} "ContainerTypeOverrideTupleGeneric" * @property {test$types.InvalidToValidType} InvalidToValidType * @property {test$types.TupleStruct} TupleStruct * @property {test$types.TupleStructWithRep} TupleStructWithRep * @property {test$types.GenericTupleStruct} "GenericTupleStruct" * @property {test$types.BracedStruct} BracedStruct * @property {test$types.Struct} Struct * @property {test$types.Struct2} Struct2 * @property {test$types.Enum} Enum * @property {test$types.Enum2} Enum2 * @property {test$types.Enum3} Enum3 * @property {test$types.StructRenameAllUppercase} StructRenameAllUppercase * @property {test$types.RenameSerdeSpecialChar} RenameSerdeSpecialChar * @property {test$types.EnumRenameAllUppercase} EnumRenameAllUppercase * @property {test$types.Recursive} Recursive * @property {test$types.RecursiveMapValue} RecursiveMapValue * @property {test$types.RecursiveTransparent} RecursiveTransparent * @property {test$types.RecursiveInEnum} RecursiveInEnum * @property {test$types.NonOptional} NonOptional * @property {test$types.OptionalOnNamedField} OptionalOnNamedField * @property {test$types.OptionalOnTransparentNamedField} OptionalOnTransparentNamedField * @property {test$types.OptionalInEnum} OptionalInEnum * @property {test$types.UntaggedVariants} UntaggedVariants * @property {test$types.UntaggedVariantsWithoutValue} UntaggedVariantsWithoutValue * @property {test$types.UntaggedVariantsWithDuplicateBranches} UntaggedVariantsWithDuplicateBranches * @property {{ [key in string]: null }} "HashMap" * @property {test$types.Regular} Regular * @property {{ [key in never]: null }} "HashMap" * @property {{ [key in test$types.TransparentStruct]: null }} "HashMap" * @property {Partial<{ [key in test$types.UnitVariants]: null }>} "HashMap" * @property {Partial<{ [key in test$types.UntaggedVariantsKey]: null }>} "HashMap" * @property {test$types.ValidMaybeValidKey} ValidMaybeValidKey * @property {test$types.ValidMaybeValidKeyNested} ValidMaybeValidKeyNested * @property {test$types.MacroStruct} MacroStruct * @property {test$types.MacroStruct2} MacroStruct2 * @property {test$types.MacroEnum} MacroEnum * @property {test$types.DeprecatedType} DeprecatedType * @property {test$types.DeprecatedTypeWithMsg} DeprecatedTypeWithMsg * @property {test$types.DeprecatedTypeWithMsg2} DeprecatedTypeWithMsg2 * @property {test$types.DeprecatedFields} DeprecatedFields * @property {test$types.DeprecatedTupleVariant} DeprecatedTupleVariant * @property {test$types.DeprecatedEnumVariants} DeprecatedEnumVariants * @property {test$types.CommentedStruct} CommentedStruct * @property {test$types.CommentedEnum} CommentedEnum * @property {test$types.SingleLineComment} SingleLineComment * @property {test$types.Demo} NonGeneric * @property {test$types.Demo} "HalfGenericA" * @property {test$types.Demo} "HalfGenericB" * @property {test$types.Demo} "FullGeneric" * @property {test$types.Demo} "Another" * @property {{ [key in string]: number }} "MapA" * @property {{ [key in number]: string }} "MapB" * @property {{ [key in string]: test$types.AGenericStruct }} "MapC" * @property {test$types.AGenericStruct} "AGenericStruct" * @property {test$types.A} A * @property {test$types.DoubleFlattened} DoubleFlattened * @property {test$types.FlattenedInner} FlattenedInner * @property {test$types.BoxFlattened} BoxFlattened * @property {test$types.BoxInline} BoxInline * @property {test$types.First} First * @property {test$types.Second} Second * @property {test$types.Third} Third * @property {test$types.Fourth} Fourth * @property {test$types.TagOnStructWithInline} TagOnStructWithInline * @property {test$types.Sixth} Sixth * @property {test$types.Seventh} Seventh * @property {test$types.Eight} Eight * @property {test$types.Ninth} Ninth * @property {test$types.Tenth} Tenth * @property {test$types.MyEnumTagged} MyEnumTagged * @property {test$types.MyEnumExternal} MyEnumExternal * @property {test$types.MyEnumAdjacent} MyEnumAdjacent * @property {test$types.MyEnumUntagged} MyEnumUntagged * @property {test$types.EmptyStruct} EmptyStruct * @property {test$types.EmptyStructWithTag} EmptyStructWithTag * @property {test$types.AdjacentlyTagged} AdjacentlyTagged * @property {test$types.LoadProjectEvent} LoadProjectEvent * @property {test$types.ExternallyTagged} ExternallyTagged * @property {test$types.Issue221External} Issue221External * @property {test$types.InternallyTaggedD} InternallyTaggedD * @property {test$types.InternallyTaggedE} InternallyTaggedE * @property {test$types.InternallyTaggedF} InternallyTaggedF * @property {test$types.InternallyTaggedH} InternallyTaggedH * @property {test$types.InternallyTaggedL} InternallyTaggedL * @property {test$types.InternallyTaggedM} InternallyTaggedM * @property {test$types.StructWithAlias} StructWithAlias * @property {test$types.StructWithMultipleAliases} StructWithMultipleAliases * @property {test$types.StructWithAliasAndRename} StructWithAliasAndRename * @property {test$types.EnumWithVariantAlias} EnumWithVariantAlias * @property {test$types.EnumWithMultipleVariantAliases} EnumWithMultipleVariantAliases * @property {test$types.EnumWithVariantAliasAndRename} EnumWithVariantAliasAndRename * @property {test$types.InternallyTaggedWithAlias} InternallyTaggedWithAlias * @property {test$types.AdjacentlyTaggedWithAlias} AdjacentlyTaggedWithAlias * @property {test$types.UntaggedWithAlias} UntaggedWithAlias * @property {test$types.Issue221UntaggedSafe} Issue221UntaggedSafe * @property {test$types.Issue221UntaggedMixed} Issue221UntaggedMixed * @property {test$types.EmptyEnum} EmptyEnum * @property {test$types.EmptyEnumTagged} EmptyEnumTagged * @property {test$types.EmptyEnumTaggedWContent} EmptyEnumTaggedWContent * @property {test$types.EmptyEnumUntagged} EmptyEnumUntagged * @property {test$types.SkipOnlyField} SkipOnlyField * @property {test$types.SkipField} SkipField * @property {test$types.SkipVariant} SkipVariant * @property {test$types.SkipUnnamedFieldInVariant} SkipUnnamedFieldInVariant * @property {test$types.SkipNamedFieldInVariant} SkipNamedFieldInVariant * @property {test$types.TransparentWithSkip} TransparentWithSkip * @property {test$types.TransparentWithSkip2} TransparentWithSkip2 * @property {test$types.TransparentWithSkip3} TransparentWithSkip3 * @property {test$types.SkipVariant2} SkipVariant2 * @property {test$types.SkipVariant3} SkipVariant3 * @property {test$types.SkipStructFields} SkipStructFields * @property {test$types.SpectaSkipNonTypeField} SpectaSkipNonTypeField * @property {test$types.FlattenA} FlattenA * @property {test$types.FlattenB} FlattenB * @property {test$types.FlattenC} FlattenC * @property {test$types.FlattenD} FlattenD * @property {test$types.FlattenE} FlattenE * @property {test$types.FlattenF} FlattenF * @property {test$types.FlattenG} FlattenG * @property {test$types.TupleNested} TupleNested * @property {test$types.Generic1} "Generic1<()>" * @property {test$types.GenericAutoBound} "GenericAutoBound<()>" * @property {test$types.GenericAutoBound2} "GenericAutoBound2<()>" * @property {test$types.Container1} Container1 * @property {test$types.Generic2} "Generic2<(), String, i32>" * @property {test$types.GenericNewType1} "GenericNewType1<()>" * @property {test$types.GenericTuple} "GenericTuple<()>" * @property {test$types.GenericStruct2} "GenericStruct2<()>" * @property {string} "InlineGenericNewtype" * @property {[string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | string | { value: string }]} "InlineGenericNested" * @property {test$types.InlineFlattenGenericsG} "InlineFlattenGenericsG<()>" * @property {test$types.InlineFlattenGenerics} InlineFlattenGenerics * @property {test$types.GenericDefault} GenericDefault * @property {test$types.ChainedGenericDefault} ChainedGenericDefault * @property {test$types.ChainedGenericDefault} "ChainedGenericDefault" * @property {test$types.ChainedGenericDefault} "ChainedGenericDefault" * @property {test$types.ChainedGenericDefault} "ChainedGenericDefault" * @property {test$types.GenericDefaultSkipped} GenericDefaultSkipped * @property {test$types.GenericDefaultSkippedNonType} GenericDefaultSkippedNonType * @property {test$types.GenericParameterOrderPreserved} GenericParameterOrderPreserved * @property {test$types.ConstGenericInNonConstContainer} ConstGenericInNonConstContainer * @property {test$types.ConstGenericInConstContainer} ConstGenericInConstContainer * @property {test$types.NamedConstGenericContainer} NamedConstGenericContainer * @property {test$types.InlineConstGenericContainer} InlineConstGenericContainer * @property {test$types.InlineRecursiveConstGenericContainer} InlineRecursiveConstGenericContainer * @property {test$types.TestCollectionRegister} TestCollectionRegister * @property {test$types.TestCollectionRegister} TestCollectionRegister */ ════════════════════════════════════════ ================================================ FILE: tests/tests/snapshots/test__jsdoc__jsdoc-export-to-files-serde.snap ================================================ --- source: tests/tests/jsdoc.rs expression: output --- std/ ops.js (295 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. /** * @typedef {{ * start: T, * end: T, * }} Range * @property {T} start * @property {T} end * * @typedef {{ * start: T, * end: T, * }} RangeInclusive * @property {T} start * @property {T} end */ ════════════════════════════════════════ result.js (181 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. /** * @typedef {{ * ok: T, * err: E, * }} Result * @property {T} ok * @property {E} err */ ════════════════════════════════════════ test/ types/ type_type.js (108 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. /** * @typedef {never} Type */ ════════════════════════════════════════ types.js (30269 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. /** * @typedef {{ * a: B, * b: { * b: number, * }, * c: B, * d: { * flattened: number, * }, * e: { * generic_flattened: number, * }, * }} A * @property {B} a * @property {{ * b: number, * }} b * @property {B} c * @property {{ * flattened: number, * }} d * @property {{ * generic_flattened: number, * }} e * * @typedef {{ * field: Demo, * }} AGenericStruct * @property {Demo} field * * @typedef {{ * a: GenericType, * }} ActualType * @property {GenericType} a * * @typedef {{ t: "A" } | { t: "B"; c: { * id: string, * method: string, * } } | { t: "C"; c: string }} AdjacentlyTagged * @property {{ t: "A" }} A * @property {{ t: "B"; c: { * id: string, * method: string, * } }} B * @property {{ t: "C"; c: string }} C * * @typedef {{ type: "A"; data: { * field: string, * } } | { type: "B"; data: { * other: number, * } }} AdjacentlyTaggedWithAlias * @property {{ type: "A"; data: { * field: string, * } }} A * @property {{ type: "B"; data: { * other: number, * } }} B * * @typedef {{ * b: number, * }} B * @property {number} b * * @typedef {"A" | "B"} BasicEnum * @property {"A"} A * @property {"B"} B * * @typedef {BoxedInner} BoxFlattened * * @typedef {{ * c: { * a: number, * }, * }} BoxInline * @property {{ * a: number, * }} c * * @typedef {{ * a: number, * }} BoxedInner * @property {number} a * * @typedef {string} BracedStruct * @property {string} "0" * * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second * * Some triple-slash comment * Some more triple-slash comment * * @typedef { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * ({ A: number }) & { B?: never } | * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * ({ B: { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * } }) & { A?: never }} CommentedEnum * @property { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * { A: number }} A - Some triple-slash comment Some more triple-slash comment * @property { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * { B: { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * } }} B - Some triple-slash comment Some more triple-slash comment * * Some triple-slash comment * Some more triple-slash comment * * @typedef {{ * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * }} CommentedStruct * @property {number} a - Some triple-slash comment Some more triple-slash comment * * @typedef {{ * data: number[], * a: number[], * d: [number, number], * }} ConstGenericInConstContainer * @property {number[]} data * @property {number[]} a * @property {[number, number]} d * * @typedef {{ * data: [number], * a: [number, number], * d: [number, number], * }} ConstGenericInNonConstContainer * @property {[number]} data * @property {[number, number]} a * @property {[number, number]} d * * @typedef {{ * foo: Generic1, * bar: Generic1[], * baz: { [key in string]: Generic1 }, * }} Container1 * @property {Generic1} foo * @property {Generic1[]} bar * @property {{ [key in string]: Generic1 }} baz * * @typedef {string} ContainerTypeOverrideEnum * * @typedef {string} ContainerTypeOverrideGeneric * * @typedef {string} ContainerTypeOverrideStruct * * @typedef {T} ContainerTypeOverrideToGeneric * * @typedef {[string, number]} ContainerTypeOverrideTuple * * @typedef {[T, string]} ContainerTypeOverrideTupleGeneric * * @typedef {{ * flattened: number, * }} D * @property {number} flattened * * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b * * @typedef { * /** * * @deprecated * */ * "A" | * /** * * @deprecated Nope * */ * "B" | * /** * * @deprecated Nope * */ * "C"} DeprecatedEnumVariants * @property { * /** * * @deprecated * */ * "A"} A - @deprecated * @property { * /** * * @deprecated Nope * */ * "B"} B - @deprecated Nope * @property { * /** * * @deprecated Nope * */ * "C"} C - @deprecated Nope * * @typedef {{ * a: number, * /** * * @deprecated * */ * b: string, * /** * * @deprecated This field is cringe! * */ * c: string, * /** * * @deprecated This field is cringe! * */ * d: string, * }} DeprecatedFields * @property {number} a * @property {string} b - @deprecated * @property {string} c - @deprecated This field is cringe! * @property {string} d - @deprecated This field is cringe! * * @typedef {[ * /** * * @deprecated * */ * string, * /** * * @deprecated Nope * */ * string, * /** * * @deprecated Nope * */ * number]} DeprecatedTupleVariant * @property {string} "0" - @deprecated * @property {string} "1" - @deprecated Nope * @property {number} "2" - @deprecated Nope * * @deprecated * @typedef {{ * a: number, * }} DeprecatedType * @property {number} a * * @deprecated Look at you big man using a deprecation message * @typedef {{ * a: number, * }} DeprecatedTypeWithMsg * @property {number} a * * @deprecated Look at you big man using a deprecation message * @typedef {{ * a: number, * }} DeprecatedTypeWithMsg2 * @property {number} a * * @typedef {{ * a: ToBeFlattened, * b: ToBeFlattened, * }} DoubleFlattened * @property {ToBeFlattened} a * @property {ToBeFlattened} b * * @typedef {{ A: string } | "B"} Eight * @property {{ A: string }} A * @property {"B"} B * * @typedef {never} EmptyEnum * * @typedef {never} EmptyEnumTagged * * @typedef {never} EmptyEnumTaggedWContent * * @typedef {never} EmptyEnumUntagged * * @typedef {Record} EmptyStruct * * @typedef {{ * a: "EmptyStructWithTag", * }} EmptyStructWithTag * @property {"EmptyStructWithTag"} a * * @typedef {{ t: "A" } | { t: "B" }} Enum * @property {{ t: "A" }} A * @property {{ t: "B" }} B * * @typedef {{ t: "C" } | { t: "B" } | { t: "D"; enumField: null }} Enum2 * @property {{ t: "C" }} C * @property {{ t: "B" }} B * @property {{ t: "D"; enumField: null }} D * * @typedef {{ t: "A"; b: string }} Enum3 * @property {{ t: "A"; b: string }} A * * @typedef {({ A: string }) & { D?: never; bbb?: never; cccc?: never } | ({ bbb: number }) & { A?: never; D?: never; cccc?: never } | ({ cccc: number }) & { A?: never; D?: never; bbb?: never } | ({ D: { * a: string, * bbbbbb: number, * } }) & { A?: never; bbb?: never; cccc?: never }} EnumMacroAttributes * @property {{ A: string }} A * @property {{ bbb: number }} bbb * @property {{ cccc: number }} cccc * @property {{ D: { * a: string, * bbbbbb: number, * } }} D * * @typedef {{ * a: Partial<{ [key in BasicEnum]: number }>, * }} EnumReferenceRecordKey * @property {Partial<{ [key in BasicEnum]: number }>} a * * @typedef {"HELLOWORLD" | "VARIANTB" | "TESTINGWORDS"} EnumRenameAllUppercase * @property {"HELLOWORLD"} HELLOWORLD * @property {"VARIANTB"} VARIANTB * @property {"TESTINGWORDS"} TESTINGWORDS * * @typedef {"Variant" | "Other"} EnumWithMultipleVariantAliases * @property {"Variant"} Variant * @property {"Other"} Other * * @typedef {"Variant" | "Other"} EnumWithVariantAlias * @property {"Variant"} Variant * @property {"Other"} Other * * @typedef {"renamed_variant" | "Other"} EnumWithVariantAliasAndRename * @property {"renamed_variant"} renamed_variant * @property {"Other"} Other * * @typedef {"A" | ({ B: { * id: string, * method: string, * } }) & { C?: never } | ({ C: string }) & { B?: never }} ExternallyTagged * @property {"A"} A * @property {{ B: { * id: string, * method: string, * } }} B * @property {{ C: string }} C * * @typedef {{ A: string }} ExtraBracketsInTupleVariant * @property {{ A: string }} A * * @typedef {string} ExtraBracketsInUnnamedStruct * @property {string} "0" * * @typedef {{ * a: string, * }} First * @property {string} a * * @typedef {{ * a: number, * b: number, * }} FlattenA * @property {number} a * @property {number} b * * @typedef {{ * c: number, * } & FlattenA} FlattenB * @property {number} c * * @typedef {{ * c: number, * } & FlattenA} FlattenC * @property {number} c * * @typedef {{ * a: FlattenA, * c: number, * }} FlattenD * @property {FlattenA} a * @property {number} c * * @typedef {{ * b: ({ * c: number, * }) & (FlattenA), * d: number, * }} FlattenE * @property {({ * c: number, * }) & (FlattenA)} b * @property {number} d * * @typedef {{ tag: "One" } | { tag: "Two" } | { tag: "Three" }} FlattenEnum * @property {{ tag: "One" }} One * @property {{ tag: "Two" }} Two * @property {{ tag: "Three" }} Three * * @typedef {{ * outer: string, * } & FlattenEnum} FlattenEnumStruct * @property {string} outer * * @typedef {{ * b: ({ * c: number, * }) & (FlattenA), * d: number, * }} FlattenF * @property {({ * c: number, * }) & (FlattenA)} b * @property {number} d * * @typedef {{ * b: FlattenB, * d: number, * }} FlattenG * @property {FlattenB} b * @property {number} d * * @typedef {{ * id: string, * } & NestedEnum} FlattenOnNestedEnum * @property {string} id * * @typedef {Inner} FlattenedInner * * @typedef {{ * a: First, * b: { * a: string, * }, * }} Fourth * @property {First} a * @property {{ * a: string, * }} b * * @typedef {{ * value: T, * values: T[], * }} Generic1 * @property {T} value * @property {T[]} values * * @typedef {({ A: A }) & { B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ B: [B, B, B] }) & { A?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ C: C[] }) & { A?: never; B?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ D: A[][][] }) & { A?: never; B?: never; C?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ E: { * a: A, * b: B, * c: C, * } }) & { A?: never; B?: never; C?: never; D?: never; X?: never; Y?: never; Z?: never } | ({ X: number[] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; Y?: never; Z?: never } | ({ Y: number }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Z?: never } | ({ Z: number[][] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never }} Generic2 * @property {{ A: A }} A * @property {{ B: [B, B, B] }} B * @property {{ C: C[] }} C * @property {{ D: A[][][] }} D * @property {{ E: { * a: A, * b: B, * c: C, * } }} E * @property {{ X: number[] }} X * @property {{ Y: number }} Y * @property {{ Z: number[][] }} Z * * @typedef {{ * value: T, * values: T[], * }} GenericAutoBound * @property {T} value * @property {T[]} values * * @typedef {{ * value: T, * values: T[], * }} GenericAutoBound2 * @property {T} value * @property {T[]} values * * @typedef {{ * value: T, * }} GenericDefault * @property {T} value * * @typedef {{ * value: T, * }} GenericDefaultSkipped * @property {T} value * * @typedef {{ * value: number, * }} GenericDefaultSkippedNonType * @property {number} value * * @typedef {{ * generic_flattened: T, * }} GenericFlattened * @property {T} generic_flattened * * @typedef {T[][]} GenericNewType1 * @property {T[][]} "0" * * @typedef {{ * pair: Pair, * }} GenericParameterOrderPreserved * @property {Pair} pair * * @typedef {{ * arg: T, * }} GenericStruct * @property {T} arg * * @typedef {{ * a: T, * b: [T, T], * c: [T, [T, T]], * d: [T, T, T], * e: [([T, T]), ([T, T]), ([T, T])], * f: T[], * g: T[][], * h: ([([T, T]), ([T, T]), ([T, T])])[], * }} GenericStruct2 * @property {T} a * @property {[T, T]} b * @property {[T, [T, T]]} c * @property {[T, T, T]} d * @property {[([T, T]), ([T, T]), ([T, T])]} e * @property {T[]} f * @property {T[][]} g * @property {([([T, T]), ([T, T]), ([T, T])])[]} h * * @typedef {[T, T[], T[][]]} GenericTuple * @property {T} "0" * @property {T[]} "1" * @property {T[][]} "2" * * @typedef {T} GenericTupleStruct * @property {T} "0" * * @typedef {"Undefined" | T} GenericType * @property {"Undefined"} Undefined * @property {T} Value * * @typedef {{ [key in number]: string }} HasGenericAlias * @property {{ [key in number]: string }} "0" * * @typedef {{ * b: { * data: [number, number], * a: [number, number], * d: [number, number, number], * }, * c: { * data: [number, number, number], * a: [number, number], * d: [number, number, number], * }, * d: [number, number], * }} InlineConstGenericContainer * @property {{ * data: [number, number], * a: [number, number], * d: [number, number, number], * }} b * @property {{ * data: [number, number, number], * a: [number, number], * d: [number, number, number], * }} c * @property {[number, number]} d * * @typedef {{ A: { * a: string, * } }} InlineEnumField * @property {{ A: { * a: string, * } }} A * * @typedef {{ * g: InlineFlattenGenericsG, * gi: { * t: string, * }, * } & InlineFlattenGenericsG} InlineFlattenGenerics * @property {InlineFlattenGenericsG} g * @property {{ * t: string, * }} gi * * @typedef {{ * t: T, * }} InlineFlattenGenericsG * @property {T} t * * @typedef {{ * optional_field: { * a: string, * } | null, * }} InlineOptionalType * @property {{ * a: string, * } | null} optional_field * * @typedef {{ * data: number[], * a: number[], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }} InlineRecursiveConstGeneric * @property {number[]} data * @property {number[]} a * @property {[number, number, number]} d * @property {InlineRecursiveConstGeneric} e * * @typedef {{ * b: { * data: [number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }, * c: { * data: [number, number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }, * d: [number, number], * }} InlineRecursiveConstGenericContainer * @property {{ * data: [number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }} b * @property {{ * data: [number, number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }} c * @property {[number, number]} d * * @typedef {{ * ref_struct: SimpleStruct, * val: number, * }} InlineStruct * @property {SimpleStruct} ref_struct * @property {number} val * * @typedef {{ * demo: [string, boolean], * }} InlineTuple * @property {[string, boolean]} demo * * @typedef {{ * demo: [{ * demo: [string, boolean], * }, boolean], * }} InlineTuple2 * @property {[{ * demo: [string, boolean], * }, boolean]} demo * * @typedef {{ * inline_this: { * ref_struct: SimpleStruct, * val: number, * }, * dont_inline_this: RefStruct, * }} InlinerStruct * @property {{ * ref_struct: SimpleStruct, * val: number, * }} inline_this * @property {RefStruct} dont_inline_this * * @typedef {{ * a: number, * } & FlattenedInner} Inner * @property {number} a * * @typedef {{ * type: "A", * } & { [key in string]: string }} InternallyTaggedD * @property {{ * type: "A", * } & { [key in string]: string }} A * * @typedef {{ type: "A" }} InternallyTaggedE * @property {{ type: "A" }} A * * @typedef {{ type: "A" }} InternallyTaggedF * @property {{ type: "A" }} A * * @typedef {null} InternallyTaggedFInner * @property {null} A * * @typedef {{ type: "A" }} InternallyTaggedH * @property {{ type: "A" }} A * * @typedef {null} InternallyTaggedHInner * @property {null} "0" * * @typedef {{ * type: "A", * } & { type: "A" } | { type: "B" }} InternallyTaggedL * @property {{ * type: "A", * } & { type: "A" } | { type: "B" }} A * * @typedef {{ type: "A" } | { type: "B" }} InternallyTaggedLInner * @property {{ type: "A" }} A * @property {{ type: "B" }} B * * @typedef {{ type: "A" }} InternallyTaggedM * @property {{ type: "A" }} A * * @typedef {"A" | "B"} InternallyTaggedMInner * @property {"A"} A * @property {"B"} B * * @typedef {{ type: "A"; field: string } | { type: "B"; other: number }} InternallyTaggedWithAlias * @property {{ type: "A"; field: string }} A * @property {{ type: "B"; other: number }} B * * @typedef {{ * cause: null, * }} InvalidToValidType * @property {null} cause * * @typedef {({ A: { * a: string, * } }) & { B?: never } | ({ B: { * b: string, * } }) & { A?: never }} Issue221External * @property {{ A: { * a: string, * } }} A * @property {{ B: { * b: string, * } }} B * * @typedef {({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never }} Issue221UntaggedMixed * @property {{ a: string }} A * @property {{ b: string }} B * @property {{ values: { [key in string]: string } }} Unsafe * * @typedef {({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }} Issue221UntaggedSafe * @property {{ a: string }} A * @property {{ b: string }} B * * @typedef {{ * default_unity_arguments: string[], * }} Issue281 * @property {string[]} default_unity_arguments * * @typedef {{ * "test-ing": string, * }} KebabCase * @property {string} "test-ing" * * @typedef {({ Borrowed: T }) & { Owned?: never } | ({ Owned: T }) & { Borrowed?: never }} LifetimeGenericEnum * @property {{ Borrowed: T }} Borrowed * @property {{ Owned: T }} Owned * * @typedef {{ * borrowed: T[], * owned: T[], * }} LifetimeGenericStruct * @property {T[]} borrowed * @property {T[]} owned * * @typedef {{ event: "started"; data: { * projectName: string, * } } | { event: "progressTest"; data: { * projectName: string, * status: string, * progress: number, * } } | { event: "finished"; data: { * projectName: string, * } }} LoadProjectEvent * @property {{ event: "started"; data: { * projectName: string, * } }} started * @property {{ event: "progressTest"; data: { * projectName: string, * status: string, * progress: number, * } }} progressTest * @property {{ event: "finished"; data: { * projectName: string, * } }} finished * * @typedef {({ Demo: string }) & { Demo2?: never } | ({ Demo2: { * demo2: string, * } }) & { Demo?: never }} MacroEnum * @property {{ Demo: string }} Demo * @property {{ Demo2: { * demo2: string, * } }} Demo2 * * @typedef {string} MacroStruct * @property {string} "0" * * @typedef {{ * demo: string, * }} MacroStruct2 * @property {string} demo * * @typedef {T} MaybeValidKey * @property {T} "0" * * @typedef {Record} MyEmptyInput * * @typedef {({ A: string }) & { B?: never } | ({ B: number }) & { A?: never }} MyEnum * @property {{ A: string }} A * @property {{ B: number }} B * * @typedef {{ t: "Variant"; c: { * inner: First, * } }} MyEnumAdjacent * @property {{ t: "Variant"; c: { * inner: First, * } }} Variant * * @typedef {{ Variant: { * inner: First, * } }} MyEnumExternal * @property {{ Variant: { * inner: First, * } }} Variant * * @typedef {{ type: "Variant"; inner: First }} MyEnumTagged * @property {{ type: "Variant"; inner: First }} Variant * * @typedef {{ inner: First }} MyEnumUntagged * @property {{ inner: First }} Variant * * @typedef {{ * data: number[], * a: number[], * d: [number, number], * }} NamedConstGeneric * @property {number[]} data * @property {number[]} a * @property {[number, number]} d * * @typedef {{ * a: NamedConstGeneric, * b: NamedConstGeneric, * d: [number, number], * }} NamedConstGenericContainer * @property {NamedConstGeneric} a * @property {NamedConstGeneric} b * @property {[number, number]} d * * @typedef {{ type: "a"; value: string } | { type: "b"; value: number }} NestedEnum * @property {{ type: "a"; value: string }} a * @property {{ type: "b"; value: number }} b * * @typedef {{ t: "A"; c: string } | { t: "B" } | { t: "C"; c: { * a: string, * } } | { t: "D"; c: First }} Ninth * @property {{ t: "A"; c: string }} A * @property {{ t: "B" }} B * @property {{ t: "C"; c: { * a: string, * } }} C * @property {{ t: "D"; c: First }} D * * @typedef {string | null} NonOptional * @property {string | null} "0" * * @typedef {({ A?: string | null }) & { B?: never; C?: never } | ({ B: { * a: string | null, * } }) & { A?: never; C?: never } | ({ C: { * a?: string | null, * } }) & { A?: never; B?: never }} OptionalInEnum * @property {{ A?: string | null }} A * @property {{ B: { * a: string | null, * } }} B * @property {{ C: { * a?: string | null, * } }} C * * @typedef {string | null} OptionalOnNamedField * @property {string | null} ["0"] * * @typedef {{ * b: string | null, * }} OptionalOnTransparentNamedField * @property {string | null} b * * @typedef {{ * overriden_field: string, * }} OverridenStruct * @property {string} overriden_field * * @typedef {{ * first: Z, * second: A, * }} Pair * @property {Z} first * @property {A} second * * @typedef {{ * a: string, * }} PlaceholderInnerField * @property {string} a * * @typedef {{ * demo: Recursive, * }} Recursive * @property {Recursive} demo * * @typedef {{ A: { * demo: RecursiveInEnum, * } }} RecursiveInEnum * @property {{ A: { * demo: RecursiveInEnum, * } }} A * * @typedef {RecursiveInline} RecursiveInline * * @typedef {{ * demo: { [key in string]: RecursiveMapValue }, * }} RecursiveMapValue * @property {{ [key in string]: RecursiveMapValue }} demo * * @typedef {RecursiveInline} RecursiveTransparent * @property {RecursiveInline} "0" * * @typedef {TestEnum} RefStruct * @property {TestEnum} "0" * * @typedef {{ [key in string]: null }} Regular * @property {{ [key in string]: null }} "0" * * @typedef {"OneWord" | "Two words"} Rename * @property {"OneWord"} OneWord * @property {"Two words"} "Two words" * * @typedef {{ * "a/b": number, * }} RenameSerdeSpecialChar * @property {number} "a/b" * * @typedef {{ * "@odata.context": string, * }} RenameWithWeirdCharsField * @property {string} "@odata.context" * * @typedef {{ "@odata.context": string }} RenameWithWeirdCharsVariant * @property {{ "@odata.context": string }} "@odata.context" * * @typedef {{ * "": string, * "a\"b": string, * "a\\b": string, * "line\nbreak": string, * "line\u2028break": string, * "line\u2029break": string, * }} RenamedFieldKeys * @property {string} "" * @property {string} "a\"b" * @property {string} "a\\b" * @property {string} "line\nbreak" * @property {string} "line\u2028break" * @property {string} "line\u2029break" * * @typedef {"a-b"} RenamedVariantWithSkippedPayload * @property {"a-b"} "a-b" * * @typedef {{ * a: number, * }} Second * @property {number} a * * @typedef {{ * a: First, * b: Second, * }} Seventh * @property {First} a * @property {Second} b * * @typedef {{ * a: number, * b: string, * c: [number, string, number], * d: string[], * e: string | null, * }} SimpleStruct * @property {number} a * @property {string} b * @property {[number, string, number]} c * @property {string[]} d * @property {string | null} e * * Some single-line comment * * @typedef { * /** Some single-line comment */ * ({ A: number }) & { B?: never } | * /** Some single-line comment */ * ({ B: { * /** Some single-line comment */ * a: number, * } }) & { A?: never }} SingleLineComment * @property { * /** Some single-line comment */ * { A: number }} A - Some single-line comment * @property { * /** Some single-line comment */ * { B: { * /** Some single-line comment */ * a: number, * } }} B - Some single-line comment * * @typedef {{ * a: First, * b: First, * }} Sixth * @property {First} a * @property {First} b * * @typedef {{ * b: number, * }} SkipField * @property {number} b * * @typedef {({ A: Record }) & { B?: never } | ({ B: { * b: number, * } }) & { A?: never }} SkipNamedFieldInVariant * @property {{ A: Record }} A * @property {{ B: { * b: number, * } }} B * * @typedef {Record} SkipOnlyField * * @typedef {{ * a: number, * }} SkipStructFields * @property {number} a * * @typedef {"A" | { B: [number] }} SkipUnnamedFieldInVariant * @property {"A"} A * @property {{ B: [number] }} B * * @typedef {{ A: string }} SkipVariant * @property {{ A: string }} A * * @typedef {{ tag: "A"; data: string }} SkipVariant2 * @property {{ tag: "A"; data: string }} A * * @typedef {{ A: { * a: string, * } }} SkipVariant3 * @property {{ A: { * a: string, * } }} A * * @typedef {{ type: "A" } | { type: "B"; data: string }} SkippedFieldWithinVariant * @property {{ type: "A" }} A * @property {{ type: "B"; data: string }} B * * @typedef {{ * a: number, * }} SpectaSkipNonTypeField * @property {number} a * * @typedef {{ * string_ident: string, * u32_ident: number, * path: string, * tuple: [string, number], * }} SpectaTypeOverride * @property {string} string_ident * @property {number} u32_ident * @property {string} path * @property {[string, number]} tuple * * @typedef {{ * b: string, * }} Struct2 * @property {string} b * * @typedef {{ * t: "StructNew", * a: string, * }} StructNew * @property {"StructNew"} t * @property {string} a * * @typedef {{ * A: number, * B: number, * }} StructRenameAllUppercase * @property {number} A * @property {number} B * * @typedef {{ * field: string, * }} StructWithAlias * @property {string} field * * @typedef {{ * renamed_field: string, * }} StructWithAliasAndRename * @property {string} renamed_field * * @typedef {{ * field: string, * }} StructWithMultipleAliases * @property {string} field * * @typedef {{ * type: "TagOnStructWithInline", * a: First, * b: { * a: string, * }, * }} TagOnStructWithInline * @property {"TagOnStructWithInline"} type * @property {First} a * @property {{ * a: string, * }} b * * @typedef {string | "B" | { * a: string, * } | First} Tenth * @property {string} A * @property {"B"} B * @property {{ * a: string, * }} C * @property {First} D * * @typedef {never} TestCollectionRegister * * @typedef {"Unit" | ({ Single: number }) & { Multiple?: never; Struct?: never } | ({ Multiple: [number, number] }) & { Single?: never; Struct?: never } | ({ Struct: { * a: number, * } }) & { Multiple?: never; Single?: never }} TestEnum * @property {"Unit"} Unit * @property {{ Single: number }} Single * @property {{ Multiple: [number, number] }} Multiple * @property {{ Struct: { * a: number, * } }} Struct * * @typedef {{ * b: { [key in string]: string }, * c: First, * } & First} Third * @property {{ [key in string]: string }} b * @property {First} c * * @typedef {{ * a: string, * }} ToBeFlattened * @property {string} a * * @typedef {string} TransparentStruct * @property {string} "0" * * @typedef {TransparentTypeInner} TransparentType * @property {TransparentTypeInner} "0" * * @typedef {null} TransparentType2 * @property {null} "0" * * @typedef {{ * inner: string, * }} TransparentTypeInner * @property {string} inner * * @typedef {string} TransparentTypeWithOverride * @property {string} "0" * * @typedef {null} TransparentWithSkip * @property {null} "0" * * @typedef {string} TransparentWithSkip2 * @property {string} "0" * * @typedef {string} TransparentWithSkip3 * @property {string} "0" * * @typedef {[number[], [number[], number[]], [number[], number[], number[]]]} TupleNested * @property {number[]} "0" * @property {[number[], number[]]} "1" * @property {[number[], number[], number[]]} "2" * * @typedef {string} TupleStruct * @property {string} "0" * * @typedef {number} TupleStruct1 * @property {number} "0" * * @typedef {[number, boolean, string]} TupleStruct3 * @property {number} "0" * @property {boolean} "1" * @property {string} "2" * * @typedef {string} TupleStructWithRep * @property {string} "0" * * @typedef {null} Unit1 * * @typedef {Record} Unit2 * * @typedef {[]} Unit3 * * @typedef {null} Unit4 * @property {null} "0" * * @typedef {"A"} Unit5 * @property {"A"} A * * @typedef {{ A: null }} Unit6 * @property {{ A: null }} A * * @typedef {{ A: Record }} Unit7 * @property {{ A: Record }} A * * @typedef {"A" | "B" | "C"} UnitVariants * @property {"A"} A * @property {"B"} B * @property {"C"} C * * @typedef {string | number | { id: string } | [string, boolean]} UntaggedVariants * @property {string} A * @property {number} B * @property {number} C * @property {{ id: string }} D * @property {[string, boolean]} E * * @typedef {string | number} UntaggedVariantsKey * @property {string} A * @property {number} B * @property {number} C * * @typedef {null | number} UntaggedVariantsWithDuplicateBranches * @property {null} A * @property {number} B * @property {null} C * * @typedef {string | [number, string] | number} UntaggedVariantsWithoutValue * @property {string} A * @property {[number, string]} B * @property {number} C * * @typedef {({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }} UntaggedWithAlias * @property {{ field: string }} A * @property {{ other: number }} B * * @typedef {{ [key in MaybeValidKey]: null }} ValidMaybeValidKey * @property {{ [key in MaybeValidKey]: null }} "0" * * @typedef {{ [key in MaybeValidKey>]: null }} ValidMaybeValidKeyNested * @property {{ [key in MaybeValidKey>]: null }} "0" */ ════════════════════════════════════════ tests/ tests/ types.js (29458 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. /** * @typedef {import("../../std/ops")} std$ops * @typedef {import("../../std/result")} std$result * @typedef {import("../../test/types")} test$types * @typedef {import("../../test/types/type_type")} test$types$type_type */ /** * @typedef {{ * i8: number, * i16: number, * i32: number, * u8: number, * u16: number, * u32: number, * f32: number, * f64: number, * bool: boolean, * char: string, * "Range": std$ops.Range, * "RangeInclusive": std$ops.RangeInclusive, * "()": null, * "(String, i32)": [string, number], * "(String, i32, bool)": [string, number, boolean], * "((String, i32), (bool, char, bool), ())": [[string, number], [boolean, string, boolean], null], * "(bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool)": [boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean], * "(Vec, Vec)": [number[], boolean[]], * String: string, * PathBuf: string, * IpAddr: string, * Ipv4Addr: string, * Ipv6Addr: string, * SocketAddr: string, * SocketAddrV4: string, * SocketAddrV6: string, * "Cow<'static, str>": string, * "Cow<'static, i32>": number, * "&'static str": string, * "&'static bool": boolean, * "&'static i32": number, * "Vec": number[], * "&'static [i32]": number[], * "&'static [i32; 3]": [number, number, number], * "[i32; 3]": [number, number, number], * "Vec": test$types.MyEnum[], * "&'static [MyEnum]": test$types.MyEnum[], * "&'static [MyEnum; 6]": [test$types.MyEnum, test$types.MyEnum, test$types.MyEnum, test$types.MyEnum, test$types.MyEnum, test$types.MyEnum], * "[MyEnum; 2]": [test$types.MyEnum, test$types.MyEnum], * "&'static [i32; 1]": [number], * "&'static [i32; 0]": [], * "Option": number | null, * "Option<()>": null, * "Option>": number[] | null, * "Result": std$result.Result, * "Vec>>": (number | null)[], * "Option>>": number[] | null, * "[Vec; 3]": [string[], string[], string[]], * "Option>": string | null, * "Option>>": string | null, * "PhantomData<()>": null, * "PhantomData": null, * Infallible: never, * Unit1: test$types.Unit1, * Unit2: test$types.Unit2, * Unit3: test$types.Unit3, * Unit4: test$types.Unit4, * Unit5: test$types.Unit5, * Unit6: test$types.Unit6, * Unit7: test$types.Unit7, * SimpleStruct: test$types.SimpleStruct, * TupleStruct1: test$types.TupleStruct1, * TupleStruct3: test$types.TupleStruct3, * TestEnum: test$types.TestEnum, * RefStruct: test$types.RefStruct, * InlinerStruct: test$types.InlinerStruct, * "GenericStruct": test$types.GenericStruct, * "GenericStruct": test$types.GenericStruct, * FlattenEnumStruct: test$types.FlattenEnumStruct, * OverridenStruct: test$types.OverridenStruct, * HasGenericAlias: test$types.HasGenericAlias, * EnumMacroAttributes: test$types.EnumMacroAttributes, * InlineEnumField: test$types.InlineEnumField, * InlineOptionalType: test$types.InlineOptionalType, * Rename: test$types.Rename, * TransparentType: test$types.TransparentType, * TransparentType2: test$types.TransparentType2, * TransparentTypeWithOverride: test$types.TransparentTypeWithOverride, * "[Option; 3]": [(number | null), (number | null), (number | null)], * "HashMap": Partial<{ [key in test$types.BasicEnum]: null }>, * "HashMap": Partial<{ [key in test$types.BasicEnum]: number }>, * "Option>>>": number | null, * "Vec": test$types.PlaceholderInnerField[], * EnumReferenceRecordKey: test$types.EnumReferenceRecordKey, * FlattenOnNestedEnum: test$types.FlattenOnNestedEnum, * MyEmptyInput: test$types.MyEmptyInput, * "(String)": string, * "(String,)": [string], * ExtraBracketsInTupleVariant: test$types.ExtraBracketsInTupleVariant, * ExtraBracketsInUnnamedStruct: test$types.ExtraBracketsInUnnamedStruct, * "Vec": test$types.MyEnum[], * InlineTuple: test$types.InlineTuple, * InlineTuple2: test$types.InlineTuple2, * "Box": string, * "Box": string, * SkippedFieldWithinVariant: test$types.SkippedFieldWithinVariant, * KebabCase: test$types.KebabCase, * "&[&str]": string[], * "Issue281<'_>": test$types.Issue281, * "LifetimeGenericStruct<'_, i32>": test$types.LifetimeGenericStruct, * "LifetimeGenericEnum<'_, i32>": test$types.LifetimeGenericEnum, * RenameWithWeirdCharsField: test$types.RenameWithWeirdCharsField, * RenameWithWeirdCharsVariant: test$types.RenameWithWeirdCharsVariant, * RenamedFieldKeys: test$types.RenamedFieldKeys, * RenamedVariantWithSkippedPayload: test$types.RenamedVariantWithSkippedPayload, * "type_type::Type": test$types$type_type.Type, * ActualType: test$types.ActualType, * SpectaTypeOverride: test$types.SpectaTypeOverride, * ContainerTypeOverrideStruct: test$types.ContainerTypeOverrideStruct, * ContainerTypeOverrideEnum: test$types.ContainerTypeOverrideEnum, * "ContainerTypeOverrideGeneric>": test$types.ContainerTypeOverrideGeneric, * "ContainerTypeOverrideToGeneric": test$types.ContainerTypeOverrideToGeneric, * ContainerTypeOverrideTuple: test$types.ContainerTypeOverrideTuple, * "ContainerTypeOverrideTupleGeneric": test$types.ContainerTypeOverrideTupleGeneric, * InvalidToValidType: test$types.InvalidToValidType, * TupleStruct: test$types.TupleStruct, * TupleStructWithRep: test$types.TupleStructWithRep, * "GenericTupleStruct": test$types.GenericTupleStruct, * BracedStruct: test$types.BracedStruct, * Struct: test$types.StructNew, * Struct2: test$types.Struct2, * Enum: test$types.Enum, * Enum2: test$types.Enum2, * Enum3: test$types.Enum3, * StructRenameAllUppercase: test$types.StructRenameAllUppercase, * RenameSerdeSpecialChar: test$types.RenameSerdeSpecialChar, * EnumRenameAllUppercase: test$types.EnumRenameAllUppercase, * Recursive: test$types.Recursive, * RecursiveMapValue: test$types.RecursiveMapValue, * RecursiveTransparent: test$types.RecursiveTransparent, * RecursiveInEnum: test$types.RecursiveInEnum, * NonOptional: test$types.NonOptional, * OptionalOnNamedField: test$types.OptionalOnNamedField, * OptionalOnTransparentNamedField: test$types.OptionalOnTransparentNamedField, * OptionalInEnum: test$types.OptionalInEnum, * UntaggedVariants: test$types.UntaggedVariants, * UntaggedVariantsWithoutValue: test$types.UntaggedVariantsWithoutValue, * UntaggedVariantsWithDuplicateBranches: test$types.UntaggedVariantsWithDuplicateBranches, * "HashMap": { [key in string]: null }, * Regular: test$types.Regular, * "HashMap": { [key in never]: null }, * "HashMap": { [key in test$types.TransparentStruct]: null }, * "HashMap": Partial<{ [key in test$types.UnitVariants]: null }>, * "HashMap": Partial<{ [key in test$types.UntaggedVariantsKey]: null }>, * ValidMaybeValidKey: test$types.ValidMaybeValidKey, * ValidMaybeValidKeyNested: test$types.ValidMaybeValidKeyNested, * MacroStruct: test$types.MacroStruct, * MacroStruct2: test$types.MacroStruct2, * MacroEnum: test$types.MacroEnum, * DeprecatedType: test$types.DeprecatedType, * DeprecatedTypeWithMsg: test$types.DeprecatedTypeWithMsg, * DeprecatedTypeWithMsg2: test$types.DeprecatedTypeWithMsg2, * DeprecatedFields: test$types.DeprecatedFields, * DeprecatedTupleVariant: test$types.DeprecatedTupleVariant, * DeprecatedEnumVariants: test$types.DeprecatedEnumVariants, * CommentedStruct: test$types.CommentedStruct, * CommentedEnum: test$types.CommentedEnum, * SingleLineComment: test$types.SingleLineComment, * NonGeneric: test$types.Demo, * "HalfGenericA": test$types.Demo, * "HalfGenericB": test$types.Demo, * "FullGeneric": test$types.Demo, * "Another": test$types.Demo, * "MapA": { [key in string]: number }, * "MapB": { [key in number]: string }, * "MapC": { [key in string]: test$types.AGenericStruct }, * "AGenericStruct": test$types.AGenericStruct, * A: test$types.A, * DoubleFlattened: test$types.DoubleFlattened, * FlattenedInner: test$types.FlattenedInner, * BoxFlattened: test$types.BoxFlattened, * BoxInline: test$types.BoxInline, * First: test$types.First, * Second: test$types.Second, * Third: test$types.Third, * Fourth: test$types.Fourth, * TagOnStructWithInline: test$types.TagOnStructWithInline, * Sixth: test$types.Sixth, * Seventh: test$types.Seventh, * Eight: test$types.Eight, * Ninth: test$types.Ninth, * Tenth: test$types.Tenth, * MyEnumTagged: test$types.MyEnumTagged, * MyEnumExternal: test$types.MyEnumExternal, * MyEnumAdjacent: test$types.MyEnumAdjacent, * MyEnumUntagged: test$types.MyEnumUntagged, * EmptyStruct: test$types.EmptyStruct, * EmptyStructWithTag: test$types.EmptyStructWithTag, * AdjacentlyTagged: test$types.AdjacentlyTagged, * LoadProjectEvent: test$types.LoadProjectEvent, * ExternallyTagged: test$types.ExternallyTagged, * Issue221External: test$types.Issue221External, * InternallyTaggedD: test$types.InternallyTaggedD, * InternallyTaggedE: test$types.InternallyTaggedE, * InternallyTaggedF: test$types.InternallyTaggedF, * InternallyTaggedH: test$types.InternallyTaggedH, * InternallyTaggedL: test$types.InternallyTaggedL, * InternallyTaggedM: test$types.InternallyTaggedM, * StructWithAlias: test$types.StructWithAlias, * StructWithMultipleAliases: test$types.StructWithMultipleAliases, * StructWithAliasAndRename: test$types.StructWithAliasAndRename, * EnumWithVariantAlias: test$types.EnumWithVariantAlias, * EnumWithMultipleVariantAliases: test$types.EnumWithMultipleVariantAliases, * EnumWithVariantAliasAndRename: test$types.EnumWithVariantAliasAndRename, * InternallyTaggedWithAlias: test$types.InternallyTaggedWithAlias, * AdjacentlyTaggedWithAlias: test$types.AdjacentlyTaggedWithAlias, * UntaggedWithAlias: test$types.UntaggedWithAlias, * Issue221UntaggedSafe: test$types.Issue221UntaggedSafe, * Issue221UntaggedMixed: test$types.Issue221UntaggedMixed, * EmptyEnum: test$types.EmptyEnum, * EmptyEnumTagged: test$types.EmptyEnumTagged, * EmptyEnumTaggedWContent: test$types.EmptyEnumTaggedWContent, * EmptyEnumUntagged: test$types.EmptyEnumUntagged, * SkipOnlyField: test$types.SkipOnlyField, * SkipField: test$types.SkipField, * SkipVariant: test$types.SkipVariant, * SkipUnnamedFieldInVariant: test$types.SkipUnnamedFieldInVariant, * SkipNamedFieldInVariant: test$types.SkipNamedFieldInVariant, * TransparentWithSkip: test$types.TransparentWithSkip, * TransparentWithSkip2: test$types.TransparentWithSkip2, * TransparentWithSkip3: test$types.TransparentWithSkip3, * SkipVariant2: test$types.SkipVariant2, * SkipVariant3: test$types.SkipVariant3, * SkipStructFields: test$types.SkipStructFields, * SpectaSkipNonTypeField: test$types.SpectaSkipNonTypeField, * FlattenA: test$types.FlattenA, * FlattenB: test$types.FlattenB, * FlattenC: test$types.FlattenC, * FlattenD: test$types.FlattenD, * FlattenE: test$types.FlattenE, * FlattenF: test$types.FlattenF, * FlattenG: test$types.FlattenG, * TupleNested: test$types.TupleNested, * "Generic1<()>": test$types.Generic1, * "GenericAutoBound<()>": test$types.GenericAutoBound, * "GenericAutoBound2<()>": test$types.GenericAutoBound2, * Container1: test$types.Container1, * "Generic2<(), String, i32>": test$types.Generic2, * "GenericNewType1<()>": test$types.GenericNewType1, * "GenericTuple<()>": test$types.GenericTuple, * "GenericStruct2<()>": test$types.GenericStruct2, * "InlineGenericNewtype": string, * "InlineGenericNested": [string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | ({ Unnamed: string }) & { Named?: never } | ({ Named: { * value: string, * } }) & { Unnamed?: never }], * "InlineFlattenGenericsG<()>": test$types.InlineFlattenGenericsG, * InlineFlattenGenerics: test$types.InlineFlattenGenerics, * GenericDefault: test$types.GenericDefault, * ChainedGenericDefault: test$types.ChainedGenericDefault, * "ChainedGenericDefault": test$types.ChainedGenericDefault, * "ChainedGenericDefault": test$types.ChainedGenericDefault, * "ChainedGenericDefault": test$types.ChainedGenericDefault, * GenericDefaultSkipped: test$types.GenericDefaultSkipped, * GenericDefaultSkippedNonType: test$types.GenericDefaultSkippedNonType, * GenericParameterOrderPreserved: test$types.GenericParameterOrderPreserved, * ConstGenericInNonConstContainer: test$types.ConstGenericInNonConstContainer, * ConstGenericInConstContainer: test$types.ConstGenericInConstContainer, * NamedConstGenericContainer: test$types.NamedConstGenericContainer, * InlineConstGenericContainer: test$types.InlineConstGenericContainer, * InlineRecursiveConstGenericContainer: test$types.InlineRecursiveConstGenericContainer, * TestCollectionRegister: test$types.TestCollectionRegister, * TestCollectionRegister: test$types.TestCollectionRegister, * }} Primitives * @property {number} i8 * @property {number} i16 * @property {number} i32 * @property {number} u8 * @property {number} u16 * @property {number} u32 * @property {number} f32 * @property {number} f64 * @property {boolean} bool * @property {string} char * @property {std$ops.Range} "Range" * @property {std$ops.RangeInclusive} "RangeInclusive" * @property {null} "()" * @property {[string, number]} "(String, i32)" * @property {[string, number, boolean]} "(String, i32, bool)" * @property {[[string, number], [boolean, string, boolean], null]} "((String, i32), (bool, char, bool), ())" * @property {[boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean]} "(bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool)" * @property {[number[], boolean[]]} "(Vec, Vec)" * @property {string} String * @property {string} PathBuf * @property {string} IpAddr * @property {string} Ipv4Addr * @property {string} Ipv6Addr * @property {string} SocketAddr * @property {string} SocketAddrV4 * @property {string} SocketAddrV6 * @property {string} "Cow<'static, str>" * @property {number} "Cow<'static, i32>" * @property {string} "&'static str" * @property {boolean} "&'static bool" * @property {number} "&'static i32" * @property {number[]} "Vec" * @property {number[]} "&'static [i32]" * @property {[number, number, number]} "&'static [i32; 3]" * @property {[number, number, number]} "[i32; 3]" * @property {test$types.MyEnum[]} "Vec" * @property {test$types.MyEnum[]} "&'static [MyEnum]" * @property {[test$types.MyEnum, test$types.MyEnum, test$types.MyEnum, test$types.MyEnum, test$types.MyEnum, test$types.MyEnum]} "&'static [MyEnum; 6]" * @property {[test$types.MyEnum, test$types.MyEnum]} "[MyEnum; 2]" * @property {[number]} "&'static [i32; 1]" * @property {[]} "&'static [i32; 0]" * @property {number | null} "Option" * @property {null} "Option<()>" * @property {number[] | null} "Option>" * @property {std$result.Result} "Result" * @property {(number | null)[]} "Vec>>" * @property {number[] | null} "Option>>" * @property {[string[], string[], string[]]} "[Vec; 3]" * @property {string | null} "Option>" * @property {string | null} "Option>>" * @property {null} "PhantomData<()>" * @property {null} "PhantomData" * @property {never} Infallible * @property {test$types.Unit1} Unit1 * @property {test$types.Unit2} Unit2 * @property {test$types.Unit3} Unit3 * @property {test$types.Unit4} Unit4 * @property {test$types.Unit5} Unit5 * @property {test$types.Unit6} Unit6 * @property {test$types.Unit7} Unit7 * @property {test$types.SimpleStruct} SimpleStruct * @property {test$types.TupleStruct1} TupleStruct1 * @property {test$types.TupleStruct3} TupleStruct3 * @property {test$types.TestEnum} TestEnum * @property {test$types.RefStruct} RefStruct * @property {test$types.InlinerStruct} InlinerStruct * @property {test$types.GenericStruct} "GenericStruct" * @property {test$types.GenericStruct} "GenericStruct" * @property {test$types.FlattenEnumStruct} FlattenEnumStruct * @property {test$types.OverridenStruct} OverridenStruct * @property {test$types.HasGenericAlias} HasGenericAlias * @property {test$types.EnumMacroAttributes} EnumMacroAttributes * @property {test$types.InlineEnumField} InlineEnumField * @property {test$types.InlineOptionalType} InlineOptionalType * @property {test$types.Rename} Rename * @property {test$types.TransparentType} TransparentType * @property {test$types.TransparentType2} TransparentType2 * @property {test$types.TransparentTypeWithOverride} TransparentTypeWithOverride * @property {[(number | null), (number | null), (number | null)]} "[Option; 3]" * @property {Partial<{ [key in test$types.BasicEnum]: null }>} "HashMap" * @property {Partial<{ [key in test$types.BasicEnum]: number }>} "HashMap" * @property {number | null} "Option>>>" * @property {test$types.PlaceholderInnerField[]} "Vec" * @property {test$types.EnumReferenceRecordKey} EnumReferenceRecordKey * @property {test$types.FlattenOnNestedEnum} FlattenOnNestedEnum * @property {test$types.MyEmptyInput} MyEmptyInput * @property {string} "(String)" * @property {[string]} "(String,)" * @property {test$types.ExtraBracketsInTupleVariant} ExtraBracketsInTupleVariant * @property {test$types.ExtraBracketsInUnnamedStruct} ExtraBracketsInUnnamedStruct * @property {test$types.MyEnum[]} "Vec" * @property {test$types.InlineTuple} InlineTuple * @property {test$types.InlineTuple2} InlineTuple2 * @property {string} "Box" * @property {string} "Box" * @property {test$types.SkippedFieldWithinVariant} SkippedFieldWithinVariant * @property {test$types.KebabCase} KebabCase * @property {string[]} "&[&str]" * @property {test$types.Issue281} "Issue281<'_>" * @property {test$types.LifetimeGenericStruct} "LifetimeGenericStruct<'_, i32>" * @property {test$types.LifetimeGenericEnum} "LifetimeGenericEnum<'_, i32>" * @property {test$types.RenameWithWeirdCharsField} RenameWithWeirdCharsField * @property {test$types.RenameWithWeirdCharsVariant} RenameWithWeirdCharsVariant * @property {test$types.RenamedFieldKeys} RenamedFieldKeys * @property {test$types.RenamedVariantWithSkippedPayload} RenamedVariantWithSkippedPayload * @property {test$types$type_type.Type} "type_type::Type" * @property {test$types.ActualType} ActualType * @property {test$types.SpectaTypeOverride} SpectaTypeOverride * @property {test$types.ContainerTypeOverrideStruct} ContainerTypeOverrideStruct * @property {test$types.ContainerTypeOverrideEnum} ContainerTypeOverrideEnum * @property {test$types.ContainerTypeOverrideGeneric} "ContainerTypeOverrideGeneric>" * @property {test$types.ContainerTypeOverrideToGeneric} "ContainerTypeOverrideToGeneric" * @property {test$types.ContainerTypeOverrideTuple} ContainerTypeOverrideTuple * @property {test$types.ContainerTypeOverrideTupleGeneric} "ContainerTypeOverrideTupleGeneric" * @property {test$types.InvalidToValidType} InvalidToValidType * @property {test$types.TupleStruct} TupleStruct * @property {test$types.TupleStructWithRep} TupleStructWithRep * @property {test$types.GenericTupleStruct} "GenericTupleStruct" * @property {test$types.BracedStruct} BracedStruct * @property {test$types.StructNew} Struct * @property {test$types.Struct2} Struct2 * @property {test$types.Enum} Enum * @property {test$types.Enum2} Enum2 * @property {test$types.Enum3} Enum3 * @property {test$types.StructRenameAllUppercase} StructRenameAllUppercase * @property {test$types.RenameSerdeSpecialChar} RenameSerdeSpecialChar * @property {test$types.EnumRenameAllUppercase} EnumRenameAllUppercase * @property {test$types.Recursive} Recursive * @property {test$types.RecursiveMapValue} RecursiveMapValue * @property {test$types.RecursiveTransparent} RecursiveTransparent * @property {test$types.RecursiveInEnum} RecursiveInEnum * @property {test$types.NonOptional} NonOptional * @property {test$types.OptionalOnNamedField} OptionalOnNamedField * @property {test$types.OptionalOnTransparentNamedField} OptionalOnTransparentNamedField * @property {test$types.OptionalInEnum} OptionalInEnum * @property {test$types.UntaggedVariants} UntaggedVariants * @property {test$types.UntaggedVariantsWithoutValue} UntaggedVariantsWithoutValue * @property {test$types.UntaggedVariantsWithDuplicateBranches} UntaggedVariantsWithDuplicateBranches * @property {{ [key in string]: null }} "HashMap" * @property {test$types.Regular} Regular * @property {{ [key in never]: null }} "HashMap" * @property {{ [key in test$types.TransparentStruct]: null }} "HashMap" * @property {Partial<{ [key in test$types.UnitVariants]: null }>} "HashMap" * @property {Partial<{ [key in test$types.UntaggedVariantsKey]: null }>} "HashMap" * @property {test$types.ValidMaybeValidKey} ValidMaybeValidKey * @property {test$types.ValidMaybeValidKeyNested} ValidMaybeValidKeyNested * @property {test$types.MacroStruct} MacroStruct * @property {test$types.MacroStruct2} MacroStruct2 * @property {test$types.MacroEnum} MacroEnum * @property {test$types.DeprecatedType} DeprecatedType * @property {test$types.DeprecatedTypeWithMsg} DeprecatedTypeWithMsg * @property {test$types.DeprecatedTypeWithMsg2} DeprecatedTypeWithMsg2 * @property {test$types.DeprecatedFields} DeprecatedFields * @property {test$types.DeprecatedTupleVariant} DeprecatedTupleVariant * @property {test$types.DeprecatedEnumVariants} DeprecatedEnumVariants * @property {test$types.CommentedStruct} CommentedStruct * @property {test$types.CommentedEnum} CommentedEnum * @property {test$types.SingleLineComment} SingleLineComment * @property {test$types.Demo} NonGeneric * @property {test$types.Demo} "HalfGenericA" * @property {test$types.Demo} "HalfGenericB" * @property {test$types.Demo} "FullGeneric" * @property {test$types.Demo} "Another" * @property {{ [key in string]: number }} "MapA" * @property {{ [key in number]: string }} "MapB" * @property {{ [key in string]: test$types.AGenericStruct }} "MapC" * @property {test$types.AGenericStruct} "AGenericStruct" * @property {test$types.A} A * @property {test$types.DoubleFlattened} DoubleFlattened * @property {test$types.FlattenedInner} FlattenedInner * @property {test$types.BoxFlattened} BoxFlattened * @property {test$types.BoxInline} BoxInline * @property {test$types.First} First * @property {test$types.Second} Second * @property {test$types.Third} Third * @property {test$types.Fourth} Fourth * @property {test$types.TagOnStructWithInline} TagOnStructWithInline * @property {test$types.Sixth} Sixth * @property {test$types.Seventh} Seventh * @property {test$types.Eight} Eight * @property {test$types.Ninth} Ninth * @property {test$types.Tenth} Tenth * @property {test$types.MyEnumTagged} MyEnumTagged * @property {test$types.MyEnumExternal} MyEnumExternal * @property {test$types.MyEnumAdjacent} MyEnumAdjacent * @property {test$types.MyEnumUntagged} MyEnumUntagged * @property {test$types.EmptyStruct} EmptyStruct * @property {test$types.EmptyStructWithTag} EmptyStructWithTag * @property {test$types.AdjacentlyTagged} AdjacentlyTagged * @property {test$types.LoadProjectEvent} LoadProjectEvent * @property {test$types.ExternallyTagged} ExternallyTagged * @property {test$types.Issue221External} Issue221External * @property {test$types.InternallyTaggedD} InternallyTaggedD * @property {test$types.InternallyTaggedE} InternallyTaggedE * @property {test$types.InternallyTaggedF} InternallyTaggedF * @property {test$types.InternallyTaggedH} InternallyTaggedH * @property {test$types.InternallyTaggedL} InternallyTaggedL * @property {test$types.InternallyTaggedM} InternallyTaggedM * @property {test$types.StructWithAlias} StructWithAlias * @property {test$types.StructWithMultipleAliases} StructWithMultipleAliases * @property {test$types.StructWithAliasAndRename} StructWithAliasAndRename * @property {test$types.EnumWithVariantAlias} EnumWithVariantAlias * @property {test$types.EnumWithMultipleVariantAliases} EnumWithMultipleVariantAliases * @property {test$types.EnumWithVariantAliasAndRename} EnumWithVariantAliasAndRename * @property {test$types.InternallyTaggedWithAlias} InternallyTaggedWithAlias * @property {test$types.AdjacentlyTaggedWithAlias} AdjacentlyTaggedWithAlias * @property {test$types.UntaggedWithAlias} UntaggedWithAlias * @property {test$types.Issue221UntaggedSafe} Issue221UntaggedSafe * @property {test$types.Issue221UntaggedMixed} Issue221UntaggedMixed * @property {test$types.EmptyEnum} EmptyEnum * @property {test$types.EmptyEnumTagged} EmptyEnumTagged * @property {test$types.EmptyEnumTaggedWContent} EmptyEnumTaggedWContent * @property {test$types.EmptyEnumUntagged} EmptyEnumUntagged * @property {test$types.SkipOnlyField} SkipOnlyField * @property {test$types.SkipField} SkipField * @property {test$types.SkipVariant} SkipVariant * @property {test$types.SkipUnnamedFieldInVariant} SkipUnnamedFieldInVariant * @property {test$types.SkipNamedFieldInVariant} SkipNamedFieldInVariant * @property {test$types.TransparentWithSkip} TransparentWithSkip * @property {test$types.TransparentWithSkip2} TransparentWithSkip2 * @property {test$types.TransparentWithSkip3} TransparentWithSkip3 * @property {test$types.SkipVariant2} SkipVariant2 * @property {test$types.SkipVariant3} SkipVariant3 * @property {test$types.SkipStructFields} SkipStructFields * @property {test$types.SpectaSkipNonTypeField} SpectaSkipNonTypeField * @property {test$types.FlattenA} FlattenA * @property {test$types.FlattenB} FlattenB * @property {test$types.FlattenC} FlattenC * @property {test$types.FlattenD} FlattenD * @property {test$types.FlattenE} FlattenE * @property {test$types.FlattenF} FlattenF * @property {test$types.FlattenG} FlattenG * @property {test$types.TupleNested} TupleNested * @property {test$types.Generic1} "Generic1<()>" * @property {test$types.GenericAutoBound} "GenericAutoBound<()>" * @property {test$types.GenericAutoBound2} "GenericAutoBound2<()>" * @property {test$types.Container1} Container1 * @property {test$types.Generic2} "Generic2<(), String, i32>" * @property {test$types.GenericNewType1} "GenericNewType1<()>" * @property {test$types.GenericTuple} "GenericTuple<()>" * @property {test$types.GenericStruct2} "GenericStruct2<()>" * @property {string} "InlineGenericNewtype" * @property {[string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | ({ Unnamed: string }) & { Named?: never } | ({ Named: { * value: string, * } }) & { Unnamed?: never }]} "InlineGenericNested" * @property {test$types.InlineFlattenGenericsG} "InlineFlattenGenericsG<()>" * @property {test$types.InlineFlattenGenerics} InlineFlattenGenerics * @property {test$types.GenericDefault} GenericDefault * @property {test$types.ChainedGenericDefault} ChainedGenericDefault * @property {test$types.ChainedGenericDefault} "ChainedGenericDefault" * @property {test$types.ChainedGenericDefault} "ChainedGenericDefault" * @property {test$types.ChainedGenericDefault} "ChainedGenericDefault" * @property {test$types.GenericDefaultSkipped} GenericDefaultSkipped * @property {test$types.GenericDefaultSkippedNonType} GenericDefaultSkippedNonType * @property {test$types.GenericParameterOrderPreserved} GenericParameterOrderPreserved * @property {test$types.ConstGenericInNonConstContainer} ConstGenericInNonConstContainer * @property {test$types.ConstGenericInConstContainer} ConstGenericInConstContainer * @property {test$types.NamedConstGenericContainer} NamedConstGenericContainer * @property {test$types.InlineConstGenericContainer} InlineConstGenericContainer * @property {test$types.InlineRecursiveConstGenericContainer} InlineRecursiveConstGenericContainer * @property {test$types.TestCollectionRegister} TestCollectionRegister * @property {test$types.TestCollectionRegister} TestCollectionRegister */ ════════════════════════════════════════ ================================================ FILE: tests/tests/snapshots/test__jsdoc__jsdoc-export-to-files-serde_phases.snap ================================================ --- source: tests/tests/jsdoc.rs expression: output --- std/ ops.js (295 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. /** * @typedef {{ * start: T, * end: T, * }} Range * @property {T} start * @property {T} end * * @typedef {{ * start: T, * end: T, * }} RangeInclusive * @property {T} start * @property {T} end */ ════════════════════════════════════════ result.js (181 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. /** * @typedef {{ * ok: T, * err: E, * }} Result * @property {T} ok * @property {E} err */ ════════════════════════════════════════ test/ types/ type_type.js (108 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. /** * @typedef {never} Type */ ════════════════════════════════════════ types.js (32192 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. /** * @typedef {{ * a: B, * b: { * b: number, * }, * c: B, * d: { * flattened: number, * }, * e: { * generic_flattened: number, * }, * }} A * @property {B} a * @property {{ * b: number, * }} b * @property {B} c * @property {{ * flattened: number, * }} d * @property {{ * generic_flattened: number, * }} e * * @typedef {{ * field: Demo, * }} AGenericStruct * @property {Demo} field * * @typedef {{ * a: GenericType, * }} ActualType * @property {GenericType} a * * @typedef {{ t: "A" } | { t: "B"; c: { * id: string, * method: string, * } } | { t: "C"; c: string }} AdjacentlyTagged * @property {{ t: "A" }} A * @property {{ t: "B"; c: { * id: string, * method: string, * } }} B * @property {{ t: "C"; c: string }} C * * @typedef {{ type: "A"; data: { * field: string, * } } | { type: "B"; data: { * other: number, * } }} AdjacentlyTaggedWithAlias * @property {{ type: "A"; data: { * field: string, * } }} A * @property {{ type: "B"; data: { * other: number, * } }} B * * @typedef {{ * b: number, * }} B * @property {number} b * * @typedef {"A" | "B"} BasicEnum * @property {"A"} A * @property {"B"} B * * @typedef {BoxedInner} BoxFlattened * * @typedef {{ * c: { * a: number, * }, * }} BoxInline * @property {{ * a: number, * }} c * * @typedef {{ * a: number, * }} BoxedInner * @property {number} a * * @typedef {string} BracedStruct * @property {string} "0" * * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second * * Some triple-slash comment * Some more triple-slash comment * * @typedef { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * ({ A: number }) & { B?: never } | * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * ({ B: { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * } }) & { A?: never }} CommentedEnum * @property { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * { A: number }} A - Some triple-slash comment Some more triple-slash comment * @property { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * { B: { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * } }} B - Some triple-slash comment Some more triple-slash comment * * Some triple-slash comment * Some more triple-slash comment * * @typedef {{ * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * }} CommentedStruct * @property {number} a - Some triple-slash comment Some more triple-slash comment * * @typedef {{ * data: number[], * a: number[], * d: [number, number], * }} ConstGenericInConstContainer * @property {number[]} data * @property {number[]} a * @property {[number, number]} d * * @typedef {{ * data: [number], * a: [number, number], * d: [number, number], * }} ConstGenericInNonConstContainer * @property {[number]} data * @property {[number, number]} a * @property {[number, number]} d * * @typedef {{ * foo: Generic1, * bar: Generic1[], * baz: { [key in string]: Generic1 }, * }} Container1 * @property {Generic1} foo * @property {Generic1[]} bar * @property {{ [key in string]: Generic1 }} baz * * @typedef {string} ContainerTypeOverrideEnum * * @typedef {string} ContainerTypeOverrideGeneric * * @typedef {string} ContainerTypeOverrideStruct * * @typedef {T} ContainerTypeOverrideToGeneric * * @typedef {[string, number]} ContainerTypeOverrideTuple * * @typedef {[T, string]} ContainerTypeOverrideTupleGeneric * * @typedef {{ * flattened: number, * }} D * @property {number} flattened * * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b * * @typedef { * /** * * @deprecated * */ * "A" | * /** * * @deprecated Nope * */ * "B" | * /** * * @deprecated Nope * */ * "C"} DeprecatedEnumVariants * @property { * /** * * @deprecated * */ * "A"} A - @deprecated * @property { * /** * * @deprecated Nope * */ * "B"} B - @deprecated Nope * @property { * /** * * @deprecated Nope * */ * "C"} C - @deprecated Nope * * @typedef {{ * a: number, * /** * * @deprecated * */ * b: string, * /** * * @deprecated This field is cringe! * */ * c: string, * /** * * @deprecated This field is cringe! * */ * d: string, * }} DeprecatedFields * @property {number} a * @property {string} b - @deprecated * @property {string} c - @deprecated This field is cringe! * @property {string} d - @deprecated This field is cringe! * * @typedef {[ * /** * * @deprecated * */ * string, * /** * * @deprecated Nope * */ * string, * /** * * @deprecated Nope * */ * number]} DeprecatedTupleVariant * @property {string} "0" - @deprecated * @property {string} "1" - @deprecated Nope * @property {number} "2" - @deprecated Nope * * @deprecated * @typedef {{ * a: number, * }} DeprecatedType * @property {number} a * * @deprecated Look at you big man using a deprecation message * @typedef {{ * a: number, * }} DeprecatedTypeWithMsg * @property {number} a * * @deprecated Look at you big man using a deprecation message * @typedef {{ * a: number, * }} DeprecatedTypeWithMsg2 * @property {number} a * * @typedef {{ * a: ToBeFlattened, * b: ToBeFlattened, * }} DoubleFlattened * @property {ToBeFlattened} a * @property {ToBeFlattened} b * * @typedef {{ A: string } | "B"} Eight * @property {{ A: string }} A * @property {"B"} B * * @typedef {never} EmptyEnum * * @typedef {never} EmptyEnumTagged * * @typedef {never} EmptyEnumTaggedWContent * * @typedef {never} EmptyEnumUntagged * * @typedef {Record} EmptyStruct * * @typedef {{ * a: "EmptyStructWithTag", * }} EmptyStructWithTag * @property {"EmptyStructWithTag"} a * * @typedef {{ t: "A" } | { t: "B" }} Enum * @property {{ t: "A" }} A * @property {{ t: "B" }} B * * @typedef {{ t: "C" } | { t: "B" } | { t: "D"; enumField: null }} Enum2 * @property {{ t: "C" }} C * @property {{ t: "B" }} B * @property {{ t: "D"; enumField: null }} D * * @typedef {{ t: "A"; b: string }} Enum3 * @property {{ t: "A"; b: string }} A * * @typedef {({ A: string }) & { D?: never; bbb?: never; cccc?: never } | ({ bbb: number }) & { A?: never; D?: never; cccc?: never } | ({ cccc: number }) & { A?: never; D?: never; bbb?: never } | ({ D: { * a: string, * bbbbbb: number, * } }) & { A?: never; bbb?: never; cccc?: never }} EnumMacroAttributes * @property {{ A: string }} A * @property {{ bbb: number }} bbb * @property {{ cccc: number }} cccc * @property {{ D: { * a: string, * bbbbbb: number, * } }} D * * @typedef {{ * a: Partial<{ [key in BasicEnum]: number }>, * }} EnumReferenceRecordKey * @property {Partial<{ [key in BasicEnum]: number }>} a * * @typedef {"HELLOWORLD" | "VARIANTB" | "TESTINGWORDS"} EnumRenameAllUppercase * @property {"HELLOWORLD"} HELLOWORLD * @property {"VARIANTB"} VARIANTB * @property {"TESTINGWORDS"} TESTINGWORDS * * @typedef {"Variant" | "Other"} EnumWithMultipleVariantAliases * @property {"Variant"} Variant * @property {"Other"} Other * * @typedef {"Variant" | "Other"} EnumWithVariantAlias * @property {"Variant"} Variant * @property {"Other"} Other * * @typedef {"renamed_variant" | "Other"} EnumWithVariantAliasAndRename * @property {"renamed_variant"} renamed_variant * @property {"Other"} Other * * @typedef {"A" | ({ B: { * id: string, * method: string, * } }) & { C?: never } | ({ C: string }) & { B?: never }} ExternallyTagged * @property {"A"} A * @property {{ B: { * id: string, * method: string, * } }} B * @property {{ C: string }} C * * @typedef {{ A: string }} ExtraBracketsInTupleVariant * @property {{ A: string }} A * * @typedef {string} ExtraBracketsInUnnamedStruct * @property {string} "0" * * @typedef {{ * a: string, * }} First * @property {string} a * * @typedef {{ * a: number, * b: number, * }} FlattenA * @property {number} a * @property {number} b * * @typedef {{ * c: number, * } & FlattenA} FlattenB * @property {number} c * * @typedef {{ * c: number, * } & FlattenA} FlattenC * @property {number} c * * @typedef {{ * a: FlattenA, * c: number, * }} FlattenD * @property {FlattenA} a * @property {number} c * * @typedef {{ * b: ({ * c: number, * }) & (FlattenA), * d: number, * }} FlattenE * @property {({ * c: number, * }) & (FlattenA)} b * @property {number} d * * @typedef {{ tag: "One" } | { tag: "Two" } | { tag: "Three" }} FlattenEnum * @property {{ tag: "One" }} One * @property {{ tag: "Two" }} Two * @property {{ tag: "Three" }} Three * * @typedef {{ * outer: string, * } & FlattenEnum} FlattenEnumStruct * @property {string} outer * * @typedef {{ * b: ({ * c: number, * }) & (FlattenA), * d: number, * }} FlattenF * @property {({ * c: number, * }) & (FlattenA)} b * @property {number} d * * @typedef {{ * b: FlattenB, * d: number, * }} FlattenG * @property {FlattenB} b * @property {number} d * * @typedef {{ * id: string, * } & NestedEnum} FlattenOnNestedEnum * @property {string} id * * @typedef {Inner} FlattenedInner * * @typedef {{ * a: First, * b: { * a: string, * }, * }} Fourth * @property {First} a * @property {{ * a: string, * }} b * * @typedef {{ * value: T, * values: T[], * }} Generic1 * @property {T} value * @property {T[]} values * * @typedef {({ A: A }) & { B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ B: [B, B, B] }) & { A?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ C: C[] }) & { A?: never; B?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ D: A[][][] }) & { A?: never; B?: never; C?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ E: { * a: A, * b: B, * c: C, * } }) & { A?: never; B?: never; C?: never; D?: never; X?: never; Y?: never; Z?: never } | ({ X: number[] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; Y?: never; Z?: never } | ({ Y: number }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Z?: never } | ({ Z: number[][] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never }} Generic2 * @property {{ A: A }} A * @property {{ B: [B, B, B] }} B * @property {{ C: C[] }} C * @property {{ D: A[][][] }} D * @property {{ E: { * a: A, * b: B, * c: C, * } }} E * @property {{ X: number[] }} X * @property {{ Y: number }} Y * @property {{ Z: number[][] }} Z * * @typedef {{ * value: T, * values: T[], * }} GenericAutoBound * @property {T} value * @property {T[]} values * * @typedef {{ * value: T, * values: T[], * }} GenericAutoBound2 * @property {T} value * @property {T[]} values * * @typedef {{ * value: T, * }} GenericDefault * @property {T} value * * @typedef {{ * value: T, * }} GenericDefaultSkipped * @property {T} value * * @typedef {{ * value: number, * }} GenericDefaultSkippedNonType * @property {number} value * * @typedef {{ * generic_flattened: T, * }} GenericFlattened * @property {T} generic_flattened * * @typedef {T[][]} GenericNewType1 * @property {T[][]} "0" * * @typedef {{ * pair: Pair, * }} GenericParameterOrderPreserved * @property {Pair} pair * * @typedef {{ * arg: T, * }} GenericStruct * @property {T} arg * * @typedef {{ * a: T, * b: [T, T], * c: [T, [T, T]], * d: [T, T, T], * e: [([T, T]), ([T, T]), ([T, T])], * f: T[], * g: T[][], * h: ([([T, T]), ([T, T]), ([T, T])])[], * }} GenericStruct2 * @property {T} a * @property {[T, T]} b * @property {[T, [T, T]]} c * @property {[T, T, T]} d * @property {[([T, T]), ([T, T]), ([T, T])]} e * @property {T[]} f * @property {T[][]} g * @property {([([T, T]), ([T, T]), ([T, T])])[]} h * * @typedef {[T, T[], T[][]]} GenericTuple * @property {T} "0" * @property {T[]} "1" * @property {T[][]} "2" * * @typedef {T} GenericTupleStruct * @property {T} "0" * * @typedef {"Undefined" | T} GenericType * @property {"Undefined"} Undefined * @property {T} Value * * @typedef {{ [key in number]: string }} HasGenericAlias * @property {{ [key in number]: string }} "0" * * @typedef {{ * b: { * data: [number, number], * a: [number, number], * d: [number, number, number], * }, * c: { * data: [number, number, number], * a: [number, number], * d: [number, number, number], * }, * d: [number, number], * }} InlineConstGenericContainer * @property {{ * data: [number, number], * a: [number, number], * d: [number, number, number], * }} b * @property {{ * data: [number, number, number], * a: [number, number], * d: [number, number, number], * }} c * @property {[number, number]} d * * @typedef {{ A: { * a: string, * } }} InlineEnumField * @property {{ A: { * a: string, * } }} A * * @typedef {{ * g: InlineFlattenGenericsG, * gi: { * t: string, * }, * } & InlineFlattenGenericsG} InlineFlattenGenerics * @property {InlineFlattenGenericsG} g * @property {{ * t: string, * }} gi * * @typedef {{ * t: T, * }} InlineFlattenGenericsG * @property {T} t * * @typedef {{ * optional_field: { * a: string, * } | null, * }} InlineOptionalType * @property {{ * a: string, * } | null} optional_field * * @typedef {{ * data: number[], * a: number[], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }} InlineRecursiveConstGeneric * @property {number[]} data * @property {number[]} a * @property {[number, number, number]} d * @property {InlineRecursiveConstGeneric} e * * @typedef {{ * b: { * data: [number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }, * c: { * data: [number, number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }, * d: [number, number], * }} InlineRecursiveConstGenericContainer * @property {{ * data: [number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }} b * @property {{ * data: [number, number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }} c * @property {[number, number]} d * * @typedef {{ * ref_struct: SimpleStruct, * val: number, * }} InlineStruct * @property {SimpleStruct} ref_struct * @property {number} val * * @typedef {{ * demo: [string, boolean], * }} InlineTuple * @property {[string, boolean]} demo * * @typedef {{ * demo: [{ * demo: [string, boolean], * }, boolean], * }} InlineTuple2 * @property {[{ * demo: [string, boolean], * }, boolean]} demo * * @typedef {{ * inline_this: { * ref_struct: SimpleStruct, * val: number, * }, * dont_inline_this: RefStruct, * }} InlinerStruct * @property {{ * ref_struct: SimpleStruct, * val: number, * }} inline_this * @property {RefStruct} dont_inline_this * * @typedef {{ * a: number, * } & FlattenedInner} Inner * @property {number} a * * @typedef {{ * type: "A", * } & { [key in string]: string }} InternallyTaggedD * @property {{ * type: "A", * } & { [key in string]: string }} A * * @typedef {{ type: "A" }} InternallyTaggedE * @property {{ type: "A" }} A * * @typedef {{ type: "A" }} InternallyTaggedF * @property {{ type: "A" }} A * * @typedef {null} InternallyTaggedFInner * @property {null} A * * @typedef {{ type: "A" }} InternallyTaggedH * @property {{ type: "A" }} A * * @typedef {null} InternallyTaggedHInner * @property {null} "0" * * @typedef {{ * type: "A", * } & { type: "A" } | { type: "B" }} InternallyTaggedL * @property {{ * type: "A", * } & { type: "A" } | { type: "B" }} A * * @typedef {{ type: "A" } | { type: "B" }} InternallyTaggedLInner * @property {{ type: "A" }} A * @property {{ type: "B" }} B * * @typedef {{ type: "A" }} InternallyTaggedM * @property {{ type: "A" }} A * * @typedef {"A" | "B"} InternallyTaggedMInner * @property {"A"} A * @property {"B"} B * * @typedef {{ type: "A"; field: string } | { type: "B"; other: number }} InternallyTaggedWithAlias * @property {{ type: "A"; field: string }} A * @property {{ type: "B"; other: number }} B * * @typedef {{ * cause: null, * }} InvalidToValidType * @property {null} cause * * @typedef {({ A: { * a: string, * } }) & { B?: never } | ({ B: { * b: string, * } }) & { A?: never }} Issue221External * @property {{ A: { * a: string, * } }} A * @property {{ B: { * b: string, * } }} B * * @typedef {({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never }} Issue221UntaggedMixed * @property {{ a: string }} A * @property {{ b: string }} B * @property {{ values: { [key in string]: string } }} Unsafe * * @typedef {({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }} Issue221UntaggedSafe * @property {{ a: string }} A * @property {{ b: string }} B * * @typedef {{ * default_unity_arguments: string[], * }} Issue281 * @property {string[]} default_unity_arguments * * https://github.com/specta-rs/specta/issues/374 * * @typedef {Issue374_Serialize | Issue374_Deserialize} Issue374 * @property {Issue374_Serialize} Serialize * @property {Issue374_Deserialize} Deserialize * * https://github.com/specta-rs/specta/issues/374 * * @typedef {{ * foo?: boolean, * bar?: boolean, * }} Issue374_Deserialize * @property {boolean} [foo] * @property {boolean} [bar] * * https://github.com/specta-rs/specta/issues/374 * * @typedef {{ * foo?: boolean, * bar?: boolean, * }} Issue374_Serialize * @property {boolean} [foo] * @property {boolean} [bar] * * @typedef {{ * "test-ing": string, * }} KebabCase * @property {string} "test-ing" * * @typedef {({ Borrowed: T }) & { Owned?: never } | ({ Owned: T }) & { Borrowed?: never }} LifetimeGenericEnum * @property {{ Borrowed: T }} Borrowed * @property {{ Owned: T }} Owned * * @typedef {{ * borrowed: T[], * owned: T[], * }} LifetimeGenericStruct * @property {T[]} borrowed * @property {T[]} owned * * @typedef {{ event: "started"; data: { * projectName: string, * } } | { event: "progressTest"; data: { * projectName: string, * status: string, * progress: number, * } } | { event: "finished"; data: { * projectName: string, * } }} LoadProjectEvent * @property {{ event: "started"; data: { * projectName: string, * } }} started * @property {{ event: "progressTest"; data: { * projectName: string, * status: string, * progress: number, * } }} progressTest * @property {{ event: "finished"; data: { * projectName: string, * } }} finished * * @typedef {({ Demo: string }) & { Demo2?: never } | ({ Demo2: { * demo2: string, * } }) & { Demo?: never }} MacroEnum * @property {{ Demo: string }} Demo * @property {{ Demo2: { * demo2: string, * } }} Demo2 * * @typedef {string} MacroStruct * @property {string} "0" * * @typedef {{ * demo: string, * }} MacroStruct2 * @property {string} demo * * @typedef {T} MaybeValidKey * @property {T} "0" * * @typedef {Record} MyEmptyInput * * @typedef {({ A: string }) & { B?: never } | ({ B: number }) & { A?: never }} MyEnum * @property {{ A: string }} A * @property {{ B: number }} B * * @typedef {{ t: "Variant"; c: { * inner: First, * } }} MyEnumAdjacent * @property {{ t: "Variant"; c: { * inner: First, * } }} Variant * * @typedef {{ Variant: { * inner: First, * } }} MyEnumExternal * @property {{ Variant: { * inner: First, * } }} Variant * * @typedef {{ type: "Variant"; inner: First }} MyEnumTagged * @property {{ type: "Variant"; inner: First }} Variant * * @typedef {{ inner: First }} MyEnumUntagged * @property {{ inner: First }} Variant * * @typedef {{ * data: number[], * a: number[], * d: [number, number], * }} NamedConstGeneric * @property {number[]} data * @property {number[]} a * @property {[number, number]} d * * @typedef {{ * a: NamedConstGeneric, * b: NamedConstGeneric, * d: [number, number], * }} NamedConstGenericContainer * @property {NamedConstGeneric} a * @property {NamedConstGeneric} b * @property {[number, number]} d * * @typedef {{ type: "a"; value: string } | { type: "b"; value: number }} NestedEnum * @property {{ type: "a"; value: string }} a * @property {{ type: "b"; value: number }} b * * @typedef {{ t: "A"; c: string } | { t: "B" } | { t: "C"; c: { * a: string, * } } | { t: "D"; c: First }} Ninth * @property {{ t: "A"; c: string }} A * @property {{ t: "B" }} B * @property {{ t: "C"; c: { * a: string, * } }} C * @property {{ t: "D"; c: First }} D * * @typedef {string | null} NonOptional * @property {string | null} "0" * * @typedef {Optional_Serialize | Optional_Deserialize} Optional * @property {Optional_Serialize} Serialize * @property {Optional_Deserialize} Deserialize * * @typedef {({ A?: string | null }) & { B?: never; C?: never } | ({ B: { * a: string | null, * } }) & { A?: never; C?: never } | ({ C: { * a?: string | null, * } }) & { A?: never; B?: never }} OptionalInEnum * @property {{ A?: string | null }} A * @property {{ B: { * a: string | null, * } }} B * @property {{ C: { * a?: string | null, * } }} C * * @typedef {string | null} OptionalOnNamedField * @property {string | null} ["0"] * * @typedef {{ * b: string | null, * }} OptionalOnTransparentNamedField * @property {string | null} b * * @typedef {{ * a: number | null, * b?: number | null, * c: string | null, * d?: boolean, * }} Optional_Deserialize * @property {number | null} a * @property {number | null} [b] * @property {string | null} c * @property {boolean} [d] * * @typedef {{ * a: number | null, * b?: number | null, * c?: string | null, * d: boolean, * }} Optional_Serialize * @property {number | null} a * @property {number | null} [b] * @property {string | null} [c] * @property {boolean} d * * @typedef {{ * overriden_field: string, * }} OverridenStruct * @property {string} overriden_field * * @typedef {{ * first: Z, * second: A, * }} Pair * @property {Z} first * @property {A} second * * @typedef {{ * a: string, * }} PlaceholderInnerField * @property {string} a * * @typedef {{ * demo: Recursive, * }} Recursive * @property {Recursive} demo * * @typedef {{ A: { * demo: RecursiveInEnum, * } }} RecursiveInEnum * @property {{ A: { * demo: RecursiveInEnum, * } }} A * * @typedef {RecursiveInline} RecursiveInline * * @typedef {{ * demo: { [key in string]: RecursiveMapValue }, * }} RecursiveMapValue * @property {{ [key in string]: RecursiveMapValue }} demo * * @typedef {RecursiveInline} RecursiveTransparent * @property {RecursiveInline} "0" * * @typedef {TestEnum} RefStruct * @property {TestEnum} "0" * * @typedef {{ [key in string]: null }} Regular * @property {{ [key in string]: null }} "0" * * @typedef {"OneWord" | "Two words"} Rename * @property {"OneWord"} OneWord * @property {"Two words"} "Two words" * * @typedef {{ * "a/b": number, * }} RenameSerdeSpecialChar * @property {number} "a/b" * * @typedef {{ * "@odata.context": string, * }} RenameWithWeirdCharsField * @property {string} "@odata.context" * * @typedef {{ "@odata.context": string }} RenameWithWeirdCharsVariant * @property {{ "@odata.context": string }} "@odata.context" * * @typedef {{ * "": string, * "a\"b": string, * "a\\b": string, * "line\nbreak": string, * "line\u2028break": string, * "line\u2029break": string, * }} RenamedFieldKeys * @property {string} "" * @property {string} "a\"b" * @property {string} "a\\b" * @property {string} "line\nbreak" * @property {string} "line\u2028break" * @property {string} "line\u2029break" * * @typedef {"a-b"} RenamedVariantWithSkippedPayload * @property {"a-b"} "a-b" * * @typedef {{ * a: number, * }} Second * @property {number} a * * @typedef {{ * a: First, * b: Second, * }} Seventh * @property {First} a * @property {Second} b * * @typedef {{ * a: number, * b: string, * c: [number, string, number], * d: string[], * e: string | null, * }} SimpleStruct * @property {number} a * @property {string} b * @property {[number, string, number]} c * @property {string[]} d * @property {string | null} e * * Some single-line comment * * @typedef { * /** Some single-line comment */ * ({ A: number }) & { B?: never } | * /** Some single-line comment */ * ({ B: { * /** Some single-line comment */ * a: number, * } }) & { A?: never }} SingleLineComment * @property { * /** Some single-line comment */ * { A: number }} A - Some single-line comment * @property { * /** Some single-line comment */ * { B: { * /** Some single-line comment */ * a: number, * } }} B - Some single-line comment * * @typedef {{ * a: First, * b: First, * }} Sixth * @property {First} a * @property {First} b * * @typedef {{ * b: number, * }} SkipField * @property {number} b * * @typedef {({ A: Record }) & { B?: never } | ({ B: { * b: number, * } }) & { A?: never }} SkipNamedFieldInVariant * @property {{ A: Record }} A * @property {{ B: { * b: number, * } }} B * * @typedef {Record} SkipOnlyField * * @typedef {{ * a: number, * }} SkipStructFields * @property {number} a * * @typedef {"A" | { B: [number] }} SkipUnnamedFieldInVariant * @property {"A"} A * @property {{ B: [number] }} B * * @typedef {{ A: string }} SkipVariant * @property {{ A: string }} A * * @typedef {{ tag: "A"; data: string }} SkipVariant2 * @property {{ tag: "A"; data: string }} A * * @typedef {{ A: { * a: string, * } }} SkipVariant3 * @property {{ A: { * a: string, * } }} A * * @typedef {{ type: "A" } | { type: "B"; data: string }} SkippedFieldWithinVariant * @property {{ type: "A" }} A * @property {{ type: "B"; data: string }} B * * @typedef {{ * a: number, * }} SpectaSkipNonTypeField * @property {number} a * * @typedef {{ * string_ident: string, * u32_ident: number, * path: string, * tuple: [string, number], * }} SpectaTypeOverride * @property {string} string_ident * @property {number} u32_ident * @property {string} path * @property {[string, number]} tuple * * @typedef {{ * b: string, * }} Struct2 * @property {string} b * * @typedef {{ * t: "StructNew", * a: string, * }} StructNew * @property {"StructNew"} t * @property {string} a * * @typedef {StructPhaseSpecificRenameSerialize | StructPhaseSpecificRenameDeserialize} StructPhaseSpecificRename * @property {StructPhaseSpecificRenameSerialize} Serialize * @property {StructPhaseSpecificRenameDeserialize} Deserialize * * @typedef {{ * kind: "StructPhaseSpecificRenameDeserialize", * der: string, * }} StructPhaseSpecificRenameDeserialize * @property {"StructPhaseSpecificRenameDeserialize"} kind * @property {string} der * * @typedef {{ * kind: "StructPhaseSpecificRenameSerialize", * ser: string, * }} StructPhaseSpecificRenameSerialize * @property {"StructPhaseSpecificRenameSerialize"} kind * @property {string} ser * * @typedef {{ * A: number, * B: number, * }} StructRenameAllUppercase * @property {number} A * @property {number} B * * @typedef {{ * field: string, * }} StructWithAlias * @property {string} field * * @typedef {{ * renamed_field: string, * }} StructWithAliasAndRename * @property {string} renamed_field * * @typedef {{ * field: string, * }} StructWithMultipleAliases * @property {string} field * * @typedef {{ * type: "TagOnStructWithInline", * a: First, * b: { * a: string, * }, * }} TagOnStructWithInline * @property {"TagOnStructWithInline"} type * @property {First} a * @property {{ * a: string, * }} b * * @typedef {string | "B" | { * a: string, * } | First} Tenth * @property {string} A * @property {"B"} B * @property {{ * a: string, * }} C * @property {First} D * * @typedef {never} TestCollectionRegister * * @typedef {"Unit" | ({ Single: number }) & { Multiple?: never; Struct?: never } | ({ Multiple: [number, number] }) & { Single?: never; Struct?: never } | ({ Struct: { * a: number, * } }) & { Multiple?: never; Single?: never }} TestEnum * @property {"Unit"} Unit * @property {{ Single: number }} Single * @property {{ Multiple: [number, number] }} Multiple * @property {{ Struct: { * a: number, * } }} Struct * * @typedef {{ * b: { [key in string]: string }, * c: First, * } & First} Third * @property {{ [key in string]: string }} b * @property {First} c * * @typedef {{ * a: string, * }} ToBeFlattened * @property {string} a * * @typedef {string} TransparentStruct * @property {string} "0" * * @typedef {TransparentTypeInner} TransparentType * @property {TransparentTypeInner} "0" * * @typedef {null} TransparentType2 * @property {null} "0" * * @typedef {{ * inner: string, * }} TransparentTypeInner * @property {string} inner * * @typedef {string} TransparentTypeWithOverride * @property {string} "0" * * @typedef {null} TransparentWithSkip * @property {null} "0" * * @typedef {string} TransparentWithSkip2 * @property {string} "0" * * @typedef {string} TransparentWithSkip3 * @property {string} "0" * * @typedef {[number[], [number[], number[]], [number[], number[], number[]]]} TupleNested * @property {number[]} "0" * @property {[number[], number[]]} "1" * @property {[number[], number[], number[]]} "2" * * @typedef {string} TupleStruct * @property {string} "0" * * @typedef {number} TupleStruct1 * @property {number} "0" * * @typedef {[number, boolean, string]} TupleStruct3 * @property {number} "0" * @property {boolean} "1" * @property {string} "2" * * @typedef {string} TupleStructWithRep * @property {string} "0" * * @typedef {null} Unit1 * * @typedef {Record} Unit2 * * @typedef {[]} Unit3 * * @typedef {null} Unit4 * @property {null} "0" * * @typedef {"A"} Unit5 * @property {"A"} A * * @typedef {{ A: null }} Unit6 * @property {{ A: null }} A * * @typedef {{ A: Record }} Unit7 * @property {{ A: Record }} A * * @typedef {"A" | "B" | "C"} UnitVariants * @property {"A"} A * @property {"B"} B * @property {"C"} C * * @typedef {string | number | { id: string } | [string, boolean]} UntaggedVariants * @property {string} A * @property {number} B * @property {number} C * @property {{ id: string }} D * @property {[string, boolean]} E * * @typedef {string | number} UntaggedVariantsKey * @property {string} A * @property {number} B * @property {number} C * * @typedef {null | number} UntaggedVariantsWithDuplicateBranches * @property {null} A * @property {number} B * @property {null} C * * @typedef {string | [number, string] | number} UntaggedVariantsWithoutValue * @property {string} A * @property {[number, string]} B * @property {number} C * * @typedef {({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }} UntaggedWithAlias * @property {{ field: string }} A * @property {{ other: number }} B * * @typedef {{ [key in MaybeValidKey]: null }} ValidMaybeValidKey * @property {{ [key in MaybeValidKey]: null }} "0" * * @typedef {{ [key in MaybeValidKey>]: null }} ValidMaybeValidKeyNested * @property {{ [key in MaybeValidKey>]: null }} "0" */ ════════════════════════════════════════ tests/ tests/ types.js (29458 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. /** * @typedef {import("../../std/ops")} std$ops * @typedef {import("../../std/result")} std$result * @typedef {import("../../test/types")} test$types * @typedef {import("../../test/types/type_type")} test$types$type_type */ /** * @typedef {{ * i8: number, * i16: number, * i32: number, * u8: number, * u16: number, * u32: number, * f32: number, * f64: number, * bool: boolean, * char: string, * "Range": std$ops.Range, * "RangeInclusive": std$ops.RangeInclusive, * "()": null, * "(String, i32)": [string, number], * "(String, i32, bool)": [string, number, boolean], * "((String, i32), (bool, char, bool), ())": [[string, number], [boolean, string, boolean], null], * "(bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool)": [boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean], * "(Vec, Vec)": [number[], boolean[]], * String: string, * PathBuf: string, * IpAddr: string, * Ipv4Addr: string, * Ipv6Addr: string, * SocketAddr: string, * SocketAddrV4: string, * SocketAddrV6: string, * "Cow<'static, str>": string, * "Cow<'static, i32>": number, * "&'static str": string, * "&'static bool": boolean, * "&'static i32": number, * "Vec": number[], * "&'static [i32]": number[], * "&'static [i32; 3]": [number, number, number], * "[i32; 3]": [number, number, number], * "Vec": test$types.MyEnum[], * "&'static [MyEnum]": test$types.MyEnum[], * "&'static [MyEnum; 6]": [test$types.MyEnum, test$types.MyEnum, test$types.MyEnum, test$types.MyEnum, test$types.MyEnum, test$types.MyEnum], * "[MyEnum; 2]": [test$types.MyEnum, test$types.MyEnum], * "&'static [i32; 1]": [number], * "&'static [i32; 0]": [], * "Option": number | null, * "Option<()>": null, * "Option>": number[] | null, * "Result": std$result.Result, * "Vec>>": (number | null)[], * "Option>>": number[] | null, * "[Vec; 3]": [string[], string[], string[]], * "Option>": string | null, * "Option>>": string | null, * "PhantomData<()>": null, * "PhantomData": null, * Infallible: never, * Unit1: test$types.Unit1, * Unit2: test$types.Unit2, * Unit3: test$types.Unit3, * Unit4: test$types.Unit4, * Unit5: test$types.Unit5, * Unit6: test$types.Unit6, * Unit7: test$types.Unit7, * SimpleStruct: test$types.SimpleStruct, * TupleStruct1: test$types.TupleStruct1, * TupleStruct3: test$types.TupleStruct3, * TestEnum: test$types.TestEnum, * RefStruct: test$types.RefStruct, * InlinerStruct: test$types.InlinerStruct, * "GenericStruct": test$types.GenericStruct, * "GenericStruct": test$types.GenericStruct, * FlattenEnumStruct: test$types.FlattenEnumStruct, * OverridenStruct: test$types.OverridenStruct, * HasGenericAlias: test$types.HasGenericAlias, * EnumMacroAttributes: test$types.EnumMacroAttributes, * InlineEnumField: test$types.InlineEnumField, * InlineOptionalType: test$types.InlineOptionalType, * Rename: test$types.Rename, * TransparentType: test$types.TransparentType, * TransparentType2: test$types.TransparentType2, * TransparentTypeWithOverride: test$types.TransparentTypeWithOverride, * "[Option; 3]": [(number | null), (number | null), (number | null)], * "HashMap": Partial<{ [key in test$types.BasicEnum]: null }>, * "HashMap": Partial<{ [key in test$types.BasicEnum]: number }>, * "Option>>>": number | null, * "Vec": test$types.PlaceholderInnerField[], * EnumReferenceRecordKey: test$types.EnumReferenceRecordKey, * FlattenOnNestedEnum: test$types.FlattenOnNestedEnum, * MyEmptyInput: test$types.MyEmptyInput, * "(String)": string, * "(String,)": [string], * ExtraBracketsInTupleVariant: test$types.ExtraBracketsInTupleVariant, * ExtraBracketsInUnnamedStruct: test$types.ExtraBracketsInUnnamedStruct, * "Vec": test$types.MyEnum[], * InlineTuple: test$types.InlineTuple, * InlineTuple2: test$types.InlineTuple2, * "Box": string, * "Box": string, * SkippedFieldWithinVariant: test$types.SkippedFieldWithinVariant, * KebabCase: test$types.KebabCase, * "&[&str]": string[], * "Issue281<'_>": test$types.Issue281, * "LifetimeGenericStruct<'_, i32>": test$types.LifetimeGenericStruct, * "LifetimeGenericEnum<'_, i32>": test$types.LifetimeGenericEnum, * RenameWithWeirdCharsField: test$types.RenameWithWeirdCharsField, * RenameWithWeirdCharsVariant: test$types.RenameWithWeirdCharsVariant, * RenamedFieldKeys: test$types.RenamedFieldKeys, * RenamedVariantWithSkippedPayload: test$types.RenamedVariantWithSkippedPayload, * "type_type::Type": test$types$type_type.Type, * ActualType: test$types.ActualType, * SpectaTypeOverride: test$types.SpectaTypeOverride, * ContainerTypeOverrideStruct: test$types.ContainerTypeOverrideStruct, * ContainerTypeOverrideEnum: test$types.ContainerTypeOverrideEnum, * "ContainerTypeOverrideGeneric>": test$types.ContainerTypeOverrideGeneric, * "ContainerTypeOverrideToGeneric": test$types.ContainerTypeOverrideToGeneric, * ContainerTypeOverrideTuple: test$types.ContainerTypeOverrideTuple, * "ContainerTypeOverrideTupleGeneric": test$types.ContainerTypeOverrideTupleGeneric, * InvalidToValidType: test$types.InvalidToValidType, * TupleStruct: test$types.TupleStruct, * TupleStructWithRep: test$types.TupleStructWithRep, * "GenericTupleStruct": test$types.GenericTupleStruct, * BracedStruct: test$types.BracedStruct, * Struct: test$types.StructNew, * Struct2: test$types.Struct2, * Enum: test$types.Enum, * Enum2: test$types.Enum2, * Enum3: test$types.Enum3, * StructRenameAllUppercase: test$types.StructRenameAllUppercase, * RenameSerdeSpecialChar: test$types.RenameSerdeSpecialChar, * EnumRenameAllUppercase: test$types.EnumRenameAllUppercase, * Recursive: test$types.Recursive, * RecursiveMapValue: test$types.RecursiveMapValue, * RecursiveTransparent: test$types.RecursiveTransparent, * RecursiveInEnum: test$types.RecursiveInEnum, * NonOptional: test$types.NonOptional, * OptionalOnNamedField: test$types.OptionalOnNamedField, * OptionalOnTransparentNamedField: test$types.OptionalOnTransparentNamedField, * OptionalInEnum: test$types.OptionalInEnum, * UntaggedVariants: test$types.UntaggedVariants, * UntaggedVariantsWithoutValue: test$types.UntaggedVariantsWithoutValue, * UntaggedVariantsWithDuplicateBranches: test$types.UntaggedVariantsWithDuplicateBranches, * "HashMap": { [key in string]: null }, * Regular: test$types.Regular, * "HashMap": { [key in never]: null }, * "HashMap": { [key in test$types.TransparentStruct]: null }, * "HashMap": Partial<{ [key in test$types.UnitVariants]: null }>, * "HashMap": Partial<{ [key in test$types.UntaggedVariantsKey]: null }>, * ValidMaybeValidKey: test$types.ValidMaybeValidKey, * ValidMaybeValidKeyNested: test$types.ValidMaybeValidKeyNested, * MacroStruct: test$types.MacroStruct, * MacroStruct2: test$types.MacroStruct2, * MacroEnum: test$types.MacroEnum, * DeprecatedType: test$types.DeprecatedType, * DeprecatedTypeWithMsg: test$types.DeprecatedTypeWithMsg, * DeprecatedTypeWithMsg2: test$types.DeprecatedTypeWithMsg2, * DeprecatedFields: test$types.DeprecatedFields, * DeprecatedTupleVariant: test$types.DeprecatedTupleVariant, * DeprecatedEnumVariants: test$types.DeprecatedEnumVariants, * CommentedStruct: test$types.CommentedStruct, * CommentedEnum: test$types.CommentedEnum, * SingleLineComment: test$types.SingleLineComment, * NonGeneric: test$types.Demo, * "HalfGenericA": test$types.Demo, * "HalfGenericB": test$types.Demo, * "FullGeneric": test$types.Demo, * "Another": test$types.Demo, * "MapA": { [key in string]: number }, * "MapB": { [key in number]: string }, * "MapC": { [key in string]: test$types.AGenericStruct }, * "AGenericStruct": test$types.AGenericStruct, * A: test$types.A, * DoubleFlattened: test$types.DoubleFlattened, * FlattenedInner: test$types.FlattenedInner, * BoxFlattened: test$types.BoxFlattened, * BoxInline: test$types.BoxInline, * First: test$types.First, * Second: test$types.Second, * Third: test$types.Third, * Fourth: test$types.Fourth, * TagOnStructWithInline: test$types.TagOnStructWithInline, * Sixth: test$types.Sixth, * Seventh: test$types.Seventh, * Eight: test$types.Eight, * Ninth: test$types.Ninth, * Tenth: test$types.Tenth, * MyEnumTagged: test$types.MyEnumTagged, * MyEnumExternal: test$types.MyEnumExternal, * MyEnumAdjacent: test$types.MyEnumAdjacent, * MyEnumUntagged: test$types.MyEnumUntagged, * EmptyStruct: test$types.EmptyStruct, * EmptyStructWithTag: test$types.EmptyStructWithTag, * AdjacentlyTagged: test$types.AdjacentlyTagged, * LoadProjectEvent: test$types.LoadProjectEvent, * ExternallyTagged: test$types.ExternallyTagged, * Issue221External: test$types.Issue221External, * InternallyTaggedD: test$types.InternallyTaggedD, * InternallyTaggedE: test$types.InternallyTaggedE, * InternallyTaggedF: test$types.InternallyTaggedF, * InternallyTaggedH: test$types.InternallyTaggedH, * InternallyTaggedL: test$types.InternallyTaggedL, * InternallyTaggedM: test$types.InternallyTaggedM, * StructWithAlias: test$types.StructWithAlias, * StructWithMultipleAliases: test$types.StructWithMultipleAliases, * StructWithAliasAndRename: test$types.StructWithAliasAndRename, * EnumWithVariantAlias: test$types.EnumWithVariantAlias, * EnumWithMultipleVariantAliases: test$types.EnumWithMultipleVariantAliases, * EnumWithVariantAliasAndRename: test$types.EnumWithVariantAliasAndRename, * InternallyTaggedWithAlias: test$types.InternallyTaggedWithAlias, * AdjacentlyTaggedWithAlias: test$types.AdjacentlyTaggedWithAlias, * UntaggedWithAlias: test$types.UntaggedWithAlias, * Issue221UntaggedSafe: test$types.Issue221UntaggedSafe, * Issue221UntaggedMixed: test$types.Issue221UntaggedMixed, * EmptyEnum: test$types.EmptyEnum, * EmptyEnumTagged: test$types.EmptyEnumTagged, * EmptyEnumTaggedWContent: test$types.EmptyEnumTaggedWContent, * EmptyEnumUntagged: test$types.EmptyEnumUntagged, * SkipOnlyField: test$types.SkipOnlyField, * SkipField: test$types.SkipField, * SkipVariant: test$types.SkipVariant, * SkipUnnamedFieldInVariant: test$types.SkipUnnamedFieldInVariant, * SkipNamedFieldInVariant: test$types.SkipNamedFieldInVariant, * TransparentWithSkip: test$types.TransparentWithSkip, * TransparentWithSkip2: test$types.TransparentWithSkip2, * TransparentWithSkip3: test$types.TransparentWithSkip3, * SkipVariant2: test$types.SkipVariant2, * SkipVariant3: test$types.SkipVariant3, * SkipStructFields: test$types.SkipStructFields, * SpectaSkipNonTypeField: test$types.SpectaSkipNonTypeField, * FlattenA: test$types.FlattenA, * FlattenB: test$types.FlattenB, * FlattenC: test$types.FlattenC, * FlattenD: test$types.FlattenD, * FlattenE: test$types.FlattenE, * FlattenF: test$types.FlattenF, * FlattenG: test$types.FlattenG, * TupleNested: test$types.TupleNested, * "Generic1<()>": test$types.Generic1, * "GenericAutoBound<()>": test$types.GenericAutoBound, * "GenericAutoBound2<()>": test$types.GenericAutoBound2, * Container1: test$types.Container1, * "Generic2<(), String, i32>": test$types.Generic2, * "GenericNewType1<()>": test$types.GenericNewType1, * "GenericTuple<()>": test$types.GenericTuple, * "GenericStruct2<()>": test$types.GenericStruct2, * "InlineGenericNewtype": string, * "InlineGenericNested": [string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | ({ Unnamed: string }) & { Named?: never } | ({ Named: { * value: string, * } }) & { Unnamed?: never }], * "InlineFlattenGenericsG<()>": test$types.InlineFlattenGenericsG, * InlineFlattenGenerics: test$types.InlineFlattenGenerics, * GenericDefault: test$types.GenericDefault, * ChainedGenericDefault: test$types.ChainedGenericDefault, * "ChainedGenericDefault": test$types.ChainedGenericDefault, * "ChainedGenericDefault": test$types.ChainedGenericDefault, * "ChainedGenericDefault": test$types.ChainedGenericDefault, * GenericDefaultSkipped: test$types.GenericDefaultSkipped, * GenericDefaultSkippedNonType: test$types.GenericDefaultSkippedNonType, * GenericParameterOrderPreserved: test$types.GenericParameterOrderPreserved, * ConstGenericInNonConstContainer: test$types.ConstGenericInNonConstContainer, * ConstGenericInConstContainer: test$types.ConstGenericInConstContainer, * NamedConstGenericContainer: test$types.NamedConstGenericContainer, * InlineConstGenericContainer: test$types.InlineConstGenericContainer, * InlineRecursiveConstGenericContainer: test$types.InlineRecursiveConstGenericContainer, * TestCollectionRegister: test$types.TestCollectionRegister, * TestCollectionRegister: test$types.TestCollectionRegister, * }} Primitives * @property {number} i8 * @property {number} i16 * @property {number} i32 * @property {number} u8 * @property {number} u16 * @property {number} u32 * @property {number} f32 * @property {number} f64 * @property {boolean} bool * @property {string} char * @property {std$ops.Range} "Range" * @property {std$ops.RangeInclusive} "RangeInclusive" * @property {null} "()" * @property {[string, number]} "(String, i32)" * @property {[string, number, boolean]} "(String, i32, bool)" * @property {[[string, number], [boolean, string, boolean], null]} "((String, i32), (bool, char, bool), ())" * @property {[boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean]} "(bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool)" * @property {[number[], boolean[]]} "(Vec, Vec)" * @property {string} String * @property {string} PathBuf * @property {string} IpAddr * @property {string} Ipv4Addr * @property {string} Ipv6Addr * @property {string} SocketAddr * @property {string} SocketAddrV4 * @property {string} SocketAddrV6 * @property {string} "Cow<'static, str>" * @property {number} "Cow<'static, i32>" * @property {string} "&'static str" * @property {boolean} "&'static bool" * @property {number} "&'static i32" * @property {number[]} "Vec" * @property {number[]} "&'static [i32]" * @property {[number, number, number]} "&'static [i32; 3]" * @property {[number, number, number]} "[i32; 3]" * @property {test$types.MyEnum[]} "Vec" * @property {test$types.MyEnum[]} "&'static [MyEnum]" * @property {[test$types.MyEnum, test$types.MyEnum, test$types.MyEnum, test$types.MyEnum, test$types.MyEnum, test$types.MyEnum]} "&'static [MyEnum; 6]" * @property {[test$types.MyEnum, test$types.MyEnum]} "[MyEnum; 2]" * @property {[number]} "&'static [i32; 1]" * @property {[]} "&'static [i32; 0]" * @property {number | null} "Option" * @property {null} "Option<()>" * @property {number[] | null} "Option>" * @property {std$result.Result} "Result" * @property {(number | null)[]} "Vec>>" * @property {number[] | null} "Option>>" * @property {[string[], string[], string[]]} "[Vec; 3]" * @property {string | null} "Option>" * @property {string | null} "Option>>" * @property {null} "PhantomData<()>" * @property {null} "PhantomData" * @property {never} Infallible * @property {test$types.Unit1} Unit1 * @property {test$types.Unit2} Unit2 * @property {test$types.Unit3} Unit3 * @property {test$types.Unit4} Unit4 * @property {test$types.Unit5} Unit5 * @property {test$types.Unit6} Unit6 * @property {test$types.Unit7} Unit7 * @property {test$types.SimpleStruct} SimpleStruct * @property {test$types.TupleStruct1} TupleStruct1 * @property {test$types.TupleStruct3} TupleStruct3 * @property {test$types.TestEnum} TestEnum * @property {test$types.RefStruct} RefStruct * @property {test$types.InlinerStruct} InlinerStruct * @property {test$types.GenericStruct} "GenericStruct" * @property {test$types.GenericStruct} "GenericStruct" * @property {test$types.FlattenEnumStruct} FlattenEnumStruct * @property {test$types.OverridenStruct} OverridenStruct * @property {test$types.HasGenericAlias} HasGenericAlias * @property {test$types.EnumMacroAttributes} EnumMacroAttributes * @property {test$types.InlineEnumField} InlineEnumField * @property {test$types.InlineOptionalType} InlineOptionalType * @property {test$types.Rename} Rename * @property {test$types.TransparentType} TransparentType * @property {test$types.TransparentType2} TransparentType2 * @property {test$types.TransparentTypeWithOverride} TransparentTypeWithOverride * @property {[(number | null), (number | null), (number | null)]} "[Option; 3]" * @property {Partial<{ [key in test$types.BasicEnum]: null }>} "HashMap" * @property {Partial<{ [key in test$types.BasicEnum]: number }>} "HashMap" * @property {number | null} "Option>>>" * @property {test$types.PlaceholderInnerField[]} "Vec" * @property {test$types.EnumReferenceRecordKey} EnumReferenceRecordKey * @property {test$types.FlattenOnNestedEnum} FlattenOnNestedEnum * @property {test$types.MyEmptyInput} MyEmptyInput * @property {string} "(String)" * @property {[string]} "(String,)" * @property {test$types.ExtraBracketsInTupleVariant} ExtraBracketsInTupleVariant * @property {test$types.ExtraBracketsInUnnamedStruct} ExtraBracketsInUnnamedStruct * @property {test$types.MyEnum[]} "Vec" * @property {test$types.InlineTuple} InlineTuple * @property {test$types.InlineTuple2} InlineTuple2 * @property {string} "Box" * @property {string} "Box" * @property {test$types.SkippedFieldWithinVariant} SkippedFieldWithinVariant * @property {test$types.KebabCase} KebabCase * @property {string[]} "&[&str]" * @property {test$types.Issue281} "Issue281<'_>" * @property {test$types.LifetimeGenericStruct} "LifetimeGenericStruct<'_, i32>" * @property {test$types.LifetimeGenericEnum} "LifetimeGenericEnum<'_, i32>" * @property {test$types.RenameWithWeirdCharsField} RenameWithWeirdCharsField * @property {test$types.RenameWithWeirdCharsVariant} RenameWithWeirdCharsVariant * @property {test$types.RenamedFieldKeys} RenamedFieldKeys * @property {test$types.RenamedVariantWithSkippedPayload} RenamedVariantWithSkippedPayload * @property {test$types$type_type.Type} "type_type::Type" * @property {test$types.ActualType} ActualType * @property {test$types.SpectaTypeOverride} SpectaTypeOverride * @property {test$types.ContainerTypeOverrideStruct} ContainerTypeOverrideStruct * @property {test$types.ContainerTypeOverrideEnum} ContainerTypeOverrideEnum * @property {test$types.ContainerTypeOverrideGeneric} "ContainerTypeOverrideGeneric>" * @property {test$types.ContainerTypeOverrideToGeneric} "ContainerTypeOverrideToGeneric" * @property {test$types.ContainerTypeOverrideTuple} ContainerTypeOverrideTuple * @property {test$types.ContainerTypeOverrideTupleGeneric} "ContainerTypeOverrideTupleGeneric" * @property {test$types.InvalidToValidType} InvalidToValidType * @property {test$types.TupleStruct} TupleStruct * @property {test$types.TupleStructWithRep} TupleStructWithRep * @property {test$types.GenericTupleStruct} "GenericTupleStruct" * @property {test$types.BracedStruct} BracedStruct * @property {test$types.StructNew} Struct * @property {test$types.Struct2} Struct2 * @property {test$types.Enum} Enum * @property {test$types.Enum2} Enum2 * @property {test$types.Enum3} Enum3 * @property {test$types.StructRenameAllUppercase} StructRenameAllUppercase * @property {test$types.RenameSerdeSpecialChar} RenameSerdeSpecialChar * @property {test$types.EnumRenameAllUppercase} EnumRenameAllUppercase * @property {test$types.Recursive} Recursive * @property {test$types.RecursiveMapValue} RecursiveMapValue * @property {test$types.RecursiveTransparent} RecursiveTransparent * @property {test$types.RecursiveInEnum} RecursiveInEnum * @property {test$types.NonOptional} NonOptional * @property {test$types.OptionalOnNamedField} OptionalOnNamedField * @property {test$types.OptionalOnTransparentNamedField} OptionalOnTransparentNamedField * @property {test$types.OptionalInEnum} OptionalInEnum * @property {test$types.UntaggedVariants} UntaggedVariants * @property {test$types.UntaggedVariantsWithoutValue} UntaggedVariantsWithoutValue * @property {test$types.UntaggedVariantsWithDuplicateBranches} UntaggedVariantsWithDuplicateBranches * @property {{ [key in string]: null }} "HashMap" * @property {test$types.Regular} Regular * @property {{ [key in never]: null }} "HashMap" * @property {{ [key in test$types.TransparentStruct]: null }} "HashMap" * @property {Partial<{ [key in test$types.UnitVariants]: null }>} "HashMap" * @property {Partial<{ [key in test$types.UntaggedVariantsKey]: null }>} "HashMap" * @property {test$types.ValidMaybeValidKey} ValidMaybeValidKey * @property {test$types.ValidMaybeValidKeyNested} ValidMaybeValidKeyNested * @property {test$types.MacroStruct} MacroStruct * @property {test$types.MacroStruct2} MacroStruct2 * @property {test$types.MacroEnum} MacroEnum * @property {test$types.DeprecatedType} DeprecatedType * @property {test$types.DeprecatedTypeWithMsg} DeprecatedTypeWithMsg * @property {test$types.DeprecatedTypeWithMsg2} DeprecatedTypeWithMsg2 * @property {test$types.DeprecatedFields} DeprecatedFields * @property {test$types.DeprecatedTupleVariant} DeprecatedTupleVariant * @property {test$types.DeprecatedEnumVariants} DeprecatedEnumVariants * @property {test$types.CommentedStruct} CommentedStruct * @property {test$types.CommentedEnum} CommentedEnum * @property {test$types.SingleLineComment} SingleLineComment * @property {test$types.Demo} NonGeneric * @property {test$types.Demo} "HalfGenericA" * @property {test$types.Demo} "HalfGenericB" * @property {test$types.Demo} "FullGeneric" * @property {test$types.Demo} "Another" * @property {{ [key in string]: number }} "MapA" * @property {{ [key in number]: string }} "MapB" * @property {{ [key in string]: test$types.AGenericStruct }} "MapC" * @property {test$types.AGenericStruct} "AGenericStruct" * @property {test$types.A} A * @property {test$types.DoubleFlattened} DoubleFlattened * @property {test$types.FlattenedInner} FlattenedInner * @property {test$types.BoxFlattened} BoxFlattened * @property {test$types.BoxInline} BoxInline * @property {test$types.First} First * @property {test$types.Second} Second * @property {test$types.Third} Third * @property {test$types.Fourth} Fourth * @property {test$types.TagOnStructWithInline} TagOnStructWithInline * @property {test$types.Sixth} Sixth * @property {test$types.Seventh} Seventh * @property {test$types.Eight} Eight * @property {test$types.Ninth} Ninth * @property {test$types.Tenth} Tenth * @property {test$types.MyEnumTagged} MyEnumTagged * @property {test$types.MyEnumExternal} MyEnumExternal * @property {test$types.MyEnumAdjacent} MyEnumAdjacent * @property {test$types.MyEnumUntagged} MyEnumUntagged * @property {test$types.EmptyStruct} EmptyStruct * @property {test$types.EmptyStructWithTag} EmptyStructWithTag * @property {test$types.AdjacentlyTagged} AdjacentlyTagged * @property {test$types.LoadProjectEvent} LoadProjectEvent * @property {test$types.ExternallyTagged} ExternallyTagged * @property {test$types.Issue221External} Issue221External * @property {test$types.InternallyTaggedD} InternallyTaggedD * @property {test$types.InternallyTaggedE} InternallyTaggedE * @property {test$types.InternallyTaggedF} InternallyTaggedF * @property {test$types.InternallyTaggedH} InternallyTaggedH * @property {test$types.InternallyTaggedL} InternallyTaggedL * @property {test$types.InternallyTaggedM} InternallyTaggedM * @property {test$types.StructWithAlias} StructWithAlias * @property {test$types.StructWithMultipleAliases} StructWithMultipleAliases * @property {test$types.StructWithAliasAndRename} StructWithAliasAndRename * @property {test$types.EnumWithVariantAlias} EnumWithVariantAlias * @property {test$types.EnumWithMultipleVariantAliases} EnumWithMultipleVariantAliases * @property {test$types.EnumWithVariantAliasAndRename} EnumWithVariantAliasAndRename * @property {test$types.InternallyTaggedWithAlias} InternallyTaggedWithAlias * @property {test$types.AdjacentlyTaggedWithAlias} AdjacentlyTaggedWithAlias * @property {test$types.UntaggedWithAlias} UntaggedWithAlias * @property {test$types.Issue221UntaggedSafe} Issue221UntaggedSafe * @property {test$types.Issue221UntaggedMixed} Issue221UntaggedMixed * @property {test$types.EmptyEnum} EmptyEnum * @property {test$types.EmptyEnumTagged} EmptyEnumTagged * @property {test$types.EmptyEnumTaggedWContent} EmptyEnumTaggedWContent * @property {test$types.EmptyEnumUntagged} EmptyEnumUntagged * @property {test$types.SkipOnlyField} SkipOnlyField * @property {test$types.SkipField} SkipField * @property {test$types.SkipVariant} SkipVariant * @property {test$types.SkipUnnamedFieldInVariant} SkipUnnamedFieldInVariant * @property {test$types.SkipNamedFieldInVariant} SkipNamedFieldInVariant * @property {test$types.TransparentWithSkip} TransparentWithSkip * @property {test$types.TransparentWithSkip2} TransparentWithSkip2 * @property {test$types.TransparentWithSkip3} TransparentWithSkip3 * @property {test$types.SkipVariant2} SkipVariant2 * @property {test$types.SkipVariant3} SkipVariant3 * @property {test$types.SkipStructFields} SkipStructFields * @property {test$types.SpectaSkipNonTypeField} SpectaSkipNonTypeField * @property {test$types.FlattenA} FlattenA * @property {test$types.FlattenB} FlattenB * @property {test$types.FlattenC} FlattenC * @property {test$types.FlattenD} FlattenD * @property {test$types.FlattenE} FlattenE * @property {test$types.FlattenF} FlattenF * @property {test$types.FlattenG} FlattenG * @property {test$types.TupleNested} TupleNested * @property {test$types.Generic1} "Generic1<()>" * @property {test$types.GenericAutoBound} "GenericAutoBound<()>" * @property {test$types.GenericAutoBound2} "GenericAutoBound2<()>" * @property {test$types.Container1} Container1 * @property {test$types.Generic2} "Generic2<(), String, i32>" * @property {test$types.GenericNewType1} "GenericNewType1<()>" * @property {test$types.GenericTuple} "GenericTuple<()>" * @property {test$types.GenericStruct2} "GenericStruct2<()>" * @property {string} "InlineGenericNewtype" * @property {[string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | ({ Unnamed: string }) & { Named?: never } | ({ Named: { * value: string, * } }) & { Unnamed?: never }]} "InlineGenericNested" * @property {test$types.InlineFlattenGenericsG} "InlineFlattenGenericsG<()>" * @property {test$types.InlineFlattenGenerics} InlineFlattenGenerics * @property {test$types.GenericDefault} GenericDefault * @property {test$types.ChainedGenericDefault} ChainedGenericDefault * @property {test$types.ChainedGenericDefault} "ChainedGenericDefault" * @property {test$types.ChainedGenericDefault} "ChainedGenericDefault" * @property {test$types.ChainedGenericDefault} "ChainedGenericDefault" * @property {test$types.GenericDefaultSkipped} GenericDefaultSkipped * @property {test$types.GenericDefaultSkippedNonType} GenericDefaultSkippedNonType * @property {test$types.GenericParameterOrderPreserved} GenericParameterOrderPreserved * @property {test$types.ConstGenericInNonConstContainer} ConstGenericInNonConstContainer * @property {test$types.ConstGenericInConstContainer} ConstGenericInConstContainer * @property {test$types.NamedConstGenericContainer} NamedConstGenericContainer * @property {test$types.InlineConstGenericContainer} InlineConstGenericContainer * @property {test$types.InlineRecursiveConstGenericContainer} InlineRecursiveConstGenericContainer * @property {test$types.TestCollectionRegister} TestCollectionRegister * @property {test$types.TestCollectionRegister} TestCollectionRegister */ ════════════════════════════════════════ ================================================ FILE: tests/tests/snapshots/test__jsdoc__jsdoc-export-to-flatfile-raw.snap ================================================ --- source: tests/tests/jsdoc.rs expression: output --- jsdoc-export-to-flatfile-raw (51729 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. /** * @typedef {{ * a: B, * b: { * b: number, * }, * c: B, * d: { * flattened: number, * }, * e: { * generic_flattened: number, * }, * }} A * @property {B} a * @property {{ * b: number, * }} b * @property {B} c * @property {{ * flattened: number, * }} d * @property {{ * generic_flattened: number, * }} e * * @typedef {{ * field: Demo, * }} AGenericStruct * @property {Demo} field * * @typedef {{ * a: GenericType, * }} ActualType * @property {GenericType} a * * @typedef {"A" | { id: string; method: string } | string} AdjacentlyTagged * @property {"A"} A * @property {{ id: string; method: string }} B * @property {string} C * * @typedef {({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }} AdjacentlyTaggedWithAlias * @property {{ field: string }} A * @property {{ other: number }} B * * @typedef {{ * b: number, * }} B * @property {number} b * * @typedef {"A" | "B"} BasicEnum * @property {"A"} A * @property {"B"} B * * @typedef {{ * b: BoxedInner, * }} BoxFlattened * @property {BoxedInner} b * * @typedef {{ * c: { * a: number, * }, * }} BoxInline * @property {{ * a: number, * }} c * * @typedef {{ * a: number, * }} BoxedInner * @property {number} a * * @typedef {string} BracedStruct * @property {string} "0" * * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second * * Some triple-slash comment * Some more triple-slash comment * * @typedef { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * number | * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number }} CommentedEnum * @property { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * number} A - Some triple-slash comment Some more triple-slash comment * @property { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number }} B - Some triple-slash comment Some more triple-slash comment * * Some triple-slash comment * Some more triple-slash comment * * @typedef {{ * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * }} CommentedStruct * @property {number} a - Some triple-slash comment Some more triple-slash comment * * @typedef {{ * data: number[], * a: number[], * d: [number, number], * }} ConstGenericInConstContainer * @property {number[]} data * @property {number[]} a * @property {[number, number]} d * * @typedef {{ * data: [number], * a: [number, number], * d: [number, number], * }} ConstGenericInNonConstContainer * @property {[number]} data * @property {[number, number]} a * @property {[number, number]} d * * @typedef {{ * foo: Generic1, * bar: Generic1[], * baz: { [key in string]: Generic1 }, * }} Container1 * @property {Generic1} foo * @property {Generic1[]} bar * @property {{ [key in string]: Generic1 }} baz * * @typedef {string} ContainerTypeOverrideEnum * * @typedef {string} ContainerTypeOverrideGeneric * * @typedef {string} ContainerTypeOverrideStruct * * @typedef {T} ContainerTypeOverrideToGeneric * * @typedef {[string, number]} ContainerTypeOverrideTuple * * @typedef {[T, string]} ContainerTypeOverrideTupleGeneric * * @typedef {{ * flattened: number, * }} D * @property {number} flattened * * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b * * @typedef { * /** * * @deprecated * */ * "A" | * /** * * @deprecated Nope * */ * "B" | * /** * * @deprecated Nope * */ * "C"} DeprecatedEnumVariants * @property { * /** * * @deprecated * */ * "A"} A - @deprecated * @property { * /** * * @deprecated Nope * */ * "B"} B - @deprecated Nope * @property { * /** * * @deprecated Nope * */ * "C"} C - @deprecated Nope * * @typedef {{ * a: number, * /** * * @deprecated * */ * b: string, * /** * * @deprecated This field is cringe! * */ * c: string, * /** * * @deprecated This field is cringe! * */ * d: string, * }} DeprecatedFields * @property {number} a * @property {string} b - @deprecated * @property {string} c - @deprecated This field is cringe! * @property {string} d - @deprecated This field is cringe! * * @typedef {[ * /** * * @deprecated * */ * string, * /** * * @deprecated Nope * */ * string, * /** * * @deprecated Nope * */ * number]} DeprecatedTupleVariant * @property {string} "0" - @deprecated * @property {string} "1" - @deprecated Nope * @property {number} "2" - @deprecated Nope * * @deprecated * @typedef {{ * a: number, * }} DeprecatedType * @property {number} a * * @deprecated Look at you big man using a deprecation message * @typedef {{ * a: number, * }} DeprecatedTypeWithMsg * @property {number} a * * @deprecated Look at you big man using a deprecation message * @typedef {{ * a: number, * }} DeprecatedTypeWithMsg2 * @property {number} a * * @typedef {{ * a: ToBeFlattened, * b: ToBeFlattened, * }} DoubleFlattened * @property {ToBeFlattened} a * @property {ToBeFlattened} b * * @typedef {string | "B"} Eight * @property {string} A * @property {"B"} B * * @typedef {never} EmptyEnum * * @typedef {never} EmptyEnumTagged * * @typedef {never} EmptyEnumTaggedWContent * * @typedef {never} EmptyEnumUntagged * * @typedef {Record} EmptyStruct * * @typedef {Record} EmptyStructWithTag * * @typedef {"A" | "B"} Enum * @property {"A"} A * @property {"B"} B * * @typedef {"A" | "B" | { enum_field: null }} Enum2 * @property {"A"} A * @property {"B"} B * @property {{ enum_field: null }} D * * @typedef {{ a: string }} Enum3 * @property {{ a: string }} A * * @typedef {string | number | { a: string; b: number }} EnumMacroAttributes * @property {string} A * @property {number} B * @property {number} C * @property {{ a: string; b: number }} D * * @typedef {{ * a: Partial<{ [key in BasicEnum]: number }>, * }} EnumReferenceRecordKey * @property {Partial<{ [key in BasicEnum]: number }>} a * * @typedef {"HelloWorld" | "VariantB" | "TestingWords"} EnumRenameAllUppercase * @property {"HelloWorld"} HelloWorld * @property {"VariantB"} VariantB * @property {"TestingWords"} TestingWords * * @typedef {"Variant" | "Other"} EnumWithMultipleVariantAliases * @property {"Variant"} Variant * @property {"Other"} Other * * @typedef {"Variant" | "Other"} EnumWithVariantAlias * @property {"Variant"} Variant * @property {"Other"} Other * * @typedef {"Variant" | "Other"} EnumWithVariantAliasAndRename * @property {"Variant"} Variant * @property {"Other"} Other * * @typedef {"A" | { id: string; method: string } | string} ExternallyTagged * @property {"A"} A * @property {{ id: string; method: string }} B * @property {string} C * * @typedef {string} ExtraBracketsInTupleVariant * @property {string} A * * @typedef {string} ExtraBracketsInUnnamedStruct * @property {string} "0" * * @typedef {{ * a: string, * }} First * @property {string} a * * @typedef {{ * a: number, * b: number, * }} FlattenA * @property {number} a * @property {number} b * * @typedef {{ * a: FlattenA, * c: number, * }} FlattenB * @property {FlattenA} a * @property {number} c * * @typedef {{ * a: FlattenA, * c: number, * }} FlattenC * @property {FlattenA} a * @property {number} c * * @typedef {{ * a: FlattenA, * c: number, * }} FlattenD * @property {FlattenA} a * @property {number} c * * @typedef {{ * b: { * a: FlattenA, * c: number, * }, * d: number, * }} FlattenE * @property {{ * a: FlattenA, * c: number, * }} b * @property {number} d * * @typedef {"One" | "Two" | "Three"} FlattenEnum * @property {"One"} One * @property {"Two"} Two * @property {"Three"} Three * * @typedef {{ * outer: string, * inner: FlattenEnum, * }} FlattenEnumStruct * @property {string} outer * @property {FlattenEnum} inner * * @typedef {{ * b: { * a: FlattenA, * c: number, * }, * d: number, * }} FlattenF * @property {{ * a: FlattenA, * c: number, * }} b * @property {number} d * * @typedef {{ * b: FlattenB, * d: number, * }} FlattenG * @property {FlattenB} b * @property {number} d * * @typedef {{ * id: string, * result: NestedEnum, * }} FlattenOnNestedEnum * @property {string} id * @property {NestedEnum} result * * @typedef {{ * c: Inner, * }} FlattenedInner * @property {Inner} c * * @typedef {{ * a: First, * b: { * a: string, * }, * }} Fourth * @property {First} a * @property {{ * a: string, * }} b * * @typedef {{ * value: T, * values: T[], * }} Generic1 * @property {T} value * @property {T[]} values * * @typedef {A | [B, B, B] | C[] | A[][][] | { a: A; b: B; c: C } | number[] | number | number[][]} Generic2 * @property {A} A * @property {[B, B, B]} B * @property {C[]} C * @property {A[][][]} D * @property {{ a: A; b: B; c: C }} E * @property {number[]} X * @property {number} Y * @property {number[][]} Z * * @typedef {{ * value: T, * values: T[], * }} GenericAutoBound * @property {T} value * @property {T[]} values * * @typedef {{ * value: T, * values: T[], * }} GenericAutoBound2 * @property {T} value * @property {T[]} values * * @typedef {{ * value: T, * }} GenericDefault * @property {T} value * * @typedef {{ * value: T, * }} GenericDefaultSkipped * @property {T} value * * @typedef {{ * value: number, * }} GenericDefaultSkippedNonType * @property {number} value * * @typedef {{ * generic_flattened: T, * }} GenericFlattened * @property {T} generic_flattened * * @typedef {T[][]} GenericNewType1 * @property {T[][]} "0" * * @typedef {{ * pair: Pair, * }} GenericParameterOrderPreserved * @property {Pair} pair * * @typedef {{ * arg: T, * }} GenericStruct * @property {T} arg * * @typedef {{ * a: T, * b: [T, T], * c: [T, [T, T]], * d: [T, T, T], * e: [([T, T]), ([T, T]), ([T, T])], * f: T[], * g: T[][], * h: ([([T, T]), ([T, T]), ([T, T])])[], * }} GenericStruct2 * @property {T} a * @property {[T, T]} b * @property {[T, [T, T]]} c * @property {[T, T, T]} d * @property {[([T, T]), ([T, T]), ([T, T])]} e * @property {T[]} f * @property {T[][]} g * @property {([([T, T]), ([T, T]), ([T, T])])[]} h * * @typedef {[T, T[], T[][]]} GenericTuple * @property {T} "0" * @property {T[]} "1" * @property {T[][]} "2" * * @typedef {T} GenericTupleStruct * @property {T} "0" * * @typedef {"Undefined" | T} GenericType * @property {"Undefined"} Undefined * @property {T} Value * * @typedef {{ [key in number]: string }} HasGenericAlias * @property {{ [key in number]: string }} "0" * * @typedef {{ * b: { * data: [number, number], * a: [number, number], * d: [number, number, number], * }, * c: { * data: [number, number, number], * a: [number, number], * d: [number, number, number], * }, * d: [number, number], * }} InlineConstGenericContainer * @property {{ * data: [number, number], * a: [number, number], * d: [number, number, number], * }} b * @property {{ * data: [number, number, number], * a: [number, number], * d: [number, number, number], * }} c * @property {[number, number]} d * * @typedef {{ * a: string, * }} InlineEnumField * @property {{ * a: string, * }} A * * @typedef {{ * g: InlineFlattenGenericsG, * gi: { * t: string, * }, * t: InlineFlattenGenericsG, * }} InlineFlattenGenerics * @property {InlineFlattenGenericsG} g * @property {{ * t: string, * }} gi * @property {InlineFlattenGenericsG} t * * @typedef {{ * t: T, * }} InlineFlattenGenericsG * @property {T} t * * @typedef {{ * optional_field: { * a: string, * } | null, * }} InlineOptionalType * @property {{ * a: string, * } | null} optional_field * * @typedef {{ * data: number[], * a: number[], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }} InlineRecursiveConstGeneric * @property {number[]} data * @property {number[]} a * @property {[number, number, number]} d * @property {InlineRecursiveConstGeneric} e * * @typedef {{ * b: { * data: [number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }, * c: { * data: [number, number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }, * d: [number, number], * }} InlineRecursiveConstGenericContainer * @property {{ * data: [number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }} b * @property {{ * data: [number, number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }} c * @property {[number, number]} d * * @typedef {{ * ref_struct: SimpleStruct, * val: number, * }} InlineStruct * @property {SimpleStruct} ref_struct * @property {number} val * * @typedef {{ * demo: [string, boolean], * }} InlineTuple * @property {[string, boolean]} demo * * @typedef {{ * demo: [{ * demo: [string, boolean], * }, boolean], * }} InlineTuple2 * @property {[{ * demo: [string, boolean], * }, boolean]} demo * * @typedef {{ * inline_this: { * ref_struct: SimpleStruct, * val: number, * }, * dont_inline_this: RefStruct, * }} InlinerStruct * @property {{ * ref_struct: SimpleStruct, * val: number, * }} inline_this * @property {RefStruct} dont_inline_this * * @typedef {{ * a: number, * b: FlattenedInner, * }} Inner * @property {number} a * @property {FlattenedInner} b * * @typedef {{ [key in string]: string }} InternallyTaggedD * @property {{ [key in string]: string }} A * * @typedef {null} InternallyTaggedE * @property {null} A * * @typedef {InternallyTaggedFInner} InternallyTaggedF * @property {InternallyTaggedFInner} A * * @typedef {null} InternallyTaggedFInner * @property {null} A * * @typedef {InternallyTaggedHInner} InternallyTaggedH * @property {InternallyTaggedHInner} A * * @typedef {null} InternallyTaggedHInner * @property {null} "0" * * @typedef {"A" | "B"} InternallyTaggedL * @property {"A" | "B"} A * * @typedef {"A" | "B"} InternallyTaggedLInner * @property {"A"} A * @property {"B"} B * * @typedef {"A" | "B"} InternallyTaggedM * @property {"A" | "B"} A * * @typedef {"A" | "B"} InternallyTaggedMInner * @property {"A"} A * @property {"B"} B * * @typedef {({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }} InternallyTaggedWithAlias * @property {{ field: string }} A * @property {{ other: number }} B * * @typedef {{ * cause: null, * }} InvalidToValidType * @property {null} cause * * @typedef {({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }} Issue221External * @property {{ a: string }} A * @property {{ b: string }} B * * @typedef {({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never }} Issue221UntaggedMixed * @property {{ a: string }} A * @property {{ b: string }} B * @property {{ values: { [key in string]: string } }} Unsafe * * @typedef {({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }} Issue221UntaggedSafe * @property {{ a: string }} A * @property {{ b: string }} B * * @typedef {{ * default_unity_arguments: string[], * }} Issue281 * @property {string[]} default_unity_arguments * * @typedef {{ * test_ing: string, * }} KebabCase * @property {string} test_ing * * @typedef {T} LifetimeGenericEnum * @property {T} Borrowed * @property {T} Owned * * @typedef {{ * borrowed: T[], * owned: T[], * }} LifetimeGenericStruct * @property {T[]} borrowed * @property {T[]} owned * * @typedef {({ project_name: string }) & { progress?: never; status?: never } | { project_name: string; status: string; progress: number }} LoadProjectEvent * @property {{ project_name: string }} Started * @property {{ project_name: string; status: string; progress: number }} ProgressTest * @property {{ project_name: string }} Finished * * @typedef {string | { demo2: string }} MacroEnum * @property {string} Demo * @property {{ demo2: string }} Demo2 * * @typedef {string} MacroStruct * @property {string} "0" * * @typedef {{ * demo: string, * }} MacroStruct2 * @property {string} demo * * @typedef {T} MaybeValidKey * @property {T} "0" * * @typedef {Record} MyEmptyInput * * @typedef {string | number} MyEnum * @property {string} A * @property {number} B * * @typedef {{ inner: First }} MyEnumAdjacent * @property {{ inner: First }} Variant * * @typedef {{ inner: First }} MyEnumExternal * @property {{ inner: First }} Variant * * @typedef {{ inner: First }} MyEnumTagged * @property {{ inner: First }} Variant * * @typedef {{ inner: First }} MyEnumUntagged * @property {{ inner: First }} Variant * * @typedef {{ * data: number[], * a: number[], * d: [number, number], * }} NamedConstGeneric * @property {number[]} data * @property {number[]} a * @property {[number, number]} d * * @typedef {{ * a: NamedConstGeneric, * b: NamedConstGeneric, * d: [number, number], * }} NamedConstGenericContainer * @property {NamedConstGeneric} a * @property {NamedConstGeneric} b * @property {[number, number]} d * * @typedef {string | number} NestedEnum * @property {string} A * @property {number} B * * @typedef {string | "B" | { * a: string, * } | First} Ninth * @property {string} A * @property {"B"} B * @property {{ * a: string, * }} C * @property {First} D * * @typedef {string | null} NonOptional * @property {string | null} "0" * * @typedef {string | null | { a: string | null } | { a?: string | null }} OptionalInEnum * @property {string | null} A * @property {{ a: string | null }} B * @property {{ a?: string | null }} C * * @typedef {string | null} OptionalOnNamedField * @property {string | null} ["0"] * * @typedef {{ * b: string | null, * }} OptionalOnTransparentNamedField * @property {string | null} b * * @typedef {{ * overriden_field: string, * }} OverridenStruct * @property {string} overriden_field * * @typedef {{ * first: Z, * second: A, * }} Pair * @property {Z} first * @property {A} second * * @typedef {{ * a: string, * }} PlaceholderInnerField * @property {string} a * * @typedef {{ * i8: number, * i16: number, * i32: number, * u8: number, * u16: number, * u32: number, * f32: number, * f64: number, * bool: boolean, * char: string, * "Range": Range, * "RangeInclusive": RangeInclusive, * "()": null, * "(String, i32)": [string, number], * "(String, i32, bool)": [string, number, boolean], * "((String, i32), (bool, char, bool), ())": [[string, number], [boolean, string, boolean], null], * "(bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool)": [boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean], * "(Vec, Vec)": [number[], boolean[]], * String: string, * PathBuf: string, * IpAddr: string, * Ipv4Addr: string, * Ipv6Addr: string, * SocketAddr: string, * SocketAddrV4: string, * SocketAddrV6: string, * "Cow<'static, str>": string, * "Cow<'static, i32>": number, * "&'static str": string, * "&'static bool": boolean, * "&'static i32": number, * "Vec": number[], * "&'static [i32]": number[], * "&'static [i32; 3]": [number, number, number], * "[i32; 3]": [number, number, number], * "Vec": MyEnum[], * "&'static [MyEnum]": MyEnum[], * "&'static [MyEnum; 6]": [MyEnum, MyEnum, MyEnum, MyEnum, MyEnum, MyEnum], * "[MyEnum; 2]": [MyEnum, MyEnum], * "&'static [i32; 1]": [number], * "&'static [i32; 0]": [], * "Option": number | null, * "Option<()>": null, * "Option>": number[] | null, * "Result": Result, * "Vec>>": (number | null)[], * "Option>>": number[] | null, * "[Vec; 3]": [string[], string[], string[]], * "Option>": string | null, * "Option>>": string | null, * "PhantomData<()>": null, * "PhantomData": null, * Infallible: never, * Unit1: Unit1, * Unit2: Unit2, * Unit3: Unit3, * Unit4: Unit4, * Unit5: Unit5, * Unit6: Unit6, * Unit7: Unit7, * SimpleStruct: SimpleStruct, * TupleStruct1: TupleStruct1, * TupleStruct3: TupleStruct3, * TestEnum: TestEnum, * RefStruct: RefStruct, * InlinerStruct: InlinerStruct, * "GenericStruct": GenericStruct, * "GenericStruct": GenericStruct, * FlattenEnumStruct: FlattenEnumStruct, * OverridenStruct: OverridenStruct, * HasGenericAlias: HasGenericAlias, * EnumMacroAttributes: EnumMacroAttributes, * InlineEnumField: InlineEnumField, * InlineOptionalType: InlineOptionalType, * Rename: Rename, * TransparentType: TransparentType, * TransparentType2: TransparentType2, * TransparentTypeWithOverride: TransparentTypeWithOverride, * "[Option; 3]": [(number | null), (number | null), (number | null)], * "HashMap": Partial<{ [key in BasicEnum]: null }>, * "HashMap": Partial<{ [key in BasicEnum]: number }>, * "Option>>>": number | null, * "Vec": PlaceholderInnerField[], * EnumReferenceRecordKey: EnumReferenceRecordKey, * FlattenOnNestedEnum: FlattenOnNestedEnum, * MyEmptyInput: MyEmptyInput, * "(String)": string, * "(String,)": [string], * ExtraBracketsInTupleVariant: ExtraBracketsInTupleVariant, * ExtraBracketsInUnnamedStruct: ExtraBracketsInUnnamedStruct, * "Vec": MyEnum[], * InlineTuple: InlineTuple, * InlineTuple2: InlineTuple2, * "Box": string, * "Box": string, * SkippedFieldWithinVariant: SkippedFieldWithinVariant, * KebabCase: KebabCase, * "&[&str]": string[], * "Issue281<'_>": Issue281, * "LifetimeGenericStruct<'_, i32>": LifetimeGenericStruct, * "LifetimeGenericEnum<'_, i32>": LifetimeGenericEnum, * RenameWithWeirdCharsField: RenameWithWeirdCharsField, * RenameWithWeirdCharsVariant: RenameWithWeirdCharsVariant, * RenamedFieldKeys: RenamedFieldKeys, * RenamedVariantWithSkippedPayload: RenamedVariantWithSkippedPayload, * "type_type::Type": Type, * ActualType: ActualType, * SpectaTypeOverride: SpectaTypeOverride, * ContainerTypeOverrideStruct: ContainerTypeOverrideStruct, * ContainerTypeOverrideEnum: ContainerTypeOverrideEnum, * "ContainerTypeOverrideGeneric>": ContainerTypeOverrideGeneric, * "ContainerTypeOverrideToGeneric": ContainerTypeOverrideToGeneric, * ContainerTypeOverrideTuple: ContainerTypeOverrideTuple, * "ContainerTypeOverrideTupleGeneric": ContainerTypeOverrideTupleGeneric, * InvalidToValidType: InvalidToValidType, * TupleStruct: TupleStruct, * TupleStructWithRep: TupleStructWithRep, * "GenericTupleStruct": GenericTupleStruct, * BracedStruct: BracedStruct, * Struct: Struct, * Struct2: Struct2, * Enum: Enum, * Enum2: Enum2, * Enum3: Enum3, * StructRenameAllUppercase: StructRenameAllUppercase, * RenameSerdeSpecialChar: RenameSerdeSpecialChar, * EnumRenameAllUppercase: EnumRenameAllUppercase, * Recursive: Recursive, * RecursiveMapValue: RecursiveMapValue, * RecursiveTransparent: RecursiveTransparent, * RecursiveInEnum: RecursiveInEnum, * NonOptional: NonOptional, * OptionalOnNamedField: OptionalOnNamedField, * OptionalOnTransparentNamedField: OptionalOnTransparentNamedField, * OptionalInEnum: OptionalInEnum, * UntaggedVariants: UntaggedVariants, * UntaggedVariantsWithoutValue: UntaggedVariantsWithoutValue, * UntaggedVariantsWithDuplicateBranches: UntaggedVariantsWithDuplicateBranches, * "HashMap": { [key in string]: null }, * Regular: Regular, * "HashMap": { [key in never]: null }, * "HashMap": { [key in TransparentStruct]: null }, * "HashMap": Partial<{ [key in UnitVariants]: null }>, * "HashMap": Partial<{ [key in UntaggedVariantsKey]: null }>, * ValidMaybeValidKey: ValidMaybeValidKey, * ValidMaybeValidKeyNested: ValidMaybeValidKeyNested, * MacroStruct: MacroStruct, * MacroStruct2: MacroStruct2, * MacroEnum: MacroEnum, * DeprecatedType: DeprecatedType, * DeprecatedTypeWithMsg: DeprecatedTypeWithMsg, * DeprecatedTypeWithMsg2: DeprecatedTypeWithMsg2, * DeprecatedFields: DeprecatedFields, * DeprecatedTupleVariant: DeprecatedTupleVariant, * DeprecatedEnumVariants: DeprecatedEnumVariants, * CommentedStruct: CommentedStruct, * CommentedEnum: CommentedEnum, * SingleLineComment: SingleLineComment, * NonGeneric: Demo, * "HalfGenericA": Demo, * "HalfGenericB": Demo, * "FullGeneric": Demo, * "Another": Demo, * "MapA": { [key in string]: number }, * "MapB": { [key in number]: string }, * "MapC": { [key in string]: AGenericStruct }, * "AGenericStruct": AGenericStruct, * A: A, * DoubleFlattened: DoubleFlattened, * FlattenedInner: FlattenedInner, * BoxFlattened: BoxFlattened, * BoxInline: BoxInline, * First: First, * Second: Second, * Third: Third, * Fourth: Fourth, * TagOnStructWithInline: TagOnStructWithInline, * Sixth: Sixth, * Seventh: Seventh, * Eight: Eight, * Ninth: Ninth, * Tenth: Tenth, * MyEnumTagged: MyEnumTagged, * MyEnumExternal: MyEnumExternal, * MyEnumAdjacent: MyEnumAdjacent, * MyEnumUntagged: MyEnumUntagged, * EmptyStruct: EmptyStruct, * EmptyStructWithTag: EmptyStructWithTag, * AdjacentlyTagged: AdjacentlyTagged, * LoadProjectEvent: LoadProjectEvent, * ExternallyTagged: ExternallyTagged, * Issue221External: Issue221External, * InternallyTaggedD: InternallyTaggedD, * InternallyTaggedE: InternallyTaggedE, * InternallyTaggedF: InternallyTaggedF, * InternallyTaggedH: InternallyTaggedH, * InternallyTaggedL: InternallyTaggedL, * InternallyTaggedM: InternallyTaggedM, * StructWithAlias: StructWithAlias, * StructWithMultipleAliases: StructWithMultipleAliases, * StructWithAliasAndRename: StructWithAliasAndRename, * EnumWithVariantAlias: EnumWithVariantAlias, * EnumWithMultipleVariantAliases: EnumWithMultipleVariantAliases, * EnumWithVariantAliasAndRename: EnumWithVariantAliasAndRename, * InternallyTaggedWithAlias: InternallyTaggedWithAlias, * AdjacentlyTaggedWithAlias: AdjacentlyTaggedWithAlias, * UntaggedWithAlias: UntaggedWithAlias, * Issue221UntaggedSafe: Issue221UntaggedSafe, * Issue221UntaggedMixed: Issue221UntaggedMixed, * EmptyEnum: EmptyEnum, * EmptyEnumTagged: EmptyEnumTagged, * EmptyEnumTaggedWContent: EmptyEnumTaggedWContent, * EmptyEnumUntagged: EmptyEnumUntagged, * SkipOnlyField: SkipOnlyField, * SkipField: SkipField, * SkipVariant: SkipVariant, * SkipUnnamedFieldInVariant: SkipUnnamedFieldInVariant, * SkipNamedFieldInVariant: SkipNamedFieldInVariant, * TransparentWithSkip: TransparentWithSkip, * TransparentWithSkip2: TransparentWithSkip2, * TransparentWithSkip3: TransparentWithSkip3, * SkipVariant2: SkipVariant2, * SkipVariant3: SkipVariant3, * SkipStructFields: SkipStructFields, * SpectaSkipNonTypeField: SpectaSkipNonTypeField, * FlattenA: FlattenA, * FlattenB: FlattenB, * FlattenC: FlattenC, * FlattenD: FlattenD, * FlattenE: FlattenE, * FlattenF: FlattenF, * FlattenG: FlattenG, * TupleNested: TupleNested, * "Generic1<()>": Generic1, * "GenericAutoBound<()>": GenericAutoBound, * "GenericAutoBound2<()>": GenericAutoBound2, * Container1: Container1, * "Generic2<(), String, i32>": Generic2, * "GenericNewType1<()>": GenericNewType1, * "GenericTuple<()>": GenericTuple, * "GenericStruct2<()>": GenericStruct2, * "InlineGenericNewtype": string, * "InlineGenericNested": [string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | string | { value: string }], * "InlineFlattenGenericsG<()>": InlineFlattenGenericsG, * InlineFlattenGenerics: InlineFlattenGenerics, * GenericDefault: GenericDefault, * ChainedGenericDefault: ChainedGenericDefault, * "ChainedGenericDefault": ChainedGenericDefault, * "ChainedGenericDefault": ChainedGenericDefault, * "ChainedGenericDefault": ChainedGenericDefault, * GenericDefaultSkipped: GenericDefaultSkipped, * GenericDefaultSkippedNonType: GenericDefaultSkippedNonType, * GenericParameterOrderPreserved: GenericParameterOrderPreserved, * ConstGenericInNonConstContainer: ConstGenericInNonConstContainer, * ConstGenericInConstContainer: ConstGenericInConstContainer, * NamedConstGenericContainer: NamedConstGenericContainer, * InlineConstGenericContainer: InlineConstGenericContainer, * InlineRecursiveConstGenericContainer: InlineRecursiveConstGenericContainer, * TestCollectionRegister: TestCollectionRegister, * TestCollectionRegister: TestCollectionRegister, * }} Primitives * @property {number} i8 * @property {number} i16 * @property {number} i32 * @property {number} u8 * @property {number} u16 * @property {number} u32 * @property {number} f32 * @property {number} f64 * @property {boolean} bool * @property {string} char * @property {Range} "Range" * @property {RangeInclusive} "RangeInclusive" * @property {null} "()" * @property {[string, number]} "(String, i32)" * @property {[string, number, boolean]} "(String, i32, bool)" * @property {[[string, number], [boolean, string, boolean], null]} "((String, i32), (bool, char, bool), ())" * @property {[boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean]} "(bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool)" * @property {[number[], boolean[]]} "(Vec, Vec)" * @property {string} String * @property {string} PathBuf * @property {string} IpAddr * @property {string} Ipv4Addr * @property {string} Ipv6Addr * @property {string} SocketAddr * @property {string} SocketAddrV4 * @property {string} SocketAddrV6 * @property {string} "Cow<'static, str>" * @property {number} "Cow<'static, i32>" * @property {string} "&'static str" * @property {boolean} "&'static bool" * @property {number} "&'static i32" * @property {number[]} "Vec" * @property {number[]} "&'static [i32]" * @property {[number, number, number]} "&'static [i32; 3]" * @property {[number, number, number]} "[i32; 3]" * @property {MyEnum[]} "Vec" * @property {MyEnum[]} "&'static [MyEnum]" * @property {[MyEnum, MyEnum, MyEnum, MyEnum, MyEnum, MyEnum]} "&'static [MyEnum; 6]" * @property {[MyEnum, MyEnum]} "[MyEnum; 2]" * @property {[number]} "&'static [i32; 1]" * @property {[]} "&'static [i32; 0]" * @property {number | null} "Option" * @property {null} "Option<()>" * @property {number[] | null} "Option>" * @property {Result} "Result" * @property {(number | null)[]} "Vec>>" * @property {number[] | null} "Option>>" * @property {[string[], string[], string[]]} "[Vec; 3]" * @property {string | null} "Option>" * @property {string | null} "Option>>" * @property {null} "PhantomData<()>" * @property {null} "PhantomData" * @property {never} Infallible * @property {Unit1} Unit1 * @property {Unit2} Unit2 * @property {Unit3} Unit3 * @property {Unit4} Unit4 * @property {Unit5} Unit5 * @property {Unit6} Unit6 * @property {Unit7} Unit7 * @property {SimpleStruct} SimpleStruct * @property {TupleStruct1} TupleStruct1 * @property {TupleStruct3} TupleStruct3 * @property {TestEnum} TestEnum * @property {RefStruct} RefStruct * @property {InlinerStruct} InlinerStruct * @property {GenericStruct} "GenericStruct" * @property {GenericStruct} "GenericStruct" * @property {FlattenEnumStruct} FlattenEnumStruct * @property {OverridenStruct} OverridenStruct * @property {HasGenericAlias} HasGenericAlias * @property {EnumMacroAttributes} EnumMacroAttributes * @property {InlineEnumField} InlineEnumField * @property {InlineOptionalType} InlineOptionalType * @property {Rename} Rename * @property {TransparentType} TransparentType * @property {TransparentType2} TransparentType2 * @property {TransparentTypeWithOverride} TransparentTypeWithOverride * @property {[(number | null), (number | null), (number | null)]} "[Option; 3]" * @property {Partial<{ [key in BasicEnum]: null }>} "HashMap" * @property {Partial<{ [key in BasicEnum]: number }>} "HashMap" * @property {number | null} "Option>>>" * @property {PlaceholderInnerField[]} "Vec" * @property {EnumReferenceRecordKey} EnumReferenceRecordKey * @property {FlattenOnNestedEnum} FlattenOnNestedEnum * @property {MyEmptyInput} MyEmptyInput * @property {string} "(String)" * @property {[string]} "(String,)" * @property {ExtraBracketsInTupleVariant} ExtraBracketsInTupleVariant * @property {ExtraBracketsInUnnamedStruct} ExtraBracketsInUnnamedStruct * @property {MyEnum[]} "Vec" * @property {InlineTuple} InlineTuple * @property {InlineTuple2} InlineTuple2 * @property {string} "Box" * @property {string} "Box" * @property {SkippedFieldWithinVariant} SkippedFieldWithinVariant * @property {KebabCase} KebabCase * @property {string[]} "&[&str]" * @property {Issue281} "Issue281<'_>" * @property {LifetimeGenericStruct} "LifetimeGenericStruct<'_, i32>" * @property {LifetimeGenericEnum} "LifetimeGenericEnum<'_, i32>" * @property {RenameWithWeirdCharsField} RenameWithWeirdCharsField * @property {RenameWithWeirdCharsVariant} RenameWithWeirdCharsVariant * @property {RenamedFieldKeys} RenamedFieldKeys * @property {RenamedVariantWithSkippedPayload} RenamedVariantWithSkippedPayload * @property {Type} "type_type::Type" * @property {ActualType} ActualType * @property {SpectaTypeOverride} SpectaTypeOverride * @property {ContainerTypeOverrideStruct} ContainerTypeOverrideStruct * @property {ContainerTypeOverrideEnum} ContainerTypeOverrideEnum * @property {ContainerTypeOverrideGeneric} "ContainerTypeOverrideGeneric>" * @property {ContainerTypeOverrideToGeneric} "ContainerTypeOverrideToGeneric" * @property {ContainerTypeOverrideTuple} ContainerTypeOverrideTuple * @property {ContainerTypeOverrideTupleGeneric} "ContainerTypeOverrideTupleGeneric" * @property {InvalidToValidType} InvalidToValidType * @property {TupleStruct} TupleStruct * @property {TupleStructWithRep} TupleStructWithRep * @property {GenericTupleStruct} "GenericTupleStruct" * @property {BracedStruct} BracedStruct * @property {Struct} Struct * @property {Struct2} Struct2 * @property {Enum} Enum * @property {Enum2} Enum2 * @property {Enum3} Enum3 * @property {StructRenameAllUppercase} StructRenameAllUppercase * @property {RenameSerdeSpecialChar} RenameSerdeSpecialChar * @property {EnumRenameAllUppercase} EnumRenameAllUppercase * @property {Recursive} Recursive * @property {RecursiveMapValue} RecursiveMapValue * @property {RecursiveTransparent} RecursiveTransparent * @property {RecursiveInEnum} RecursiveInEnum * @property {NonOptional} NonOptional * @property {OptionalOnNamedField} OptionalOnNamedField * @property {OptionalOnTransparentNamedField} OptionalOnTransparentNamedField * @property {OptionalInEnum} OptionalInEnum * @property {UntaggedVariants} UntaggedVariants * @property {UntaggedVariantsWithoutValue} UntaggedVariantsWithoutValue * @property {UntaggedVariantsWithDuplicateBranches} UntaggedVariantsWithDuplicateBranches * @property {{ [key in string]: null }} "HashMap" * @property {Regular} Regular * @property {{ [key in never]: null }} "HashMap" * @property {{ [key in TransparentStruct]: null }} "HashMap" * @property {Partial<{ [key in UnitVariants]: null }>} "HashMap" * @property {Partial<{ [key in UntaggedVariantsKey]: null }>} "HashMap" * @property {ValidMaybeValidKey} ValidMaybeValidKey * @property {ValidMaybeValidKeyNested} ValidMaybeValidKeyNested * @property {MacroStruct} MacroStruct * @property {MacroStruct2} MacroStruct2 * @property {MacroEnum} MacroEnum * @property {DeprecatedType} DeprecatedType * @property {DeprecatedTypeWithMsg} DeprecatedTypeWithMsg * @property {DeprecatedTypeWithMsg2} DeprecatedTypeWithMsg2 * @property {DeprecatedFields} DeprecatedFields * @property {DeprecatedTupleVariant} DeprecatedTupleVariant * @property {DeprecatedEnumVariants} DeprecatedEnumVariants * @property {CommentedStruct} CommentedStruct * @property {CommentedEnum} CommentedEnum * @property {SingleLineComment} SingleLineComment * @property {Demo} NonGeneric * @property {Demo} "HalfGenericA" * @property {Demo} "HalfGenericB" * @property {Demo} "FullGeneric" * @property {Demo} "Another" * @property {{ [key in string]: number }} "MapA" * @property {{ [key in number]: string }} "MapB" * @property {{ [key in string]: AGenericStruct }} "MapC" * @property {AGenericStruct} "AGenericStruct" * @property {A} A * @property {DoubleFlattened} DoubleFlattened * @property {FlattenedInner} FlattenedInner * @property {BoxFlattened} BoxFlattened * @property {BoxInline} BoxInline * @property {First} First * @property {Second} Second * @property {Third} Third * @property {Fourth} Fourth * @property {TagOnStructWithInline} TagOnStructWithInline * @property {Sixth} Sixth * @property {Seventh} Seventh * @property {Eight} Eight * @property {Ninth} Ninth * @property {Tenth} Tenth * @property {MyEnumTagged} MyEnumTagged * @property {MyEnumExternal} MyEnumExternal * @property {MyEnumAdjacent} MyEnumAdjacent * @property {MyEnumUntagged} MyEnumUntagged * @property {EmptyStruct} EmptyStruct * @property {EmptyStructWithTag} EmptyStructWithTag * @property {AdjacentlyTagged} AdjacentlyTagged * @property {LoadProjectEvent} LoadProjectEvent * @property {ExternallyTagged} ExternallyTagged * @property {Issue221External} Issue221External * @property {InternallyTaggedD} InternallyTaggedD * @property {InternallyTaggedE} InternallyTaggedE * @property {InternallyTaggedF} InternallyTaggedF * @property {InternallyTaggedH} InternallyTaggedH * @property {InternallyTaggedL} InternallyTaggedL * @property {InternallyTaggedM} InternallyTaggedM * @property {StructWithAlias} StructWithAlias * @property {StructWithMultipleAliases} StructWithMultipleAliases * @property {StructWithAliasAndRename} StructWithAliasAndRename * @property {EnumWithVariantAlias} EnumWithVariantAlias * @property {EnumWithMultipleVariantAliases} EnumWithMultipleVariantAliases * @property {EnumWithVariantAliasAndRename} EnumWithVariantAliasAndRename * @property {InternallyTaggedWithAlias} InternallyTaggedWithAlias * @property {AdjacentlyTaggedWithAlias} AdjacentlyTaggedWithAlias * @property {UntaggedWithAlias} UntaggedWithAlias * @property {Issue221UntaggedSafe} Issue221UntaggedSafe * @property {Issue221UntaggedMixed} Issue221UntaggedMixed * @property {EmptyEnum} EmptyEnum * @property {EmptyEnumTagged} EmptyEnumTagged * @property {EmptyEnumTaggedWContent} EmptyEnumTaggedWContent * @property {EmptyEnumUntagged} EmptyEnumUntagged * @property {SkipOnlyField} SkipOnlyField * @property {SkipField} SkipField * @property {SkipVariant} SkipVariant * @property {SkipUnnamedFieldInVariant} SkipUnnamedFieldInVariant * @property {SkipNamedFieldInVariant} SkipNamedFieldInVariant * @property {TransparentWithSkip} TransparentWithSkip * @property {TransparentWithSkip2} TransparentWithSkip2 * @property {TransparentWithSkip3} TransparentWithSkip3 * @property {SkipVariant2} SkipVariant2 * @property {SkipVariant3} SkipVariant3 * @property {SkipStructFields} SkipStructFields * @property {SpectaSkipNonTypeField} SpectaSkipNonTypeField * @property {FlattenA} FlattenA * @property {FlattenB} FlattenB * @property {FlattenC} FlattenC * @property {FlattenD} FlattenD * @property {FlattenE} FlattenE * @property {FlattenF} FlattenF * @property {FlattenG} FlattenG * @property {TupleNested} TupleNested * @property {Generic1} "Generic1<()>" * @property {GenericAutoBound} "GenericAutoBound<()>" * @property {GenericAutoBound2} "GenericAutoBound2<()>" * @property {Container1} Container1 * @property {Generic2} "Generic2<(), String, i32>" * @property {GenericNewType1} "GenericNewType1<()>" * @property {GenericTuple} "GenericTuple<()>" * @property {GenericStruct2} "GenericStruct2<()>" * @property {string} "InlineGenericNewtype" * @property {[string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | string | { value: string }]} "InlineGenericNested" * @property {InlineFlattenGenericsG} "InlineFlattenGenericsG<()>" * @property {InlineFlattenGenerics} InlineFlattenGenerics * @property {GenericDefault} GenericDefault * @property {ChainedGenericDefault} ChainedGenericDefault * @property {ChainedGenericDefault} "ChainedGenericDefault" * @property {ChainedGenericDefault} "ChainedGenericDefault" * @property {ChainedGenericDefault} "ChainedGenericDefault" * @property {GenericDefaultSkipped} GenericDefaultSkipped * @property {GenericDefaultSkippedNonType} GenericDefaultSkippedNonType * @property {GenericParameterOrderPreserved} GenericParameterOrderPreserved * @property {ConstGenericInNonConstContainer} ConstGenericInNonConstContainer * @property {ConstGenericInConstContainer} ConstGenericInConstContainer * @property {NamedConstGenericContainer} NamedConstGenericContainer * @property {InlineConstGenericContainer} InlineConstGenericContainer * @property {InlineRecursiveConstGenericContainer} InlineRecursiveConstGenericContainer * @property {TestCollectionRegister} TestCollectionRegister * @property {TestCollectionRegister} TestCollectionRegister * * @typedef {{ * start: T, * end: T, * }} Range * @property {T} start * @property {T} end * * @typedef {{ * start: T, * end: T, * }} RangeInclusive * @property {T} start * @property {T} end * * @typedef {{ * demo: Recursive, * }} Recursive * @property {Recursive} demo * * @typedef {{ demo: RecursiveInEnum }} RecursiveInEnum * @property {{ demo: RecursiveInEnum }} A * * @typedef {{ * demo: RecursiveInline, * }} RecursiveInline * @property {RecursiveInline} demo * * @typedef {{ * demo: { [key in string]: RecursiveMapValue }, * }} RecursiveMapValue * @property {{ [key in string]: RecursiveMapValue }} demo * * @typedef {RecursiveInline} RecursiveTransparent * @property {RecursiveInline} "0" * * @typedef {TestEnum} RefStruct * @property {TestEnum} "0" * * @typedef {{ [key in string]: null }} Regular * @property {{ [key in string]: null }} "0" * * @typedef {"OneWord" | "TwoWords"} Rename * @property {"OneWord"} OneWord * @property {"TwoWords"} TwoWords * * @typedef {{ * b: number, * }} RenameSerdeSpecialChar * @property {number} b * * @typedef {{ * odata_context: string, * }} RenameWithWeirdCharsField * @property {string} odata_context * * @typedef {string} RenameWithWeirdCharsVariant * @property {string} A * * @typedef {{ * empty: string, * quote: string, * backslash: string, * newline: string, * line_separator: string, * paragraph_separator: string, * }} RenamedFieldKeys * @property {string} empty * @property {string} quote * @property {string} backslash * @property {string} newline * @property {string} line_separator * @property {string} paragraph_separator * * @typedef {never} RenamedVariantWithSkippedPayload * @property {never} A * * @typedef {{ * ok: T, * err: E, * }} Result * @property {T} ok * @property {E} err * * @typedef {{ * a: number, * }} Second * @property {number} a * * @typedef {{ * a: First, * b: Second, * }} Seventh * @property {First} a * @property {Second} b * * @typedef {{ * a: number, * b: string, * c: [number, string, number], * d: string[], * e: string | null, * }} SimpleStruct * @property {number} a * @property {string} b * @property {[number, string, number]} c * @property {string[]} d * @property {string | null} e * * Some single-line comment * * @typedef { * /** Some single-line comment */ * number | * /** Some single-line comment */ * { * /** Some single-line comment */ * a: number }} SingleLineComment * @property { * /** Some single-line comment */ * number} A - Some single-line comment * @property { * /** Some single-line comment */ * { * /** Some single-line comment */ * a: number }} B - Some single-line comment * * @typedef {{ * a: First, * b: First, * }} Sixth * @property {First} a * @property {First} b * * @typedef {{ * b: number, * }} SkipField * @property {number} b * * @typedef {Record | { b: number }} SkipNamedFieldInVariant * @property {Record} A * @property {{ b: number }} B * * @typedef {Record} SkipOnlyField * * @typedef {{ * a: number, * }} SkipStructFields * @property {number} a * * @typedef {never | [number]} SkipUnnamedFieldInVariant * @property {never} A * @property {[number]} B * * @typedef {string} SkipVariant * @property {string} A * * @typedef {string} SkipVariant2 * @property {string} A * * @typedef {{ a: string }} SkipVariant3 * @property {{ a: string }} A * * @typedef {never | string} SkippedFieldWithinVariant * @property {never} A * @property {string} B * * @typedef {{ * a: number, * }} SpectaSkipNonTypeField * @property {number} a * * @typedef {{ * string_ident: string, * u32_ident: number, * path: string, * tuple: [string, number], * }} SpectaTypeOverride * @property {string} string_ident * @property {number} u32_ident * @property {string} path * @property {[string, number]} tuple * * @typedef {{ * a: string, * }} Struct * @property {string} a * * @typedef {{ * a: string, * }} Struct2 * @property {string} a * * @typedef {{ * a: number, * b: number, * }} StructRenameAllUppercase * @property {number} a * @property {number} b * * @typedef {{ * field: string, * }} StructWithAlias * @property {string} field * * @typedef {{ * field: string, * }} StructWithAliasAndRename * @property {string} field * * @typedef {{ * field: string, * }} StructWithMultipleAliases * @property {string} field * * @typedef {{ * a: First, * b: { * a: string, * }, * }} TagOnStructWithInline * @property {First} a * @property {{ * a: string, * }} b * * @typedef {string | "B" | { * a: string, * } | First} Tenth * @property {string} A * @property {"B"} B * @property {{ * a: string, * }} C * @property {First} D * * @typedef {never} TestCollectionRegister * * @typedef {"Unit" | number | [number, number] | { a: number }} TestEnum * @property {"Unit"} Unit * @property {number} Single * @property {[number, number]} Multiple * @property {{ a: number }} Struct * * @typedef {{ * a: First, * b: { [key in string]: string }, * c: First, * }} Third * @property {First} a * @property {{ [key in string]: string }} b * @property {First} c * * @typedef {{ * a: string, * }} ToBeFlattened * @property {string} a * * @typedef {string} TransparentStruct * @property {string} "0" * * @typedef {TransparentTypeInner} TransparentType * @property {TransparentTypeInner} "0" * * @typedef {null} TransparentType2 * @property {null} "0" * * @typedef {{ * inner: string, * }} TransparentTypeInner * @property {string} inner * * @typedef {string} TransparentTypeWithOverride * @property {string} "0" * * @typedef {null} TransparentWithSkip * @property {null} "0" * * @typedef {string} TransparentWithSkip2 * @property {string} "0" * * @typedef {string} TransparentWithSkip3 * @property {string} "0" * * @typedef {[number[], [number[], number[]], [number[], number[], number[]]]} TupleNested * @property {number[]} "0" * @property {[number[], number[]]} "1" * @property {[number[], number[], number[]]} "2" * * @typedef {string} TupleStruct * @property {string} "0" * * @typedef {number} TupleStruct1 * @property {number} "0" * * @typedef {[number, boolean, string]} TupleStruct3 * @property {number} "0" * @property {boolean} "1" * @property {string} "2" * * @typedef {string} TupleStructWithRep * @property {string} "0" * * @typedef {never} Type * * @typedef {null} Unit1 * * @typedef {Record} Unit2 * * @typedef {[]} Unit3 * * @typedef {null} Unit4 * @property {null} "0" * * @typedef {"A"} Unit5 * @property {"A"} A * * @typedef {[]} Unit6 * @property {[]} A * * @typedef {Record} Unit7 * @property {Record} A * * @typedef {"A" | "B" | "C"} UnitVariants * @property {"A"} A * @property {"B"} B * @property {"C"} C * * @typedef {string | number | { id: string } | [string, boolean]} UntaggedVariants * @property {string} A * @property {number} B * @property {number} C * @property {{ id: string }} D * @property {[string, boolean]} E * * @typedef {string | number} UntaggedVariantsKey * @property {string} A * @property {number} B * @property {number} C * * @typedef {null | number} UntaggedVariantsWithDuplicateBranches * @property {null} A * @property {number} B * @property {null} C * * @typedef {string | [number, string] | number} UntaggedVariantsWithoutValue * @property {string} A * @property {[number, string]} B * @property {number} C * * @typedef {({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }} UntaggedWithAlias * @property {{ field: string }} A * @property {{ other: number }} B * * @typedef {{ [key in MaybeValidKey]: null }} ValidMaybeValidKey * @property {{ [key in MaybeValidKey]: null }} "0" * * @typedef {{ [key in MaybeValidKey>]: null }} ValidMaybeValidKeyNested * @property {{ [key in MaybeValidKey>]: null }} "0" */ ════════════════════════════════════════ ================================================ FILE: tests/tests/snapshots/test__jsdoc__jsdoc-export-to-flatfile-serde.snap ================================================ --- source: tests/tests/jsdoc.rs expression: output --- jsdoc-export-to-flatfile-serde (55198 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. /** * @typedef {{ * a: B, * b: { * b: number, * }, * c: B, * d: { * flattened: number, * }, * e: { * generic_flattened: number, * }, * }} A * @property {B} a * @property {{ * b: number, * }} b * @property {B} c * @property {{ * flattened: number, * }} d * @property {{ * generic_flattened: number, * }} e * * @typedef {{ * field: Demo, * }} AGenericStruct * @property {Demo} field * * @typedef {{ * a: GenericType, * }} ActualType * @property {GenericType} a * * @typedef {{ t: "A" } | { t: "B"; c: { * id: string, * method: string, * } } | { t: "C"; c: string }} AdjacentlyTagged * @property {{ t: "A" }} A * @property {{ t: "B"; c: { * id: string, * method: string, * } }} B * @property {{ t: "C"; c: string }} C * * @typedef {{ type: "A"; data: { * field: string, * } } | { type: "B"; data: { * other: number, * } }} AdjacentlyTaggedWithAlias * @property {{ type: "A"; data: { * field: string, * } }} A * @property {{ type: "B"; data: { * other: number, * } }} B * * @typedef {{ * b: number, * }} B * @property {number} b * * @typedef {"A" | "B"} BasicEnum * @property {"A"} A * @property {"B"} B * * @typedef {BoxedInner} BoxFlattened * * @typedef {{ * c: { * a: number, * }, * }} BoxInline * @property {{ * a: number, * }} c * * @typedef {{ * a: number, * }} BoxedInner * @property {number} a * * @typedef {string} BracedStruct * @property {string} "0" * * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second * * Some triple-slash comment * Some more triple-slash comment * * @typedef { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * ({ A: number }) & { B?: never } | * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * ({ B: { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * } }) & { A?: never }} CommentedEnum * @property { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * { A: number }} A - Some triple-slash comment Some more triple-slash comment * @property { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * { B: { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * } }} B - Some triple-slash comment Some more triple-slash comment * * Some triple-slash comment * Some more triple-slash comment * * @typedef {{ * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * }} CommentedStruct * @property {number} a - Some triple-slash comment Some more triple-slash comment * * @typedef {{ * data: number[], * a: number[], * d: [number, number], * }} ConstGenericInConstContainer * @property {number[]} data * @property {number[]} a * @property {[number, number]} d * * @typedef {{ * data: [number], * a: [number, number], * d: [number, number], * }} ConstGenericInNonConstContainer * @property {[number]} data * @property {[number, number]} a * @property {[number, number]} d * * @typedef {{ * foo: Generic1, * bar: Generic1[], * baz: { [key in string]: Generic1 }, * }} Container1 * @property {Generic1} foo * @property {Generic1[]} bar * @property {{ [key in string]: Generic1 }} baz * * @typedef {string} ContainerTypeOverrideEnum * * @typedef {string} ContainerTypeOverrideGeneric * * @typedef {string} ContainerTypeOverrideStruct * * @typedef {T} ContainerTypeOverrideToGeneric * * @typedef {[string, number]} ContainerTypeOverrideTuple * * @typedef {[T, string]} ContainerTypeOverrideTupleGeneric * * @typedef {{ * flattened: number, * }} D * @property {number} flattened * * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b * * @typedef { * /** * * @deprecated * */ * "A" | * /** * * @deprecated Nope * */ * "B" | * /** * * @deprecated Nope * */ * "C"} DeprecatedEnumVariants * @property { * /** * * @deprecated * */ * "A"} A - @deprecated * @property { * /** * * @deprecated Nope * */ * "B"} B - @deprecated Nope * @property { * /** * * @deprecated Nope * */ * "C"} C - @deprecated Nope * * @typedef {{ * a: number, * /** * * @deprecated * */ * b: string, * /** * * @deprecated This field is cringe! * */ * c: string, * /** * * @deprecated This field is cringe! * */ * d: string, * }} DeprecatedFields * @property {number} a * @property {string} b - @deprecated * @property {string} c - @deprecated This field is cringe! * @property {string} d - @deprecated This field is cringe! * * @typedef {[ * /** * * @deprecated * */ * string, * /** * * @deprecated Nope * */ * string, * /** * * @deprecated Nope * */ * number]} DeprecatedTupleVariant * @property {string} "0" - @deprecated * @property {string} "1" - @deprecated Nope * @property {number} "2" - @deprecated Nope * * @deprecated * @typedef {{ * a: number, * }} DeprecatedType * @property {number} a * * @deprecated Look at you big man using a deprecation message * @typedef {{ * a: number, * }} DeprecatedTypeWithMsg * @property {number} a * * @deprecated Look at you big man using a deprecation message * @typedef {{ * a: number, * }} DeprecatedTypeWithMsg2 * @property {number} a * * @typedef {{ * a: ToBeFlattened, * b: ToBeFlattened, * }} DoubleFlattened * @property {ToBeFlattened} a * @property {ToBeFlattened} b * * @typedef {{ A: string } | "B"} Eight * @property {{ A: string }} A * @property {"B"} B * * @typedef {never} EmptyEnum * * @typedef {never} EmptyEnumTagged * * @typedef {never} EmptyEnumTaggedWContent * * @typedef {never} EmptyEnumUntagged * * @typedef {Record} EmptyStruct * * @typedef {{ * a: "EmptyStructWithTag", * }} EmptyStructWithTag * @property {"EmptyStructWithTag"} a * * @typedef {{ t: "A" } | { t: "B" }} Enum * @property {{ t: "A" }} A * @property {{ t: "B" }} B * * @typedef {{ t: "C" } | { t: "B" } | { t: "D"; enumField: null }} Enum2 * @property {{ t: "C" }} C * @property {{ t: "B" }} B * @property {{ t: "D"; enumField: null }} D * * @typedef {{ t: "A"; b: string }} Enum3 * @property {{ t: "A"; b: string }} A * * @typedef {({ A: string }) & { D?: never; bbb?: never; cccc?: never } | ({ bbb: number }) & { A?: never; D?: never; cccc?: never } | ({ cccc: number }) & { A?: never; D?: never; bbb?: never } | ({ D: { * a: string, * bbbbbb: number, * } }) & { A?: never; bbb?: never; cccc?: never }} EnumMacroAttributes * @property {{ A: string }} A * @property {{ bbb: number }} bbb * @property {{ cccc: number }} cccc * @property {{ D: { * a: string, * bbbbbb: number, * } }} D * * @typedef {{ * a: Partial<{ [key in BasicEnum]: number }>, * }} EnumReferenceRecordKey * @property {Partial<{ [key in BasicEnum]: number }>} a * * @typedef {"HELLOWORLD" | "VARIANTB" | "TESTINGWORDS"} EnumRenameAllUppercase * @property {"HELLOWORLD"} HELLOWORLD * @property {"VARIANTB"} VARIANTB * @property {"TESTINGWORDS"} TESTINGWORDS * * @typedef {"Variant" | "Other"} EnumWithMultipleVariantAliases * @property {"Variant"} Variant * @property {"Other"} Other * * @typedef {"Variant" | "Other"} EnumWithVariantAlias * @property {"Variant"} Variant * @property {"Other"} Other * * @typedef {"renamed_variant" | "Other"} EnumWithVariantAliasAndRename * @property {"renamed_variant"} renamed_variant * @property {"Other"} Other * * @typedef {"A" | ({ B: { * id: string, * method: string, * } }) & { C?: never } | ({ C: string }) & { B?: never }} ExternallyTagged * @property {"A"} A * @property {{ B: { * id: string, * method: string, * } }} B * @property {{ C: string }} C * * @typedef {{ A: string }} ExtraBracketsInTupleVariant * @property {{ A: string }} A * * @typedef {string} ExtraBracketsInUnnamedStruct * @property {string} "0" * * @typedef {{ * a: string, * }} First * @property {string} a * * @typedef {{ * a: number, * b: number, * }} FlattenA * @property {number} a * @property {number} b * * @typedef {{ * c: number, * } & FlattenA} FlattenB * @property {number} c * * @typedef {{ * c: number, * } & FlattenA} FlattenC * @property {number} c * * @typedef {{ * a: FlattenA, * c: number, * }} FlattenD * @property {FlattenA} a * @property {number} c * * @typedef {{ * b: ({ * c: number, * }) & (FlattenA), * d: number, * }} FlattenE * @property {({ * c: number, * }) & (FlattenA)} b * @property {number} d * * @typedef {{ tag: "One" } | { tag: "Two" } | { tag: "Three" }} FlattenEnum * @property {{ tag: "One" }} One * @property {{ tag: "Two" }} Two * @property {{ tag: "Three" }} Three * * @typedef {{ * outer: string, * } & FlattenEnum} FlattenEnumStruct * @property {string} outer * * @typedef {{ * b: ({ * c: number, * }) & (FlattenA), * d: number, * }} FlattenF * @property {({ * c: number, * }) & (FlattenA)} b * @property {number} d * * @typedef {{ * b: FlattenB, * d: number, * }} FlattenG * @property {FlattenB} b * @property {number} d * * @typedef {{ * id: string, * } & NestedEnum} FlattenOnNestedEnum * @property {string} id * * @typedef {Inner} FlattenedInner * * @typedef {{ * a: First, * b: { * a: string, * }, * }} Fourth * @property {First} a * @property {{ * a: string, * }} b * * @typedef {{ * value: T, * values: T[], * }} Generic1 * @property {T} value * @property {T[]} values * * @typedef {({ A: A }) & { B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ B: [B, B, B] }) & { A?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ C: C[] }) & { A?: never; B?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ D: A[][][] }) & { A?: never; B?: never; C?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ E: { * a: A, * b: B, * c: C, * } }) & { A?: never; B?: never; C?: never; D?: never; X?: never; Y?: never; Z?: never } | ({ X: number[] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; Y?: never; Z?: never } | ({ Y: number }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Z?: never } | ({ Z: number[][] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never }} Generic2 * @property {{ A: A }} A * @property {{ B: [B, B, B] }} B * @property {{ C: C[] }} C * @property {{ D: A[][][] }} D * @property {{ E: { * a: A, * b: B, * c: C, * } }} E * @property {{ X: number[] }} X * @property {{ Y: number }} Y * @property {{ Z: number[][] }} Z * * @typedef {{ * value: T, * values: T[], * }} GenericAutoBound * @property {T} value * @property {T[]} values * * @typedef {{ * value: T, * values: T[], * }} GenericAutoBound2 * @property {T} value * @property {T[]} values * * @typedef {{ * value: T, * }} GenericDefault * @property {T} value * * @typedef {{ * value: T, * }} GenericDefaultSkipped * @property {T} value * * @typedef {{ * value: number, * }} GenericDefaultSkippedNonType * @property {number} value * * @typedef {{ * generic_flattened: T, * }} GenericFlattened * @property {T} generic_flattened * * @typedef {T[][]} GenericNewType1 * @property {T[][]} "0" * * @typedef {{ * pair: Pair, * }} GenericParameterOrderPreserved * @property {Pair} pair * * @typedef {{ * arg: T, * }} GenericStruct * @property {T} arg * * @typedef {{ * a: T, * b: [T, T], * c: [T, [T, T]], * d: [T, T, T], * e: [([T, T]), ([T, T]), ([T, T])], * f: T[], * g: T[][], * h: ([([T, T]), ([T, T]), ([T, T])])[], * }} GenericStruct2 * @property {T} a * @property {[T, T]} b * @property {[T, [T, T]]} c * @property {[T, T, T]} d * @property {[([T, T]), ([T, T]), ([T, T])]} e * @property {T[]} f * @property {T[][]} g * @property {([([T, T]), ([T, T]), ([T, T])])[]} h * * @typedef {[T, T[], T[][]]} GenericTuple * @property {T} "0" * @property {T[]} "1" * @property {T[][]} "2" * * @typedef {T} GenericTupleStruct * @property {T} "0" * * @typedef {"Undefined" | T} GenericType * @property {"Undefined"} Undefined * @property {T} Value * * @typedef {{ [key in number]: string }} HasGenericAlias * @property {{ [key in number]: string }} "0" * * @typedef {{ * b: { * data: [number, number], * a: [number, number], * d: [number, number, number], * }, * c: { * data: [number, number, number], * a: [number, number], * d: [number, number, number], * }, * d: [number, number], * }} InlineConstGenericContainer * @property {{ * data: [number, number], * a: [number, number], * d: [number, number, number], * }} b * @property {{ * data: [number, number, number], * a: [number, number], * d: [number, number, number], * }} c * @property {[number, number]} d * * @typedef {{ A: { * a: string, * } }} InlineEnumField * @property {{ A: { * a: string, * } }} A * * @typedef {{ * g: InlineFlattenGenericsG, * gi: { * t: string, * }, * } & InlineFlattenGenericsG} InlineFlattenGenerics * @property {InlineFlattenGenericsG} g * @property {{ * t: string, * }} gi * * @typedef {{ * t: T, * }} InlineFlattenGenericsG * @property {T} t * * @typedef {{ * optional_field: { * a: string, * } | null, * }} InlineOptionalType * @property {{ * a: string, * } | null} optional_field * * @typedef {{ * data: number[], * a: number[], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }} InlineRecursiveConstGeneric * @property {number[]} data * @property {number[]} a * @property {[number, number, number]} d * @property {InlineRecursiveConstGeneric} e * * @typedef {{ * b: { * data: [number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }, * c: { * data: [number, number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }, * d: [number, number], * }} InlineRecursiveConstGenericContainer * @property {{ * data: [number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }} b * @property {{ * data: [number, number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }} c * @property {[number, number]} d * * @typedef {{ * ref_struct: SimpleStruct, * val: number, * }} InlineStruct * @property {SimpleStruct} ref_struct * @property {number} val * * @typedef {{ * demo: [string, boolean], * }} InlineTuple * @property {[string, boolean]} demo * * @typedef {{ * demo: [{ * demo: [string, boolean], * }, boolean], * }} InlineTuple2 * @property {[{ * demo: [string, boolean], * }, boolean]} demo * * @typedef {{ * inline_this: { * ref_struct: SimpleStruct, * val: number, * }, * dont_inline_this: RefStruct, * }} InlinerStruct * @property {{ * ref_struct: SimpleStruct, * val: number, * }} inline_this * @property {RefStruct} dont_inline_this * * @typedef {{ * a: number, * } & FlattenedInner} Inner * @property {number} a * * @typedef {{ * type: "A", * } & { [key in string]: string }} InternallyTaggedD * @property {{ * type: "A", * } & { [key in string]: string }} A * * @typedef {{ type: "A" }} InternallyTaggedE * @property {{ type: "A" }} A * * @typedef {{ type: "A" }} InternallyTaggedF * @property {{ type: "A" }} A * * @typedef {null} InternallyTaggedFInner * @property {null} A * * @typedef {{ type: "A" }} InternallyTaggedH * @property {{ type: "A" }} A * * @typedef {null} InternallyTaggedHInner * @property {null} "0" * * @typedef {{ * type: "A", * } & { type: "A" } | { type: "B" }} InternallyTaggedL * @property {{ * type: "A", * } & { type: "A" } | { type: "B" }} A * * @typedef {{ type: "A" } | { type: "B" }} InternallyTaggedLInner * @property {{ type: "A" }} A * @property {{ type: "B" }} B * * @typedef {{ type: "A" }} InternallyTaggedM * @property {{ type: "A" }} A * * @typedef {"A" | "B"} InternallyTaggedMInner * @property {"A"} A * @property {"B"} B * * @typedef {{ type: "A"; field: string } | { type: "B"; other: number }} InternallyTaggedWithAlias * @property {{ type: "A"; field: string }} A * @property {{ type: "B"; other: number }} B * * @typedef {{ * cause: null, * }} InvalidToValidType * @property {null} cause * * @typedef {({ A: { * a: string, * } }) & { B?: never } | ({ B: { * b: string, * } }) & { A?: never }} Issue221External * @property {{ A: { * a: string, * } }} A * @property {{ B: { * b: string, * } }} B * * @typedef {({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never }} Issue221UntaggedMixed * @property {{ a: string }} A * @property {{ b: string }} B * @property {{ values: { [key in string]: string } }} Unsafe * * @typedef {({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }} Issue221UntaggedSafe * @property {{ a: string }} A * @property {{ b: string }} B * * @typedef {{ * default_unity_arguments: string[], * }} Issue281 * @property {string[]} default_unity_arguments * * @typedef {{ * "test-ing": string, * }} KebabCase * @property {string} "test-ing" * * @typedef {({ Borrowed: T }) & { Owned?: never } | ({ Owned: T }) & { Borrowed?: never }} LifetimeGenericEnum * @property {{ Borrowed: T }} Borrowed * @property {{ Owned: T }} Owned * * @typedef {{ * borrowed: T[], * owned: T[], * }} LifetimeGenericStruct * @property {T[]} borrowed * @property {T[]} owned * * @typedef {{ event: "started"; data: { * projectName: string, * } } | { event: "progressTest"; data: { * projectName: string, * status: string, * progress: number, * } } | { event: "finished"; data: { * projectName: string, * } }} LoadProjectEvent * @property {{ event: "started"; data: { * projectName: string, * } }} started * @property {{ event: "progressTest"; data: { * projectName: string, * status: string, * progress: number, * } }} progressTest * @property {{ event: "finished"; data: { * projectName: string, * } }} finished * * @typedef {({ Demo: string }) & { Demo2?: never } | ({ Demo2: { * demo2: string, * } }) & { Demo?: never }} MacroEnum * @property {{ Demo: string }} Demo * @property {{ Demo2: { * demo2: string, * } }} Demo2 * * @typedef {string} MacroStruct * @property {string} "0" * * @typedef {{ * demo: string, * }} MacroStruct2 * @property {string} demo * * @typedef {T} MaybeValidKey * @property {T} "0" * * @typedef {Record} MyEmptyInput * * @typedef {({ A: string }) & { B?: never } | ({ B: number }) & { A?: never }} MyEnum * @property {{ A: string }} A * @property {{ B: number }} B * * @typedef {{ t: "Variant"; c: { * inner: First, * } }} MyEnumAdjacent * @property {{ t: "Variant"; c: { * inner: First, * } }} Variant * * @typedef {{ Variant: { * inner: First, * } }} MyEnumExternal * @property {{ Variant: { * inner: First, * } }} Variant * * @typedef {{ type: "Variant"; inner: First }} MyEnumTagged * @property {{ type: "Variant"; inner: First }} Variant * * @typedef {{ inner: First }} MyEnumUntagged * @property {{ inner: First }} Variant * * @typedef {{ * data: number[], * a: number[], * d: [number, number], * }} NamedConstGeneric * @property {number[]} data * @property {number[]} a * @property {[number, number]} d * * @typedef {{ * a: NamedConstGeneric, * b: NamedConstGeneric, * d: [number, number], * }} NamedConstGenericContainer * @property {NamedConstGeneric} a * @property {NamedConstGeneric} b * @property {[number, number]} d * * @typedef {{ type: "a"; value: string } | { type: "b"; value: number }} NestedEnum * @property {{ type: "a"; value: string }} a * @property {{ type: "b"; value: number }} b * * @typedef {{ t: "A"; c: string } | { t: "B" } | { t: "C"; c: { * a: string, * } } | { t: "D"; c: First }} Ninth * @property {{ t: "A"; c: string }} A * @property {{ t: "B" }} B * @property {{ t: "C"; c: { * a: string, * } }} C * @property {{ t: "D"; c: First }} D * * @typedef {string | null} NonOptional * @property {string | null} "0" * * @typedef {({ A?: string | null }) & { B?: never; C?: never } | ({ B: { * a: string | null, * } }) & { A?: never; C?: never } | ({ C: { * a?: string | null, * } }) & { A?: never; B?: never }} OptionalInEnum * @property {{ A?: string | null }} A * @property {{ B: { * a: string | null, * } }} B * @property {{ C: { * a?: string | null, * } }} C * * @typedef {string | null} OptionalOnNamedField * @property {string | null} ["0"] * * @typedef {{ * b: string | null, * }} OptionalOnTransparentNamedField * @property {string | null} b * * @typedef {{ * overriden_field: string, * }} OverridenStruct * @property {string} overriden_field * * @typedef {{ * first: Z, * second: A, * }} Pair * @property {Z} first * @property {A} second * * @typedef {{ * a: string, * }} PlaceholderInnerField * @property {string} a * * @typedef {{ * i8: number, * i16: number, * i32: number, * u8: number, * u16: number, * u32: number, * f32: number, * f64: number, * bool: boolean, * char: string, * "Range": Range, * "RangeInclusive": RangeInclusive, * "()": null, * "(String, i32)": [string, number], * "(String, i32, bool)": [string, number, boolean], * "((String, i32), (bool, char, bool), ())": [[string, number], [boolean, string, boolean], null], * "(bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool)": [boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean], * "(Vec, Vec)": [number[], boolean[]], * String: string, * PathBuf: string, * IpAddr: string, * Ipv4Addr: string, * Ipv6Addr: string, * SocketAddr: string, * SocketAddrV4: string, * SocketAddrV6: string, * "Cow<'static, str>": string, * "Cow<'static, i32>": number, * "&'static str": string, * "&'static bool": boolean, * "&'static i32": number, * "Vec": number[], * "&'static [i32]": number[], * "&'static [i32; 3]": [number, number, number], * "[i32; 3]": [number, number, number], * "Vec": MyEnum[], * "&'static [MyEnum]": MyEnum[], * "&'static [MyEnum; 6]": [MyEnum, MyEnum, MyEnum, MyEnum, MyEnum, MyEnum], * "[MyEnum; 2]": [MyEnum, MyEnum], * "&'static [i32; 1]": [number], * "&'static [i32; 0]": [], * "Option": number | null, * "Option<()>": null, * "Option>": number[] | null, * "Result": Result, * "Vec>>": (number | null)[], * "Option>>": number[] | null, * "[Vec; 3]": [string[], string[], string[]], * "Option>": string | null, * "Option>>": string | null, * "PhantomData<()>": null, * "PhantomData": null, * Infallible: never, * Unit1: Unit1, * Unit2: Unit2, * Unit3: Unit3, * Unit4: Unit4, * Unit5: Unit5, * Unit6: Unit6, * Unit7: Unit7, * SimpleStruct: SimpleStruct, * TupleStruct1: TupleStruct1, * TupleStruct3: TupleStruct3, * TestEnum: TestEnum, * RefStruct: RefStruct, * InlinerStruct: InlinerStruct, * "GenericStruct": GenericStruct, * "GenericStruct": GenericStruct, * FlattenEnumStruct: FlattenEnumStruct, * OverridenStruct: OverridenStruct, * HasGenericAlias: HasGenericAlias, * EnumMacroAttributes: EnumMacroAttributes, * InlineEnumField: InlineEnumField, * InlineOptionalType: InlineOptionalType, * Rename: Rename, * TransparentType: TransparentType, * TransparentType2: TransparentType2, * TransparentTypeWithOverride: TransparentTypeWithOverride, * "[Option; 3]": [(number | null), (number | null), (number | null)], * "HashMap": Partial<{ [key in BasicEnum]: null }>, * "HashMap": Partial<{ [key in BasicEnum]: number }>, * "Option>>>": number | null, * "Vec": PlaceholderInnerField[], * EnumReferenceRecordKey: EnumReferenceRecordKey, * FlattenOnNestedEnum: FlattenOnNestedEnum, * MyEmptyInput: MyEmptyInput, * "(String)": string, * "(String,)": [string], * ExtraBracketsInTupleVariant: ExtraBracketsInTupleVariant, * ExtraBracketsInUnnamedStruct: ExtraBracketsInUnnamedStruct, * "Vec": MyEnum[], * InlineTuple: InlineTuple, * InlineTuple2: InlineTuple2, * "Box": string, * "Box": string, * SkippedFieldWithinVariant: SkippedFieldWithinVariant, * KebabCase: KebabCase, * "&[&str]": string[], * "Issue281<'_>": Issue281, * "LifetimeGenericStruct<'_, i32>": LifetimeGenericStruct, * "LifetimeGenericEnum<'_, i32>": LifetimeGenericEnum, * RenameWithWeirdCharsField: RenameWithWeirdCharsField, * RenameWithWeirdCharsVariant: RenameWithWeirdCharsVariant, * RenamedFieldKeys: RenamedFieldKeys, * RenamedVariantWithSkippedPayload: RenamedVariantWithSkippedPayload, * "type_type::Type": Type, * ActualType: ActualType, * SpectaTypeOverride: SpectaTypeOverride, * ContainerTypeOverrideStruct: ContainerTypeOverrideStruct, * ContainerTypeOverrideEnum: ContainerTypeOverrideEnum, * "ContainerTypeOverrideGeneric>": ContainerTypeOverrideGeneric, * "ContainerTypeOverrideToGeneric": ContainerTypeOverrideToGeneric, * ContainerTypeOverrideTuple: ContainerTypeOverrideTuple, * "ContainerTypeOverrideTupleGeneric": ContainerTypeOverrideTupleGeneric, * InvalidToValidType: InvalidToValidType, * TupleStruct: TupleStruct, * TupleStructWithRep: TupleStructWithRep, * "GenericTupleStruct": GenericTupleStruct, * BracedStruct: BracedStruct, * Struct: StructNew, * Struct2: Struct2, * Enum: Enum, * Enum2: Enum2, * Enum3: Enum3, * StructRenameAllUppercase: StructRenameAllUppercase, * RenameSerdeSpecialChar: RenameSerdeSpecialChar, * EnumRenameAllUppercase: EnumRenameAllUppercase, * Recursive: Recursive, * RecursiveMapValue: RecursiveMapValue, * RecursiveTransparent: RecursiveTransparent, * RecursiveInEnum: RecursiveInEnum, * NonOptional: NonOptional, * OptionalOnNamedField: OptionalOnNamedField, * OptionalOnTransparentNamedField: OptionalOnTransparentNamedField, * OptionalInEnum: OptionalInEnum, * UntaggedVariants: UntaggedVariants, * UntaggedVariantsWithoutValue: UntaggedVariantsWithoutValue, * UntaggedVariantsWithDuplicateBranches: UntaggedVariantsWithDuplicateBranches, * "HashMap": { [key in string]: null }, * Regular: Regular, * "HashMap": { [key in never]: null }, * "HashMap": { [key in TransparentStruct]: null }, * "HashMap": Partial<{ [key in UnitVariants]: null }>, * "HashMap": Partial<{ [key in UntaggedVariantsKey]: null }>, * ValidMaybeValidKey: ValidMaybeValidKey, * ValidMaybeValidKeyNested: ValidMaybeValidKeyNested, * MacroStruct: MacroStruct, * MacroStruct2: MacroStruct2, * MacroEnum: MacroEnum, * DeprecatedType: DeprecatedType, * DeprecatedTypeWithMsg: DeprecatedTypeWithMsg, * DeprecatedTypeWithMsg2: DeprecatedTypeWithMsg2, * DeprecatedFields: DeprecatedFields, * DeprecatedTupleVariant: DeprecatedTupleVariant, * DeprecatedEnumVariants: DeprecatedEnumVariants, * CommentedStruct: CommentedStruct, * CommentedEnum: CommentedEnum, * SingleLineComment: SingleLineComment, * NonGeneric: Demo, * "HalfGenericA": Demo, * "HalfGenericB": Demo, * "FullGeneric": Demo, * "Another": Demo, * "MapA": { [key in string]: number }, * "MapB": { [key in number]: string }, * "MapC": { [key in string]: AGenericStruct }, * "AGenericStruct": AGenericStruct, * A: A, * DoubleFlattened: DoubleFlattened, * FlattenedInner: FlattenedInner, * BoxFlattened: BoxFlattened, * BoxInline: BoxInline, * First: First, * Second: Second, * Third: Third, * Fourth: Fourth, * TagOnStructWithInline: TagOnStructWithInline, * Sixth: Sixth, * Seventh: Seventh, * Eight: Eight, * Ninth: Ninth, * Tenth: Tenth, * MyEnumTagged: MyEnumTagged, * MyEnumExternal: MyEnumExternal, * MyEnumAdjacent: MyEnumAdjacent, * MyEnumUntagged: MyEnumUntagged, * EmptyStruct: EmptyStruct, * EmptyStructWithTag: EmptyStructWithTag, * AdjacentlyTagged: AdjacentlyTagged, * LoadProjectEvent: LoadProjectEvent, * ExternallyTagged: ExternallyTagged, * Issue221External: Issue221External, * InternallyTaggedD: InternallyTaggedD, * InternallyTaggedE: InternallyTaggedE, * InternallyTaggedF: InternallyTaggedF, * InternallyTaggedH: InternallyTaggedH, * InternallyTaggedL: InternallyTaggedL, * InternallyTaggedM: InternallyTaggedM, * StructWithAlias: StructWithAlias, * StructWithMultipleAliases: StructWithMultipleAliases, * StructWithAliasAndRename: StructWithAliasAndRename, * EnumWithVariantAlias: EnumWithVariantAlias, * EnumWithMultipleVariantAliases: EnumWithMultipleVariantAliases, * EnumWithVariantAliasAndRename: EnumWithVariantAliasAndRename, * InternallyTaggedWithAlias: InternallyTaggedWithAlias, * AdjacentlyTaggedWithAlias: AdjacentlyTaggedWithAlias, * UntaggedWithAlias: UntaggedWithAlias, * Issue221UntaggedSafe: Issue221UntaggedSafe, * Issue221UntaggedMixed: Issue221UntaggedMixed, * EmptyEnum: EmptyEnum, * EmptyEnumTagged: EmptyEnumTagged, * EmptyEnumTaggedWContent: EmptyEnumTaggedWContent, * EmptyEnumUntagged: EmptyEnumUntagged, * SkipOnlyField: SkipOnlyField, * SkipField: SkipField, * SkipVariant: SkipVariant, * SkipUnnamedFieldInVariant: SkipUnnamedFieldInVariant, * SkipNamedFieldInVariant: SkipNamedFieldInVariant, * TransparentWithSkip: TransparentWithSkip, * TransparentWithSkip2: TransparentWithSkip2, * TransparentWithSkip3: TransparentWithSkip3, * SkipVariant2: SkipVariant2, * SkipVariant3: SkipVariant3, * SkipStructFields: SkipStructFields, * SpectaSkipNonTypeField: SpectaSkipNonTypeField, * FlattenA: FlattenA, * FlattenB: FlattenB, * FlattenC: FlattenC, * FlattenD: FlattenD, * FlattenE: FlattenE, * FlattenF: FlattenF, * FlattenG: FlattenG, * TupleNested: TupleNested, * "Generic1<()>": Generic1, * "GenericAutoBound<()>": GenericAutoBound, * "GenericAutoBound2<()>": GenericAutoBound2, * Container1: Container1, * "Generic2<(), String, i32>": Generic2, * "GenericNewType1<()>": GenericNewType1, * "GenericTuple<()>": GenericTuple, * "GenericStruct2<()>": GenericStruct2, * "InlineGenericNewtype": string, * "InlineGenericNested": [string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | ({ Unnamed: string }) & { Named?: never } | ({ Named: { * value: string, * } }) & { Unnamed?: never }], * "InlineFlattenGenericsG<()>": InlineFlattenGenericsG, * InlineFlattenGenerics: InlineFlattenGenerics, * GenericDefault: GenericDefault, * ChainedGenericDefault: ChainedGenericDefault, * "ChainedGenericDefault": ChainedGenericDefault, * "ChainedGenericDefault": ChainedGenericDefault, * "ChainedGenericDefault": ChainedGenericDefault, * GenericDefaultSkipped: GenericDefaultSkipped, * GenericDefaultSkippedNonType: GenericDefaultSkippedNonType, * GenericParameterOrderPreserved: GenericParameterOrderPreserved, * ConstGenericInNonConstContainer: ConstGenericInNonConstContainer, * ConstGenericInConstContainer: ConstGenericInConstContainer, * NamedConstGenericContainer: NamedConstGenericContainer, * InlineConstGenericContainer: InlineConstGenericContainer, * InlineRecursiveConstGenericContainer: InlineRecursiveConstGenericContainer, * TestCollectionRegister: TestCollectionRegister, * TestCollectionRegister: TestCollectionRegister, * }} Primitives * @property {number} i8 * @property {number} i16 * @property {number} i32 * @property {number} u8 * @property {number} u16 * @property {number} u32 * @property {number} f32 * @property {number} f64 * @property {boolean} bool * @property {string} char * @property {Range} "Range" * @property {RangeInclusive} "RangeInclusive" * @property {null} "()" * @property {[string, number]} "(String, i32)" * @property {[string, number, boolean]} "(String, i32, bool)" * @property {[[string, number], [boolean, string, boolean], null]} "((String, i32), (bool, char, bool), ())" * @property {[boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean]} "(bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool)" * @property {[number[], boolean[]]} "(Vec, Vec)" * @property {string} String * @property {string} PathBuf * @property {string} IpAddr * @property {string} Ipv4Addr * @property {string} Ipv6Addr * @property {string} SocketAddr * @property {string} SocketAddrV4 * @property {string} SocketAddrV6 * @property {string} "Cow<'static, str>" * @property {number} "Cow<'static, i32>" * @property {string} "&'static str" * @property {boolean} "&'static bool" * @property {number} "&'static i32" * @property {number[]} "Vec" * @property {number[]} "&'static [i32]" * @property {[number, number, number]} "&'static [i32; 3]" * @property {[number, number, number]} "[i32; 3]" * @property {MyEnum[]} "Vec" * @property {MyEnum[]} "&'static [MyEnum]" * @property {[MyEnum, MyEnum, MyEnum, MyEnum, MyEnum, MyEnum]} "&'static [MyEnum; 6]" * @property {[MyEnum, MyEnum]} "[MyEnum; 2]" * @property {[number]} "&'static [i32; 1]" * @property {[]} "&'static [i32; 0]" * @property {number | null} "Option" * @property {null} "Option<()>" * @property {number[] | null} "Option>" * @property {Result} "Result" * @property {(number | null)[]} "Vec>>" * @property {number[] | null} "Option>>" * @property {[string[], string[], string[]]} "[Vec; 3]" * @property {string | null} "Option>" * @property {string | null} "Option>>" * @property {null} "PhantomData<()>" * @property {null} "PhantomData" * @property {never} Infallible * @property {Unit1} Unit1 * @property {Unit2} Unit2 * @property {Unit3} Unit3 * @property {Unit4} Unit4 * @property {Unit5} Unit5 * @property {Unit6} Unit6 * @property {Unit7} Unit7 * @property {SimpleStruct} SimpleStruct * @property {TupleStruct1} TupleStruct1 * @property {TupleStruct3} TupleStruct3 * @property {TestEnum} TestEnum * @property {RefStruct} RefStruct * @property {InlinerStruct} InlinerStruct * @property {GenericStruct} "GenericStruct" * @property {GenericStruct} "GenericStruct" * @property {FlattenEnumStruct} FlattenEnumStruct * @property {OverridenStruct} OverridenStruct * @property {HasGenericAlias} HasGenericAlias * @property {EnumMacroAttributes} EnumMacroAttributes * @property {InlineEnumField} InlineEnumField * @property {InlineOptionalType} InlineOptionalType * @property {Rename} Rename * @property {TransparentType} TransparentType * @property {TransparentType2} TransparentType2 * @property {TransparentTypeWithOverride} TransparentTypeWithOverride * @property {[(number | null), (number | null), (number | null)]} "[Option; 3]" * @property {Partial<{ [key in BasicEnum]: null }>} "HashMap" * @property {Partial<{ [key in BasicEnum]: number }>} "HashMap" * @property {number | null} "Option>>>" * @property {PlaceholderInnerField[]} "Vec" * @property {EnumReferenceRecordKey} EnumReferenceRecordKey * @property {FlattenOnNestedEnum} FlattenOnNestedEnum * @property {MyEmptyInput} MyEmptyInput * @property {string} "(String)" * @property {[string]} "(String,)" * @property {ExtraBracketsInTupleVariant} ExtraBracketsInTupleVariant * @property {ExtraBracketsInUnnamedStruct} ExtraBracketsInUnnamedStruct * @property {MyEnum[]} "Vec" * @property {InlineTuple} InlineTuple * @property {InlineTuple2} InlineTuple2 * @property {string} "Box" * @property {string} "Box" * @property {SkippedFieldWithinVariant} SkippedFieldWithinVariant * @property {KebabCase} KebabCase * @property {string[]} "&[&str]" * @property {Issue281} "Issue281<'_>" * @property {LifetimeGenericStruct} "LifetimeGenericStruct<'_, i32>" * @property {LifetimeGenericEnum} "LifetimeGenericEnum<'_, i32>" * @property {RenameWithWeirdCharsField} RenameWithWeirdCharsField * @property {RenameWithWeirdCharsVariant} RenameWithWeirdCharsVariant * @property {RenamedFieldKeys} RenamedFieldKeys * @property {RenamedVariantWithSkippedPayload} RenamedVariantWithSkippedPayload * @property {Type} "type_type::Type" * @property {ActualType} ActualType * @property {SpectaTypeOverride} SpectaTypeOverride * @property {ContainerTypeOverrideStruct} ContainerTypeOverrideStruct * @property {ContainerTypeOverrideEnum} ContainerTypeOverrideEnum * @property {ContainerTypeOverrideGeneric} "ContainerTypeOverrideGeneric>" * @property {ContainerTypeOverrideToGeneric} "ContainerTypeOverrideToGeneric" * @property {ContainerTypeOverrideTuple} ContainerTypeOverrideTuple * @property {ContainerTypeOverrideTupleGeneric} "ContainerTypeOverrideTupleGeneric" * @property {InvalidToValidType} InvalidToValidType * @property {TupleStruct} TupleStruct * @property {TupleStructWithRep} TupleStructWithRep * @property {GenericTupleStruct} "GenericTupleStruct" * @property {BracedStruct} BracedStruct * @property {StructNew} Struct * @property {Struct2} Struct2 * @property {Enum} Enum * @property {Enum2} Enum2 * @property {Enum3} Enum3 * @property {StructRenameAllUppercase} StructRenameAllUppercase * @property {RenameSerdeSpecialChar} RenameSerdeSpecialChar * @property {EnumRenameAllUppercase} EnumRenameAllUppercase * @property {Recursive} Recursive * @property {RecursiveMapValue} RecursiveMapValue * @property {RecursiveTransparent} RecursiveTransparent * @property {RecursiveInEnum} RecursiveInEnum * @property {NonOptional} NonOptional * @property {OptionalOnNamedField} OptionalOnNamedField * @property {OptionalOnTransparentNamedField} OptionalOnTransparentNamedField * @property {OptionalInEnum} OptionalInEnum * @property {UntaggedVariants} UntaggedVariants * @property {UntaggedVariantsWithoutValue} UntaggedVariantsWithoutValue * @property {UntaggedVariantsWithDuplicateBranches} UntaggedVariantsWithDuplicateBranches * @property {{ [key in string]: null }} "HashMap" * @property {Regular} Regular * @property {{ [key in never]: null }} "HashMap" * @property {{ [key in TransparentStruct]: null }} "HashMap" * @property {Partial<{ [key in UnitVariants]: null }>} "HashMap" * @property {Partial<{ [key in UntaggedVariantsKey]: null }>} "HashMap" * @property {ValidMaybeValidKey} ValidMaybeValidKey * @property {ValidMaybeValidKeyNested} ValidMaybeValidKeyNested * @property {MacroStruct} MacroStruct * @property {MacroStruct2} MacroStruct2 * @property {MacroEnum} MacroEnum * @property {DeprecatedType} DeprecatedType * @property {DeprecatedTypeWithMsg} DeprecatedTypeWithMsg * @property {DeprecatedTypeWithMsg2} DeprecatedTypeWithMsg2 * @property {DeprecatedFields} DeprecatedFields * @property {DeprecatedTupleVariant} DeprecatedTupleVariant * @property {DeprecatedEnumVariants} DeprecatedEnumVariants * @property {CommentedStruct} CommentedStruct * @property {CommentedEnum} CommentedEnum * @property {SingleLineComment} SingleLineComment * @property {Demo} NonGeneric * @property {Demo} "HalfGenericA" * @property {Demo} "HalfGenericB" * @property {Demo} "FullGeneric" * @property {Demo} "Another" * @property {{ [key in string]: number }} "MapA" * @property {{ [key in number]: string }} "MapB" * @property {{ [key in string]: AGenericStruct }} "MapC" * @property {AGenericStruct} "AGenericStruct" * @property {A} A * @property {DoubleFlattened} DoubleFlattened * @property {FlattenedInner} FlattenedInner * @property {BoxFlattened} BoxFlattened * @property {BoxInline} BoxInline * @property {First} First * @property {Second} Second * @property {Third} Third * @property {Fourth} Fourth * @property {TagOnStructWithInline} TagOnStructWithInline * @property {Sixth} Sixth * @property {Seventh} Seventh * @property {Eight} Eight * @property {Ninth} Ninth * @property {Tenth} Tenth * @property {MyEnumTagged} MyEnumTagged * @property {MyEnumExternal} MyEnumExternal * @property {MyEnumAdjacent} MyEnumAdjacent * @property {MyEnumUntagged} MyEnumUntagged * @property {EmptyStruct} EmptyStruct * @property {EmptyStructWithTag} EmptyStructWithTag * @property {AdjacentlyTagged} AdjacentlyTagged * @property {LoadProjectEvent} LoadProjectEvent * @property {ExternallyTagged} ExternallyTagged * @property {Issue221External} Issue221External * @property {InternallyTaggedD} InternallyTaggedD * @property {InternallyTaggedE} InternallyTaggedE * @property {InternallyTaggedF} InternallyTaggedF * @property {InternallyTaggedH} InternallyTaggedH * @property {InternallyTaggedL} InternallyTaggedL * @property {InternallyTaggedM} InternallyTaggedM * @property {StructWithAlias} StructWithAlias * @property {StructWithMultipleAliases} StructWithMultipleAliases * @property {StructWithAliasAndRename} StructWithAliasAndRename * @property {EnumWithVariantAlias} EnumWithVariantAlias * @property {EnumWithMultipleVariantAliases} EnumWithMultipleVariantAliases * @property {EnumWithVariantAliasAndRename} EnumWithVariantAliasAndRename * @property {InternallyTaggedWithAlias} InternallyTaggedWithAlias * @property {AdjacentlyTaggedWithAlias} AdjacentlyTaggedWithAlias * @property {UntaggedWithAlias} UntaggedWithAlias * @property {Issue221UntaggedSafe} Issue221UntaggedSafe * @property {Issue221UntaggedMixed} Issue221UntaggedMixed * @property {EmptyEnum} EmptyEnum * @property {EmptyEnumTagged} EmptyEnumTagged * @property {EmptyEnumTaggedWContent} EmptyEnumTaggedWContent * @property {EmptyEnumUntagged} EmptyEnumUntagged * @property {SkipOnlyField} SkipOnlyField * @property {SkipField} SkipField * @property {SkipVariant} SkipVariant * @property {SkipUnnamedFieldInVariant} SkipUnnamedFieldInVariant * @property {SkipNamedFieldInVariant} SkipNamedFieldInVariant * @property {TransparentWithSkip} TransparentWithSkip * @property {TransparentWithSkip2} TransparentWithSkip2 * @property {TransparentWithSkip3} TransparentWithSkip3 * @property {SkipVariant2} SkipVariant2 * @property {SkipVariant3} SkipVariant3 * @property {SkipStructFields} SkipStructFields * @property {SpectaSkipNonTypeField} SpectaSkipNonTypeField * @property {FlattenA} FlattenA * @property {FlattenB} FlattenB * @property {FlattenC} FlattenC * @property {FlattenD} FlattenD * @property {FlattenE} FlattenE * @property {FlattenF} FlattenF * @property {FlattenG} FlattenG * @property {TupleNested} TupleNested * @property {Generic1} "Generic1<()>" * @property {GenericAutoBound} "GenericAutoBound<()>" * @property {GenericAutoBound2} "GenericAutoBound2<()>" * @property {Container1} Container1 * @property {Generic2} "Generic2<(), String, i32>" * @property {GenericNewType1} "GenericNewType1<()>" * @property {GenericTuple} "GenericTuple<()>" * @property {GenericStruct2} "GenericStruct2<()>" * @property {string} "InlineGenericNewtype" * @property {[string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | ({ Unnamed: string }) & { Named?: never } | ({ Named: { * value: string, * } }) & { Unnamed?: never }]} "InlineGenericNested" * @property {InlineFlattenGenericsG} "InlineFlattenGenericsG<()>" * @property {InlineFlattenGenerics} InlineFlattenGenerics * @property {GenericDefault} GenericDefault * @property {ChainedGenericDefault} ChainedGenericDefault * @property {ChainedGenericDefault} "ChainedGenericDefault" * @property {ChainedGenericDefault} "ChainedGenericDefault" * @property {ChainedGenericDefault} "ChainedGenericDefault" * @property {GenericDefaultSkipped} GenericDefaultSkipped * @property {GenericDefaultSkippedNonType} GenericDefaultSkippedNonType * @property {GenericParameterOrderPreserved} GenericParameterOrderPreserved * @property {ConstGenericInNonConstContainer} ConstGenericInNonConstContainer * @property {ConstGenericInConstContainer} ConstGenericInConstContainer * @property {NamedConstGenericContainer} NamedConstGenericContainer * @property {InlineConstGenericContainer} InlineConstGenericContainer * @property {InlineRecursiveConstGenericContainer} InlineRecursiveConstGenericContainer * @property {TestCollectionRegister} TestCollectionRegister * @property {TestCollectionRegister} TestCollectionRegister * * @typedef {{ * start: T, * end: T, * }} Range * @property {T} start * @property {T} end * * @typedef {{ * start: T, * end: T, * }} RangeInclusive * @property {T} start * @property {T} end * * @typedef {{ * demo: Recursive, * }} Recursive * @property {Recursive} demo * * @typedef {{ A: { * demo: RecursiveInEnum, * } }} RecursiveInEnum * @property {{ A: { * demo: RecursiveInEnum, * } }} A * * @typedef {RecursiveInline} RecursiveInline * * @typedef {{ * demo: { [key in string]: RecursiveMapValue }, * }} RecursiveMapValue * @property {{ [key in string]: RecursiveMapValue }} demo * * @typedef {RecursiveInline} RecursiveTransparent * @property {RecursiveInline} "0" * * @typedef {TestEnum} RefStruct * @property {TestEnum} "0" * * @typedef {{ [key in string]: null }} Regular * @property {{ [key in string]: null }} "0" * * @typedef {"OneWord" | "Two words"} Rename * @property {"OneWord"} OneWord * @property {"Two words"} "Two words" * * @typedef {{ * "a/b": number, * }} RenameSerdeSpecialChar * @property {number} "a/b" * * @typedef {{ * "@odata.context": string, * }} RenameWithWeirdCharsField * @property {string} "@odata.context" * * @typedef {{ "@odata.context": string }} RenameWithWeirdCharsVariant * @property {{ "@odata.context": string }} "@odata.context" * * @typedef {{ * "": string, * "a\"b": string, * "a\\b": string, * "line\nbreak": string, * "line\u2028break": string, * "line\u2029break": string, * }} RenamedFieldKeys * @property {string} "" * @property {string} "a\"b" * @property {string} "a\\b" * @property {string} "line\nbreak" * @property {string} "line\u2028break" * @property {string} "line\u2029break" * * @typedef {"a-b"} RenamedVariantWithSkippedPayload * @property {"a-b"} "a-b" * * @typedef {{ * ok: T, * err: E, * }} Result * @property {T} ok * @property {E} err * * @typedef {{ * a: number, * }} Second * @property {number} a * * @typedef {{ * a: First, * b: Second, * }} Seventh * @property {First} a * @property {Second} b * * @typedef {{ * a: number, * b: string, * c: [number, string, number], * d: string[], * e: string | null, * }} SimpleStruct * @property {number} a * @property {string} b * @property {[number, string, number]} c * @property {string[]} d * @property {string | null} e * * Some single-line comment * * @typedef { * /** Some single-line comment */ * ({ A: number }) & { B?: never } | * /** Some single-line comment */ * ({ B: { * /** Some single-line comment */ * a: number, * } }) & { A?: never }} SingleLineComment * @property { * /** Some single-line comment */ * { A: number }} A - Some single-line comment * @property { * /** Some single-line comment */ * { B: { * /** Some single-line comment */ * a: number, * } }} B - Some single-line comment * * @typedef {{ * a: First, * b: First, * }} Sixth * @property {First} a * @property {First} b * * @typedef {{ * b: number, * }} SkipField * @property {number} b * * @typedef {({ A: Record }) & { B?: never } | ({ B: { * b: number, * } }) & { A?: never }} SkipNamedFieldInVariant * @property {{ A: Record }} A * @property {{ B: { * b: number, * } }} B * * @typedef {Record} SkipOnlyField * * @typedef {{ * a: number, * }} SkipStructFields * @property {number} a * * @typedef {"A" | { B: [number] }} SkipUnnamedFieldInVariant * @property {"A"} A * @property {{ B: [number] }} B * * @typedef {{ A: string }} SkipVariant * @property {{ A: string }} A * * @typedef {{ tag: "A"; data: string }} SkipVariant2 * @property {{ tag: "A"; data: string }} A * * @typedef {{ A: { * a: string, * } }} SkipVariant3 * @property {{ A: { * a: string, * } }} A * * @typedef {{ type: "A" } | { type: "B"; data: string }} SkippedFieldWithinVariant * @property {{ type: "A" }} A * @property {{ type: "B"; data: string }} B * * @typedef {{ * a: number, * }} SpectaSkipNonTypeField * @property {number} a * * @typedef {{ * string_ident: string, * u32_ident: number, * path: string, * tuple: [string, number], * }} SpectaTypeOverride * @property {string} string_ident * @property {number} u32_ident * @property {string} path * @property {[string, number]} tuple * * @typedef {{ * b: string, * }} Struct2 * @property {string} b * * @typedef {{ * t: "StructNew", * a: string, * }} StructNew * @property {"StructNew"} t * @property {string} a * * @typedef {{ * A: number, * B: number, * }} StructRenameAllUppercase * @property {number} A * @property {number} B * * @typedef {{ * field: string, * }} StructWithAlias * @property {string} field * * @typedef {{ * renamed_field: string, * }} StructWithAliasAndRename * @property {string} renamed_field * * @typedef {{ * field: string, * }} StructWithMultipleAliases * @property {string} field * * @typedef {{ * type: "TagOnStructWithInline", * a: First, * b: { * a: string, * }, * }} TagOnStructWithInline * @property {"TagOnStructWithInline"} type * @property {First} a * @property {{ * a: string, * }} b * * @typedef {string | "B" | { * a: string, * } | First} Tenth * @property {string} A * @property {"B"} B * @property {{ * a: string, * }} C * @property {First} D * * @typedef {never} TestCollectionRegister * * @typedef {"Unit" | ({ Single: number }) & { Multiple?: never; Struct?: never } | ({ Multiple: [number, number] }) & { Single?: never; Struct?: never } | ({ Struct: { * a: number, * } }) & { Multiple?: never; Single?: never }} TestEnum * @property {"Unit"} Unit * @property {{ Single: number }} Single * @property {{ Multiple: [number, number] }} Multiple * @property {{ Struct: { * a: number, * } }} Struct * * @typedef {{ * b: { [key in string]: string }, * c: First, * } & First} Third * @property {{ [key in string]: string }} b * @property {First} c * * @typedef {{ * a: string, * }} ToBeFlattened * @property {string} a * * @typedef {string} TransparentStruct * @property {string} "0" * * @typedef {TransparentTypeInner} TransparentType * @property {TransparentTypeInner} "0" * * @typedef {null} TransparentType2 * @property {null} "0" * * @typedef {{ * inner: string, * }} TransparentTypeInner * @property {string} inner * * @typedef {string} TransparentTypeWithOverride * @property {string} "0" * * @typedef {null} TransparentWithSkip * @property {null} "0" * * @typedef {string} TransparentWithSkip2 * @property {string} "0" * * @typedef {string} TransparentWithSkip3 * @property {string} "0" * * @typedef {[number[], [number[], number[]], [number[], number[], number[]]]} TupleNested * @property {number[]} "0" * @property {[number[], number[]]} "1" * @property {[number[], number[], number[]]} "2" * * @typedef {string} TupleStruct * @property {string} "0" * * @typedef {number} TupleStruct1 * @property {number} "0" * * @typedef {[number, boolean, string]} TupleStruct3 * @property {number} "0" * @property {boolean} "1" * @property {string} "2" * * @typedef {string} TupleStructWithRep * @property {string} "0" * * @typedef {never} Type * * @typedef {null} Unit1 * * @typedef {Record} Unit2 * * @typedef {[]} Unit3 * * @typedef {null} Unit4 * @property {null} "0" * * @typedef {"A"} Unit5 * @property {"A"} A * * @typedef {{ A: null }} Unit6 * @property {{ A: null }} A * * @typedef {{ A: Record }} Unit7 * @property {{ A: Record }} A * * @typedef {"A" | "B" | "C"} UnitVariants * @property {"A"} A * @property {"B"} B * @property {"C"} C * * @typedef {string | number | { id: string } | [string, boolean]} UntaggedVariants * @property {string} A * @property {number} B * @property {number} C * @property {{ id: string }} D * @property {[string, boolean]} E * * @typedef {string | number} UntaggedVariantsKey * @property {string} A * @property {number} B * @property {number} C * * @typedef {null | number} UntaggedVariantsWithDuplicateBranches * @property {null} A * @property {number} B * @property {null} C * * @typedef {string | [number, string] | number} UntaggedVariantsWithoutValue * @property {string} A * @property {[number, string]} B * @property {number} C * * @typedef {({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }} UntaggedWithAlias * @property {{ field: string }} A * @property {{ other: number }} B * * @typedef {{ [key in MaybeValidKey]: null }} ValidMaybeValidKey * @property {{ [key in MaybeValidKey]: null }} "0" * * @typedef {{ [key in MaybeValidKey>]: null }} ValidMaybeValidKeyNested * @property {{ [key in MaybeValidKey>]: null }} "0" */ ════════════════════════════════════════ ================================================ FILE: tests/tests/snapshots/test__jsdoc__jsdoc-export-to-flatfile-serde_phases.snap ================================================ --- source: tests/tests/jsdoc.rs expression: output --- jsdoc-export-to-flatfile-serde_phases (57121 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. /** * @typedef {{ * a: B, * b: { * b: number, * }, * c: B, * d: { * flattened: number, * }, * e: { * generic_flattened: number, * }, * }} A * @property {B} a * @property {{ * b: number, * }} b * @property {B} c * @property {{ * flattened: number, * }} d * @property {{ * generic_flattened: number, * }} e * * @typedef {{ * field: Demo, * }} AGenericStruct * @property {Demo} field * * @typedef {{ * a: GenericType, * }} ActualType * @property {GenericType} a * * @typedef {{ t: "A" } | { t: "B"; c: { * id: string, * method: string, * } } | { t: "C"; c: string }} AdjacentlyTagged * @property {{ t: "A" }} A * @property {{ t: "B"; c: { * id: string, * method: string, * } }} B * @property {{ t: "C"; c: string }} C * * @typedef {{ type: "A"; data: { * field: string, * } } | { type: "B"; data: { * other: number, * } }} AdjacentlyTaggedWithAlias * @property {{ type: "A"; data: { * field: string, * } }} A * @property {{ type: "B"; data: { * other: number, * } }} B * * @typedef {{ * b: number, * }} B * @property {number} b * * @typedef {"A" | "B"} BasicEnum * @property {"A"} A * @property {"B"} B * * @typedef {BoxedInner} BoxFlattened * * @typedef {{ * c: { * a: number, * }, * }} BoxInline * @property {{ * a: number, * }} c * * @typedef {{ * a: number, * }} BoxedInner * @property {number} a * * @typedef {string} BracedStruct * @property {string} "0" * * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second * * Some triple-slash comment * Some more triple-slash comment * * @typedef { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * ({ A: number }) & { B?: never } | * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * ({ B: { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * } }) & { A?: never }} CommentedEnum * @property { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * { A: number }} A - Some triple-slash comment Some more triple-slash comment * @property { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * { B: { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * } }} B - Some triple-slash comment Some more triple-slash comment * * Some triple-slash comment * Some more triple-slash comment * * @typedef {{ * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * }} CommentedStruct * @property {number} a - Some triple-slash comment Some more triple-slash comment * * @typedef {{ * data: number[], * a: number[], * d: [number, number], * }} ConstGenericInConstContainer * @property {number[]} data * @property {number[]} a * @property {[number, number]} d * * @typedef {{ * data: [number], * a: [number, number], * d: [number, number], * }} ConstGenericInNonConstContainer * @property {[number]} data * @property {[number, number]} a * @property {[number, number]} d * * @typedef {{ * foo: Generic1, * bar: Generic1[], * baz: { [key in string]: Generic1 }, * }} Container1 * @property {Generic1} foo * @property {Generic1[]} bar * @property {{ [key in string]: Generic1 }} baz * * @typedef {string} ContainerTypeOverrideEnum * * @typedef {string} ContainerTypeOverrideGeneric * * @typedef {string} ContainerTypeOverrideStruct * * @typedef {T} ContainerTypeOverrideToGeneric * * @typedef {[string, number]} ContainerTypeOverrideTuple * * @typedef {[T, string]} ContainerTypeOverrideTupleGeneric * * @typedef {{ * flattened: number, * }} D * @property {number} flattened * * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b * * @typedef { * /** * * @deprecated * */ * "A" | * /** * * @deprecated Nope * */ * "B" | * /** * * @deprecated Nope * */ * "C"} DeprecatedEnumVariants * @property { * /** * * @deprecated * */ * "A"} A - @deprecated * @property { * /** * * @deprecated Nope * */ * "B"} B - @deprecated Nope * @property { * /** * * @deprecated Nope * */ * "C"} C - @deprecated Nope * * @typedef {{ * a: number, * /** * * @deprecated * */ * b: string, * /** * * @deprecated This field is cringe! * */ * c: string, * /** * * @deprecated This field is cringe! * */ * d: string, * }} DeprecatedFields * @property {number} a * @property {string} b - @deprecated * @property {string} c - @deprecated This field is cringe! * @property {string} d - @deprecated This field is cringe! * * @typedef {[ * /** * * @deprecated * */ * string, * /** * * @deprecated Nope * */ * string, * /** * * @deprecated Nope * */ * number]} DeprecatedTupleVariant * @property {string} "0" - @deprecated * @property {string} "1" - @deprecated Nope * @property {number} "2" - @deprecated Nope * * @deprecated * @typedef {{ * a: number, * }} DeprecatedType * @property {number} a * * @deprecated Look at you big man using a deprecation message * @typedef {{ * a: number, * }} DeprecatedTypeWithMsg * @property {number} a * * @deprecated Look at you big man using a deprecation message * @typedef {{ * a: number, * }} DeprecatedTypeWithMsg2 * @property {number} a * * @typedef {{ * a: ToBeFlattened, * b: ToBeFlattened, * }} DoubleFlattened * @property {ToBeFlattened} a * @property {ToBeFlattened} b * * @typedef {{ A: string } | "B"} Eight * @property {{ A: string }} A * @property {"B"} B * * @typedef {never} EmptyEnum * * @typedef {never} EmptyEnumTagged * * @typedef {never} EmptyEnumTaggedWContent * * @typedef {never} EmptyEnumUntagged * * @typedef {Record} EmptyStruct * * @typedef {{ * a: "EmptyStructWithTag", * }} EmptyStructWithTag * @property {"EmptyStructWithTag"} a * * @typedef {{ t: "A" } | { t: "B" }} Enum * @property {{ t: "A" }} A * @property {{ t: "B" }} B * * @typedef {{ t: "C" } | { t: "B" } | { t: "D"; enumField: null }} Enum2 * @property {{ t: "C" }} C * @property {{ t: "B" }} B * @property {{ t: "D"; enumField: null }} D * * @typedef {{ t: "A"; b: string }} Enum3 * @property {{ t: "A"; b: string }} A * * @typedef {({ A: string }) & { D?: never; bbb?: never; cccc?: never } | ({ bbb: number }) & { A?: never; D?: never; cccc?: never } | ({ cccc: number }) & { A?: never; D?: never; bbb?: never } | ({ D: { * a: string, * bbbbbb: number, * } }) & { A?: never; bbb?: never; cccc?: never }} EnumMacroAttributes * @property {{ A: string }} A * @property {{ bbb: number }} bbb * @property {{ cccc: number }} cccc * @property {{ D: { * a: string, * bbbbbb: number, * } }} D * * @typedef {{ * a: Partial<{ [key in BasicEnum]: number }>, * }} EnumReferenceRecordKey * @property {Partial<{ [key in BasicEnum]: number }>} a * * @typedef {"HELLOWORLD" | "VARIANTB" | "TESTINGWORDS"} EnumRenameAllUppercase * @property {"HELLOWORLD"} HELLOWORLD * @property {"VARIANTB"} VARIANTB * @property {"TESTINGWORDS"} TESTINGWORDS * * @typedef {"Variant" | "Other"} EnumWithMultipleVariantAliases * @property {"Variant"} Variant * @property {"Other"} Other * * @typedef {"Variant" | "Other"} EnumWithVariantAlias * @property {"Variant"} Variant * @property {"Other"} Other * * @typedef {"renamed_variant" | "Other"} EnumWithVariantAliasAndRename * @property {"renamed_variant"} renamed_variant * @property {"Other"} Other * * @typedef {"A" | ({ B: { * id: string, * method: string, * } }) & { C?: never } | ({ C: string }) & { B?: never }} ExternallyTagged * @property {"A"} A * @property {{ B: { * id: string, * method: string, * } }} B * @property {{ C: string }} C * * @typedef {{ A: string }} ExtraBracketsInTupleVariant * @property {{ A: string }} A * * @typedef {string} ExtraBracketsInUnnamedStruct * @property {string} "0" * * @typedef {{ * a: string, * }} First * @property {string} a * * @typedef {{ * a: number, * b: number, * }} FlattenA * @property {number} a * @property {number} b * * @typedef {{ * c: number, * } & FlattenA} FlattenB * @property {number} c * * @typedef {{ * c: number, * } & FlattenA} FlattenC * @property {number} c * * @typedef {{ * a: FlattenA, * c: number, * }} FlattenD * @property {FlattenA} a * @property {number} c * * @typedef {{ * b: ({ * c: number, * }) & (FlattenA), * d: number, * }} FlattenE * @property {({ * c: number, * }) & (FlattenA)} b * @property {number} d * * @typedef {{ tag: "One" } | { tag: "Two" } | { tag: "Three" }} FlattenEnum * @property {{ tag: "One" }} One * @property {{ tag: "Two" }} Two * @property {{ tag: "Three" }} Three * * @typedef {{ * outer: string, * } & FlattenEnum} FlattenEnumStruct * @property {string} outer * * @typedef {{ * b: ({ * c: number, * }) & (FlattenA), * d: number, * }} FlattenF * @property {({ * c: number, * }) & (FlattenA)} b * @property {number} d * * @typedef {{ * b: FlattenB, * d: number, * }} FlattenG * @property {FlattenB} b * @property {number} d * * @typedef {{ * id: string, * } & NestedEnum} FlattenOnNestedEnum * @property {string} id * * @typedef {Inner} FlattenedInner * * @typedef {{ * a: First, * b: { * a: string, * }, * }} Fourth * @property {First} a * @property {{ * a: string, * }} b * * @typedef {{ * value: T, * values: T[], * }} Generic1 * @property {T} value * @property {T[]} values * * @typedef {({ A: A }) & { B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ B: [B, B, B] }) & { A?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ C: C[] }) & { A?: never; B?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ D: A[][][] }) & { A?: never; B?: never; C?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ E: { * a: A, * b: B, * c: C, * } }) & { A?: never; B?: never; C?: never; D?: never; X?: never; Y?: never; Z?: never } | ({ X: number[] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; Y?: never; Z?: never } | ({ Y: number }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Z?: never } | ({ Z: number[][] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never }} Generic2 * @property {{ A: A }} A * @property {{ B: [B, B, B] }} B * @property {{ C: C[] }} C * @property {{ D: A[][][] }} D * @property {{ E: { * a: A, * b: B, * c: C, * } }} E * @property {{ X: number[] }} X * @property {{ Y: number }} Y * @property {{ Z: number[][] }} Z * * @typedef {{ * value: T, * values: T[], * }} GenericAutoBound * @property {T} value * @property {T[]} values * * @typedef {{ * value: T, * values: T[], * }} GenericAutoBound2 * @property {T} value * @property {T[]} values * * @typedef {{ * value: T, * }} GenericDefault * @property {T} value * * @typedef {{ * value: T, * }} GenericDefaultSkipped * @property {T} value * * @typedef {{ * value: number, * }} GenericDefaultSkippedNonType * @property {number} value * * @typedef {{ * generic_flattened: T, * }} GenericFlattened * @property {T} generic_flattened * * @typedef {T[][]} GenericNewType1 * @property {T[][]} "0" * * @typedef {{ * pair: Pair, * }} GenericParameterOrderPreserved * @property {Pair} pair * * @typedef {{ * arg: T, * }} GenericStruct * @property {T} arg * * @typedef {{ * a: T, * b: [T, T], * c: [T, [T, T]], * d: [T, T, T], * e: [([T, T]), ([T, T]), ([T, T])], * f: T[], * g: T[][], * h: ([([T, T]), ([T, T]), ([T, T])])[], * }} GenericStruct2 * @property {T} a * @property {[T, T]} b * @property {[T, [T, T]]} c * @property {[T, T, T]} d * @property {[([T, T]), ([T, T]), ([T, T])]} e * @property {T[]} f * @property {T[][]} g * @property {([([T, T]), ([T, T]), ([T, T])])[]} h * * @typedef {[T, T[], T[][]]} GenericTuple * @property {T} "0" * @property {T[]} "1" * @property {T[][]} "2" * * @typedef {T} GenericTupleStruct * @property {T} "0" * * @typedef {"Undefined" | T} GenericType * @property {"Undefined"} Undefined * @property {T} Value * * @typedef {{ [key in number]: string }} HasGenericAlias * @property {{ [key in number]: string }} "0" * * @typedef {{ * b: { * data: [number, number], * a: [number, number], * d: [number, number, number], * }, * c: { * data: [number, number, number], * a: [number, number], * d: [number, number, number], * }, * d: [number, number], * }} InlineConstGenericContainer * @property {{ * data: [number, number], * a: [number, number], * d: [number, number, number], * }} b * @property {{ * data: [number, number, number], * a: [number, number], * d: [number, number, number], * }} c * @property {[number, number]} d * * @typedef {{ A: { * a: string, * } }} InlineEnumField * @property {{ A: { * a: string, * } }} A * * @typedef {{ * g: InlineFlattenGenericsG, * gi: { * t: string, * }, * } & InlineFlattenGenericsG} InlineFlattenGenerics * @property {InlineFlattenGenericsG} g * @property {{ * t: string, * }} gi * * @typedef {{ * t: T, * }} InlineFlattenGenericsG * @property {T} t * * @typedef {{ * optional_field: { * a: string, * } | null, * }} InlineOptionalType * @property {{ * a: string, * } | null} optional_field * * @typedef {{ * data: number[], * a: number[], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }} InlineRecursiveConstGeneric * @property {number[]} data * @property {number[]} a * @property {[number, number, number]} d * @property {InlineRecursiveConstGeneric} e * * @typedef {{ * b: { * data: [number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }, * c: { * data: [number, number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }, * d: [number, number], * }} InlineRecursiveConstGenericContainer * @property {{ * data: [number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }} b * @property {{ * data: [number, number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }} c * @property {[number, number]} d * * @typedef {{ * ref_struct: SimpleStruct, * val: number, * }} InlineStruct * @property {SimpleStruct} ref_struct * @property {number} val * * @typedef {{ * demo: [string, boolean], * }} InlineTuple * @property {[string, boolean]} demo * * @typedef {{ * demo: [{ * demo: [string, boolean], * }, boolean], * }} InlineTuple2 * @property {[{ * demo: [string, boolean], * }, boolean]} demo * * @typedef {{ * inline_this: { * ref_struct: SimpleStruct, * val: number, * }, * dont_inline_this: RefStruct, * }} InlinerStruct * @property {{ * ref_struct: SimpleStruct, * val: number, * }} inline_this * @property {RefStruct} dont_inline_this * * @typedef {{ * a: number, * } & FlattenedInner} Inner * @property {number} a * * @typedef {{ * type: "A", * } & { [key in string]: string }} InternallyTaggedD * @property {{ * type: "A", * } & { [key in string]: string }} A * * @typedef {{ type: "A" }} InternallyTaggedE * @property {{ type: "A" }} A * * @typedef {{ type: "A" }} InternallyTaggedF * @property {{ type: "A" }} A * * @typedef {null} InternallyTaggedFInner * @property {null} A * * @typedef {{ type: "A" }} InternallyTaggedH * @property {{ type: "A" }} A * * @typedef {null} InternallyTaggedHInner * @property {null} "0" * * @typedef {{ * type: "A", * } & { type: "A" } | { type: "B" }} InternallyTaggedL * @property {{ * type: "A", * } & { type: "A" } | { type: "B" }} A * * @typedef {{ type: "A" } | { type: "B" }} InternallyTaggedLInner * @property {{ type: "A" }} A * @property {{ type: "B" }} B * * @typedef {{ type: "A" }} InternallyTaggedM * @property {{ type: "A" }} A * * @typedef {"A" | "B"} InternallyTaggedMInner * @property {"A"} A * @property {"B"} B * * @typedef {{ type: "A"; field: string } | { type: "B"; other: number }} InternallyTaggedWithAlias * @property {{ type: "A"; field: string }} A * @property {{ type: "B"; other: number }} B * * @typedef {{ * cause: null, * }} InvalidToValidType * @property {null} cause * * @typedef {({ A: { * a: string, * } }) & { B?: never } | ({ B: { * b: string, * } }) & { A?: never }} Issue221External * @property {{ A: { * a: string, * } }} A * @property {{ B: { * b: string, * } }} B * * @typedef {({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never }} Issue221UntaggedMixed * @property {{ a: string }} A * @property {{ b: string }} B * @property {{ values: { [key in string]: string } }} Unsafe * * @typedef {({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }} Issue221UntaggedSafe * @property {{ a: string }} A * @property {{ b: string }} B * * @typedef {{ * default_unity_arguments: string[], * }} Issue281 * @property {string[]} default_unity_arguments * * https://github.com/specta-rs/specta/issues/374 * * @typedef {Issue374_Serialize | Issue374_Deserialize} Issue374 * @property {Issue374_Serialize} Serialize * @property {Issue374_Deserialize} Deserialize * * https://github.com/specta-rs/specta/issues/374 * * @typedef {{ * foo?: boolean, * bar?: boolean, * }} Issue374_Deserialize * @property {boolean} [foo] * @property {boolean} [bar] * * https://github.com/specta-rs/specta/issues/374 * * @typedef {{ * foo?: boolean, * bar?: boolean, * }} Issue374_Serialize * @property {boolean} [foo] * @property {boolean} [bar] * * @typedef {{ * "test-ing": string, * }} KebabCase * @property {string} "test-ing" * * @typedef {({ Borrowed: T }) & { Owned?: never } | ({ Owned: T }) & { Borrowed?: never }} LifetimeGenericEnum * @property {{ Borrowed: T }} Borrowed * @property {{ Owned: T }} Owned * * @typedef {{ * borrowed: T[], * owned: T[], * }} LifetimeGenericStruct * @property {T[]} borrowed * @property {T[]} owned * * @typedef {{ event: "started"; data: { * projectName: string, * } } | { event: "progressTest"; data: { * projectName: string, * status: string, * progress: number, * } } | { event: "finished"; data: { * projectName: string, * } }} LoadProjectEvent * @property {{ event: "started"; data: { * projectName: string, * } }} started * @property {{ event: "progressTest"; data: { * projectName: string, * status: string, * progress: number, * } }} progressTest * @property {{ event: "finished"; data: { * projectName: string, * } }} finished * * @typedef {({ Demo: string }) & { Demo2?: never } | ({ Demo2: { * demo2: string, * } }) & { Demo?: never }} MacroEnum * @property {{ Demo: string }} Demo * @property {{ Demo2: { * demo2: string, * } }} Demo2 * * @typedef {string} MacroStruct * @property {string} "0" * * @typedef {{ * demo: string, * }} MacroStruct2 * @property {string} demo * * @typedef {T} MaybeValidKey * @property {T} "0" * * @typedef {Record} MyEmptyInput * * @typedef {({ A: string }) & { B?: never } | ({ B: number }) & { A?: never }} MyEnum * @property {{ A: string }} A * @property {{ B: number }} B * * @typedef {{ t: "Variant"; c: { * inner: First, * } }} MyEnumAdjacent * @property {{ t: "Variant"; c: { * inner: First, * } }} Variant * * @typedef {{ Variant: { * inner: First, * } }} MyEnumExternal * @property {{ Variant: { * inner: First, * } }} Variant * * @typedef {{ type: "Variant"; inner: First }} MyEnumTagged * @property {{ type: "Variant"; inner: First }} Variant * * @typedef {{ inner: First }} MyEnumUntagged * @property {{ inner: First }} Variant * * @typedef {{ * data: number[], * a: number[], * d: [number, number], * }} NamedConstGeneric * @property {number[]} data * @property {number[]} a * @property {[number, number]} d * * @typedef {{ * a: NamedConstGeneric, * b: NamedConstGeneric, * d: [number, number], * }} NamedConstGenericContainer * @property {NamedConstGeneric} a * @property {NamedConstGeneric} b * @property {[number, number]} d * * @typedef {{ type: "a"; value: string } | { type: "b"; value: number }} NestedEnum * @property {{ type: "a"; value: string }} a * @property {{ type: "b"; value: number }} b * * @typedef {{ t: "A"; c: string } | { t: "B" } | { t: "C"; c: { * a: string, * } } | { t: "D"; c: First }} Ninth * @property {{ t: "A"; c: string }} A * @property {{ t: "B" }} B * @property {{ t: "C"; c: { * a: string, * } }} C * @property {{ t: "D"; c: First }} D * * @typedef {string | null} NonOptional * @property {string | null} "0" * * @typedef {Optional_Serialize | Optional_Deserialize} Optional * @property {Optional_Serialize} Serialize * @property {Optional_Deserialize} Deserialize * * @typedef {({ A?: string | null }) & { B?: never; C?: never } | ({ B: { * a: string | null, * } }) & { A?: never; C?: never } | ({ C: { * a?: string | null, * } }) & { A?: never; B?: never }} OptionalInEnum * @property {{ A?: string | null }} A * @property {{ B: { * a: string | null, * } }} B * @property {{ C: { * a?: string | null, * } }} C * * @typedef {string | null} OptionalOnNamedField * @property {string | null} ["0"] * * @typedef {{ * b: string | null, * }} OptionalOnTransparentNamedField * @property {string | null} b * * @typedef {{ * a: number | null, * b?: number | null, * c: string | null, * d?: boolean, * }} Optional_Deserialize * @property {number | null} a * @property {number | null} [b] * @property {string | null} c * @property {boolean} [d] * * @typedef {{ * a: number | null, * b?: number | null, * c?: string | null, * d: boolean, * }} Optional_Serialize * @property {number | null} a * @property {number | null} [b] * @property {string | null} [c] * @property {boolean} d * * @typedef {{ * overriden_field: string, * }} OverridenStruct * @property {string} overriden_field * * @typedef {{ * first: Z, * second: A, * }} Pair * @property {Z} first * @property {A} second * * @typedef {{ * a: string, * }} PlaceholderInnerField * @property {string} a * * @typedef {{ * i8: number, * i16: number, * i32: number, * u8: number, * u16: number, * u32: number, * f32: number, * f64: number, * bool: boolean, * char: string, * "Range": Range, * "RangeInclusive": RangeInclusive, * "()": null, * "(String, i32)": [string, number], * "(String, i32, bool)": [string, number, boolean], * "((String, i32), (bool, char, bool), ())": [[string, number], [boolean, string, boolean], null], * "(bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool)": [boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean], * "(Vec, Vec)": [number[], boolean[]], * String: string, * PathBuf: string, * IpAddr: string, * Ipv4Addr: string, * Ipv6Addr: string, * SocketAddr: string, * SocketAddrV4: string, * SocketAddrV6: string, * "Cow<'static, str>": string, * "Cow<'static, i32>": number, * "&'static str": string, * "&'static bool": boolean, * "&'static i32": number, * "Vec": number[], * "&'static [i32]": number[], * "&'static [i32; 3]": [number, number, number], * "[i32; 3]": [number, number, number], * "Vec": MyEnum[], * "&'static [MyEnum]": MyEnum[], * "&'static [MyEnum; 6]": [MyEnum, MyEnum, MyEnum, MyEnum, MyEnum, MyEnum], * "[MyEnum; 2]": [MyEnum, MyEnum], * "&'static [i32; 1]": [number], * "&'static [i32; 0]": [], * "Option": number | null, * "Option<()>": null, * "Option>": number[] | null, * "Result": Result, * "Vec>>": (number | null)[], * "Option>>": number[] | null, * "[Vec; 3]": [string[], string[], string[]], * "Option>": string | null, * "Option>>": string | null, * "PhantomData<()>": null, * "PhantomData": null, * Infallible: never, * Unit1: Unit1, * Unit2: Unit2, * Unit3: Unit3, * Unit4: Unit4, * Unit5: Unit5, * Unit6: Unit6, * Unit7: Unit7, * SimpleStruct: SimpleStruct, * TupleStruct1: TupleStruct1, * TupleStruct3: TupleStruct3, * TestEnum: TestEnum, * RefStruct: RefStruct, * InlinerStruct: InlinerStruct, * "GenericStruct": GenericStruct, * "GenericStruct": GenericStruct, * FlattenEnumStruct: FlattenEnumStruct, * OverridenStruct: OverridenStruct, * HasGenericAlias: HasGenericAlias, * EnumMacroAttributes: EnumMacroAttributes, * InlineEnumField: InlineEnumField, * InlineOptionalType: InlineOptionalType, * Rename: Rename, * TransparentType: TransparentType, * TransparentType2: TransparentType2, * TransparentTypeWithOverride: TransparentTypeWithOverride, * "[Option; 3]": [(number | null), (number | null), (number | null)], * "HashMap": Partial<{ [key in BasicEnum]: null }>, * "HashMap": Partial<{ [key in BasicEnum]: number }>, * "Option>>>": number | null, * "Vec": PlaceholderInnerField[], * EnumReferenceRecordKey: EnumReferenceRecordKey, * FlattenOnNestedEnum: FlattenOnNestedEnum, * MyEmptyInput: MyEmptyInput, * "(String)": string, * "(String,)": [string], * ExtraBracketsInTupleVariant: ExtraBracketsInTupleVariant, * ExtraBracketsInUnnamedStruct: ExtraBracketsInUnnamedStruct, * "Vec": MyEnum[], * InlineTuple: InlineTuple, * InlineTuple2: InlineTuple2, * "Box": string, * "Box": string, * SkippedFieldWithinVariant: SkippedFieldWithinVariant, * KebabCase: KebabCase, * "&[&str]": string[], * "Issue281<'_>": Issue281, * "LifetimeGenericStruct<'_, i32>": LifetimeGenericStruct, * "LifetimeGenericEnum<'_, i32>": LifetimeGenericEnum, * RenameWithWeirdCharsField: RenameWithWeirdCharsField, * RenameWithWeirdCharsVariant: RenameWithWeirdCharsVariant, * RenamedFieldKeys: RenamedFieldKeys, * RenamedVariantWithSkippedPayload: RenamedVariantWithSkippedPayload, * "type_type::Type": Type, * ActualType: ActualType, * SpectaTypeOverride: SpectaTypeOverride, * ContainerTypeOverrideStruct: ContainerTypeOverrideStruct, * ContainerTypeOverrideEnum: ContainerTypeOverrideEnum, * "ContainerTypeOverrideGeneric>": ContainerTypeOverrideGeneric, * "ContainerTypeOverrideToGeneric": ContainerTypeOverrideToGeneric, * ContainerTypeOverrideTuple: ContainerTypeOverrideTuple, * "ContainerTypeOverrideTupleGeneric": ContainerTypeOverrideTupleGeneric, * InvalidToValidType: InvalidToValidType, * TupleStruct: TupleStruct, * TupleStructWithRep: TupleStructWithRep, * "GenericTupleStruct": GenericTupleStruct, * BracedStruct: BracedStruct, * Struct: StructNew, * Struct2: Struct2, * Enum: Enum, * Enum2: Enum2, * Enum3: Enum3, * StructRenameAllUppercase: StructRenameAllUppercase, * RenameSerdeSpecialChar: RenameSerdeSpecialChar, * EnumRenameAllUppercase: EnumRenameAllUppercase, * Recursive: Recursive, * RecursiveMapValue: RecursiveMapValue, * RecursiveTransparent: RecursiveTransparent, * RecursiveInEnum: RecursiveInEnum, * NonOptional: NonOptional, * OptionalOnNamedField: OptionalOnNamedField, * OptionalOnTransparentNamedField: OptionalOnTransparentNamedField, * OptionalInEnum: OptionalInEnum, * UntaggedVariants: UntaggedVariants, * UntaggedVariantsWithoutValue: UntaggedVariantsWithoutValue, * UntaggedVariantsWithDuplicateBranches: UntaggedVariantsWithDuplicateBranches, * "HashMap": { [key in string]: null }, * Regular: Regular, * "HashMap": { [key in never]: null }, * "HashMap": { [key in TransparentStruct]: null }, * "HashMap": Partial<{ [key in UnitVariants]: null }>, * "HashMap": Partial<{ [key in UntaggedVariantsKey]: null }>, * ValidMaybeValidKey: ValidMaybeValidKey, * ValidMaybeValidKeyNested: ValidMaybeValidKeyNested, * MacroStruct: MacroStruct, * MacroStruct2: MacroStruct2, * MacroEnum: MacroEnum, * DeprecatedType: DeprecatedType, * DeprecatedTypeWithMsg: DeprecatedTypeWithMsg, * DeprecatedTypeWithMsg2: DeprecatedTypeWithMsg2, * DeprecatedFields: DeprecatedFields, * DeprecatedTupleVariant: DeprecatedTupleVariant, * DeprecatedEnumVariants: DeprecatedEnumVariants, * CommentedStruct: CommentedStruct, * CommentedEnum: CommentedEnum, * SingleLineComment: SingleLineComment, * NonGeneric: Demo, * "HalfGenericA": Demo, * "HalfGenericB": Demo, * "FullGeneric": Demo, * "Another": Demo, * "MapA": { [key in string]: number }, * "MapB": { [key in number]: string }, * "MapC": { [key in string]: AGenericStruct }, * "AGenericStruct": AGenericStruct, * A: A, * DoubleFlattened: DoubleFlattened, * FlattenedInner: FlattenedInner, * BoxFlattened: BoxFlattened, * BoxInline: BoxInline, * First: First, * Second: Second, * Third: Third, * Fourth: Fourth, * TagOnStructWithInline: TagOnStructWithInline, * Sixth: Sixth, * Seventh: Seventh, * Eight: Eight, * Ninth: Ninth, * Tenth: Tenth, * MyEnumTagged: MyEnumTagged, * MyEnumExternal: MyEnumExternal, * MyEnumAdjacent: MyEnumAdjacent, * MyEnumUntagged: MyEnumUntagged, * EmptyStruct: EmptyStruct, * EmptyStructWithTag: EmptyStructWithTag, * AdjacentlyTagged: AdjacentlyTagged, * LoadProjectEvent: LoadProjectEvent, * ExternallyTagged: ExternallyTagged, * Issue221External: Issue221External, * InternallyTaggedD: InternallyTaggedD, * InternallyTaggedE: InternallyTaggedE, * InternallyTaggedF: InternallyTaggedF, * InternallyTaggedH: InternallyTaggedH, * InternallyTaggedL: InternallyTaggedL, * InternallyTaggedM: InternallyTaggedM, * StructWithAlias: StructWithAlias, * StructWithMultipleAliases: StructWithMultipleAliases, * StructWithAliasAndRename: StructWithAliasAndRename, * EnumWithVariantAlias: EnumWithVariantAlias, * EnumWithMultipleVariantAliases: EnumWithMultipleVariantAliases, * EnumWithVariantAliasAndRename: EnumWithVariantAliasAndRename, * InternallyTaggedWithAlias: InternallyTaggedWithAlias, * AdjacentlyTaggedWithAlias: AdjacentlyTaggedWithAlias, * UntaggedWithAlias: UntaggedWithAlias, * Issue221UntaggedSafe: Issue221UntaggedSafe, * Issue221UntaggedMixed: Issue221UntaggedMixed, * EmptyEnum: EmptyEnum, * EmptyEnumTagged: EmptyEnumTagged, * EmptyEnumTaggedWContent: EmptyEnumTaggedWContent, * EmptyEnumUntagged: EmptyEnumUntagged, * SkipOnlyField: SkipOnlyField, * SkipField: SkipField, * SkipVariant: SkipVariant, * SkipUnnamedFieldInVariant: SkipUnnamedFieldInVariant, * SkipNamedFieldInVariant: SkipNamedFieldInVariant, * TransparentWithSkip: TransparentWithSkip, * TransparentWithSkip2: TransparentWithSkip2, * TransparentWithSkip3: TransparentWithSkip3, * SkipVariant2: SkipVariant2, * SkipVariant3: SkipVariant3, * SkipStructFields: SkipStructFields, * SpectaSkipNonTypeField: SpectaSkipNonTypeField, * FlattenA: FlattenA, * FlattenB: FlattenB, * FlattenC: FlattenC, * FlattenD: FlattenD, * FlattenE: FlattenE, * FlattenF: FlattenF, * FlattenG: FlattenG, * TupleNested: TupleNested, * "Generic1<()>": Generic1, * "GenericAutoBound<()>": GenericAutoBound, * "GenericAutoBound2<()>": GenericAutoBound2, * Container1: Container1, * "Generic2<(), String, i32>": Generic2, * "GenericNewType1<()>": GenericNewType1, * "GenericTuple<()>": GenericTuple, * "GenericStruct2<()>": GenericStruct2, * "InlineGenericNewtype": string, * "InlineGenericNested": [string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | ({ Unnamed: string }) & { Named?: never } | ({ Named: { * value: string, * } }) & { Unnamed?: never }], * "InlineFlattenGenericsG<()>": InlineFlattenGenericsG, * InlineFlattenGenerics: InlineFlattenGenerics, * GenericDefault: GenericDefault, * ChainedGenericDefault: ChainedGenericDefault, * "ChainedGenericDefault": ChainedGenericDefault, * "ChainedGenericDefault": ChainedGenericDefault, * "ChainedGenericDefault": ChainedGenericDefault, * GenericDefaultSkipped: GenericDefaultSkipped, * GenericDefaultSkippedNonType: GenericDefaultSkippedNonType, * GenericParameterOrderPreserved: GenericParameterOrderPreserved, * ConstGenericInNonConstContainer: ConstGenericInNonConstContainer, * ConstGenericInConstContainer: ConstGenericInConstContainer, * NamedConstGenericContainer: NamedConstGenericContainer, * InlineConstGenericContainer: InlineConstGenericContainer, * InlineRecursiveConstGenericContainer: InlineRecursiveConstGenericContainer, * TestCollectionRegister: TestCollectionRegister, * TestCollectionRegister: TestCollectionRegister, * }} Primitives * @property {number} i8 * @property {number} i16 * @property {number} i32 * @property {number} u8 * @property {number} u16 * @property {number} u32 * @property {number} f32 * @property {number} f64 * @property {boolean} bool * @property {string} char * @property {Range} "Range" * @property {RangeInclusive} "RangeInclusive" * @property {null} "()" * @property {[string, number]} "(String, i32)" * @property {[string, number, boolean]} "(String, i32, bool)" * @property {[[string, number], [boolean, string, boolean], null]} "((String, i32), (bool, char, bool), ())" * @property {[boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean]} "(bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool)" * @property {[number[], boolean[]]} "(Vec, Vec)" * @property {string} String * @property {string} PathBuf * @property {string} IpAddr * @property {string} Ipv4Addr * @property {string} Ipv6Addr * @property {string} SocketAddr * @property {string} SocketAddrV4 * @property {string} SocketAddrV6 * @property {string} "Cow<'static, str>" * @property {number} "Cow<'static, i32>" * @property {string} "&'static str" * @property {boolean} "&'static bool" * @property {number} "&'static i32" * @property {number[]} "Vec" * @property {number[]} "&'static [i32]" * @property {[number, number, number]} "&'static [i32; 3]" * @property {[number, number, number]} "[i32; 3]" * @property {MyEnum[]} "Vec" * @property {MyEnum[]} "&'static [MyEnum]" * @property {[MyEnum, MyEnum, MyEnum, MyEnum, MyEnum, MyEnum]} "&'static [MyEnum; 6]" * @property {[MyEnum, MyEnum]} "[MyEnum; 2]" * @property {[number]} "&'static [i32; 1]" * @property {[]} "&'static [i32; 0]" * @property {number | null} "Option" * @property {null} "Option<()>" * @property {number[] | null} "Option>" * @property {Result} "Result" * @property {(number | null)[]} "Vec>>" * @property {number[] | null} "Option>>" * @property {[string[], string[], string[]]} "[Vec; 3]" * @property {string | null} "Option>" * @property {string | null} "Option>>" * @property {null} "PhantomData<()>" * @property {null} "PhantomData" * @property {never} Infallible * @property {Unit1} Unit1 * @property {Unit2} Unit2 * @property {Unit3} Unit3 * @property {Unit4} Unit4 * @property {Unit5} Unit5 * @property {Unit6} Unit6 * @property {Unit7} Unit7 * @property {SimpleStruct} SimpleStruct * @property {TupleStruct1} TupleStruct1 * @property {TupleStruct3} TupleStruct3 * @property {TestEnum} TestEnum * @property {RefStruct} RefStruct * @property {InlinerStruct} InlinerStruct * @property {GenericStruct} "GenericStruct" * @property {GenericStruct} "GenericStruct" * @property {FlattenEnumStruct} FlattenEnumStruct * @property {OverridenStruct} OverridenStruct * @property {HasGenericAlias} HasGenericAlias * @property {EnumMacroAttributes} EnumMacroAttributes * @property {InlineEnumField} InlineEnumField * @property {InlineOptionalType} InlineOptionalType * @property {Rename} Rename * @property {TransparentType} TransparentType * @property {TransparentType2} TransparentType2 * @property {TransparentTypeWithOverride} TransparentTypeWithOverride * @property {[(number | null), (number | null), (number | null)]} "[Option; 3]" * @property {Partial<{ [key in BasicEnum]: null }>} "HashMap" * @property {Partial<{ [key in BasicEnum]: number }>} "HashMap" * @property {number | null} "Option>>>" * @property {PlaceholderInnerField[]} "Vec" * @property {EnumReferenceRecordKey} EnumReferenceRecordKey * @property {FlattenOnNestedEnum} FlattenOnNestedEnum * @property {MyEmptyInput} MyEmptyInput * @property {string} "(String)" * @property {[string]} "(String,)" * @property {ExtraBracketsInTupleVariant} ExtraBracketsInTupleVariant * @property {ExtraBracketsInUnnamedStruct} ExtraBracketsInUnnamedStruct * @property {MyEnum[]} "Vec" * @property {InlineTuple} InlineTuple * @property {InlineTuple2} InlineTuple2 * @property {string} "Box" * @property {string} "Box" * @property {SkippedFieldWithinVariant} SkippedFieldWithinVariant * @property {KebabCase} KebabCase * @property {string[]} "&[&str]" * @property {Issue281} "Issue281<'_>" * @property {LifetimeGenericStruct} "LifetimeGenericStruct<'_, i32>" * @property {LifetimeGenericEnum} "LifetimeGenericEnum<'_, i32>" * @property {RenameWithWeirdCharsField} RenameWithWeirdCharsField * @property {RenameWithWeirdCharsVariant} RenameWithWeirdCharsVariant * @property {RenamedFieldKeys} RenamedFieldKeys * @property {RenamedVariantWithSkippedPayload} RenamedVariantWithSkippedPayload * @property {Type} "type_type::Type" * @property {ActualType} ActualType * @property {SpectaTypeOverride} SpectaTypeOverride * @property {ContainerTypeOverrideStruct} ContainerTypeOverrideStruct * @property {ContainerTypeOverrideEnum} ContainerTypeOverrideEnum * @property {ContainerTypeOverrideGeneric} "ContainerTypeOverrideGeneric>" * @property {ContainerTypeOverrideToGeneric} "ContainerTypeOverrideToGeneric" * @property {ContainerTypeOverrideTuple} ContainerTypeOverrideTuple * @property {ContainerTypeOverrideTupleGeneric} "ContainerTypeOverrideTupleGeneric" * @property {InvalidToValidType} InvalidToValidType * @property {TupleStruct} TupleStruct * @property {TupleStructWithRep} TupleStructWithRep * @property {GenericTupleStruct} "GenericTupleStruct" * @property {BracedStruct} BracedStruct * @property {StructNew} Struct * @property {Struct2} Struct2 * @property {Enum} Enum * @property {Enum2} Enum2 * @property {Enum3} Enum3 * @property {StructRenameAllUppercase} StructRenameAllUppercase * @property {RenameSerdeSpecialChar} RenameSerdeSpecialChar * @property {EnumRenameAllUppercase} EnumRenameAllUppercase * @property {Recursive} Recursive * @property {RecursiveMapValue} RecursiveMapValue * @property {RecursiveTransparent} RecursiveTransparent * @property {RecursiveInEnum} RecursiveInEnum * @property {NonOptional} NonOptional * @property {OptionalOnNamedField} OptionalOnNamedField * @property {OptionalOnTransparentNamedField} OptionalOnTransparentNamedField * @property {OptionalInEnum} OptionalInEnum * @property {UntaggedVariants} UntaggedVariants * @property {UntaggedVariantsWithoutValue} UntaggedVariantsWithoutValue * @property {UntaggedVariantsWithDuplicateBranches} UntaggedVariantsWithDuplicateBranches * @property {{ [key in string]: null }} "HashMap" * @property {Regular} Regular * @property {{ [key in never]: null }} "HashMap" * @property {{ [key in TransparentStruct]: null }} "HashMap" * @property {Partial<{ [key in UnitVariants]: null }>} "HashMap" * @property {Partial<{ [key in UntaggedVariantsKey]: null }>} "HashMap" * @property {ValidMaybeValidKey} ValidMaybeValidKey * @property {ValidMaybeValidKeyNested} ValidMaybeValidKeyNested * @property {MacroStruct} MacroStruct * @property {MacroStruct2} MacroStruct2 * @property {MacroEnum} MacroEnum * @property {DeprecatedType} DeprecatedType * @property {DeprecatedTypeWithMsg} DeprecatedTypeWithMsg * @property {DeprecatedTypeWithMsg2} DeprecatedTypeWithMsg2 * @property {DeprecatedFields} DeprecatedFields * @property {DeprecatedTupleVariant} DeprecatedTupleVariant * @property {DeprecatedEnumVariants} DeprecatedEnumVariants * @property {CommentedStruct} CommentedStruct * @property {CommentedEnum} CommentedEnum * @property {SingleLineComment} SingleLineComment * @property {Demo} NonGeneric * @property {Demo} "HalfGenericA" * @property {Demo} "HalfGenericB" * @property {Demo} "FullGeneric" * @property {Demo} "Another" * @property {{ [key in string]: number }} "MapA" * @property {{ [key in number]: string }} "MapB" * @property {{ [key in string]: AGenericStruct }} "MapC" * @property {AGenericStruct} "AGenericStruct" * @property {A} A * @property {DoubleFlattened} DoubleFlattened * @property {FlattenedInner} FlattenedInner * @property {BoxFlattened} BoxFlattened * @property {BoxInline} BoxInline * @property {First} First * @property {Second} Second * @property {Third} Third * @property {Fourth} Fourth * @property {TagOnStructWithInline} TagOnStructWithInline * @property {Sixth} Sixth * @property {Seventh} Seventh * @property {Eight} Eight * @property {Ninth} Ninth * @property {Tenth} Tenth * @property {MyEnumTagged} MyEnumTagged * @property {MyEnumExternal} MyEnumExternal * @property {MyEnumAdjacent} MyEnumAdjacent * @property {MyEnumUntagged} MyEnumUntagged * @property {EmptyStruct} EmptyStruct * @property {EmptyStructWithTag} EmptyStructWithTag * @property {AdjacentlyTagged} AdjacentlyTagged * @property {LoadProjectEvent} LoadProjectEvent * @property {ExternallyTagged} ExternallyTagged * @property {Issue221External} Issue221External * @property {InternallyTaggedD} InternallyTaggedD * @property {InternallyTaggedE} InternallyTaggedE * @property {InternallyTaggedF} InternallyTaggedF * @property {InternallyTaggedH} InternallyTaggedH * @property {InternallyTaggedL} InternallyTaggedL * @property {InternallyTaggedM} InternallyTaggedM * @property {StructWithAlias} StructWithAlias * @property {StructWithMultipleAliases} StructWithMultipleAliases * @property {StructWithAliasAndRename} StructWithAliasAndRename * @property {EnumWithVariantAlias} EnumWithVariantAlias * @property {EnumWithMultipleVariantAliases} EnumWithMultipleVariantAliases * @property {EnumWithVariantAliasAndRename} EnumWithVariantAliasAndRename * @property {InternallyTaggedWithAlias} InternallyTaggedWithAlias * @property {AdjacentlyTaggedWithAlias} AdjacentlyTaggedWithAlias * @property {UntaggedWithAlias} UntaggedWithAlias * @property {Issue221UntaggedSafe} Issue221UntaggedSafe * @property {Issue221UntaggedMixed} Issue221UntaggedMixed * @property {EmptyEnum} EmptyEnum * @property {EmptyEnumTagged} EmptyEnumTagged * @property {EmptyEnumTaggedWContent} EmptyEnumTaggedWContent * @property {EmptyEnumUntagged} EmptyEnumUntagged * @property {SkipOnlyField} SkipOnlyField * @property {SkipField} SkipField * @property {SkipVariant} SkipVariant * @property {SkipUnnamedFieldInVariant} SkipUnnamedFieldInVariant * @property {SkipNamedFieldInVariant} SkipNamedFieldInVariant * @property {TransparentWithSkip} TransparentWithSkip * @property {TransparentWithSkip2} TransparentWithSkip2 * @property {TransparentWithSkip3} TransparentWithSkip3 * @property {SkipVariant2} SkipVariant2 * @property {SkipVariant3} SkipVariant3 * @property {SkipStructFields} SkipStructFields * @property {SpectaSkipNonTypeField} SpectaSkipNonTypeField * @property {FlattenA} FlattenA * @property {FlattenB} FlattenB * @property {FlattenC} FlattenC * @property {FlattenD} FlattenD * @property {FlattenE} FlattenE * @property {FlattenF} FlattenF * @property {FlattenG} FlattenG * @property {TupleNested} TupleNested * @property {Generic1} "Generic1<()>" * @property {GenericAutoBound} "GenericAutoBound<()>" * @property {GenericAutoBound2} "GenericAutoBound2<()>" * @property {Container1} Container1 * @property {Generic2} "Generic2<(), String, i32>" * @property {GenericNewType1} "GenericNewType1<()>" * @property {GenericTuple} "GenericTuple<()>" * @property {GenericStruct2} "GenericStruct2<()>" * @property {string} "InlineGenericNewtype" * @property {[string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | ({ Unnamed: string }) & { Named?: never } | ({ Named: { * value: string, * } }) & { Unnamed?: never }]} "InlineGenericNested" * @property {InlineFlattenGenericsG} "InlineFlattenGenericsG<()>" * @property {InlineFlattenGenerics} InlineFlattenGenerics * @property {GenericDefault} GenericDefault * @property {ChainedGenericDefault} ChainedGenericDefault * @property {ChainedGenericDefault} "ChainedGenericDefault" * @property {ChainedGenericDefault} "ChainedGenericDefault" * @property {ChainedGenericDefault} "ChainedGenericDefault" * @property {GenericDefaultSkipped} GenericDefaultSkipped * @property {GenericDefaultSkippedNonType} GenericDefaultSkippedNonType * @property {GenericParameterOrderPreserved} GenericParameterOrderPreserved * @property {ConstGenericInNonConstContainer} ConstGenericInNonConstContainer * @property {ConstGenericInConstContainer} ConstGenericInConstContainer * @property {NamedConstGenericContainer} NamedConstGenericContainer * @property {InlineConstGenericContainer} InlineConstGenericContainer * @property {InlineRecursiveConstGenericContainer} InlineRecursiveConstGenericContainer * @property {TestCollectionRegister} TestCollectionRegister * @property {TestCollectionRegister} TestCollectionRegister * * @typedef {{ * start: T, * end: T, * }} Range * @property {T} start * @property {T} end * * @typedef {{ * start: T, * end: T, * }} RangeInclusive * @property {T} start * @property {T} end * * @typedef {{ * demo: Recursive, * }} Recursive * @property {Recursive} demo * * @typedef {{ A: { * demo: RecursiveInEnum, * } }} RecursiveInEnum * @property {{ A: { * demo: RecursiveInEnum, * } }} A * * @typedef {RecursiveInline} RecursiveInline * * @typedef {{ * demo: { [key in string]: RecursiveMapValue }, * }} RecursiveMapValue * @property {{ [key in string]: RecursiveMapValue }} demo * * @typedef {RecursiveInline} RecursiveTransparent * @property {RecursiveInline} "0" * * @typedef {TestEnum} RefStruct * @property {TestEnum} "0" * * @typedef {{ [key in string]: null }} Regular * @property {{ [key in string]: null }} "0" * * @typedef {"OneWord" | "Two words"} Rename * @property {"OneWord"} OneWord * @property {"Two words"} "Two words" * * @typedef {{ * "a/b": number, * }} RenameSerdeSpecialChar * @property {number} "a/b" * * @typedef {{ * "@odata.context": string, * }} RenameWithWeirdCharsField * @property {string} "@odata.context" * * @typedef {{ "@odata.context": string }} RenameWithWeirdCharsVariant * @property {{ "@odata.context": string }} "@odata.context" * * @typedef {{ * "": string, * "a\"b": string, * "a\\b": string, * "line\nbreak": string, * "line\u2028break": string, * "line\u2029break": string, * }} RenamedFieldKeys * @property {string} "" * @property {string} "a\"b" * @property {string} "a\\b" * @property {string} "line\nbreak" * @property {string} "line\u2028break" * @property {string} "line\u2029break" * * @typedef {"a-b"} RenamedVariantWithSkippedPayload * @property {"a-b"} "a-b" * * @typedef {{ * ok: T, * err: E, * }} Result * @property {T} ok * @property {E} err * * @typedef {{ * a: number, * }} Second * @property {number} a * * @typedef {{ * a: First, * b: Second, * }} Seventh * @property {First} a * @property {Second} b * * @typedef {{ * a: number, * b: string, * c: [number, string, number], * d: string[], * e: string | null, * }} SimpleStruct * @property {number} a * @property {string} b * @property {[number, string, number]} c * @property {string[]} d * @property {string | null} e * * Some single-line comment * * @typedef { * /** Some single-line comment */ * ({ A: number }) & { B?: never } | * /** Some single-line comment */ * ({ B: { * /** Some single-line comment */ * a: number, * } }) & { A?: never }} SingleLineComment * @property { * /** Some single-line comment */ * { A: number }} A - Some single-line comment * @property { * /** Some single-line comment */ * { B: { * /** Some single-line comment */ * a: number, * } }} B - Some single-line comment * * @typedef {{ * a: First, * b: First, * }} Sixth * @property {First} a * @property {First} b * * @typedef {{ * b: number, * }} SkipField * @property {number} b * * @typedef {({ A: Record }) & { B?: never } | ({ B: { * b: number, * } }) & { A?: never }} SkipNamedFieldInVariant * @property {{ A: Record }} A * @property {{ B: { * b: number, * } }} B * * @typedef {Record} SkipOnlyField * * @typedef {{ * a: number, * }} SkipStructFields * @property {number} a * * @typedef {"A" | { B: [number] }} SkipUnnamedFieldInVariant * @property {"A"} A * @property {{ B: [number] }} B * * @typedef {{ A: string }} SkipVariant * @property {{ A: string }} A * * @typedef {{ tag: "A"; data: string }} SkipVariant2 * @property {{ tag: "A"; data: string }} A * * @typedef {{ A: { * a: string, * } }} SkipVariant3 * @property {{ A: { * a: string, * } }} A * * @typedef {{ type: "A" } | { type: "B"; data: string }} SkippedFieldWithinVariant * @property {{ type: "A" }} A * @property {{ type: "B"; data: string }} B * * @typedef {{ * a: number, * }} SpectaSkipNonTypeField * @property {number} a * * @typedef {{ * string_ident: string, * u32_ident: number, * path: string, * tuple: [string, number], * }} SpectaTypeOverride * @property {string} string_ident * @property {number} u32_ident * @property {string} path * @property {[string, number]} tuple * * @typedef {{ * b: string, * }} Struct2 * @property {string} b * * @typedef {{ * t: "StructNew", * a: string, * }} StructNew * @property {"StructNew"} t * @property {string} a * * @typedef {StructPhaseSpecificRenameSerialize | StructPhaseSpecificRenameDeserialize} StructPhaseSpecificRename * @property {StructPhaseSpecificRenameSerialize} Serialize * @property {StructPhaseSpecificRenameDeserialize} Deserialize * * @typedef {{ * kind: "StructPhaseSpecificRenameDeserialize", * der: string, * }} StructPhaseSpecificRenameDeserialize * @property {"StructPhaseSpecificRenameDeserialize"} kind * @property {string} der * * @typedef {{ * kind: "StructPhaseSpecificRenameSerialize", * ser: string, * }} StructPhaseSpecificRenameSerialize * @property {"StructPhaseSpecificRenameSerialize"} kind * @property {string} ser * * @typedef {{ * A: number, * B: number, * }} StructRenameAllUppercase * @property {number} A * @property {number} B * * @typedef {{ * field: string, * }} StructWithAlias * @property {string} field * * @typedef {{ * renamed_field: string, * }} StructWithAliasAndRename * @property {string} renamed_field * * @typedef {{ * field: string, * }} StructWithMultipleAliases * @property {string} field * * @typedef {{ * type: "TagOnStructWithInline", * a: First, * b: { * a: string, * }, * }} TagOnStructWithInline * @property {"TagOnStructWithInline"} type * @property {First} a * @property {{ * a: string, * }} b * * @typedef {string | "B" | { * a: string, * } | First} Tenth * @property {string} A * @property {"B"} B * @property {{ * a: string, * }} C * @property {First} D * * @typedef {never} TestCollectionRegister * * @typedef {"Unit" | ({ Single: number }) & { Multiple?: never; Struct?: never } | ({ Multiple: [number, number] }) & { Single?: never; Struct?: never } | ({ Struct: { * a: number, * } }) & { Multiple?: never; Single?: never }} TestEnum * @property {"Unit"} Unit * @property {{ Single: number }} Single * @property {{ Multiple: [number, number] }} Multiple * @property {{ Struct: { * a: number, * } }} Struct * * @typedef {{ * b: { [key in string]: string }, * c: First, * } & First} Third * @property {{ [key in string]: string }} b * @property {First} c * * @typedef {{ * a: string, * }} ToBeFlattened * @property {string} a * * @typedef {string} TransparentStruct * @property {string} "0" * * @typedef {TransparentTypeInner} TransparentType * @property {TransparentTypeInner} "0" * * @typedef {null} TransparentType2 * @property {null} "0" * * @typedef {{ * inner: string, * }} TransparentTypeInner * @property {string} inner * * @typedef {string} TransparentTypeWithOverride * @property {string} "0" * * @typedef {null} TransparentWithSkip * @property {null} "0" * * @typedef {string} TransparentWithSkip2 * @property {string} "0" * * @typedef {string} TransparentWithSkip3 * @property {string} "0" * * @typedef {[number[], [number[], number[]], [number[], number[], number[]]]} TupleNested * @property {number[]} "0" * @property {[number[], number[]]} "1" * @property {[number[], number[], number[]]} "2" * * @typedef {string} TupleStruct * @property {string} "0" * * @typedef {number} TupleStruct1 * @property {number} "0" * * @typedef {[number, boolean, string]} TupleStruct3 * @property {number} "0" * @property {boolean} "1" * @property {string} "2" * * @typedef {string} TupleStructWithRep * @property {string} "0" * * @typedef {never} Type * * @typedef {null} Unit1 * * @typedef {Record} Unit2 * * @typedef {[]} Unit3 * * @typedef {null} Unit4 * @property {null} "0" * * @typedef {"A"} Unit5 * @property {"A"} A * * @typedef {{ A: null }} Unit6 * @property {{ A: null }} A * * @typedef {{ A: Record }} Unit7 * @property {{ A: Record }} A * * @typedef {"A" | "B" | "C"} UnitVariants * @property {"A"} A * @property {"B"} B * @property {"C"} C * * @typedef {string | number | { id: string } | [string, boolean]} UntaggedVariants * @property {string} A * @property {number} B * @property {number} C * @property {{ id: string }} D * @property {[string, boolean]} E * * @typedef {string | number} UntaggedVariantsKey * @property {string} A * @property {number} B * @property {number} C * * @typedef {null | number} UntaggedVariantsWithDuplicateBranches * @property {null} A * @property {number} B * @property {null} C * * @typedef {string | [number, string] | number} UntaggedVariantsWithoutValue * @property {string} A * @property {[number, string]} B * @property {number} C * * @typedef {({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }} UntaggedWithAlias * @property {{ field: string }} A * @property {{ other: number }} B * * @typedef {{ [key in MaybeValidKey]: null }} ValidMaybeValidKey * @property {{ [key in MaybeValidKey]: null }} "0" * * @typedef {{ [key in MaybeValidKey>]: null }} ValidMaybeValidKeyNested * @property {{ [key in MaybeValidKey>]: null }} "0" */ ════════════════════════════════════════ ================================================ FILE: tests/tests/snapshots/test__jsdoc__jsdoc-export-to-moduleprefixedname-raw.snap ================================================ --- source: tests/tests/jsdoc.rs expression: output --- jsdoc-export-to-moduleprefixedname-raw (57567 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. /** * @typedef {{ * a: test_types_B, * b: { * b: number, * }, * c: test_types_B, * d: { * flattened: number, * }, * e: { * generic_flattened: number, * }, * }} A * @property {test_types_B} a * @property {{ * b: number, * }} b * @property {test_types_B} c * @property {{ * flattened: number, * }} d * @property {{ * generic_flattened: number, * }} e * * @typedef {{ * field: test_types_Demo, * }} AGenericStruct * @property {test_types_Demo} field * * @typedef {{ * a: test_types_GenericType, * }} ActualType * @property {test_types_GenericType} a * * @typedef {"A" | { id: string; method: string } | string} AdjacentlyTagged * @property {"A"} A * @property {{ id: string; method: string }} B * @property {string} C * * @typedef {({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }} AdjacentlyTaggedWithAlias * @property {{ field: string }} A * @property {{ other: number }} B * * @typedef {{ * b: number, * }} B * @property {number} b * * @typedef {"A" | "B"} BasicEnum * @property {"A"} A * @property {"B"} B * * @typedef {{ * b: test_types_BoxedInner, * }} BoxFlattened * @property {test_types_BoxedInner} b * * @typedef {{ * c: { * a: number, * }, * }} BoxInline * @property {{ * a: number, * }} c * * @typedef {{ * a: number, * }} BoxedInner * @property {number} a * * @typedef {string} BracedStruct * @property {string} "0" * * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second * * Some triple-slash comment * Some more triple-slash comment * * @typedef { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * number | * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number }} CommentedEnum * @property { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * number} A - Some triple-slash comment Some more triple-slash comment * @property { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number }} B - Some triple-slash comment Some more triple-slash comment * * Some triple-slash comment * Some more triple-slash comment * * @typedef {{ * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * }} CommentedStruct * @property {number} a - Some triple-slash comment Some more triple-slash comment * * @typedef {{ * data: number[], * a: number[], * d: [number, number], * }} ConstGenericInConstContainer * @property {number[]} data * @property {number[]} a * @property {[number, number]} d * * @typedef {{ * data: [number], * a: [number, number], * d: [number, number], * }} ConstGenericInNonConstContainer * @property {[number]} data * @property {[number, number]} a * @property {[number, number]} d * * @typedef {{ * foo: test_types_Generic1, * bar: test_types_Generic1[], * baz: { [key in string]: test_types_Generic1 }, * }} Container1 * @property {test_types_Generic1} foo * @property {test_types_Generic1[]} bar * @property {{ [key in string]: test_types_Generic1 }} baz * * @typedef {string} ContainerTypeOverrideEnum * * @typedef {string} ContainerTypeOverrideGeneric * * @typedef {string} ContainerTypeOverrideStruct * * @typedef {T} ContainerTypeOverrideToGeneric * * @typedef {[string, number]} ContainerTypeOverrideTuple * * @typedef {[T, string]} ContainerTypeOverrideTupleGeneric * * @typedef {{ * flattened: number, * }} D * @property {number} flattened * * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b * * @typedef { * /** * * @deprecated * */ * "A" | * /** * * @deprecated Nope * */ * "B" | * /** * * @deprecated Nope * */ * "C"} DeprecatedEnumVariants * @property { * /** * * @deprecated * */ * "A"} A - @deprecated * @property { * /** * * @deprecated Nope * */ * "B"} B - @deprecated Nope * @property { * /** * * @deprecated Nope * */ * "C"} C - @deprecated Nope * * @typedef {{ * a: number, * /** * * @deprecated * */ * b: string, * /** * * @deprecated This field is cringe! * */ * c: string, * /** * * @deprecated This field is cringe! * */ * d: string, * }} DeprecatedFields * @property {number} a * @property {string} b - @deprecated * @property {string} c - @deprecated This field is cringe! * @property {string} d - @deprecated This field is cringe! * * @typedef {[ * /** * * @deprecated * */ * string, * /** * * @deprecated Nope * */ * string, * /** * * @deprecated Nope * */ * number]} DeprecatedTupleVariant * @property {string} "0" - @deprecated * @property {string} "1" - @deprecated Nope * @property {number} "2" - @deprecated Nope * * @deprecated * @typedef {{ * a: number, * }} DeprecatedType * @property {number} a * * @deprecated Look at you big man using a deprecation message * @typedef {{ * a: number, * }} DeprecatedTypeWithMsg * @property {number} a * * @deprecated Look at you big man using a deprecation message * @typedef {{ * a: number, * }} DeprecatedTypeWithMsg2 * @property {number} a * * @typedef {{ * a: test_types_ToBeFlattened, * b: test_types_ToBeFlattened, * }} DoubleFlattened * @property {test_types_ToBeFlattened} a * @property {test_types_ToBeFlattened} b * * @typedef {string | "B"} Eight * @property {string} A * @property {"B"} B * * @typedef {never} EmptyEnum * * @typedef {never} EmptyEnumTagged * * @typedef {never} EmptyEnumTaggedWContent * * @typedef {never} EmptyEnumUntagged * * @typedef {Record} EmptyStruct * * @typedef {Record} EmptyStructWithTag * * @typedef {"A" | "B"} Enum * @property {"A"} A * @property {"B"} B * * @typedef {"A" | "B" | { enum_field: null }} Enum2 * @property {"A"} A * @property {"B"} B * @property {{ enum_field: null }} D * * @typedef {{ a: string }} Enum3 * @property {{ a: string }} A * * @typedef {string | number | { a: string; b: number }} EnumMacroAttributes * @property {string} A * @property {number} B * @property {number} C * @property {{ a: string; b: number }} D * * @typedef {{ * a: Partial<{ [key in test_types_BasicEnum]: number }>, * }} EnumReferenceRecordKey * @property {Partial<{ [key in test_types_BasicEnum]: number }>} a * * @typedef {"HelloWorld" | "VariantB" | "TestingWords"} EnumRenameAllUppercase * @property {"HelloWorld"} HelloWorld * @property {"VariantB"} VariantB * @property {"TestingWords"} TestingWords * * @typedef {"Variant" | "Other"} EnumWithMultipleVariantAliases * @property {"Variant"} Variant * @property {"Other"} Other * * @typedef {"Variant" | "Other"} EnumWithVariantAlias * @property {"Variant"} Variant * @property {"Other"} Other * * @typedef {"Variant" | "Other"} EnumWithVariantAliasAndRename * @property {"Variant"} Variant * @property {"Other"} Other * * @typedef {"A" | { id: string; method: string } | string} ExternallyTagged * @property {"A"} A * @property {{ id: string; method: string }} B * @property {string} C * * @typedef {string} ExtraBracketsInTupleVariant * @property {string} A * * @typedef {string} ExtraBracketsInUnnamedStruct * @property {string} "0" * * @typedef {{ * a: string, * }} First * @property {string} a * * @typedef {{ * a: number, * b: number, * }} FlattenA * @property {number} a * @property {number} b * * @typedef {{ * a: test_types_FlattenA, * c: number, * }} FlattenB * @property {test_types_FlattenA} a * @property {number} c * * @typedef {{ * a: test_types_FlattenA, * c: number, * }} FlattenC * @property {test_types_FlattenA} a * @property {number} c * * @typedef {{ * a: test_types_FlattenA, * c: number, * }} FlattenD * @property {test_types_FlattenA} a * @property {number} c * * @typedef {{ * b: { * a: test_types_FlattenA, * c: number, * }, * d: number, * }} FlattenE * @property {{ * a: test_types_FlattenA, * c: number, * }} b * @property {number} d * * @typedef {"One" | "Two" | "Three"} FlattenEnum * @property {"One"} One * @property {"Two"} Two * @property {"Three"} Three * * @typedef {{ * outer: string, * inner: test_types_FlattenEnum, * }} FlattenEnumStruct * @property {string} outer * @property {test_types_FlattenEnum} inner * * @typedef {{ * b: { * a: test_types_FlattenA, * c: number, * }, * d: number, * }} FlattenF * @property {{ * a: test_types_FlattenA, * c: number, * }} b * @property {number} d * * @typedef {{ * b: test_types_FlattenB, * d: number, * }} FlattenG * @property {test_types_FlattenB} b * @property {number} d * * @typedef {{ * id: string, * result: test_types_NestedEnum, * }} FlattenOnNestedEnum * @property {string} id * @property {test_types_NestedEnum} result * * @typedef {{ * c: test_types_Inner, * }} FlattenedInner * @property {test_types_Inner} c * * @typedef {{ * a: test_types_First, * b: { * a: string, * }, * }} Fourth * @property {test_types_First} a * @property {{ * a: string, * }} b * * @typedef {{ * value: T, * values: T[], * }} Generic1 * @property {T} value * @property {T[]} values * * @typedef {A | [B, B, B] | C[] | A[][][] | { a: A; b: B; c: C } | number[] | number | number[][]} Generic2 * @property {A} A * @property {[B, B, B]} B * @property {C[]} C * @property {A[][][]} D * @property {{ a: A; b: B; c: C }} E * @property {number[]} X * @property {number} Y * @property {number[][]} Z * * @typedef {{ * value: T, * values: T[], * }} GenericAutoBound * @property {T} value * @property {T[]} values * * @typedef {{ * value: T, * values: T[], * }} GenericAutoBound2 * @property {T} value * @property {T[]} values * * @typedef {{ * value: T, * }} GenericDefault * @property {T} value * * @typedef {{ * value: T, * }} GenericDefaultSkipped * @property {T} value * * @typedef {{ * value: number, * }} GenericDefaultSkippedNonType * @property {number} value * * @typedef {{ * generic_flattened: T, * }} GenericFlattened * @property {T} generic_flattened * * @typedef {T[][]} GenericNewType1 * @property {T[][]} "0" * * @typedef {{ * pair: test_types_Pair, * }} GenericParameterOrderPreserved * @property {test_types_Pair} pair * * @typedef {{ * arg: T, * }} GenericStruct * @property {T} arg * * @typedef {{ * a: T, * b: [T, T], * c: [T, [T, T]], * d: [T, T, T], * e: [([T, T]), ([T, T]), ([T, T])], * f: T[], * g: T[][], * h: ([([T, T]), ([T, T]), ([T, T])])[], * }} GenericStruct2 * @property {T} a * @property {[T, T]} b * @property {[T, [T, T]]} c * @property {[T, T, T]} d * @property {[([T, T]), ([T, T]), ([T, T])]} e * @property {T[]} f * @property {T[][]} g * @property {([([T, T]), ([T, T]), ([T, T])])[]} h * * @typedef {[T, T[], T[][]]} GenericTuple * @property {T} "0" * @property {T[]} "1" * @property {T[][]} "2" * * @typedef {T} GenericTupleStruct * @property {T} "0" * * @typedef {"Undefined" | T} GenericType * @property {"Undefined"} Undefined * @property {T} Value * * @typedef {{ [key in number]: string }} HasGenericAlias * @property {{ [key in number]: string }} "0" * * @typedef {{ * b: { * data: [number, number], * a: [number, number], * d: [number, number, number], * }, * c: { * data: [number, number, number], * a: [number, number], * d: [number, number, number], * }, * d: [number, number], * }} InlineConstGenericContainer * @property {{ * data: [number, number], * a: [number, number], * d: [number, number, number], * }} b * @property {{ * data: [number, number, number], * a: [number, number], * d: [number, number, number], * }} c * @property {[number, number]} d * * @typedef {{ * a: string, * }} InlineEnumField * @property {{ * a: string, * }} A * * @typedef {{ * g: test_types_InlineFlattenGenericsG, * gi: { * t: string, * }, * t: test_types_InlineFlattenGenericsG, * }} InlineFlattenGenerics * @property {test_types_InlineFlattenGenericsG} g * @property {{ * t: string, * }} gi * @property {test_types_InlineFlattenGenericsG} t * * @typedef {{ * t: T, * }} InlineFlattenGenericsG * @property {T} t * * @typedef {{ * optional_field: { * a: string, * } | null, * }} InlineOptionalType * @property {{ * a: string, * } | null} optional_field * * @typedef {{ * data: number[], * a: number[], * d: [number, number, number], * e: test_types_InlineRecursiveConstGeneric, * }} InlineRecursiveConstGeneric * @property {number[]} data * @property {number[]} a * @property {[number, number, number]} d * @property {test_types_InlineRecursiveConstGeneric} e * * @typedef {{ * b: { * data: [number, number], * a: [number, number], * d: [number, number, number], * e: test_types_InlineRecursiveConstGeneric, * }, * c: { * data: [number, number, number], * a: [number, number], * d: [number, number, number], * e: test_types_InlineRecursiveConstGeneric, * }, * d: [number, number], * }} InlineRecursiveConstGenericContainer * @property {{ * data: [number, number], * a: [number, number], * d: [number, number, number], * e: test_types_InlineRecursiveConstGeneric, * }} b * @property {{ * data: [number, number, number], * a: [number, number], * d: [number, number, number], * e: test_types_InlineRecursiveConstGeneric, * }} c * @property {[number, number]} d * * @typedef {{ * ref_struct: test_types_SimpleStruct, * val: number, * }} InlineStruct * @property {test_types_SimpleStruct} ref_struct * @property {number} val * * @typedef {{ * demo: [string, boolean], * }} InlineTuple * @property {[string, boolean]} demo * * @typedef {{ * demo: [{ * demo: [string, boolean], * }, boolean], * }} InlineTuple2 * @property {[{ * demo: [string, boolean], * }, boolean]} demo * * @typedef {{ * inline_this: { * ref_struct: test_types_SimpleStruct, * val: number, * }, * dont_inline_this: test_types_RefStruct, * }} InlinerStruct * @property {{ * ref_struct: test_types_SimpleStruct, * val: number, * }} inline_this * @property {test_types_RefStruct} dont_inline_this * * @typedef {{ * a: number, * b: test_types_FlattenedInner, * }} Inner * @property {number} a * @property {test_types_FlattenedInner} b * * @typedef {{ [key in string]: string }} InternallyTaggedD * @property {{ [key in string]: string }} A * * @typedef {null} InternallyTaggedE * @property {null} A * * @typedef {test_types_InternallyTaggedFInner} InternallyTaggedF * @property {test_types_InternallyTaggedFInner} A * * @typedef {null} InternallyTaggedFInner * @property {null} A * * @typedef {test_types_InternallyTaggedHInner} InternallyTaggedH * @property {test_types_InternallyTaggedHInner} A * * @typedef {null} InternallyTaggedHInner * @property {null} "0" * * @typedef {"A" | "B"} InternallyTaggedL * @property {"A" | "B"} A * * @typedef {"A" | "B"} InternallyTaggedLInner * @property {"A"} A * @property {"B"} B * * @typedef {"A" | "B"} InternallyTaggedM * @property {"A" | "B"} A * * @typedef {"A" | "B"} InternallyTaggedMInner * @property {"A"} A * @property {"B"} B * * @typedef {({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }} InternallyTaggedWithAlias * @property {{ field: string }} A * @property {{ other: number }} B * * @typedef {{ * cause: null, * }} InvalidToValidType * @property {null} cause * * @typedef {({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }} Issue221External * @property {{ a: string }} A * @property {{ b: string }} B * * @typedef {({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never }} Issue221UntaggedMixed * @property {{ a: string }} A * @property {{ b: string }} B * @property {{ values: { [key in string]: string } }} Unsafe * * @typedef {({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }} Issue221UntaggedSafe * @property {{ a: string }} A * @property {{ b: string }} B * * @typedef {{ * default_unity_arguments: string[], * }} Issue281 * @property {string[]} default_unity_arguments * * @typedef {{ * test_ing: string, * }} KebabCase * @property {string} test_ing * * @typedef {T} LifetimeGenericEnum * @property {T} Borrowed * @property {T} Owned * * @typedef {{ * borrowed: T[], * owned: T[], * }} LifetimeGenericStruct * @property {T[]} borrowed * @property {T[]} owned * * @typedef {({ project_name: string }) & { progress?: never; status?: never } | { project_name: string; status: string; progress: number }} LoadProjectEvent * @property {{ project_name: string }} Started * @property {{ project_name: string; status: string; progress: number }} ProgressTest * @property {{ project_name: string }} Finished * * @typedef {string | { demo2: string }} MacroEnum * @property {string} Demo * @property {{ demo2: string }} Demo2 * * @typedef {string} MacroStruct * @property {string} "0" * * @typedef {{ * demo: string, * }} MacroStruct2 * @property {string} demo * * @typedef {T} MaybeValidKey * @property {T} "0" * * @typedef {Record} MyEmptyInput * * @typedef {string | number} MyEnum * @property {string} A * @property {number} B * * @typedef {{ inner: test_types_First }} MyEnumAdjacent * @property {{ inner: test_types_First }} Variant * * @typedef {{ inner: test_types_First }} MyEnumExternal * @property {{ inner: test_types_First }} Variant * * @typedef {{ inner: test_types_First }} MyEnumTagged * @property {{ inner: test_types_First }} Variant * * @typedef {{ inner: test_types_First }} MyEnumUntagged * @property {{ inner: test_types_First }} Variant * * @typedef {{ * data: number[], * a: number[], * d: [number, number], * }} NamedConstGeneric * @property {number[]} data * @property {number[]} a * @property {[number, number]} d * * @typedef {{ * a: test_types_NamedConstGeneric, * b: test_types_NamedConstGeneric, * d: [number, number], * }} NamedConstGenericContainer * @property {test_types_NamedConstGeneric} a * @property {test_types_NamedConstGeneric} b * @property {[number, number]} d * * @typedef {string | number} NestedEnum * @property {string} A * @property {number} B * * @typedef {string | "B" | { * a: string, * } | test_types_First} Ninth * @property {string} A * @property {"B"} B * @property {{ * a: string, * }} C * @property {test_types_First} D * * @typedef {string | null} NonOptional * @property {string | null} "0" * * @typedef {string | null | { a: string | null } | { a?: string | null }} OptionalInEnum * @property {string | null} A * @property {{ a: string | null }} B * @property {{ a?: string | null }} C * * @typedef {string | null} OptionalOnNamedField * @property {string | null} ["0"] * * @typedef {{ * b: string | null, * }} OptionalOnTransparentNamedField * @property {string | null} b * * @typedef {{ * overriden_field: string, * }} OverridenStruct * @property {string} overriden_field * * @typedef {{ * first: Z, * second: A, * }} Pair * @property {Z} first * @property {A} second * * @typedef {{ * a: string, * }} PlaceholderInnerField * @property {string} a * * @typedef {{ * i8: number, * i16: number, * i32: number, * u8: number, * u16: number, * u32: number, * f32: number, * f64: number, * bool: boolean, * char: string, * "Range": std_ops_Range, * "RangeInclusive": std_ops_RangeInclusive, * "()": null, * "(String, i32)": [string, number], * "(String, i32, bool)": [string, number, boolean], * "((String, i32), (bool, char, bool), ())": [[string, number], [boolean, string, boolean], null], * "(bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool)": [boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean], * "(Vec, Vec)": [number[], boolean[]], * String: string, * PathBuf: string, * IpAddr: string, * Ipv4Addr: string, * Ipv6Addr: string, * SocketAddr: string, * SocketAddrV4: string, * SocketAddrV6: string, * "Cow<'static, str>": string, * "Cow<'static, i32>": number, * "&'static str": string, * "&'static bool": boolean, * "&'static i32": number, * "Vec": number[], * "&'static [i32]": number[], * "&'static [i32; 3]": [number, number, number], * "[i32; 3]": [number, number, number], * "Vec": test_types_MyEnum[], * "&'static [MyEnum]": test_types_MyEnum[], * "&'static [MyEnum; 6]": [test_types_MyEnum, test_types_MyEnum, test_types_MyEnum, test_types_MyEnum, test_types_MyEnum, test_types_MyEnum], * "[MyEnum; 2]": [test_types_MyEnum, test_types_MyEnum], * "&'static [i32; 1]": [number], * "&'static [i32; 0]": [], * "Option": number | null, * "Option<()>": null, * "Option>": number[] | null, * "Result": std_result_Result, * "Vec>>": (number | null)[], * "Option>>": number[] | null, * "[Vec; 3]": [string[], string[], string[]], * "Option>": string | null, * "Option>>": string | null, * "PhantomData<()>": null, * "PhantomData": null, * Infallible: never, * Unit1: test_types_Unit1, * Unit2: test_types_Unit2, * Unit3: test_types_Unit3, * Unit4: test_types_Unit4, * Unit5: test_types_Unit5, * Unit6: test_types_Unit6, * Unit7: test_types_Unit7, * SimpleStruct: test_types_SimpleStruct, * TupleStruct1: test_types_TupleStruct1, * TupleStruct3: test_types_TupleStruct3, * TestEnum: test_types_TestEnum, * RefStruct: test_types_RefStruct, * InlinerStruct: test_types_InlinerStruct, * "GenericStruct": test_types_GenericStruct, * "GenericStruct": test_types_GenericStruct, * FlattenEnumStruct: test_types_FlattenEnumStruct, * OverridenStruct: test_types_OverridenStruct, * HasGenericAlias: test_types_HasGenericAlias, * EnumMacroAttributes: test_types_EnumMacroAttributes, * InlineEnumField: test_types_InlineEnumField, * InlineOptionalType: test_types_InlineOptionalType, * Rename: test_types_Rename, * TransparentType: test_types_TransparentType, * TransparentType2: test_types_TransparentType2, * TransparentTypeWithOverride: test_types_TransparentTypeWithOverride, * "[Option; 3]": [(number | null), (number | null), (number | null)], * "HashMap": Partial<{ [key in test_types_BasicEnum]: null }>, * "HashMap": Partial<{ [key in test_types_BasicEnum]: number }>, * "Option>>>": number | null, * "Vec": test_types_PlaceholderInnerField[], * EnumReferenceRecordKey: test_types_EnumReferenceRecordKey, * FlattenOnNestedEnum: test_types_FlattenOnNestedEnum, * MyEmptyInput: test_types_MyEmptyInput, * "(String)": string, * "(String,)": [string], * ExtraBracketsInTupleVariant: test_types_ExtraBracketsInTupleVariant, * ExtraBracketsInUnnamedStruct: test_types_ExtraBracketsInUnnamedStruct, * "Vec": test_types_MyEnum[], * InlineTuple: test_types_InlineTuple, * InlineTuple2: test_types_InlineTuple2, * "Box": string, * "Box": string, * SkippedFieldWithinVariant: test_types_SkippedFieldWithinVariant, * KebabCase: test_types_KebabCase, * "&[&str]": string[], * "Issue281<'_>": test_types_Issue281, * "LifetimeGenericStruct<'_, i32>": test_types_LifetimeGenericStruct, * "LifetimeGenericEnum<'_, i32>": test_types_LifetimeGenericEnum, * RenameWithWeirdCharsField: test_types_RenameWithWeirdCharsField, * RenameWithWeirdCharsVariant: test_types_RenameWithWeirdCharsVariant, * RenamedFieldKeys: test_types_RenamedFieldKeys, * RenamedVariantWithSkippedPayload: test_types_RenamedVariantWithSkippedPayload, * "type_type::Type": test_types_type_type_Type, * ActualType: test_types_ActualType, * SpectaTypeOverride: test_types_SpectaTypeOverride, * ContainerTypeOverrideStruct: test_types_ContainerTypeOverrideStruct, * ContainerTypeOverrideEnum: test_types_ContainerTypeOverrideEnum, * "ContainerTypeOverrideGeneric>": test_types_ContainerTypeOverrideGeneric, * "ContainerTypeOverrideToGeneric": test_types_ContainerTypeOverrideToGeneric, * ContainerTypeOverrideTuple: test_types_ContainerTypeOverrideTuple, * "ContainerTypeOverrideTupleGeneric": test_types_ContainerTypeOverrideTupleGeneric, * InvalidToValidType: test_types_InvalidToValidType, * TupleStruct: test_types_TupleStruct, * TupleStructWithRep: test_types_TupleStructWithRep, * "GenericTupleStruct": test_types_GenericTupleStruct, * BracedStruct: test_types_BracedStruct, * Struct: test_types_Struct, * Struct2: test_types_Struct2, * Enum: test_types_Enum, * Enum2: test_types_Enum2, * Enum3: test_types_Enum3, * StructRenameAllUppercase: test_types_StructRenameAllUppercase, * RenameSerdeSpecialChar: test_types_RenameSerdeSpecialChar, * EnumRenameAllUppercase: test_types_EnumRenameAllUppercase, * Recursive: test_types_Recursive, * RecursiveMapValue: test_types_RecursiveMapValue, * RecursiveTransparent: test_types_RecursiveTransparent, * RecursiveInEnum: test_types_RecursiveInEnum, * NonOptional: test_types_NonOptional, * OptionalOnNamedField: test_types_OptionalOnNamedField, * OptionalOnTransparentNamedField: test_types_OptionalOnTransparentNamedField, * OptionalInEnum: test_types_OptionalInEnum, * UntaggedVariants: test_types_UntaggedVariants, * UntaggedVariantsWithoutValue: test_types_UntaggedVariantsWithoutValue, * UntaggedVariantsWithDuplicateBranches: test_types_UntaggedVariantsWithDuplicateBranches, * "HashMap": { [key in string]: null }, * Regular: test_types_Regular, * "HashMap": { [key in never]: null }, * "HashMap": { [key in test_types_TransparentStruct]: null }, * "HashMap": Partial<{ [key in test_types_UnitVariants]: null }>, * "HashMap": Partial<{ [key in test_types_UntaggedVariantsKey]: null }>, * ValidMaybeValidKey: test_types_ValidMaybeValidKey, * ValidMaybeValidKeyNested: test_types_ValidMaybeValidKeyNested, * MacroStruct: test_types_MacroStruct, * MacroStruct2: test_types_MacroStruct2, * MacroEnum: test_types_MacroEnum, * DeprecatedType: test_types_DeprecatedType, * DeprecatedTypeWithMsg: test_types_DeprecatedTypeWithMsg, * DeprecatedTypeWithMsg2: test_types_DeprecatedTypeWithMsg2, * DeprecatedFields: test_types_DeprecatedFields, * DeprecatedTupleVariant: test_types_DeprecatedTupleVariant, * DeprecatedEnumVariants: test_types_DeprecatedEnumVariants, * CommentedStruct: test_types_CommentedStruct, * CommentedEnum: test_types_CommentedEnum, * SingleLineComment: test_types_SingleLineComment, * NonGeneric: test_types_Demo, * "HalfGenericA": test_types_Demo, * "HalfGenericB": test_types_Demo, * "FullGeneric": test_types_Demo, * "Another": test_types_Demo, * "MapA": { [key in string]: number }, * "MapB": { [key in number]: string }, * "MapC": { [key in string]: test_types_AGenericStruct }, * "AGenericStruct": test_types_AGenericStruct, * A: test_types_A, * DoubleFlattened: test_types_DoubleFlattened, * FlattenedInner: test_types_FlattenedInner, * BoxFlattened: test_types_BoxFlattened, * BoxInline: test_types_BoxInline, * First: test_types_First, * Second: test_types_Second, * Third: test_types_Third, * Fourth: test_types_Fourth, * TagOnStructWithInline: test_types_TagOnStructWithInline, * Sixth: test_types_Sixth, * Seventh: test_types_Seventh, * Eight: test_types_Eight, * Ninth: test_types_Ninth, * Tenth: test_types_Tenth, * MyEnumTagged: test_types_MyEnumTagged, * MyEnumExternal: test_types_MyEnumExternal, * MyEnumAdjacent: test_types_MyEnumAdjacent, * MyEnumUntagged: test_types_MyEnumUntagged, * EmptyStruct: test_types_EmptyStruct, * EmptyStructWithTag: test_types_EmptyStructWithTag, * AdjacentlyTagged: test_types_AdjacentlyTagged, * LoadProjectEvent: test_types_LoadProjectEvent, * ExternallyTagged: test_types_ExternallyTagged, * Issue221External: test_types_Issue221External, * InternallyTaggedD: test_types_InternallyTaggedD, * InternallyTaggedE: test_types_InternallyTaggedE, * InternallyTaggedF: test_types_InternallyTaggedF, * InternallyTaggedH: test_types_InternallyTaggedH, * InternallyTaggedL: test_types_InternallyTaggedL, * InternallyTaggedM: test_types_InternallyTaggedM, * StructWithAlias: test_types_StructWithAlias, * StructWithMultipleAliases: test_types_StructWithMultipleAliases, * StructWithAliasAndRename: test_types_StructWithAliasAndRename, * EnumWithVariantAlias: test_types_EnumWithVariantAlias, * EnumWithMultipleVariantAliases: test_types_EnumWithMultipleVariantAliases, * EnumWithVariantAliasAndRename: test_types_EnumWithVariantAliasAndRename, * InternallyTaggedWithAlias: test_types_InternallyTaggedWithAlias, * AdjacentlyTaggedWithAlias: test_types_AdjacentlyTaggedWithAlias, * UntaggedWithAlias: test_types_UntaggedWithAlias, * Issue221UntaggedSafe: test_types_Issue221UntaggedSafe, * Issue221UntaggedMixed: test_types_Issue221UntaggedMixed, * EmptyEnum: test_types_EmptyEnum, * EmptyEnumTagged: test_types_EmptyEnumTagged, * EmptyEnumTaggedWContent: test_types_EmptyEnumTaggedWContent, * EmptyEnumUntagged: test_types_EmptyEnumUntagged, * SkipOnlyField: test_types_SkipOnlyField, * SkipField: test_types_SkipField, * SkipVariant: test_types_SkipVariant, * SkipUnnamedFieldInVariant: test_types_SkipUnnamedFieldInVariant, * SkipNamedFieldInVariant: test_types_SkipNamedFieldInVariant, * TransparentWithSkip: test_types_TransparentWithSkip, * TransparentWithSkip2: test_types_TransparentWithSkip2, * TransparentWithSkip3: test_types_TransparentWithSkip3, * SkipVariant2: test_types_SkipVariant2, * SkipVariant3: test_types_SkipVariant3, * SkipStructFields: test_types_SkipStructFields, * SpectaSkipNonTypeField: test_types_SpectaSkipNonTypeField, * FlattenA: test_types_FlattenA, * FlattenB: test_types_FlattenB, * FlattenC: test_types_FlattenC, * FlattenD: test_types_FlattenD, * FlattenE: test_types_FlattenE, * FlattenF: test_types_FlattenF, * FlattenG: test_types_FlattenG, * TupleNested: test_types_TupleNested, * "Generic1<()>": test_types_Generic1, * "GenericAutoBound<()>": test_types_GenericAutoBound, * "GenericAutoBound2<()>": test_types_GenericAutoBound2, * Container1: test_types_Container1, * "Generic2<(), String, i32>": test_types_Generic2, * "GenericNewType1<()>": test_types_GenericNewType1, * "GenericTuple<()>": test_types_GenericTuple, * "GenericStruct2<()>": test_types_GenericStruct2, * "InlineGenericNewtype": string, * "InlineGenericNested": [string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | string | { value: string }], * "InlineFlattenGenericsG<()>": test_types_InlineFlattenGenericsG, * InlineFlattenGenerics: test_types_InlineFlattenGenerics, * GenericDefault: test_types_GenericDefault, * ChainedGenericDefault: test_types_ChainedGenericDefault, * "ChainedGenericDefault": test_types_ChainedGenericDefault, * "ChainedGenericDefault": test_types_ChainedGenericDefault, * "ChainedGenericDefault": test_types_ChainedGenericDefault, * GenericDefaultSkipped: test_types_GenericDefaultSkipped, * GenericDefaultSkippedNonType: test_types_GenericDefaultSkippedNonType, * GenericParameterOrderPreserved: test_types_GenericParameterOrderPreserved, * ConstGenericInNonConstContainer: test_types_ConstGenericInNonConstContainer, * ConstGenericInConstContainer: test_types_ConstGenericInConstContainer, * NamedConstGenericContainer: test_types_NamedConstGenericContainer, * InlineConstGenericContainer: test_types_InlineConstGenericContainer, * InlineRecursiveConstGenericContainer: test_types_InlineRecursiveConstGenericContainer, * TestCollectionRegister: test_types_TestCollectionRegister, * TestCollectionRegister: test_types_TestCollectionRegister, * }} Primitives * @property {number} i8 * @property {number} i16 * @property {number} i32 * @property {number} u8 * @property {number} u16 * @property {number} u32 * @property {number} f32 * @property {number} f64 * @property {boolean} bool * @property {string} char * @property {std_ops_Range} "Range" * @property {std_ops_RangeInclusive} "RangeInclusive" * @property {null} "()" * @property {[string, number]} "(String, i32)" * @property {[string, number, boolean]} "(String, i32, bool)" * @property {[[string, number], [boolean, string, boolean], null]} "((String, i32), (bool, char, bool), ())" * @property {[boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean]} "(bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool)" * @property {[number[], boolean[]]} "(Vec, Vec)" * @property {string} String * @property {string} PathBuf * @property {string} IpAddr * @property {string} Ipv4Addr * @property {string} Ipv6Addr * @property {string} SocketAddr * @property {string} SocketAddrV4 * @property {string} SocketAddrV6 * @property {string} "Cow<'static, str>" * @property {number} "Cow<'static, i32>" * @property {string} "&'static str" * @property {boolean} "&'static bool" * @property {number} "&'static i32" * @property {number[]} "Vec" * @property {number[]} "&'static [i32]" * @property {[number, number, number]} "&'static [i32; 3]" * @property {[number, number, number]} "[i32; 3]" * @property {test_types_MyEnum[]} "Vec" * @property {test_types_MyEnum[]} "&'static [MyEnum]" * @property {[test_types_MyEnum, test_types_MyEnum, test_types_MyEnum, test_types_MyEnum, test_types_MyEnum, test_types_MyEnum]} "&'static [MyEnum; 6]" * @property {[test_types_MyEnum, test_types_MyEnum]} "[MyEnum; 2]" * @property {[number]} "&'static [i32; 1]" * @property {[]} "&'static [i32; 0]" * @property {number | null} "Option" * @property {null} "Option<()>" * @property {number[] | null} "Option>" * @property {std_result_Result} "Result" * @property {(number | null)[]} "Vec>>" * @property {number[] | null} "Option>>" * @property {[string[], string[], string[]]} "[Vec; 3]" * @property {string | null} "Option>" * @property {string | null} "Option>>" * @property {null} "PhantomData<()>" * @property {null} "PhantomData" * @property {never} Infallible * @property {test_types_Unit1} Unit1 * @property {test_types_Unit2} Unit2 * @property {test_types_Unit3} Unit3 * @property {test_types_Unit4} Unit4 * @property {test_types_Unit5} Unit5 * @property {test_types_Unit6} Unit6 * @property {test_types_Unit7} Unit7 * @property {test_types_SimpleStruct} SimpleStruct * @property {test_types_TupleStruct1} TupleStruct1 * @property {test_types_TupleStruct3} TupleStruct3 * @property {test_types_TestEnum} TestEnum * @property {test_types_RefStruct} RefStruct * @property {test_types_InlinerStruct} InlinerStruct * @property {test_types_GenericStruct} "GenericStruct" * @property {test_types_GenericStruct} "GenericStruct" * @property {test_types_FlattenEnumStruct} FlattenEnumStruct * @property {test_types_OverridenStruct} OverridenStruct * @property {test_types_HasGenericAlias} HasGenericAlias * @property {test_types_EnumMacroAttributes} EnumMacroAttributes * @property {test_types_InlineEnumField} InlineEnumField * @property {test_types_InlineOptionalType} InlineOptionalType * @property {test_types_Rename} Rename * @property {test_types_TransparentType} TransparentType * @property {test_types_TransparentType2} TransparentType2 * @property {test_types_TransparentTypeWithOverride} TransparentTypeWithOverride * @property {[(number | null), (number | null), (number | null)]} "[Option; 3]" * @property {Partial<{ [key in test_types_BasicEnum]: null }>} "HashMap" * @property {Partial<{ [key in test_types_BasicEnum]: number }>} "HashMap" * @property {number | null} "Option>>>" * @property {test_types_PlaceholderInnerField[]} "Vec" * @property {test_types_EnumReferenceRecordKey} EnumReferenceRecordKey * @property {test_types_FlattenOnNestedEnum} FlattenOnNestedEnum * @property {test_types_MyEmptyInput} MyEmptyInput * @property {string} "(String)" * @property {[string]} "(String,)" * @property {test_types_ExtraBracketsInTupleVariant} ExtraBracketsInTupleVariant * @property {test_types_ExtraBracketsInUnnamedStruct} ExtraBracketsInUnnamedStruct * @property {test_types_MyEnum[]} "Vec" * @property {test_types_InlineTuple} InlineTuple * @property {test_types_InlineTuple2} InlineTuple2 * @property {string} "Box" * @property {string} "Box" * @property {test_types_SkippedFieldWithinVariant} SkippedFieldWithinVariant * @property {test_types_KebabCase} KebabCase * @property {string[]} "&[&str]" * @property {test_types_Issue281} "Issue281<'_>" * @property {test_types_LifetimeGenericStruct} "LifetimeGenericStruct<'_, i32>" * @property {test_types_LifetimeGenericEnum} "LifetimeGenericEnum<'_, i32>" * @property {test_types_RenameWithWeirdCharsField} RenameWithWeirdCharsField * @property {test_types_RenameWithWeirdCharsVariant} RenameWithWeirdCharsVariant * @property {test_types_RenamedFieldKeys} RenamedFieldKeys * @property {test_types_RenamedVariantWithSkippedPayload} RenamedVariantWithSkippedPayload * @property {test_types_type_type_Type} "type_type::Type" * @property {test_types_ActualType} ActualType * @property {test_types_SpectaTypeOverride} SpectaTypeOverride * @property {test_types_ContainerTypeOverrideStruct} ContainerTypeOverrideStruct * @property {test_types_ContainerTypeOverrideEnum} ContainerTypeOverrideEnum * @property {test_types_ContainerTypeOverrideGeneric} "ContainerTypeOverrideGeneric>" * @property {test_types_ContainerTypeOverrideToGeneric} "ContainerTypeOverrideToGeneric" * @property {test_types_ContainerTypeOverrideTuple} ContainerTypeOverrideTuple * @property {test_types_ContainerTypeOverrideTupleGeneric} "ContainerTypeOverrideTupleGeneric" * @property {test_types_InvalidToValidType} InvalidToValidType * @property {test_types_TupleStruct} TupleStruct * @property {test_types_TupleStructWithRep} TupleStructWithRep * @property {test_types_GenericTupleStruct} "GenericTupleStruct" * @property {test_types_BracedStruct} BracedStruct * @property {test_types_Struct} Struct * @property {test_types_Struct2} Struct2 * @property {test_types_Enum} Enum * @property {test_types_Enum2} Enum2 * @property {test_types_Enum3} Enum3 * @property {test_types_StructRenameAllUppercase} StructRenameAllUppercase * @property {test_types_RenameSerdeSpecialChar} RenameSerdeSpecialChar * @property {test_types_EnumRenameAllUppercase} EnumRenameAllUppercase * @property {test_types_Recursive} Recursive * @property {test_types_RecursiveMapValue} RecursiveMapValue * @property {test_types_RecursiveTransparent} RecursiveTransparent * @property {test_types_RecursiveInEnum} RecursiveInEnum * @property {test_types_NonOptional} NonOptional * @property {test_types_OptionalOnNamedField} OptionalOnNamedField * @property {test_types_OptionalOnTransparentNamedField} OptionalOnTransparentNamedField * @property {test_types_OptionalInEnum} OptionalInEnum * @property {test_types_UntaggedVariants} UntaggedVariants * @property {test_types_UntaggedVariantsWithoutValue} UntaggedVariantsWithoutValue * @property {test_types_UntaggedVariantsWithDuplicateBranches} UntaggedVariantsWithDuplicateBranches * @property {{ [key in string]: null }} "HashMap" * @property {test_types_Regular} Regular * @property {{ [key in never]: null }} "HashMap" * @property {{ [key in test_types_TransparentStruct]: null }} "HashMap" * @property {Partial<{ [key in test_types_UnitVariants]: null }>} "HashMap" * @property {Partial<{ [key in test_types_UntaggedVariantsKey]: null }>} "HashMap" * @property {test_types_ValidMaybeValidKey} ValidMaybeValidKey * @property {test_types_ValidMaybeValidKeyNested} ValidMaybeValidKeyNested * @property {test_types_MacroStruct} MacroStruct * @property {test_types_MacroStruct2} MacroStruct2 * @property {test_types_MacroEnum} MacroEnum * @property {test_types_DeprecatedType} DeprecatedType * @property {test_types_DeprecatedTypeWithMsg} DeprecatedTypeWithMsg * @property {test_types_DeprecatedTypeWithMsg2} DeprecatedTypeWithMsg2 * @property {test_types_DeprecatedFields} DeprecatedFields * @property {test_types_DeprecatedTupleVariant} DeprecatedTupleVariant * @property {test_types_DeprecatedEnumVariants} DeprecatedEnumVariants * @property {test_types_CommentedStruct} CommentedStruct * @property {test_types_CommentedEnum} CommentedEnum * @property {test_types_SingleLineComment} SingleLineComment * @property {test_types_Demo} NonGeneric * @property {test_types_Demo} "HalfGenericA" * @property {test_types_Demo} "HalfGenericB" * @property {test_types_Demo} "FullGeneric" * @property {test_types_Demo} "Another" * @property {{ [key in string]: number }} "MapA" * @property {{ [key in number]: string }} "MapB" * @property {{ [key in string]: test_types_AGenericStruct }} "MapC" * @property {test_types_AGenericStruct} "AGenericStruct" * @property {test_types_A} A * @property {test_types_DoubleFlattened} DoubleFlattened * @property {test_types_FlattenedInner} FlattenedInner * @property {test_types_BoxFlattened} BoxFlattened * @property {test_types_BoxInline} BoxInline * @property {test_types_First} First * @property {test_types_Second} Second * @property {test_types_Third} Third * @property {test_types_Fourth} Fourth * @property {test_types_TagOnStructWithInline} TagOnStructWithInline * @property {test_types_Sixth} Sixth * @property {test_types_Seventh} Seventh * @property {test_types_Eight} Eight * @property {test_types_Ninth} Ninth * @property {test_types_Tenth} Tenth * @property {test_types_MyEnumTagged} MyEnumTagged * @property {test_types_MyEnumExternal} MyEnumExternal * @property {test_types_MyEnumAdjacent} MyEnumAdjacent * @property {test_types_MyEnumUntagged} MyEnumUntagged * @property {test_types_EmptyStruct} EmptyStruct * @property {test_types_EmptyStructWithTag} EmptyStructWithTag * @property {test_types_AdjacentlyTagged} AdjacentlyTagged * @property {test_types_LoadProjectEvent} LoadProjectEvent * @property {test_types_ExternallyTagged} ExternallyTagged * @property {test_types_Issue221External} Issue221External * @property {test_types_InternallyTaggedD} InternallyTaggedD * @property {test_types_InternallyTaggedE} InternallyTaggedE * @property {test_types_InternallyTaggedF} InternallyTaggedF * @property {test_types_InternallyTaggedH} InternallyTaggedH * @property {test_types_InternallyTaggedL} InternallyTaggedL * @property {test_types_InternallyTaggedM} InternallyTaggedM * @property {test_types_StructWithAlias} StructWithAlias * @property {test_types_StructWithMultipleAliases} StructWithMultipleAliases * @property {test_types_StructWithAliasAndRename} StructWithAliasAndRename * @property {test_types_EnumWithVariantAlias} EnumWithVariantAlias * @property {test_types_EnumWithMultipleVariantAliases} EnumWithMultipleVariantAliases * @property {test_types_EnumWithVariantAliasAndRename} EnumWithVariantAliasAndRename * @property {test_types_InternallyTaggedWithAlias} InternallyTaggedWithAlias * @property {test_types_AdjacentlyTaggedWithAlias} AdjacentlyTaggedWithAlias * @property {test_types_UntaggedWithAlias} UntaggedWithAlias * @property {test_types_Issue221UntaggedSafe} Issue221UntaggedSafe * @property {test_types_Issue221UntaggedMixed} Issue221UntaggedMixed * @property {test_types_EmptyEnum} EmptyEnum * @property {test_types_EmptyEnumTagged} EmptyEnumTagged * @property {test_types_EmptyEnumTaggedWContent} EmptyEnumTaggedWContent * @property {test_types_EmptyEnumUntagged} EmptyEnumUntagged * @property {test_types_SkipOnlyField} SkipOnlyField * @property {test_types_SkipField} SkipField * @property {test_types_SkipVariant} SkipVariant * @property {test_types_SkipUnnamedFieldInVariant} SkipUnnamedFieldInVariant * @property {test_types_SkipNamedFieldInVariant} SkipNamedFieldInVariant * @property {test_types_TransparentWithSkip} TransparentWithSkip * @property {test_types_TransparentWithSkip2} TransparentWithSkip2 * @property {test_types_TransparentWithSkip3} TransparentWithSkip3 * @property {test_types_SkipVariant2} SkipVariant2 * @property {test_types_SkipVariant3} SkipVariant3 * @property {test_types_SkipStructFields} SkipStructFields * @property {test_types_SpectaSkipNonTypeField} SpectaSkipNonTypeField * @property {test_types_FlattenA} FlattenA * @property {test_types_FlattenB} FlattenB * @property {test_types_FlattenC} FlattenC * @property {test_types_FlattenD} FlattenD * @property {test_types_FlattenE} FlattenE * @property {test_types_FlattenF} FlattenF * @property {test_types_FlattenG} FlattenG * @property {test_types_TupleNested} TupleNested * @property {test_types_Generic1} "Generic1<()>" * @property {test_types_GenericAutoBound} "GenericAutoBound<()>" * @property {test_types_GenericAutoBound2} "GenericAutoBound2<()>" * @property {test_types_Container1} Container1 * @property {test_types_Generic2} "Generic2<(), String, i32>" * @property {test_types_GenericNewType1} "GenericNewType1<()>" * @property {test_types_GenericTuple} "GenericTuple<()>" * @property {test_types_GenericStruct2} "GenericStruct2<()>" * @property {string} "InlineGenericNewtype" * @property {[string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | string | { value: string }]} "InlineGenericNested" * @property {test_types_InlineFlattenGenericsG} "InlineFlattenGenericsG<()>" * @property {test_types_InlineFlattenGenerics} InlineFlattenGenerics * @property {test_types_GenericDefault} GenericDefault * @property {test_types_ChainedGenericDefault} ChainedGenericDefault * @property {test_types_ChainedGenericDefault} "ChainedGenericDefault" * @property {test_types_ChainedGenericDefault} "ChainedGenericDefault" * @property {test_types_ChainedGenericDefault} "ChainedGenericDefault" * @property {test_types_GenericDefaultSkipped} GenericDefaultSkipped * @property {test_types_GenericDefaultSkippedNonType} GenericDefaultSkippedNonType * @property {test_types_GenericParameterOrderPreserved} GenericParameterOrderPreserved * @property {test_types_ConstGenericInNonConstContainer} ConstGenericInNonConstContainer * @property {test_types_ConstGenericInConstContainer} ConstGenericInConstContainer * @property {test_types_NamedConstGenericContainer} NamedConstGenericContainer * @property {test_types_InlineConstGenericContainer} InlineConstGenericContainer * @property {test_types_InlineRecursiveConstGenericContainer} InlineRecursiveConstGenericContainer * @property {test_types_TestCollectionRegister} TestCollectionRegister * @property {test_types_TestCollectionRegister} TestCollectionRegister * * @typedef {{ * start: T, * end: T, * }} Range * @property {T} start * @property {T} end * * @typedef {{ * start: T, * end: T, * }} RangeInclusive * @property {T} start * @property {T} end * * @typedef {{ * demo: test_types_Recursive, * }} Recursive * @property {test_types_Recursive} demo * * @typedef {{ demo: test_types_RecursiveInEnum }} RecursiveInEnum * @property {{ demo: test_types_RecursiveInEnum }} A * * @typedef {{ * demo: test_types_RecursiveInline, * }} RecursiveInline * @property {test_types_RecursiveInline} demo * * @typedef {{ * demo: { [key in string]: test_types_RecursiveMapValue }, * }} RecursiveMapValue * @property {{ [key in string]: test_types_RecursiveMapValue }} demo * * @typedef {test_types_RecursiveInline} RecursiveTransparent * @property {test_types_RecursiveInline} "0" * * @typedef {test_types_TestEnum} RefStruct * @property {test_types_TestEnum} "0" * * @typedef {{ [key in string]: null }} Regular * @property {{ [key in string]: null }} "0" * * @typedef {"OneWord" | "TwoWords"} Rename * @property {"OneWord"} OneWord * @property {"TwoWords"} TwoWords * * @typedef {{ * b: number, * }} RenameSerdeSpecialChar * @property {number} b * * @typedef {{ * odata_context: string, * }} RenameWithWeirdCharsField * @property {string} odata_context * * @typedef {string} RenameWithWeirdCharsVariant * @property {string} A * * @typedef {{ * empty: string, * quote: string, * backslash: string, * newline: string, * line_separator: string, * paragraph_separator: string, * }} RenamedFieldKeys * @property {string} empty * @property {string} quote * @property {string} backslash * @property {string} newline * @property {string} line_separator * @property {string} paragraph_separator * * @typedef {never} RenamedVariantWithSkippedPayload * @property {never} A * * @typedef {{ * ok: T, * err: E, * }} Result * @property {T} ok * @property {E} err * * @typedef {{ * a: number, * }} Second * @property {number} a * * @typedef {{ * a: test_types_First, * b: test_types_Second, * }} Seventh * @property {test_types_First} a * @property {test_types_Second} b * * @typedef {{ * a: number, * b: string, * c: [number, string, number], * d: string[], * e: string | null, * }} SimpleStruct * @property {number} a * @property {string} b * @property {[number, string, number]} c * @property {string[]} d * @property {string | null} e * * Some single-line comment * * @typedef { * /** Some single-line comment */ * number | * /** Some single-line comment */ * { * /** Some single-line comment */ * a: number }} SingleLineComment * @property { * /** Some single-line comment */ * number} A - Some single-line comment * @property { * /** Some single-line comment */ * { * /** Some single-line comment */ * a: number }} B - Some single-line comment * * @typedef {{ * a: test_types_First, * b: test_types_First, * }} Sixth * @property {test_types_First} a * @property {test_types_First} b * * @typedef {{ * b: number, * }} SkipField * @property {number} b * * @typedef {Record | { b: number }} SkipNamedFieldInVariant * @property {Record} A * @property {{ b: number }} B * * @typedef {Record} SkipOnlyField * * @typedef {{ * a: number, * }} SkipStructFields * @property {number} a * * @typedef {never | [number]} SkipUnnamedFieldInVariant * @property {never} A * @property {[number]} B * * @typedef {string} SkipVariant * @property {string} A * * @typedef {string} SkipVariant2 * @property {string} A * * @typedef {{ a: string }} SkipVariant3 * @property {{ a: string }} A * * @typedef {never | string} SkippedFieldWithinVariant * @property {never} A * @property {string} B * * @typedef {{ * a: number, * }} SpectaSkipNonTypeField * @property {number} a * * @typedef {{ * string_ident: string, * u32_ident: number, * path: string, * tuple: [string, number], * }} SpectaTypeOverride * @property {string} string_ident * @property {number} u32_ident * @property {string} path * @property {[string, number]} tuple * * @typedef {{ * a: string, * }} Struct * @property {string} a * * @typedef {{ * a: string, * }} Struct2 * @property {string} a * * @typedef {{ * a: number, * b: number, * }} StructRenameAllUppercase * @property {number} a * @property {number} b * * @typedef {{ * field: string, * }} StructWithAlias * @property {string} field * * @typedef {{ * field: string, * }} StructWithAliasAndRename * @property {string} field * * @typedef {{ * field: string, * }} StructWithMultipleAliases * @property {string} field * * @typedef {{ * a: test_types_First, * b: { * a: string, * }, * }} TagOnStructWithInline * @property {test_types_First} a * @property {{ * a: string, * }} b * * @typedef {string | "B" | { * a: string, * } | test_types_First} Tenth * @property {string} A * @property {"B"} B * @property {{ * a: string, * }} C * @property {test_types_First} D * * @typedef {never} TestCollectionRegister * * @typedef {"Unit" | number | [number, number] | { a: number }} TestEnum * @property {"Unit"} Unit * @property {number} Single * @property {[number, number]} Multiple * @property {{ a: number }} Struct * * @typedef {{ * a: test_types_First, * b: { [key in string]: string }, * c: test_types_First, * }} Third * @property {test_types_First} a * @property {{ [key in string]: string }} b * @property {test_types_First} c * * @typedef {{ * a: string, * }} ToBeFlattened * @property {string} a * * @typedef {string} TransparentStruct * @property {string} "0" * * @typedef {test_types_TransparentTypeInner} TransparentType * @property {test_types_TransparentTypeInner} "0" * * @typedef {null} TransparentType2 * @property {null} "0" * * @typedef {{ * inner: string, * }} TransparentTypeInner * @property {string} inner * * @typedef {string} TransparentTypeWithOverride * @property {string} "0" * * @typedef {null} TransparentWithSkip * @property {null} "0" * * @typedef {string} TransparentWithSkip2 * @property {string} "0" * * @typedef {string} TransparentWithSkip3 * @property {string} "0" * * @typedef {[number[], [number[], number[]], [number[], number[], number[]]]} TupleNested * @property {number[]} "0" * @property {[number[], number[]]} "1" * @property {[number[], number[], number[]]} "2" * * @typedef {string} TupleStruct * @property {string} "0" * * @typedef {number} TupleStruct1 * @property {number} "0" * * @typedef {[number, boolean, string]} TupleStruct3 * @property {number} "0" * @property {boolean} "1" * @property {string} "2" * * @typedef {string} TupleStructWithRep * @property {string} "0" * * @typedef {never} Type * * @typedef {null} Unit1 * * @typedef {Record} Unit2 * * @typedef {[]} Unit3 * * @typedef {null} Unit4 * @property {null} "0" * * @typedef {"A"} Unit5 * @property {"A"} A * * @typedef {[]} Unit6 * @property {[]} A * * @typedef {Record} Unit7 * @property {Record} A * * @typedef {"A" | "B" | "C"} UnitVariants * @property {"A"} A * @property {"B"} B * @property {"C"} C * * @typedef {string | number | { id: string } | [string, boolean]} UntaggedVariants * @property {string} A * @property {number} B * @property {number} C * @property {{ id: string }} D * @property {[string, boolean]} E * * @typedef {string | number} UntaggedVariantsKey * @property {string} A * @property {number} B * @property {number} C * * @typedef {null | number} UntaggedVariantsWithDuplicateBranches * @property {null} A * @property {number} B * @property {null} C * * @typedef {string | [number, string] | number} UntaggedVariantsWithoutValue * @property {string} A * @property {[number, string]} B * @property {number} C * * @typedef {({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }} UntaggedWithAlias * @property {{ field: string }} A * @property {{ other: number }} B * * @typedef {{ [key in test_types_MaybeValidKey]: null }} ValidMaybeValidKey * @property {{ [key in test_types_MaybeValidKey]: null }} "0" * * @typedef {{ [key in test_types_MaybeValidKey>]: null }} ValidMaybeValidKeyNested * @property {{ [key in test_types_MaybeValidKey>]: null }} "0" */ ════════════════════════════════════════ ================================================ FILE: tests/tests/snapshots/test__jsdoc__jsdoc-export-to-moduleprefixedname-serde.snap ================================================ --- source: tests/tests/jsdoc.rs expression: output --- jsdoc-export-to-moduleprefixedname-serde (60882 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. /** * @typedef {{ * a: test_types_B, * b: { * b: number, * }, * c: test_types_B, * d: { * flattened: number, * }, * e: { * generic_flattened: number, * }, * }} A * @property {test_types_B} a * @property {{ * b: number, * }} b * @property {test_types_B} c * @property {{ * flattened: number, * }} d * @property {{ * generic_flattened: number, * }} e * * @typedef {{ * field: test_types_Demo, * }} AGenericStruct * @property {test_types_Demo} field * * @typedef {{ * a: test_types_GenericType, * }} ActualType * @property {test_types_GenericType} a * * @typedef {{ t: "A" } | { t: "B"; c: { * id: string, * method: string, * } } | { t: "C"; c: string }} AdjacentlyTagged * @property {{ t: "A" }} A * @property {{ t: "B"; c: { * id: string, * method: string, * } }} B * @property {{ t: "C"; c: string }} C * * @typedef {{ type: "A"; data: { * field: string, * } } | { type: "B"; data: { * other: number, * } }} AdjacentlyTaggedWithAlias * @property {{ type: "A"; data: { * field: string, * } }} A * @property {{ type: "B"; data: { * other: number, * } }} B * * @typedef {{ * b: number, * }} B * @property {number} b * * @typedef {"A" | "B"} BasicEnum * @property {"A"} A * @property {"B"} B * * @typedef {test_types_BoxedInner} BoxFlattened * * @typedef {{ * c: { * a: number, * }, * }} BoxInline * @property {{ * a: number, * }} c * * @typedef {{ * a: number, * }} BoxedInner * @property {number} a * * @typedef {string} BracedStruct * @property {string} "0" * * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second * * Some triple-slash comment * Some more triple-slash comment * * @typedef { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * ({ A: number }) & { B?: never } | * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * ({ B: { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * } }) & { A?: never }} CommentedEnum * @property { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * { A: number }} A - Some triple-slash comment Some more triple-slash comment * @property { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * { B: { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * } }} B - Some triple-slash comment Some more triple-slash comment * * Some triple-slash comment * Some more triple-slash comment * * @typedef {{ * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * }} CommentedStruct * @property {number} a - Some triple-slash comment Some more triple-slash comment * * @typedef {{ * data: number[], * a: number[], * d: [number, number], * }} ConstGenericInConstContainer * @property {number[]} data * @property {number[]} a * @property {[number, number]} d * * @typedef {{ * data: [number], * a: [number, number], * d: [number, number], * }} ConstGenericInNonConstContainer * @property {[number]} data * @property {[number, number]} a * @property {[number, number]} d * * @typedef {{ * foo: test_types_Generic1, * bar: test_types_Generic1[], * baz: { [key in string]: test_types_Generic1 }, * }} Container1 * @property {test_types_Generic1} foo * @property {test_types_Generic1[]} bar * @property {{ [key in string]: test_types_Generic1 }} baz * * @typedef {string} ContainerTypeOverrideEnum * * @typedef {string} ContainerTypeOverrideGeneric * * @typedef {string} ContainerTypeOverrideStruct * * @typedef {T} ContainerTypeOverrideToGeneric * * @typedef {[string, number]} ContainerTypeOverrideTuple * * @typedef {[T, string]} ContainerTypeOverrideTupleGeneric * * @typedef {{ * flattened: number, * }} D * @property {number} flattened * * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b * * @typedef { * /** * * @deprecated * */ * "A" | * /** * * @deprecated Nope * */ * "B" | * /** * * @deprecated Nope * */ * "C"} DeprecatedEnumVariants * @property { * /** * * @deprecated * */ * "A"} A - @deprecated * @property { * /** * * @deprecated Nope * */ * "B"} B - @deprecated Nope * @property { * /** * * @deprecated Nope * */ * "C"} C - @deprecated Nope * * @typedef {{ * a: number, * /** * * @deprecated * */ * b: string, * /** * * @deprecated This field is cringe! * */ * c: string, * /** * * @deprecated This field is cringe! * */ * d: string, * }} DeprecatedFields * @property {number} a * @property {string} b - @deprecated * @property {string} c - @deprecated This field is cringe! * @property {string} d - @deprecated This field is cringe! * * @typedef {[ * /** * * @deprecated * */ * string, * /** * * @deprecated Nope * */ * string, * /** * * @deprecated Nope * */ * number]} DeprecatedTupleVariant * @property {string} "0" - @deprecated * @property {string} "1" - @deprecated Nope * @property {number} "2" - @deprecated Nope * * @deprecated * @typedef {{ * a: number, * }} DeprecatedType * @property {number} a * * @deprecated Look at you big man using a deprecation message * @typedef {{ * a: number, * }} DeprecatedTypeWithMsg * @property {number} a * * @deprecated Look at you big man using a deprecation message * @typedef {{ * a: number, * }} DeprecatedTypeWithMsg2 * @property {number} a * * @typedef {{ * a: test_types_ToBeFlattened, * b: test_types_ToBeFlattened, * }} DoubleFlattened * @property {test_types_ToBeFlattened} a * @property {test_types_ToBeFlattened} b * * @typedef {{ A: string } | "B"} Eight * @property {{ A: string }} A * @property {"B"} B * * @typedef {never} EmptyEnum * * @typedef {never} EmptyEnumTagged * * @typedef {never} EmptyEnumTaggedWContent * * @typedef {never} EmptyEnumUntagged * * @typedef {Record} EmptyStruct * * @typedef {{ * a: "EmptyStructWithTag", * }} EmptyStructWithTag * @property {"EmptyStructWithTag"} a * * @typedef {{ t: "A" } | { t: "B" }} Enum * @property {{ t: "A" }} A * @property {{ t: "B" }} B * * @typedef {{ t: "C" } | { t: "B" } | { t: "D"; enumField: null }} Enum2 * @property {{ t: "C" }} C * @property {{ t: "B" }} B * @property {{ t: "D"; enumField: null }} D * * @typedef {{ t: "A"; b: string }} Enum3 * @property {{ t: "A"; b: string }} A * * @typedef {({ A: string }) & { D?: never; bbb?: never; cccc?: never } | ({ bbb: number }) & { A?: never; D?: never; cccc?: never } | ({ cccc: number }) & { A?: never; D?: never; bbb?: never } | ({ D: { * a: string, * bbbbbb: number, * } }) & { A?: never; bbb?: never; cccc?: never }} EnumMacroAttributes * @property {{ A: string }} A * @property {{ bbb: number }} bbb * @property {{ cccc: number }} cccc * @property {{ D: { * a: string, * bbbbbb: number, * } }} D * * @typedef {{ * a: Partial<{ [key in test_types_BasicEnum]: number }>, * }} EnumReferenceRecordKey * @property {Partial<{ [key in test_types_BasicEnum]: number }>} a * * @typedef {"HELLOWORLD" | "VARIANTB" | "TESTINGWORDS"} EnumRenameAllUppercase * @property {"HELLOWORLD"} HELLOWORLD * @property {"VARIANTB"} VARIANTB * @property {"TESTINGWORDS"} TESTINGWORDS * * @typedef {"Variant" | "Other"} EnumWithMultipleVariantAliases * @property {"Variant"} Variant * @property {"Other"} Other * * @typedef {"Variant" | "Other"} EnumWithVariantAlias * @property {"Variant"} Variant * @property {"Other"} Other * * @typedef {"renamed_variant" | "Other"} EnumWithVariantAliasAndRename * @property {"renamed_variant"} renamed_variant * @property {"Other"} Other * * @typedef {"A" | ({ B: { * id: string, * method: string, * } }) & { C?: never } | ({ C: string }) & { B?: never }} ExternallyTagged * @property {"A"} A * @property {{ B: { * id: string, * method: string, * } }} B * @property {{ C: string }} C * * @typedef {{ A: string }} ExtraBracketsInTupleVariant * @property {{ A: string }} A * * @typedef {string} ExtraBracketsInUnnamedStruct * @property {string} "0" * * @typedef {{ * a: string, * }} First * @property {string} a * * @typedef {{ * a: number, * b: number, * }} FlattenA * @property {number} a * @property {number} b * * @typedef {{ * c: number, * } & test_types_FlattenA} FlattenB * @property {number} c * * @typedef {{ * c: number, * } & test_types_FlattenA} FlattenC * @property {number} c * * @typedef {{ * a: test_types_FlattenA, * c: number, * }} FlattenD * @property {test_types_FlattenA} a * @property {number} c * * @typedef {{ * b: ({ * c: number, * }) & (test_types_FlattenA), * d: number, * }} FlattenE * @property {({ * c: number, * }) & (test_types_FlattenA)} b * @property {number} d * * @typedef {{ tag: "One" } | { tag: "Two" } | { tag: "Three" }} FlattenEnum * @property {{ tag: "One" }} One * @property {{ tag: "Two" }} Two * @property {{ tag: "Three" }} Three * * @typedef {{ * outer: string, * } & test_types_FlattenEnum} FlattenEnumStruct * @property {string} outer * * @typedef {{ * b: ({ * c: number, * }) & (test_types_FlattenA), * d: number, * }} FlattenF * @property {({ * c: number, * }) & (test_types_FlattenA)} b * @property {number} d * * @typedef {{ * b: test_types_FlattenB, * d: number, * }} FlattenG * @property {test_types_FlattenB} b * @property {number} d * * @typedef {{ * id: string, * } & test_types_NestedEnum} FlattenOnNestedEnum * @property {string} id * * @typedef {test_types_Inner} FlattenedInner * * @typedef {{ * a: test_types_First, * b: { * a: string, * }, * }} Fourth * @property {test_types_First} a * @property {{ * a: string, * }} b * * @typedef {{ * value: T, * values: T[], * }} Generic1 * @property {T} value * @property {T[]} values * * @typedef {({ A: A }) & { B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ B: [B, B, B] }) & { A?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ C: C[] }) & { A?: never; B?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ D: A[][][] }) & { A?: never; B?: never; C?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ E: { * a: A, * b: B, * c: C, * } }) & { A?: never; B?: never; C?: never; D?: never; X?: never; Y?: never; Z?: never } | ({ X: number[] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; Y?: never; Z?: never } | ({ Y: number }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Z?: never } | ({ Z: number[][] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never }} Generic2 * @property {{ A: A }} A * @property {{ B: [B, B, B] }} B * @property {{ C: C[] }} C * @property {{ D: A[][][] }} D * @property {{ E: { * a: A, * b: B, * c: C, * } }} E * @property {{ X: number[] }} X * @property {{ Y: number }} Y * @property {{ Z: number[][] }} Z * * @typedef {{ * value: T, * values: T[], * }} GenericAutoBound * @property {T} value * @property {T[]} values * * @typedef {{ * value: T, * values: T[], * }} GenericAutoBound2 * @property {T} value * @property {T[]} values * * @typedef {{ * value: T, * }} GenericDefault * @property {T} value * * @typedef {{ * value: T, * }} GenericDefaultSkipped * @property {T} value * * @typedef {{ * value: number, * }} GenericDefaultSkippedNonType * @property {number} value * * @typedef {{ * generic_flattened: T, * }} GenericFlattened * @property {T} generic_flattened * * @typedef {T[][]} GenericNewType1 * @property {T[][]} "0" * * @typedef {{ * pair: test_types_Pair, * }} GenericParameterOrderPreserved * @property {test_types_Pair} pair * * @typedef {{ * arg: T, * }} GenericStruct * @property {T} arg * * @typedef {{ * a: T, * b: [T, T], * c: [T, [T, T]], * d: [T, T, T], * e: [([T, T]), ([T, T]), ([T, T])], * f: T[], * g: T[][], * h: ([([T, T]), ([T, T]), ([T, T])])[], * }} GenericStruct2 * @property {T} a * @property {[T, T]} b * @property {[T, [T, T]]} c * @property {[T, T, T]} d * @property {[([T, T]), ([T, T]), ([T, T])]} e * @property {T[]} f * @property {T[][]} g * @property {([([T, T]), ([T, T]), ([T, T])])[]} h * * @typedef {[T, T[], T[][]]} GenericTuple * @property {T} "0" * @property {T[]} "1" * @property {T[][]} "2" * * @typedef {T} GenericTupleStruct * @property {T} "0" * * @typedef {"Undefined" | T} GenericType * @property {"Undefined"} Undefined * @property {T} Value * * @typedef {{ [key in number]: string }} HasGenericAlias * @property {{ [key in number]: string }} "0" * * @typedef {{ * b: { * data: [number, number], * a: [number, number], * d: [number, number, number], * }, * c: { * data: [number, number, number], * a: [number, number], * d: [number, number, number], * }, * d: [number, number], * }} InlineConstGenericContainer * @property {{ * data: [number, number], * a: [number, number], * d: [number, number, number], * }} b * @property {{ * data: [number, number, number], * a: [number, number], * d: [number, number, number], * }} c * @property {[number, number]} d * * @typedef {{ A: { * a: string, * } }} InlineEnumField * @property {{ A: { * a: string, * } }} A * * @typedef {{ * g: test_types_InlineFlattenGenericsG, * gi: { * t: string, * }, * } & test_types_InlineFlattenGenericsG} InlineFlattenGenerics * @property {test_types_InlineFlattenGenericsG} g * @property {{ * t: string, * }} gi * * @typedef {{ * t: T, * }} InlineFlattenGenericsG * @property {T} t * * @typedef {{ * optional_field: { * a: string, * } | null, * }} InlineOptionalType * @property {{ * a: string, * } | null} optional_field * * @typedef {{ * data: number[], * a: number[], * d: [number, number, number], * e: test_types_InlineRecursiveConstGeneric, * }} InlineRecursiveConstGeneric * @property {number[]} data * @property {number[]} a * @property {[number, number, number]} d * @property {test_types_InlineRecursiveConstGeneric} e * * @typedef {{ * b: { * data: [number, number], * a: [number, number], * d: [number, number, number], * e: test_types_InlineRecursiveConstGeneric, * }, * c: { * data: [number, number, number], * a: [number, number], * d: [number, number, number], * e: test_types_InlineRecursiveConstGeneric, * }, * d: [number, number], * }} InlineRecursiveConstGenericContainer * @property {{ * data: [number, number], * a: [number, number], * d: [number, number, number], * e: test_types_InlineRecursiveConstGeneric, * }} b * @property {{ * data: [number, number, number], * a: [number, number], * d: [number, number, number], * e: test_types_InlineRecursiveConstGeneric, * }} c * @property {[number, number]} d * * @typedef {{ * ref_struct: test_types_SimpleStruct, * val: number, * }} InlineStruct * @property {test_types_SimpleStruct} ref_struct * @property {number} val * * @typedef {{ * demo: [string, boolean], * }} InlineTuple * @property {[string, boolean]} demo * * @typedef {{ * demo: [{ * demo: [string, boolean], * }, boolean], * }} InlineTuple2 * @property {[{ * demo: [string, boolean], * }, boolean]} demo * * @typedef {{ * inline_this: { * ref_struct: test_types_SimpleStruct, * val: number, * }, * dont_inline_this: test_types_RefStruct, * }} InlinerStruct * @property {{ * ref_struct: test_types_SimpleStruct, * val: number, * }} inline_this * @property {test_types_RefStruct} dont_inline_this * * @typedef {{ * a: number, * } & test_types_FlattenedInner} Inner * @property {number} a * * @typedef {{ * type: "A", * } & { [key in string]: string }} InternallyTaggedD * @property {{ * type: "A", * } & { [key in string]: string }} A * * @typedef {{ type: "A" }} InternallyTaggedE * @property {{ type: "A" }} A * * @typedef {{ type: "A" }} InternallyTaggedF * @property {{ type: "A" }} A * * @typedef {null} InternallyTaggedFInner * @property {null} A * * @typedef {{ type: "A" }} InternallyTaggedH * @property {{ type: "A" }} A * * @typedef {null} InternallyTaggedHInner * @property {null} "0" * * @typedef {{ * type: "A", * } & { type: "A" } | { type: "B" }} InternallyTaggedL * @property {{ * type: "A", * } & { type: "A" } | { type: "B" }} A * * @typedef {{ type: "A" } | { type: "B" }} InternallyTaggedLInner * @property {{ type: "A" }} A * @property {{ type: "B" }} B * * @typedef {{ type: "A" }} InternallyTaggedM * @property {{ type: "A" }} A * * @typedef {"A" | "B"} InternallyTaggedMInner * @property {"A"} A * @property {"B"} B * * @typedef {{ type: "A"; field: string } | { type: "B"; other: number }} InternallyTaggedWithAlias * @property {{ type: "A"; field: string }} A * @property {{ type: "B"; other: number }} B * * @typedef {{ * cause: null, * }} InvalidToValidType * @property {null} cause * * @typedef {({ A: { * a: string, * } }) & { B?: never } | ({ B: { * b: string, * } }) & { A?: never }} Issue221External * @property {{ A: { * a: string, * } }} A * @property {{ B: { * b: string, * } }} B * * @typedef {({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never }} Issue221UntaggedMixed * @property {{ a: string }} A * @property {{ b: string }} B * @property {{ values: { [key in string]: string } }} Unsafe * * @typedef {({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }} Issue221UntaggedSafe * @property {{ a: string }} A * @property {{ b: string }} B * * @typedef {{ * default_unity_arguments: string[], * }} Issue281 * @property {string[]} default_unity_arguments * * @typedef {{ * "test-ing": string, * }} KebabCase * @property {string} "test-ing" * * @typedef {({ Borrowed: T }) & { Owned?: never } | ({ Owned: T }) & { Borrowed?: never }} LifetimeGenericEnum * @property {{ Borrowed: T }} Borrowed * @property {{ Owned: T }} Owned * * @typedef {{ * borrowed: T[], * owned: T[], * }} LifetimeGenericStruct * @property {T[]} borrowed * @property {T[]} owned * * @typedef {{ event: "started"; data: { * projectName: string, * } } | { event: "progressTest"; data: { * projectName: string, * status: string, * progress: number, * } } | { event: "finished"; data: { * projectName: string, * } }} LoadProjectEvent * @property {{ event: "started"; data: { * projectName: string, * } }} started * @property {{ event: "progressTest"; data: { * projectName: string, * status: string, * progress: number, * } }} progressTest * @property {{ event: "finished"; data: { * projectName: string, * } }} finished * * @typedef {({ Demo: string }) & { Demo2?: never } | ({ Demo2: { * demo2: string, * } }) & { Demo?: never }} MacroEnum * @property {{ Demo: string }} Demo * @property {{ Demo2: { * demo2: string, * } }} Demo2 * * @typedef {string} MacroStruct * @property {string} "0" * * @typedef {{ * demo: string, * }} MacroStruct2 * @property {string} demo * * @typedef {T} MaybeValidKey * @property {T} "0" * * @typedef {Record} MyEmptyInput * * @typedef {({ A: string }) & { B?: never } | ({ B: number }) & { A?: never }} MyEnum * @property {{ A: string }} A * @property {{ B: number }} B * * @typedef {{ t: "Variant"; c: { * inner: test_types_First, * } }} MyEnumAdjacent * @property {{ t: "Variant"; c: { * inner: test_types_First, * } }} Variant * * @typedef {{ Variant: { * inner: test_types_First, * } }} MyEnumExternal * @property {{ Variant: { * inner: test_types_First, * } }} Variant * * @typedef {{ type: "Variant"; inner: test_types_First }} MyEnumTagged * @property {{ type: "Variant"; inner: test_types_First }} Variant * * @typedef {{ inner: test_types_First }} MyEnumUntagged * @property {{ inner: test_types_First }} Variant * * @typedef {{ * data: number[], * a: number[], * d: [number, number], * }} NamedConstGeneric * @property {number[]} data * @property {number[]} a * @property {[number, number]} d * * @typedef {{ * a: test_types_NamedConstGeneric, * b: test_types_NamedConstGeneric, * d: [number, number], * }} NamedConstGenericContainer * @property {test_types_NamedConstGeneric} a * @property {test_types_NamedConstGeneric} b * @property {[number, number]} d * * @typedef {{ type: "a"; value: string } | { type: "b"; value: number }} NestedEnum * @property {{ type: "a"; value: string }} a * @property {{ type: "b"; value: number }} b * * @typedef {{ t: "A"; c: string } | { t: "B" } | { t: "C"; c: { * a: string, * } } | { t: "D"; c: test_types_First }} Ninth * @property {{ t: "A"; c: string }} A * @property {{ t: "B" }} B * @property {{ t: "C"; c: { * a: string, * } }} C * @property {{ t: "D"; c: test_types_First }} D * * @typedef {string | null} NonOptional * @property {string | null} "0" * * @typedef {({ A?: string | null }) & { B?: never; C?: never } | ({ B: { * a: string | null, * } }) & { A?: never; C?: never } | ({ C: { * a?: string | null, * } }) & { A?: never; B?: never }} OptionalInEnum * @property {{ A?: string | null }} A * @property {{ B: { * a: string | null, * } }} B * @property {{ C: { * a?: string | null, * } }} C * * @typedef {string | null} OptionalOnNamedField * @property {string | null} ["0"] * * @typedef {{ * b: string | null, * }} OptionalOnTransparentNamedField * @property {string | null} b * * @typedef {{ * overriden_field: string, * }} OverridenStruct * @property {string} overriden_field * * @typedef {{ * first: Z, * second: A, * }} Pair * @property {Z} first * @property {A} second * * @typedef {{ * a: string, * }} PlaceholderInnerField * @property {string} a * * @typedef {{ * i8: number, * i16: number, * i32: number, * u8: number, * u16: number, * u32: number, * f32: number, * f64: number, * bool: boolean, * char: string, * "Range": std_ops_Range, * "RangeInclusive": std_ops_RangeInclusive, * "()": null, * "(String, i32)": [string, number], * "(String, i32, bool)": [string, number, boolean], * "((String, i32), (bool, char, bool), ())": [[string, number], [boolean, string, boolean], null], * "(bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool)": [boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean], * "(Vec, Vec)": [number[], boolean[]], * String: string, * PathBuf: string, * IpAddr: string, * Ipv4Addr: string, * Ipv6Addr: string, * SocketAddr: string, * SocketAddrV4: string, * SocketAddrV6: string, * "Cow<'static, str>": string, * "Cow<'static, i32>": number, * "&'static str": string, * "&'static bool": boolean, * "&'static i32": number, * "Vec": number[], * "&'static [i32]": number[], * "&'static [i32; 3]": [number, number, number], * "[i32; 3]": [number, number, number], * "Vec": test_types_MyEnum[], * "&'static [MyEnum]": test_types_MyEnum[], * "&'static [MyEnum; 6]": [test_types_MyEnum, test_types_MyEnum, test_types_MyEnum, test_types_MyEnum, test_types_MyEnum, test_types_MyEnum], * "[MyEnum; 2]": [test_types_MyEnum, test_types_MyEnum], * "&'static [i32; 1]": [number], * "&'static [i32; 0]": [], * "Option": number | null, * "Option<()>": null, * "Option>": number[] | null, * "Result": std_result_Result, * "Vec>>": (number | null)[], * "Option>>": number[] | null, * "[Vec; 3]": [string[], string[], string[]], * "Option>": string | null, * "Option>>": string | null, * "PhantomData<()>": null, * "PhantomData": null, * Infallible: never, * Unit1: test_types_Unit1, * Unit2: test_types_Unit2, * Unit3: test_types_Unit3, * Unit4: test_types_Unit4, * Unit5: test_types_Unit5, * Unit6: test_types_Unit6, * Unit7: test_types_Unit7, * SimpleStruct: test_types_SimpleStruct, * TupleStruct1: test_types_TupleStruct1, * TupleStruct3: test_types_TupleStruct3, * TestEnum: test_types_TestEnum, * RefStruct: test_types_RefStruct, * InlinerStruct: test_types_InlinerStruct, * "GenericStruct": test_types_GenericStruct, * "GenericStruct": test_types_GenericStruct, * FlattenEnumStruct: test_types_FlattenEnumStruct, * OverridenStruct: test_types_OverridenStruct, * HasGenericAlias: test_types_HasGenericAlias, * EnumMacroAttributes: test_types_EnumMacroAttributes, * InlineEnumField: test_types_InlineEnumField, * InlineOptionalType: test_types_InlineOptionalType, * Rename: test_types_Rename, * TransparentType: test_types_TransparentType, * TransparentType2: test_types_TransparentType2, * TransparentTypeWithOverride: test_types_TransparentTypeWithOverride, * "[Option; 3]": [(number | null), (number | null), (number | null)], * "HashMap": Partial<{ [key in test_types_BasicEnum]: null }>, * "HashMap": Partial<{ [key in test_types_BasicEnum]: number }>, * "Option>>>": number | null, * "Vec": test_types_PlaceholderInnerField[], * EnumReferenceRecordKey: test_types_EnumReferenceRecordKey, * FlattenOnNestedEnum: test_types_FlattenOnNestedEnum, * MyEmptyInput: test_types_MyEmptyInput, * "(String)": string, * "(String,)": [string], * ExtraBracketsInTupleVariant: test_types_ExtraBracketsInTupleVariant, * ExtraBracketsInUnnamedStruct: test_types_ExtraBracketsInUnnamedStruct, * "Vec": test_types_MyEnum[], * InlineTuple: test_types_InlineTuple, * InlineTuple2: test_types_InlineTuple2, * "Box": string, * "Box": string, * SkippedFieldWithinVariant: test_types_SkippedFieldWithinVariant, * KebabCase: test_types_KebabCase, * "&[&str]": string[], * "Issue281<'_>": test_types_Issue281, * "LifetimeGenericStruct<'_, i32>": test_types_LifetimeGenericStruct, * "LifetimeGenericEnum<'_, i32>": test_types_LifetimeGenericEnum, * RenameWithWeirdCharsField: test_types_RenameWithWeirdCharsField, * RenameWithWeirdCharsVariant: test_types_RenameWithWeirdCharsVariant, * RenamedFieldKeys: test_types_RenamedFieldKeys, * RenamedVariantWithSkippedPayload: test_types_RenamedVariantWithSkippedPayload, * "type_type::Type": test_types_type_type_Type, * ActualType: test_types_ActualType, * SpectaTypeOverride: test_types_SpectaTypeOverride, * ContainerTypeOverrideStruct: test_types_ContainerTypeOverrideStruct, * ContainerTypeOverrideEnum: test_types_ContainerTypeOverrideEnum, * "ContainerTypeOverrideGeneric>": test_types_ContainerTypeOverrideGeneric, * "ContainerTypeOverrideToGeneric": test_types_ContainerTypeOverrideToGeneric, * ContainerTypeOverrideTuple: test_types_ContainerTypeOverrideTuple, * "ContainerTypeOverrideTupleGeneric": test_types_ContainerTypeOverrideTupleGeneric, * InvalidToValidType: test_types_InvalidToValidType, * TupleStruct: test_types_TupleStruct, * TupleStructWithRep: test_types_TupleStructWithRep, * "GenericTupleStruct": test_types_GenericTupleStruct, * BracedStruct: test_types_BracedStruct, * Struct: test_types_StructNew, * Struct2: test_types_Struct2, * Enum: test_types_Enum, * Enum2: test_types_Enum2, * Enum3: test_types_Enum3, * StructRenameAllUppercase: test_types_StructRenameAllUppercase, * RenameSerdeSpecialChar: test_types_RenameSerdeSpecialChar, * EnumRenameAllUppercase: test_types_EnumRenameAllUppercase, * Recursive: test_types_Recursive, * RecursiveMapValue: test_types_RecursiveMapValue, * RecursiveTransparent: test_types_RecursiveTransparent, * RecursiveInEnum: test_types_RecursiveInEnum, * NonOptional: test_types_NonOptional, * OptionalOnNamedField: test_types_OptionalOnNamedField, * OptionalOnTransparentNamedField: test_types_OptionalOnTransparentNamedField, * OptionalInEnum: test_types_OptionalInEnum, * UntaggedVariants: test_types_UntaggedVariants, * UntaggedVariantsWithoutValue: test_types_UntaggedVariantsWithoutValue, * UntaggedVariantsWithDuplicateBranches: test_types_UntaggedVariantsWithDuplicateBranches, * "HashMap": { [key in string]: null }, * Regular: test_types_Regular, * "HashMap": { [key in never]: null }, * "HashMap": { [key in test_types_TransparentStruct]: null }, * "HashMap": Partial<{ [key in test_types_UnitVariants]: null }>, * "HashMap": Partial<{ [key in test_types_UntaggedVariantsKey]: null }>, * ValidMaybeValidKey: test_types_ValidMaybeValidKey, * ValidMaybeValidKeyNested: test_types_ValidMaybeValidKeyNested, * MacroStruct: test_types_MacroStruct, * MacroStruct2: test_types_MacroStruct2, * MacroEnum: test_types_MacroEnum, * DeprecatedType: test_types_DeprecatedType, * DeprecatedTypeWithMsg: test_types_DeprecatedTypeWithMsg, * DeprecatedTypeWithMsg2: test_types_DeprecatedTypeWithMsg2, * DeprecatedFields: test_types_DeprecatedFields, * DeprecatedTupleVariant: test_types_DeprecatedTupleVariant, * DeprecatedEnumVariants: test_types_DeprecatedEnumVariants, * CommentedStruct: test_types_CommentedStruct, * CommentedEnum: test_types_CommentedEnum, * SingleLineComment: test_types_SingleLineComment, * NonGeneric: test_types_Demo, * "HalfGenericA": test_types_Demo, * "HalfGenericB": test_types_Demo, * "FullGeneric": test_types_Demo, * "Another": test_types_Demo, * "MapA": { [key in string]: number }, * "MapB": { [key in number]: string }, * "MapC": { [key in string]: test_types_AGenericStruct }, * "AGenericStruct": test_types_AGenericStruct, * A: test_types_A, * DoubleFlattened: test_types_DoubleFlattened, * FlattenedInner: test_types_FlattenedInner, * BoxFlattened: test_types_BoxFlattened, * BoxInline: test_types_BoxInline, * First: test_types_First, * Second: test_types_Second, * Third: test_types_Third, * Fourth: test_types_Fourth, * TagOnStructWithInline: test_types_TagOnStructWithInline, * Sixth: test_types_Sixth, * Seventh: test_types_Seventh, * Eight: test_types_Eight, * Ninth: test_types_Ninth, * Tenth: test_types_Tenth, * MyEnumTagged: test_types_MyEnumTagged, * MyEnumExternal: test_types_MyEnumExternal, * MyEnumAdjacent: test_types_MyEnumAdjacent, * MyEnumUntagged: test_types_MyEnumUntagged, * EmptyStruct: test_types_EmptyStruct, * EmptyStructWithTag: test_types_EmptyStructWithTag, * AdjacentlyTagged: test_types_AdjacentlyTagged, * LoadProjectEvent: test_types_LoadProjectEvent, * ExternallyTagged: test_types_ExternallyTagged, * Issue221External: test_types_Issue221External, * InternallyTaggedD: test_types_InternallyTaggedD, * InternallyTaggedE: test_types_InternallyTaggedE, * InternallyTaggedF: test_types_InternallyTaggedF, * InternallyTaggedH: test_types_InternallyTaggedH, * InternallyTaggedL: test_types_InternallyTaggedL, * InternallyTaggedM: test_types_InternallyTaggedM, * StructWithAlias: test_types_StructWithAlias, * StructWithMultipleAliases: test_types_StructWithMultipleAliases, * StructWithAliasAndRename: test_types_StructWithAliasAndRename, * EnumWithVariantAlias: test_types_EnumWithVariantAlias, * EnumWithMultipleVariantAliases: test_types_EnumWithMultipleVariantAliases, * EnumWithVariantAliasAndRename: test_types_EnumWithVariantAliasAndRename, * InternallyTaggedWithAlias: test_types_InternallyTaggedWithAlias, * AdjacentlyTaggedWithAlias: test_types_AdjacentlyTaggedWithAlias, * UntaggedWithAlias: test_types_UntaggedWithAlias, * Issue221UntaggedSafe: test_types_Issue221UntaggedSafe, * Issue221UntaggedMixed: test_types_Issue221UntaggedMixed, * EmptyEnum: test_types_EmptyEnum, * EmptyEnumTagged: test_types_EmptyEnumTagged, * EmptyEnumTaggedWContent: test_types_EmptyEnumTaggedWContent, * EmptyEnumUntagged: test_types_EmptyEnumUntagged, * SkipOnlyField: test_types_SkipOnlyField, * SkipField: test_types_SkipField, * SkipVariant: test_types_SkipVariant, * SkipUnnamedFieldInVariant: test_types_SkipUnnamedFieldInVariant, * SkipNamedFieldInVariant: test_types_SkipNamedFieldInVariant, * TransparentWithSkip: test_types_TransparentWithSkip, * TransparentWithSkip2: test_types_TransparentWithSkip2, * TransparentWithSkip3: test_types_TransparentWithSkip3, * SkipVariant2: test_types_SkipVariant2, * SkipVariant3: test_types_SkipVariant3, * SkipStructFields: test_types_SkipStructFields, * SpectaSkipNonTypeField: test_types_SpectaSkipNonTypeField, * FlattenA: test_types_FlattenA, * FlattenB: test_types_FlattenB, * FlattenC: test_types_FlattenC, * FlattenD: test_types_FlattenD, * FlattenE: test_types_FlattenE, * FlattenF: test_types_FlattenF, * FlattenG: test_types_FlattenG, * TupleNested: test_types_TupleNested, * "Generic1<()>": test_types_Generic1, * "GenericAutoBound<()>": test_types_GenericAutoBound, * "GenericAutoBound2<()>": test_types_GenericAutoBound2, * Container1: test_types_Container1, * "Generic2<(), String, i32>": test_types_Generic2, * "GenericNewType1<()>": test_types_GenericNewType1, * "GenericTuple<()>": test_types_GenericTuple, * "GenericStruct2<()>": test_types_GenericStruct2, * "InlineGenericNewtype": string, * "InlineGenericNested": [string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | ({ Unnamed: string }) & { Named?: never } | ({ Named: { * value: string, * } }) & { Unnamed?: never }], * "InlineFlattenGenericsG<()>": test_types_InlineFlattenGenericsG, * InlineFlattenGenerics: test_types_InlineFlattenGenerics, * GenericDefault: test_types_GenericDefault, * ChainedGenericDefault: test_types_ChainedGenericDefault, * "ChainedGenericDefault": test_types_ChainedGenericDefault, * "ChainedGenericDefault": test_types_ChainedGenericDefault, * "ChainedGenericDefault": test_types_ChainedGenericDefault, * GenericDefaultSkipped: test_types_GenericDefaultSkipped, * GenericDefaultSkippedNonType: test_types_GenericDefaultSkippedNonType, * GenericParameterOrderPreserved: test_types_GenericParameterOrderPreserved, * ConstGenericInNonConstContainer: test_types_ConstGenericInNonConstContainer, * ConstGenericInConstContainer: test_types_ConstGenericInConstContainer, * NamedConstGenericContainer: test_types_NamedConstGenericContainer, * InlineConstGenericContainer: test_types_InlineConstGenericContainer, * InlineRecursiveConstGenericContainer: test_types_InlineRecursiveConstGenericContainer, * TestCollectionRegister: test_types_TestCollectionRegister, * TestCollectionRegister: test_types_TestCollectionRegister, * }} Primitives * @property {number} i8 * @property {number} i16 * @property {number} i32 * @property {number} u8 * @property {number} u16 * @property {number} u32 * @property {number} f32 * @property {number} f64 * @property {boolean} bool * @property {string} char * @property {std_ops_Range} "Range" * @property {std_ops_RangeInclusive} "RangeInclusive" * @property {null} "()" * @property {[string, number]} "(String, i32)" * @property {[string, number, boolean]} "(String, i32, bool)" * @property {[[string, number], [boolean, string, boolean], null]} "((String, i32), (bool, char, bool), ())" * @property {[boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean]} "(bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool)" * @property {[number[], boolean[]]} "(Vec, Vec)" * @property {string} String * @property {string} PathBuf * @property {string} IpAddr * @property {string} Ipv4Addr * @property {string} Ipv6Addr * @property {string} SocketAddr * @property {string} SocketAddrV4 * @property {string} SocketAddrV6 * @property {string} "Cow<'static, str>" * @property {number} "Cow<'static, i32>" * @property {string} "&'static str" * @property {boolean} "&'static bool" * @property {number} "&'static i32" * @property {number[]} "Vec" * @property {number[]} "&'static [i32]" * @property {[number, number, number]} "&'static [i32; 3]" * @property {[number, number, number]} "[i32; 3]" * @property {test_types_MyEnum[]} "Vec" * @property {test_types_MyEnum[]} "&'static [MyEnum]" * @property {[test_types_MyEnum, test_types_MyEnum, test_types_MyEnum, test_types_MyEnum, test_types_MyEnum, test_types_MyEnum]} "&'static [MyEnum; 6]" * @property {[test_types_MyEnum, test_types_MyEnum]} "[MyEnum; 2]" * @property {[number]} "&'static [i32; 1]" * @property {[]} "&'static [i32; 0]" * @property {number | null} "Option" * @property {null} "Option<()>" * @property {number[] | null} "Option>" * @property {std_result_Result} "Result" * @property {(number | null)[]} "Vec>>" * @property {number[] | null} "Option>>" * @property {[string[], string[], string[]]} "[Vec; 3]" * @property {string | null} "Option>" * @property {string | null} "Option>>" * @property {null} "PhantomData<()>" * @property {null} "PhantomData" * @property {never} Infallible * @property {test_types_Unit1} Unit1 * @property {test_types_Unit2} Unit2 * @property {test_types_Unit3} Unit3 * @property {test_types_Unit4} Unit4 * @property {test_types_Unit5} Unit5 * @property {test_types_Unit6} Unit6 * @property {test_types_Unit7} Unit7 * @property {test_types_SimpleStruct} SimpleStruct * @property {test_types_TupleStruct1} TupleStruct1 * @property {test_types_TupleStruct3} TupleStruct3 * @property {test_types_TestEnum} TestEnum * @property {test_types_RefStruct} RefStruct * @property {test_types_InlinerStruct} InlinerStruct * @property {test_types_GenericStruct} "GenericStruct" * @property {test_types_GenericStruct} "GenericStruct" * @property {test_types_FlattenEnumStruct} FlattenEnumStruct * @property {test_types_OverridenStruct} OverridenStruct * @property {test_types_HasGenericAlias} HasGenericAlias * @property {test_types_EnumMacroAttributes} EnumMacroAttributes * @property {test_types_InlineEnumField} InlineEnumField * @property {test_types_InlineOptionalType} InlineOptionalType * @property {test_types_Rename} Rename * @property {test_types_TransparentType} TransparentType * @property {test_types_TransparentType2} TransparentType2 * @property {test_types_TransparentTypeWithOverride} TransparentTypeWithOverride * @property {[(number | null), (number | null), (number | null)]} "[Option; 3]" * @property {Partial<{ [key in test_types_BasicEnum]: null }>} "HashMap" * @property {Partial<{ [key in test_types_BasicEnum]: number }>} "HashMap" * @property {number | null} "Option>>>" * @property {test_types_PlaceholderInnerField[]} "Vec" * @property {test_types_EnumReferenceRecordKey} EnumReferenceRecordKey * @property {test_types_FlattenOnNestedEnum} FlattenOnNestedEnum * @property {test_types_MyEmptyInput} MyEmptyInput * @property {string} "(String)" * @property {[string]} "(String,)" * @property {test_types_ExtraBracketsInTupleVariant} ExtraBracketsInTupleVariant * @property {test_types_ExtraBracketsInUnnamedStruct} ExtraBracketsInUnnamedStruct * @property {test_types_MyEnum[]} "Vec" * @property {test_types_InlineTuple} InlineTuple * @property {test_types_InlineTuple2} InlineTuple2 * @property {string} "Box" * @property {string} "Box" * @property {test_types_SkippedFieldWithinVariant} SkippedFieldWithinVariant * @property {test_types_KebabCase} KebabCase * @property {string[]} "&[&str]" * @property {test_types_Issue281} "Issue281<'_>" * @property {test_types_LifetimeGenericStruct} "LifetimeGenericStruct<'_, i32>" * @property {test_types_LifetimeGenericEnum} "LifetimeGenericEnum<'_, i32>" * @property {test_types_RenameWithWeirdCharsField} RenameWithWeirdCharsField * @property {test_types_RenameWithWeirdCharsVariant} RenameWithWeirdCharsVariant * @property {test_types_RenamedFieldKeys} RenamedFieldKeys * @property {test_types_RenamedVariantWithSkippedPayload} RenamedVariantWithSkippedPayload * @property {test_types_type_type_Type} "type_type::Type" * @property {test_types_ActualType} ActualType * @property {test_types_SpectaTypeOverride} SpectaTypeOverride * @property {test_types_ContainerTypeOverrideStruct} ContainerTypeOverrideStruct * @property {test_types_ContainerTypeOverrideEnum} ContainerTypeOverrideEnum * @property {test_types_ContainerTypeOverrideGeneric} "ContainerTypeOverrideGeneric>" * @property {test_types_ContainerTypeOverrideToGeneric} "ContainerTypeOverrideToGeneric" * @property {test_types_ContainerTypeOverrideTuple} ContainerTypeOverrideTuple * @property {test_types_ContainerTypeOverrideTupleGeneric} "ContainerTypeOverrideTupleGeneric" * @property {test_types_InvalidToValidType} InvalidToValidType * @property {test_types_TupleStruct} TupleStruct * @property {test_types_TupleStructWithRep} TupleStructWithRep * @property {test_types_GenericTupleStruct} "GenericTupleStruct" * @property {test_types_BracedStruct} BracedStruct * @property {test_types_StructNew} Struct * @property {test_types_Struct2} Struct2 * @property {test_types_Enum} Enum * @property {test_types_Enum2} Enum2 * @property {test_types_Enum3} Enum3 * @property {test_types_StructRenameAllUppercase} StructRenameAllUppercase * @property {test_types_RenameSerdeSpecialChar} RenameSerdeSpecialChar * @property {test_types_EnumRenameAllUppercase} EnumRenameAllUppercase * @property {test_types_Recursive} Recursive * @property {test_types_RecursiveMapValue} RecursiveMapValue * @property {test_types_RecursiveTransparent} RecursiveTransparent * @property {test_types_RecursiveInEnum} RecursiveInEnum * @property {test_types_NonOptional} NonOptional * @property {test_types_OptionalOnNamedField} OptionalOnNamedField * @property {test_types_OptionalOnTransparentNamedField} OptionalOnTransparentNamedField * @property {test_types_OptionalInEnum} OptionalInEnum * @property {test_types_UntaggedVariants} UntaggedVariants * @property {test_types_UntaggedVariantsWithoutValue} UntaggedVariantsWithoutValue * @property {test_types_UntaggedVariantsWithDuplicateBranches} UntaggedVariantsWithDuplicateBranches * @property {{ [key in string]: null }} "HashMap" * @property {test_types_Regular} Regular * @property {{ [key in never]: null }} "HashMap" * @property {{ [key in test_types_TransparentStruct]: null }} "HashMap" * @property {Partial<{ [key in test_types_UnitVariants]: null }>} "HashMap" * @property {Partial<{ [key in test_types_UntaggedVariantsKey]: null }>} "HashMap" * @property {test_types_ValidMaybeValidKey} ValidMaybeValidKey * @property {test_types_ValidMaybeValidKeyNested} ValidMaybeValidKeyNested * @property {test_types_MacroStruct} MacroStruct * @property {test_types_MacroStruct2} MacroStruct2 * @property {test_types_MacroEnum} MacroEnum * @property {test_types_DeprecatedType} DeprecatedType * @property {test_types_DeprecatedTypeWithMsg} DeprecatedTypeWithMsg * @property {test_types_DeprecatedTypeWithMsg2} DeprecatedTypeWithMsg2 * @property {test_types_DeprecatedFields} DeprecatedFields * @property {test_types_DeprecatedTupleVariant} DeprecatedTupleVariant * @property {test_types_DeprecatedEnumVariants} DeprecatedEnumVariants * @property {test_types_CommentedStruct} CommentedStruct * @property {test_types_CommentedEnum} CommentedEnum * @property {test_types_SingleLineComment} SingleLineComment * @property {test_types_Demo} NonGeneric * @property {test_types_Demo} "HalfGenericA" * @property {test_types_Demo} "HalfGenericB" * @property {test_types_Demo} "FullGeneric" * @property {test_types_Demo} "Another" * @property {{ [key in string]: number }} "MapA" * @property {{ [key in number]: string }} "MapB" * @property {{ [key in string]: test_types_AGenericStruct }} "MapC" * @property {test_types_AGenericStruct} "AGenericStruct" * @property {test_types_A} A * @property {test_types_DoubleFlattened} DoubleFlattened * @property {test_types_FlattenedInner} FlattenedInner * @property {test_types_BoxFlattened} BoxFlattened * @property {test_types_BoxInline} BoxInline * @property {test_types_First} First * @property {test_types_Second} Second * @property {test_types_Third} Third * @property {test_types_Fourth} Fourth * @property {test_types_TagOnStructWithInline} TagOnStructWithInline * @property {test_types_Sixth} Sixth * @property {test_types_Seventh} Seventh * @property {test_types_Eight} Eight * @property {test_types_Ninth} Ninth * @property {test_types_Tenth} Tenth * @property {test_types_MyEnumTagged} MyEnumTagged * @property {test_types_MyEnumExternal} MyEnumExternal * @property {test_types_MyEnumAdjacent} MyEnumAdjacent * @property {test_types_MyEnumUntagged} MyEnumUntagged * @property {test_types_EmptyStruct} EmptyStruct * @property {test_types_EmptyStructWithTag} EmptyStructWithTag * @property {test_types_AdjacentlyTagged} AdjacentlyTagged * @property {test_types_LoadProjectEvent} LoadProjectEvent * @property {test_types_ExternallyTagged} ExternallyTagged * @property {test_types_Issue221External} Issue221External * @property {test_types_InternallyTaggedD} InternallyTaggedD * @property {test_types_InternallyTaggedE} InternallyTaggedE * @property {test_types_InternallyTaggedF} InternallyTaggedF * @property {test_types_InternallyTaggedH} InternallyTaggedH * @property {test_types_InternallyTaggedL} InternallyTaggedL * @property {test_types_InternallyTaggedM} InternallyTaggedM * @property {test_types_StructWithAlias} StructWithAlias * @property {test_types_StructWithMultipleAliases} StructWithMultipleAliases * @property {test_types_StructWithAliasAndRename} StructWithAliasAndRename * @property {test_types_EnumWithVariantAlias} EnumWithVariantAlias * @property {test_types_EnumWithMultipleVariantAliases} EnumWithMultipleVariantAliases * @property {test_types_EnumWithVariantAliasAndRename} EnumWithVariantAliasAndRename * @property {test_types_InternallyTaggedWithAlias} InternallyTaggedWithAlias * @property {test_types_AdjacentlyTaggedWithAlias} AdjacentlyTaggedWithAlias * @property {test_types_UntaggedWithAlias} UntaggedWithAlias * @property {test_types_Issue221UntaggedSafe} Issue221UntaggedSafe * @property {test_types_Issue221UntaggedMixed} Issue221UntaggedMixed * @property {test_types_EmptyEnum} EmptyEnum * @property {test_types_EmptyEnumTagged} EmptyEnumTagged * @property {test_types_EmptyEnumTaggedWContent} EmptyEnumTaggedWContent * @property {test_types_EmptyEnumUntagged} EmptyEnumUntagged * @property {test_types_SkipOnlyField} SkipOnlyField * @property {test_types_SkipField} SkipField * @property {test_types_SkipVariant} SkipVariant * @property {test_types_SkipUnnamedFieldInVariant} SkipUnnamedFieldInVariant * @property {test_types_SkipNamedFieldInVariant} SkipNamedFieldInVariant * @property {test_types_TransparentWithSkip} TransparentWithSkip * @property {test_types_TransparentWithSkip2} TransparentWithSkip2 * @property {test_types_TransparentWithSkip3} TransparentWithSkip3 * @property {test_types_SkipVariant2} SkipVariant2 * @property {test_types_SkipVariant3} SkipVariant3 * @property {test_types_SkipStructFields} SkipStructFields * @property {test_types_SpectaSkipNonTypeField} SpectaSkipNonTypeField * @property {test_types_FlattenA} FlattenA * @property {test_types_FlattenB} FlattenB * @property {test_types_FlattenC} FlattenC * @property {test_types_FlattenD} FlattenD * @property {test_types_FlattenE} FlattenE * @property {test_types_FlattenF} FlattenF * @property {test_types_FlattenG} FlattenG * @property {test_types_TupleNested} TupleNested * @property {test_types_Generic1} "Generic1<()>" * @property {test_types_GenericAutoBound} "GenericAutoBound<()>" * @property {test_types_GenericAutoBound2} "GenericAutoBound2<()>" * @property {test_types_Container1} Container1 * @property {test_types_Generic2} "Generic2<(), String, i32>" * @property {test_types_GenericNewType1} "GenericNewType1<()>" * @property {test_types_GenericTuple} "GenericTuple<()>" * @property {test_types_GenericStruct2} "GenericStruct2<()>" * @property {string} "InlineGenericNewtype" * @property {[string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | ({ Unnamed: string }) & { Named?: never } | ({ Named: { * value: string, * } }) & { Unnamed?: never }]} "InlineGenericNested" * @property {test_types_InlineFlattenGenericsG} "InlineFlattenGenericsG<()>" * @property {test_types_InlineFlattenGenerics} InlineFlattenGenerics * @property {test_types_GenericDefault} GenericDefault * @property {test_types_ChainedGenericDefault} ChainedGenericDefault * @property {test_types_ChainedGenericDefault} "ChainedGenericDefault" * @property {test_types_ChainedGenericDefault} "ChainedGenericDefault" * @property {test_types_ChainedGenericDefault} "ChainedGenericDefault" * @property {test_types_GenericDefaultSkipped} GenericDefaultSkipped * @property {test_types_GenericDefaultSkippedNonType} GenericDefaultSkippedNonType * @property {test_types_GenericParameterOrderPreserved} GenericParameterOrderPreserved * @property {test_types_ConstGenericInNonConstContainer} ConstGenericInNonConstContainer * @property {test_types_ConstGenericInConstContainer} ConstGenericInConstContainer * @property {test_types_NamedConstGenericContainer} NamedConstGenericContainer * @property {test_types_InlineConstGenericContainer} InlineConstGenericContainer * @property {test_types_InlineRecursiveConstGenericContainer} InlineRecursiveConstGenericContainer * @property {test_types_TestCollectionRegister} TestCollectionRegister * @property {test_types_TestCollectionRegister} TestCollectionRegister * * @typedef {{ * start: T, * end: T, * }} Range * @property {T} start * @property {T} end * * @typedef {{ * start: T, * end: T, * }} RangeInclusive * @property {T} start * @property {T} end * * @typedef {{ * demo: test_types_Recursive, * }} Recursive * @property {test_types_Recursive} demo * * @typedef {{ A: { * demo: test_types_RecursiveInEnum, * } }} RecursiveInEnum * @property {{ A: { * demo: test_types_RecursiveInEnum, * } }} A * * @typedef {test_types_RecursiveInline} RecursiveInline * * @typedef {{ * demo: { [key in string]: test_types_RecursiveMapValue }, * }} RecursiveMapValue * @property {{ [key in string]: test_types_RecursiveMapValue }} demo * * @typedef {test_types_RecursiveInline} RecursiveTransparent * @property {test_types_RecursiveInline} "0" * * @typedef {test_types_TestEnum} RefStruct * @property {test_types_TestEnum} "0" * * @typedef {{ [key in string]: null }} Regular * @property {{ [key in string]: null }} "0" * * @typedef {"OneWord" | "Two words"} Rename * @property {"OneWord"} OneWord * @property {"Two words"} "Two words" * * @typedef {{ * "a/b": number, * }} RenameSerdeSpecialChar * @property {number} "a/b" * * @typedef {{ * "@odata.context": string, * }} RenameWithWeirdCharsField * @property {string} "@odata.context" * * @typedef {{ "@odata.context": string }} RenameWithWeirdCharsVariant * @property {{ "@odata.context": string }} "@odata.context" * * @typedef {{ * "": string, * "a\"b": string, * "a\\b": string, * "line\nbreak": string, * "line\u2028break": string, * "line\u2029break": string, * }} RenamedFieldKeys * @property {string} "" * @property {string} "a\"b" * @property {string} "a\\b" * @property {string} "line\nbreak" * @property {string} "line\u2028break" * @property {string} "line\u2029break" * * @typedef {"a-b"} RenamedVariantWithSkippedPayload * @property {"a-b"} "a-b" * * @typedef {{ * ok: T, * err: E, * }} Result * @property {T} ok * @property {E} err * * @typedef {{ * a: number, * }} Second * @property {number} a * * @typedef {{ * a: test_types_First, * b: test_types_Second, * }} Seventh * @property {test_types_First} a * @property {test_types_Second} b * * @typedef {{ * a: number, * b: string, * c: [number, string, number], * d: string[], * e: string | null, * }} SimpleStruct * @property {number} a * @property {string} b * @property {[number, string, number]} c * @property {string[]} d * @property {string | null} e * * Some single-line comment * * @typedef { * /** Some single-line comment */ * ({ A: number }) & { B?: never } | * /** Some single-line comment */ * ({ B: { * /** Some single-line comment */ * a: number, * } }) & { A?: never }} SingleLineComment * @property { * /** Some single-line comment */ * { A: number }} A - Some single-line comment * @property { * /** Some single-line comment */ * { B: { * /** Some single-line comment */ * a: number, * } }} B - Some single-line comment * * @typedef {{ * a: test_types_First, * b: test_types_First, * }} Sixth * @property {test_types_First} a * @property {test_types_First} b * * @typedef {{ * b: number, * }} SkipField * @property {number} b * * @typedef {({ A: Record }) & { B?: never } | ({ B: { * b: number, * } }) & { A?: never }} SkipNamedFieldInVariant * @property {{ A: Record }} A * @property {{ B: { * b: number, * } }} B * * @typedef {Record} SkipOnlyField * * @typedef {{ * a: number, * }} SkipStructFields * @property {number} a * * @typedef {"A" | { B: [number] }} SkipUnnamedFieldInVariant * @property {"A"} A * @property {{ B: [number] }} B * * @typedef {{ A: string }} SkipVariant * @property {{ A: string }} A * * @typedef {{ tag: "A"; data: string }} SkipVariant2 * @property {{ tag: "A"; data: string }} A * * @typedef {{ A: { * a: string, * } }} SkipVariant3 * @property {{ A: { * a: string, * } }} A * * @typedef {{ type: "A" } | { type: "B"; data: string }} SkippedFieldWithinVariant * @property {{ type: "A" }} A * @property {{ type: "B"; data: string }} B * * @typedef {{ * a: number, * }} SpectaSkipNonTypeField * @property {number} a * * @typedef {{ * string_ident: string, * u32_ident: number, * path: string, * tuple: [string, number], * }} SpectaTypeOverride * @property {string} string_ident * @property {number} u32_ident * @property {string} path * @property {[string, number]} tuple * * @typedef {{ * b: string, * }} Struct2 * @property {string} b * * @typedef {{ * t: "StructNew", * a: string, * }} StructNew * @property {"StructNew"} t * @property {string} a * * @typedef {{ * A: number, * B: number, * }} StructRenameAllUppercase * @property {number} A * @property {number} B * * @typedef {{ * field: string, * }} StructWithAlias * @property {string} field * * @typedef {{ * renamed_field: string, * }} StructWithAliasAndRename * @property {string} renamed_field * * @typedef {{ * field: string, * }} StructWithMultipleAliases * @property {string} field * * @typedef {{ * type: "TagOnStructWithInline", * a: test_types_First, * b: { * a: string, * }, * }} TagOnStructWithInline * @property {"TagOnStructWithInline"} type * @property {test_types_First} a * @property {{ * a: string, * }} b * * @typedef {string | "B" | { * a: string, * } | test_types_First} Tenth * @property {string} A * @property {"B"} B * @property {{ * a: string, * }} C * @property {test_types_First} D * * @typedef {never} TestCollectionRegister * * @typedef {"Unit" | ({ Single: number }) & { Multiple?: never; Struct?: never } | ({ Multiple: [number, number] }) & { Single?: never; Struct?: never } | ({ Struct: { * a: number, * } }) & { Multiple?: never; Single?: never }} TestEnum * @property {"Unit"} Unit * @property {{ Single: number }} Single * @property {{ Multiple: [number, number] }} Multiple * @property {{ Struct: { * a: number, * } }} Struct * * @typedef {{ * b: { [key in string]: string }, * c: test_types_First, * } & test_types_First} Third * @property {{ [key in string]: string }} b * @property {test_types_First} c * * @typedef {{ * a: string, * }} ToBeFlattened * @property {string} a * * @typedef {string} TransparentStruct * @property {string} "0" * * @typedef {test_types_TransparentTypeInner} TransparentType * @property {test_types_TransparentTypeInner} "0" * * @typedef {null} TransparentType2 * @property {null} "0" * * @typedef {{ * inner: string, * }} TransparentTypeInner * @property {string} inner * * @typedef {string} TransparentTypeWithOverride * @property {string} "0" * * @typedef {null} TransparentWithSkip * @property {null} "0" * * @typedef {string} TransparentWithSkip2 * @property {string} "0" * * @typedef {string} TransparentWithSkip3 * @property {string} "0" * * @typedef {[number[], [number[], number[]], [number[], number[], number[]]]} TupleNested * @property {number[]} "0" * @property {[number[], number[]]} "1" * @property {[number[], number[], number[]]} "2" * * @typedef {string} TupleStruct * @property {string} "0" * * @typedef {number} TupleStruct1 * @property {number} "0" * * @typedef {[number, boolean, string]} TupleStruct3 * @property {number} "0" * @property {boolean} "1" * @property {string} "2" * * @typedef {string} TupleStructWithRep * @property {string} "0" * * @typedef {never} Type * * @typedef {null} Unit1 * * @typedef {Record} Unit2 * * @typedef {[]} Unit3 * * @typedef {null} Unit4 * @property {null} "0" * * @typedef {"A"} Unit5 * @property {"A"} A * * @typedef {{ A: null }} Unit6 * @property {{ A: null }} A * * @typedef {{ A: Record }} Unit7 * @property {{ A: Record }} A * * @typedef {"A" | "B" | "C"} UnitVariants * @property {"A"} A * @property {"B"} B * @property {"C"} C * * @typedef {string | number | { id: string } | [string, boolean]} UntaggedVariants * @property {string} A * @property {number} B * @property {number} C * @property {{ id: string }} D * @property {[string, boolean]} E * * @typedef {string | number} UntaggedVariantsKey * @property {string} A * @property {number} B * @property {number} C * * @typedef {null | number} UntaggedVariantsWithDuplicateBranches * @property {null} A * @property {number} B * @property {null} C * * @typedef {string | [number, string] | number} UntaggedVariantsWithoutValue * @property {string} A * @property {[number, string]} B * @property {number} C * * @typedef {({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }} UntaggedWithAlias * @property {{ field: string }} A * @property {{ other: number }} B * * @typedef {{ [key in test_types_MaybeValidKey]: null }} ValidMaybeValidKey * @property {{ [key in test_types_MaybeValidKey]: null }} "0" * * @typedef {{ [key in test_types_MaybeValidKey>]: null }} ValidMaybeValidKeyNested * @property {{ [key in test_types_MaybeValidKey>]: null }} "0" */ ════════════════════════════════════════ ================================================ FILE: tests/tests/snapshots/test__jsdoc__jsdoc-export-to-moduleprefixedname-serde_phases.snap ================================================ --- source: tests/tests/jsdoc.rs expression: output --- jsdoc-export-to-moduleprefixedname-serde_phases (62937 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. /** * @typedef {{ * a: test_types_B, * b: { * b: number, * }, * c: test_types_B, * d: { * flattened: number, * }, * e: { * generic_flattened: number, * }, * }} A * @property {test_types_B} a * @property {{ * b: number, * }} b * @property {test_types_B} c * @property {{ * flattened: number, * }} d * @property {{ * generic_flattened: number, * }} e * * @typedef {{ * field: test_types_Demo, * }} AGenericStruct * @property {test_types_Demo} field * * @typedef {{ * a: test_types_GenericType, * }} ActualType * @property {test_types_GenericType} a * * @typedef {{ t: "A" } | { t: "B"; c: { * id: string, * method: string, * } } | { t: "C"; c: string }} AdjacentlyTagged * @property {{ t: "A" }} A * @property {{ t: "B"; c: { * id: string, * method: string, * } }} B * @property {{ t: "C"; c: string }} C * * @typedef {{ type: "A"; data: { * field: string, * } } | { type: "B"; data: { * other: number, * } }} AdjacentlyTaggedWithAlias * @property {{ type: "A"; data: { * field: string, * } }} A * @property {{ type: "B"; data: { * other: number, * } }} B * * @typedef {{ * b: number, * }} B * @property {number} b * * @typedef {"A" | "B"} BasicEnum * @property {"A"} A * @property {"B"} B * * @typedef {test_types_BoxedInner} BoxFlattened * * @typedef {{ * c: { * a: number, * }, * }} BoxInline * @property {{ * a: number, * }} c * * @typedef {{ * a: number, * }} BoxedInner * @property {number} a * * @typedef {string} BracedStruct * @property {string} "0" * * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second * * Some triple-slash comment * Some more triple-slash comment * * @typedef { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * ({ A: number }) & { B?: never } | * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * ({ B: { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * } }) & { A?: never }} CommentedEnum * @property { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * { A: number }} A - Some triple-slash comment Some more triple-slash comment * @property { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * { B: { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * } }} B - Some triple-slash comment Some more triple-slash comment * * Some triple-slash comment * Some more triple-slash comment * * @typedef {{ * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * }} CommentedStruct * @property {number} a - Some triple-slash comment Some more triple-slash comment * * @typedef {{ * data: number[], * a: number[], * d: [number, number], * }} ConstGenericInConstContainer * @property {number[]} data * @property {number[]} a * @property {[number, number]} d * * @typedef {{ * data: [number], * a: [number, number], * d: [number, number], * }} ConstGenericInNonConstContainer * @property {[number]} data * @property {[number, number]} a * @property {[number, number]} d * * @typedef {{ * foo: test_types_Generic1, * bar: test_types_Generic1[], * baz: { [key in string]: test_types_Generic1 }, * }} Container1 * @property {test_types_Generic1} foo * @property {test_types_Generic1[]} bar * @property {{ [key in string]: test_types_Generic1 }} baz * * @typedef {string} ContainerTypeOverrideEnum * * @typedef {string} ContainerTypeOverrideGeneric * * @typedef {string} ContainerTypeOverrideStruct * * @typedef {T} ContainerTypeOverrideToGeneric * * @typedef {[string, number]} ContainerTypeOverrideTuple * * @typedef {[T, string]} ContainerTypeOverrideTupleGeneric * * @typedef {{ * flattened: number, * }} D * @property {number} flattened * * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b * * @typedef { * /** * * @deprecated * */ * "A" | * /** * * @deprecated Nope * */ * "B" | * /** * * @deprecated Nope * */ * "C"} DeprecatedEnumVariants * @property { * /** * * @deprecated * */ * "A"} A - @deprecated * @property { * /** * * @deprecated Nope * */ * "B"} B - @deprecated Nope * @property { * /** * * @deprecated Nope * */ * "C"} C - @deprecated Nope * * @typedef {{ * a: number, * /** * * @deprecated * */ * b: string, * /** * * @deprecated This field is cringe! * */ * c: string, * /** * * @deprecated This field is cringe! * */ * d: string, * }} DeprecatedFields * @property {number} a * @property {string} b - @deprecated * @property {string} c - @deprecated This field is cringe! * @property {string} d - @deprecated This field is cringe! * * @typedef {[ * /** * * @deprecated * */ * string, * /** * * @deprecated Nope * */ * string, * /** * * @deprecated Nope * */ * number]} DeprecatedTupleVariant * @property {string} "0" - @deprecated * @property {string} "1" - @deprecated Nope * @property {number} "2" - @deprecated Nope * * @deprecated * @typedef {{ * a: number, * }} DeprecatedType * @property {number} a * * @deprecated Look at you big man using a deprecation message * @typedef {{ * a: number, * }} DeprecatedTypeWithMsg * @property {number} a * * @deprecated Look at you big man using a deprecation message * @typedef {{ * a: number, * }} DeprecatedTypeWithMsg2 * @property {number} a * * @typedef {{ * a: test_types_ToBeFlattened, * b: test_types_ToBeFlattened, * }} DoubleFlattened * @property {test_types_ToBeFlattened} a * @property {test_types_ToBeFlattened} b * * @typedef {{ A: string } | "B"} Eight * @property {{ A: string }} A * @property {"B"} B * * @typedef {never} EmptyEnum * * @typedef {never} EmptyEnumTagged * * @typedef {never} EmptyEnumTaggedWContent * * @typedef {never} EmptyEnumUntagged * * @typedef {Record} EmptyStruct * * @typedef {{ * a: "EmptyStructWithTag", * }} EmptyStructWithTag * @property {"EmptyStructWithTag"} a * * @typedef {{ t: "A" } | { t: "B" }} Enum * @property {{ t: "A" }} A * @property {{ t: "B" }} B * * @typedef {{ t: "C" } | { t: "B" } | { t: "D"; enumField: null }} Enum2 * @property {{ t: "C" }} C * @property {{ t: "B" }} B * @property {{ t: "D"; enumField: null }} D * * @typedef {{ t: "A"; b: string }} Enum3 * @property {{ t: "A"; b: string }} A * * @typedef {({ A: string }) & { D?: never; bbb?: never; cccc?: never } | ({ bbb: number }) & { A?: never; D?: never; cccc?: never } | ({ cccc: number }) & { A?: never; D?: never; bbb?: never } | ({ D: { * a: string, * bbbbbb: number, * } }) & { A?: never; bbb?: never; cccc?: never }} EnumMacroAttributes * @property {{ A: string }} A * @property {{ bbb: number }} bbb * @property {{ cccc: number }} cccc * @property {{ D: { * a: string, * bbbbbb: number, * } }} D * * @typedef {{ * a: Partial<{ [key in test_types_BasicEnum]: number }>, * }} EnumReferenceRecordKey * @property {Partial<{ [key in test_types_BasicEnum]: number }>} a * * @typedef {"HELLOWORLD" | "VARIANTB" | "TESTINGWORDS"} EnumRenameAllUppercase * @property {"HELLOWORLD"} HELLOWORLD * @property {"VARIANTB"} VARIANTB * @property {"TESTINGWORDS"} TESTINGWORDS * * @typedef {"Variant" | "Other"} EnumWithMultipleVariantAliases * @property {"Variant"} Variant * @property {"Other"} Other * * @typedef {"Variant" | "Other"} EnumWithVariantAlias * @property {"Variant"} Variant * @property {"Other"} Other * * @typedef {"renamed_variant" | "Other"} EnumWithVariantAliasAndRename * @property {"renamed_variant"} renamed_variant * @property {"Other"} Other * * @typedef {"A" | ({ B: { * id: string, * method: string, * } }) & { C?: never } | ({ C: string }) & { B?: never }} ExternallyTagged * @property {"A"} A * @property {{ B: { * id: string, * method: string, * } }} B * @property {{ C: string }} C * * @typedef {{ A: string }} ExtraBracketsInTupleVariant * @property {{ A: string }} A * * @typedef {string} ExtraBracketsInUnnamedStruct * @property {string} "0" * * @typedef {{ * a: string, * }} First * @property {string} a * * @typedef {{ * a: number, * b: number, * }} FlattenA * @property {number} a * @property {number} b * * @typedef {{ * c: number, * } & test_types_FlattenA} FlattenB * @property {number} c * * @typedef {{ * c: number, * } & test_types_FlattenA} FlattenC * @property {number} c * * @typedef {{ * a: test_types_FlattenA, * c: number, * }} FlattenD * @property {test_types_FlattenA} a * @property {number} c * * @typedef {{ * b: ({ * c: number, * }) & (test_types_FlattenA), * d: number, * }} FlattenE * @property {({ * c: number, * }) & (test_types_FlattenA)} b * @property {number} d * * @typedef {{ tag: "One" } | { tag: "Two" } | { tag: "Three" }} FlattenEnum * @property {{ tag: "One" }} One * @property {{ tag: "Two" }} Two * @property {{ tag: "Three" }} Three * * @typedef {{ * outer: string, * } & test_types_FlattenEnum} FlattenEnumStruct * @property {string} outer * * @typedef {{ * b: ({ * c: number, * }) & (test_types_FlattenA), * d: number, * }} FlattenF * @property {({ * c: number, * }) & (test_types_FlattenA)} b * @property {number} d * * @typedef {{ * b: test_types_FlattenB, * d: number, * }} FlattenG * @property {test_types_FlattenB} b * @property {number} d * * @typedef {{ * id: string, * } & test_types_NestedEnum} FlattenOnNestedEnum * @property {string} id * * @typedef {test_types_Inner} FlattenedInner * * @typedef {{ * a: test_types_First, * b: { * a: string, * }, * }} Fourth * @property {test_types_First} a * @property {{ * a: string, * }} b * * @typedef {{ * value: T, * values: T[], * }} Generic1 * @property {T} value * @property {T[]} values * * @typedef {({ A: A }) & { B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ B: [B, B, B] }) & { A?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ C: C[] }) & { A?: never; B?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ D: A[][][] }) & { A?: never; B?: never; C?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ E: { * a: A, * b: B, * c: C, * } }) & { A?: never; B?: never; C?: never; D?: never; X?: never; Y?: never; Z?: never } | ({ X: number[] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; Y?: never; Z?: never } | ({ Y: number }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Z?: never } | ({ Z: number[][] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never }} Generic2 * @property {{ A: A }} A * @property {{ B: [B, B, B] }} B * @property {{ C: C[] }} C * @property {{ D: A[][][] }} D * @property {{ E: { * a: A, * b: B, * c: C, * } }} E * @property {{ X: number[] }} X * @property {{ Y: number }} Y * @property {{ Z: number[][] }} Z * * @typedef {{ * value: T, * values: T[], * }} GenericAutoBound * @property {T} value * @property {T[]} values * * @typedef {{ * value: T, * values: T[], * }} GenericAutoBound2 * @property {T} value * @property {T[]} values * * @typedef {{ * value: T, * }} GenericDefault * @property {T} value * * @typedef {{ * value: T, * }} GenericDefaultSkipped * @property {T} value * * @typedef {{ * value: number, * }} GenericDefaultSkippedNonType * @property {number} value * * @typedef {{ * generic_flattened: T, * }} GenericFlattened * @property {T} generic_flattened * * @typedef {T[][]} GenericNewType1 * @property {T[][]} "0" * * @typedef {{ * pair: test_types_Pair, * }} GenericParameterOrderPreserved * @property {test_types_Pair} pair * * @typedef {{ * arg: T, * }} GenericStruct * @property {T} arg * * @typedef {{ * a: T, * b: [T, T], * c: [T, [T, T]], * d: [T, T, T], * e: [([T, T]), ([T, T]), ([T, T])], * f: T[], * g: T[][], * h: ([([T, T]), ([T, T]), ([T, T])])[], * }} GenericStruct2 * @property {T} a * @property {[T, T]} b * @property {[T, [T, T]]} c * @property {[T, T, T]} d * @property {[([T, T]), ([T, T]), ([T, T])]} e * @property {T[]} f * @property {T[][]} g * @property {([([T, T]), ([T, T]), ([T, T])])[]} h * * @typedef {[T, T[], T[][]]} GenericTuple * @property {T} "0" * @property {T[]} "1" * @property {T[][]} "2" * * @typedef {T} GenericTupleStruct * @property {T} "0" * * @typedef {"Undefined" | T} GenericType * @property {"Undefined"} Undefined * @property {T} Value * * @typedef {{ [key in number]: string }} HasGenericAlias * @property {{ [key in number]: string }} "0" * * @typedef {{ * b: { * data: [number, number], * a: [number, number], * d: [number, number, number], * }, * c: { * data: [number, number, number], * a: [number, number], * d: [number, number, number], * }, * d: [number, number], * }} InlineConstGenericContainer * @property {{ * data: [number, number], * a: [number, number], * d: [number, number, number], * }} b * @property {{ * data: [number, number, number], * a: [number, number], * d: [number, number, number], * }} c * @property {[number, number]} d * * @typedef {{ A: { * a: string, * } }} InlineEnumField * @property {{ A: { * a: string, * } }} A * * @typedef {{ * g: test_types_InlineFlattenGenericsG, * gi: { * t: string, * }, * } & test_types_InlineFlattenGenericsG} InlineFlattenGenerics * @property {test_types_InlineFlattenGenericsG} g * @property {{ * t: string, * }} gi * * @typedef {{ * t: T, * }} InlineFlattenGenericsG * @property {T} t * * @typedef {{ * optional_field: { * a: string, * } | null, * }} InlineOptionalType * @property {{ * a: string, * } | null} optional_field * * @typedef {{ * data: number[], * a: number[], * d: [number, number, number], * e: test_types_InlineRecursiveConstGeneric, * }} InlineRecursiveConstGeneric * @property {number[]} data * @property {number[]} a * @property {[number, number, number]} d * @property {test_types_InlineRecursiveConstGeneric} e * * @typedef {{ * b: { * data: [number, number], * a: [number, number], * d: [number, number, number], * e: test_types_InlineRecursiveConstGeneric, * }, * c: { * data: [number, number, number], * a: [number, number], * d: [number, number, number], * e: test_types_InlineRecursiveConstGeneric, * }, * d: [number, number], * }} InlineRecursiveConstGenericContainer * @property {{ * data: [number, number], * a: [number, number], * d: [number, number, number], * e: test_types_InlineRecursiveConstGeneric, * }} b * @property {{ * data: [number, number, number], * a: [number, number], * d: [number, number, number], * e: test_types_InlineRecursiveConstGeneric, * }} c * @property {[number, number]} d * * @typedef {{ * ref_struct: test_types_SimpleStruct, * val: number, * }} InlineStruct * @property {test_types_SimpleStruct} ref_struct * @property {number} val * * @typedef {{ * demo: [string, boolean], * }} InlineTuple * @property {[string, boolean]} demo * * @typedef {{ * demo: [{ * demo: [string, boolean], * }, boolean], * }} InlineTuple2 * @property {[{ * demo: [string, boolean], * }, boolean]} demo * * @typedef {{ * inline_this: { * ref_struct: test_types_SimpleStruct, * val: number, * }, * dont_inline_this: test_types_RefStruct, * }} InlinerStruct * @property {{ * ref_struct: test_types_SimpleStruct, * val: number, * }} inline_this * @property {test_types_RefStruct} dont_inline_this * * @typedef {{ * a: number, * } & test_types_FlattenedInner} Inner * @property {number} a * * @typedef {{ * type: "A", * } & { [key in string]: string }} InternallyTaggedD * @property {{ * type: "A", * } & { [key in string]: string }} A * * @typedef {{ type: "A" }} InternallyTaggedE * @property {{ type: "A" }} A * * @typedef {{ type: "A" }} InternallyTaggedF * @property {{ type: "A" }} A * * @typedef {null} InternallyTaggedFInner * @property {null} A * * @typedef {{ type: "A" }} InternallyTaggedH * @property {{ type: "A" }} A * * @typedef {null} InternallyTaggedHInner * @property {null} "0" * * @typedef {{ * type: "A", * } & { type: "A" } | { type: "B" }} InternallyTaggedL * @property {{ * type: "A", * } & { type: "A" } | { type: "B" }} A * * @typedef {{ type: "A" } | { type: "B" }} InternallyTaggedLInner * @property {{ type: "A" }} A * @property {{ type: "B" }} B * * @typedef {{ type: "A" }} InternallyTaggedM * @property {{ type: "A" }} A * * @typedef {"A" | "B"} InternallyTaggedMInner * @property {"A"} A * @property {"B"} B * * @typedef {{ type: "A"; field: string } | { type: "B"; other: number }} InternallyTaggedWithAlias * @property {{ type: "A"; field: string }} A * @property {{ type: "B"; other: number }} B * * @typedef {{ * cause: null, * }} InvalidToValidType * @property {null} cause * * @typedef {({ A: { * a: string, * } }) & { B?: never } | ({ B: { * b: string, * } }) & { A?: never }} Issue221External * @property {{ A: { * a: string, * } }} A * @property {{ B: { * b: string, * } }} B * * @typedef {({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never }} Issue221UntaggedMixed * @property {{ a: string }} A * @property {{ b: string }} B * @property {{ values: { [key in string]: string } }} Unsafe * * @typedef {({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }} Issue221UntaggedSafe * @property {{ a: string }} A * @property {{ b: string }} B * * @typedef {{ * default_unity_arguments: string[], * }} Issue281 * @property {string[]} default_unity_arguments * * https://github.com/specta-rs/specta/issues/374 * * @typedef {test_types_Issue374_Serialize | test_types_Issue374_Deserialize} Issue374 * @property {test_types_Issue374_Serialize} Serialize * @property {test_types_Issue374_Deserialize} Deserialize * * https://github.com/specta-rs/specta/issues/374 * * @typedef {{ * foo?: boolean, * bar?: boolean, * }} Issue374_Deserialize * @property {boolean} [foo] * @property {boolean} [bar] * * https://github.com/specta-rs/specta/issues/374 * * @typedef {{ * foo?: boolean, * bar?: boolean, * }} Issue374_Serialize * @property {boolean} [foo] * @property {boolean} [bar] * * @typedef {{ * "test-ing": string, * }} KebabCase * @property {string} "test-ing" * * @typedef {({ Borrowed: T }) & { Owned?: never } | ({ Owned: T }) & { Borrowed?: never }} LifetimeGenericEnum * @property {{ Borrowed: T }} Borrowed * @property {{ Owned: T }} Owned * * @typedef {{ * borrowed: T[], * owned: T[], * }} LifetimeGenericStruct * @property {T[]} borrowed * @property {T[]} owned * * @typedef {{ event: "started"; data: { * projectName: string, * } } | { event: "progressTest"; data: { * projectName: string, * status: string, * progress: number, * } } | { event: "finished"; data: { * projectName: string, * } }} LoadProjectEvent * @property {{ event: "started"; data: { * projectName: string, * } }} started * @property {{ event: "progressTest"; data: { * projectName: string, * status: string, * progress: number, * } }} progressTest * @property {{ event: "finished"; data: { * projectName: string, * } }} finished * * @typedef {({ Demo: string }) & { Demo2?: never } | ({ Demo2: { * demo2: string, * } }) & { Demo?: never }} MacroEnum * @property {{ Demo: string }} Demo * @property {{ Demo2: { * demo2: string, * } }} Demo2 * * @typedef {string} MacroStruct * @property {string} "0" * * @typedef {{ * demo: string, * }} MacroStruct2 * @property {string} demo * * @typedef {T} MaybeValidKey * @property {T} "0" * * @typedef {Record} MyEmptyInput * * @typedef {({ A: string }) & { B?: never } | ({ B: number }) & { A?: never }} MyEnum * @property {{ A: string }} A * @property {{ B: number }} B * * @typedef {{ t: "Variant"; c: { * inner: test_types_First, * } }} MyEnumAdjacent * @property {{ t: "Variant"; c: { * inner: test_types_First, * } }} Variant * * @typedef {{ Variant: { * inner: test_types_First, * } }} MyEnumExternal * @property {{ Variant: { * inner: test_types_First, * } }} Variant * * @typedef {{ type: "Variant"; inner: test_types_First }} MyEnumTagged * @property {{ type: "Variant"; inner: test_types_First }} Variant * * @typedef {{ inner: test_types_First }} MyEnumUntagged * @property {{ inner: test_types_First }} Variant * * @typedef {{ * data: number[], * a: number[], * d: [number, number], * }} NamedConstGeneric * @property {number[]} data * @property {number[]} a * @property {[number, number]} d * * @typedef {{ * a: test_types_NamedConstGeneric, * b: test_types_NamedConstGeneric, * d: [number, number], * }} NamedConstGenericContainer * @property {test_types_NamedConstGeneric} a * @property {test_types_NamedConstGeneric} b * @property {[number, number]} d * * @typedef {{ type: "a"; value: string } | { type: "b"; value: number }} NestedEnum * @property {{ type: "a"; value: string }} a * @property {{ type: "b"; value: number }} b * * @typedef {{ t: "A"; c: string } | { t: "B" } | { t: "C"; c: { * a: string, * } } | { t: "D"; c: test_types_First }} Ninth * @property {{ t: "A"; c: string }} A * @property {{ t: "B" }} B * @property {{ t: "C"; c: { * a: string, * } }} C * @property {{ t: "D"; c: test_types_First }} D * * @typedef {string | null} NonOptional * @property {string | null} "0" * * @typedef {test_types_Optional_Serialize | test_types_Optional_Deserialize} Optional * @property {test_types_Optional_Serialize} Serialize * @property {test_types_Optional_Deserialize} Deserialize * * @typedef {({ A?: string | null }) & { B?: never; C?: never } | ({ B: { * a: string | null, * } }) & { A?: never; C?: never } | ({ C: { * a?: string | null, * } }) & { A?: never; B?: never }} OptionalInEnum * @property {{ A?: string | null }} A * @property {{ B: { * a: string | null, * } }} B * @property {{ C: { * a?: string | null, * } }} C * * @typedef {string | null} OptionalOnNamedField * @property {string | null} ["0"] * * @typedef {{ * b: string | null, * }} OptionalOnTransparentNamedField * @property {string | null} b * * @typedef {{ * a: number | null, * b?: number | null, * c: string | null, * d?: boolean, * }} Optional_Deserialize * @property {number | null} a * @property {number | null} [b] * @property {string | null} c * @property {boolean} [d] * * @typedef {{ * a: number | null, * b?: number | null, * c?: string | null, * d: boolean, * }} Optional_Serialize * @property {number | null} a * @property {number | null} [b] * @property {string | null} [c] * @property {boolean} d * * @typedef {{ * overriden_field: string, * }} OverridenStruct * @property {string} overriden_field * * @typedef {{ * first: Z, * second: A, * }} Pair * @property {Z} first * @property {A} second * * @typedef {{ * a: string, * }} PlaceholderInnerField * @property {string} a * * @typedef {{ * i8: number, * i16: number, * i32: number, * u8: number, * u16: number, * u32: number, * f32: number, * f64: number, * bool: boolean, * char: string, * "Range": std_ops_Range, * "RangeInclusive": std_ops_RangeInclusive, * "()": null, * "(String, i32)": [string, number], * "(String, i32, bool)": [string, number, boolean], * "((String, i32), (bool, char, bool), ())": [[string, number], [boolean, string, boolean], null], * "(bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool)": [boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean], * "(Vec, Vec)": [number[], boolean[]], * String: string, * PathBuf: string, * IpAddr: string, * Ipv4Addr: string, * Ipv6Addr: string, * SocketAddr: string, * SocketAddrV4: string, * SocketAddrV6: string, * "Cow<'static, str>": string, * "Cow<'static, i32>": number, * "&'static str": string, * "&'static bool": boolean, * "&'static i32": number, * "Vec": number[], * "&'static [i32]": number[], * "&'static [i32; 3]": [number, number, number], * "[i32; 3]": [number, number, number], * "Vec": test_types_MyEnum[], * "&'static [MyEnum]": test_types_MyEnum[], * "&'static [MyEnum; 6]": [test_types_MyEnum, test_types_MyEnum, test_types_MyEnum, test_types_MyEnum, test_types_MyEnum, test_types_MyEnum], * "[MyEnum; 2]": [test_types_MyEnum, test_types_MyEnum], * "&'static [i32; 1]": [number], * "&'static [i32; 0]": [], * "Option": number | null, * "Option<()>": null, * "Option>": number[] | null, * "Result": std_result_Result, * "Vec>>": (number | null)[], * "Option>>": number[] | null, * "[Vec; 3]": [string[], string[], string[]], * "Option>": string | null, * "Option>>": string | null, * "PhantomData<()>": null, * "PhantomData": null, * Infallible: never, * Unit1: test_types_Unit1, * Unit2: test_types_Unit2, * Unit3: test_types_Unit3, * Unit4: test_types_Unit4, * Unit5: test_types_Unit5, * Unit6: test_types_Unit6, * Unit7: test_types_Unit7, * SimpleStruct: test_types_SimpleStruct, * TupleStruct1: test_types_TupleStruct1, * TupleStruct3: test_types_TupleStruct3, * TestEnum: test_types_TestEnum, * RefStruct: test_types_RefStruct, * InlinerStruct: test_types_InlinerStruct, * "GenericStruct": test_types_GenericStruct, * "GenericStruct": test_types_GenericStruct, * FlattenEnumStruct: test_types_FlattenEnumStruct, * OverridenStruct: test_types_OverridenStruct, * HasGenericAlias: test_types_HasGenericAlias, * EnumMacroAttributes: test_types_EnumMacroAttributes, * InlineEnumField: test_types_InlineEnumField, * InlineOptionalType: test_types_InlineOptionalType, * Rename: test_types_Rename, * TransparentType: test_types_TransparentType, * TransparentType2: test_types_TransparentType2, * TransparentTypeWithOverride: test_types_TransparentTypeWithOverride, * "[Option; 3]": [(number | null), (number | null), (number | null)], * "HashMap": Partial<{ [key in test_types_BasicEnum]: null }>, * "HashMap": Partial<{ [key in test_types_BasicEnum]: number }>, * "Option>>>": number | null, * "Vec": test_types_PlaceholderInnerField[], * EnumReferenceRecordKey: test_types_EnumReferenceRecordKey, * FlattenOnNestedEnum: test_types_FlattenOnNestedEnum, * MyEmptyInput: test_types_MyEmptyInput, * "(String)": string, * "(String,)": [string], * ExtraBracketsInTupleVariant: test_types_ExtraBracketsInTupleVariant, * ExtraBracketsInUnnamedStruct: test_types_ExtraBracketsInUnnamedStruct, * "Vec": test_types_MyEnum[], * InlineTuple: test_types_InlineTuple, * InlineTuple2: test_types_InlineTuple2, * "Box": string, * "Box": string, * SkippedFieldWithinVariant: test_types_SkippedFieldWithinVariant, * KebabCase: test_types_KebabCase, * "&[&str]": string[], * "Issue281<'_>": test_types_Issue281, * "LifetimeGenericStruct<'_, i32>": test_types_LifetimeGenericStruct, * "LifetimeGenericEnum<'_, i32>": test_types_LifetimeGenericEnum, * RenameWithWeirdCharsField: test_types_RenameWithWeirdCharsField, * RenameWithWeirdCharsVariant: test_types_RenameWithWeirdCharsVariant, * RenamedFieldKeys: test_types_RenamedFieldKeys, * RenamedVariantWithSkippedPayload: test_types_RenamedVariantWithSkippedPayload, * "type_type::Type": test_types_type_type_Type, * ActualType: test_types_ActualType, * SpectaTypeOverride: test_types_SpectaTypeOverride, * ContainerTypeOverrideStruct: test_types_ContainerTypeOverrideStruct, * ContainerTypeOverrideEnum: test_types_ContainerTypeOverrideEnum, * "ContainerTypeOverrideGeneric>": test_types_ContainerTypeOverrideGeneric, * "ContainerTypeOverrideToGeneric": test_types_ContainerTypeOverrideToGeneric, * ContainerTypeOverrideTuple: test_types_ContainerTypeOverrideTuple, * "ContainerTypeOverrideTupleGeneric": test_types_ContainerTypeOverrideTupleGeneric, * InvalidToValidType: test_types_InvalidToValidType, * TupleStruct: test_types_TupleStruct, * TupleStructWithRep: test_types_TupleStructWithRep, * "GenericTupleStruct": test_types_GenericTupleStruct, * BracedStruct: test_types_BracedStruct, * Struct: test_types_StructNew, * Struct2: test_types_Struct2, * Enum: test_types_Enum, * Enum2: test_types_Enum2, * Enum3: test_types_Enum3, * StructRenameAllUppercase: test_types_StructRenameAllUppercase, * RenameSerdeSpecialChar: test_types_RenameSerdeSpecialChar, * EnumRenameAllUppercase: test_types_EnumRenameAllUppercase, * Recursive: test_types_Recursive, * RecursiveMapValue: test_types_RecursiveMapValue, * RecursiveTransparent: test_types_RecursiveTransparent, * RecursiveInEnum: test_types_RecursiveInEnum, * NonOptional: test_types_NonOptional, * OptionalOnNamedField: test_types_OptionalOnNamedField, * OptionalOnTransparentNamedField: test_types_OptionalOnTransparentNamedField, * OptionalInEnum: test_types_OptionalInEnum, * UntaggedVariants: test_types_UntaggedVariants, * UntaggedVariantsWithoutValue: test_types_UntaggedVariantsWithoutValue, * UntaggedVariantsWithDuplicateBranches: test_types_UntaggedVariantsWithDuplicateBranches, * "HashMap": { [key in string]: null }, * Regular: test_types_Regular, * "HashMap": { [key in never]: null }, * "HashMap": { [key in test_types_TransparentStruct]: null }, * "HashMap": Partial<{ [key in test_types_UnitVariants]: null }>, * "HashMap": Partial<{ [key in test_types_UntaggedVariantsKey]: null }>, * ValidMaybeValidKey: test_types_ValidMaybeValidKey, * ValidMaybeValidKeyNested: test_types_ValidMaybeValidKeyNested, * MacroStruct: test_types_MacroStruct, * MacroStruct2: test_types_MacroStruct2, * MacroEnum: test_types_MacroEnum, * DeprecatedType: test_types_DeprecatedType, * DeprecatedTypeWithMsg: test_types_DeprecatedTypeWithMsg, * DeprecatedTypeWithMsg2: test_types_DeprecatedTypeWithMsg2, * DeprecatedFields: test_types_DeprecatedFields, * DeprecatedTupleVariant: test_types_DeprecatedTupleVariant, * DeprecatedEnumVariants: test_types_DeprecatedEnumVariants, * CommentedStruct: test_types_CommentedStruct, * CommentedEnum: test_types_CommentedEnum, * SingleLineComment: test_types_SingleLineComment, * NonGeneric: test_types_Demo, * "HalfGenericA": test_types_Demo, * "HalfGenericB": test_types_Demo, * "FullGeneric": test_types_Demo, * "Another": test_types_Demo, * "MapA": { [key in string]: number }, * "MapB": { [key in number]: string }, * "MapC": { [key in string]: test_types_AGenericStruct }, * "AGenericStruct": test_types_AGenericStruct, * A: test_types_A, * DoubleFlattened: test_types_DoubleFlattened, * FlattenedInner: test_types_FlattenedInner, * BoxFlattened: test_types_BoxFlattened, * BoxInline: test_types_BoxInline, * First: test_types_First, * Second: test_types_Second, * Third: test_types_Third, * Fourth: test_types_Fourth, * TagOnStructWithInline: test_types_TagOnStructWithInline, * Sixth: test_types_Sixth, * Seventh: test_types_Seventh, * Eight: test_types_Eight, * Ninth: test_types_Ninth, * Tenth: test_types_Tenth, * MyEnumTagged: test_types_MyEnumTagged, * MyEnumExternal: test_types_MyEnumExternal, * MyEnumAdjacent: test_types_MyEnumAdjacent, * MyEnumUntagged: test_types_MyEnumUntagged, * EmptyStruct: test_types_EmptyStruct, * EmptyStructWithTag: test_types_EmptyStructWithTag, * AdjacentlyTagged: test_types_AdjacentlyTagged, * LoadProjectEvent: test_types_LoadProjectEvent, * ExternallyTagged: test_types_ExternallyTagged, * Issue221External: test_types_Issue221External, * InternallyTaggedD: test_types_InternallyTaggedD, * InternallyTaggedE: test_types_InternallyTaggedE, * InternallyTaggedF: test_types_InternallyTaggedF, * InternallyTaggedH: test_types_InternallyTaggedH, * InternallyTaggedL: test_types_InternallyTaggedL, * InternallyTaggedM: test_types_InternallyTaggedM, * StructWithAlias: test_types_StructWithAlias, * StructWithMultipleAliases: test_types_StructWithMultipleAliases, * StructWithAliasAndRename: test_types_StructWithAliasAndRename, * EnumWithVariantAlias: test_types_EnumWithVariantAlias, * EnumWithMultipleVariantAliases: test_types_EnumWithMultipleVariantAliases, * EnumWithVariantAliasAndRename: test_types_EnumWithVariantAliasAndRename, * InternallyTaggedWithAlias: test_types_InternallyTaggedWithAlias, * AdjacentlyTaggedWithAlias: test_types_AdjacentlyTaggedWithAlias, * UntaggedWithAlias: test_types_UntaggedWithAlias, * Issue221UntaggedSafe: test_types_Issue221UntaggedSafe, * Issue221UntaggedMixed: test_types_Issue221UntaggedMixed, * EmptyEnum: test_types_EmptyEnum, * EmptyEnumTagged: test_types_EmptyEnumTagged, * EmptyEnumTaggedWContent: test_types_EmptyEnumTaggedWContent, * EmptyEnumUntagged: test_types_EmptyEnumUntagged, * SkipOnlyField: test_types_SkipOnlyField, * SkipField: test_types_SkipField, * SkipVariant: test_types_SkipVariant, * SkipUnnamedFieldInVariant: test_types_SkipUnnamedFieldInVariant, * SkipNamedFieldInVariant: test_types_SkipNamedFieldInVariant, * TransparentWithSkip: test_types_TransparentWithSkip, * TransparentWithSkip2: test_types_TransparentWithSkip2, * TransparentWithSkip3: test_types_TransparentWithSkip3, * SkipVariant2: test_types_SkipVariant2, * SkipVariant3: test_types_SkipVariant3, * SkipStructFields: test_types_SkipStructFields, * SpectaSkipNonTypeField: test_types_SpectaSkipNonTypeField, * FlattenA: test_types_FlattenA, * FlattenB: test_types_FlattenB, * FlattenC: test_types_FlattenC, * FlattenD: test_types_FlattenD, * FlattenE: test_types_FlattenE, * FlattenF: test_types_FlattenF, * FlattenG: test_types_FlattenG, * TupleNested: test_types_TupleNested, * "Generic1<()>": test_types_Generic1, * "GenericAutoBound<()>": test_types_GenericAutoBound, * "GenericAutoBound2<()>": test_types_GenericAutoBound2, * Container1: test_types_Container1, * "Generic2<(), String, i32>": test_types_Generic2, * "GenericNewType1<()>": test_types_GenericNewType1, * "GenericTuple<()>": test_types_GenericTuple, * "GenericStruct2<()>": test_types_GenericStruct2, * "InlineGenericNewtype": string, * "InlineGenericNested": [string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | ({ Unnamed: string }) & { Named?: never } | ({ Named: { * value: string, * } }) & { Unnamed?: never }], * "InlineFlattenGenericsG<()>": test_types_InlineFlattenGenericsG, * InlineFlattenGenerics: test_types_InlineFlattenGenerics, * GenericDefault: test_types_GenericDefault, * ChainedGenericDefault: test_types_ChainedGenericDefault, * "ChainedGenericDefault": test_types_ChainedGenericDefault, * "ChainedGenericDefault": test_types_ChainedGenericDefault, * "ChainedGenericDefault": test_types_ChainedGenericDefault, * GenericDefaultSkipped: test_types_GenericDefaultSkipped, * GenericDefaultSkippedNonType: test_types_GenericDefaultSkippedNonType, * GenericParameterOrderPreserved: test_types_GenericParameterOrderPreserved, * ConstGenericInNonConstContainer: test_types_ConstGenericInNonConstContainer, * ConstGenericInConstContainer: test_types_ConstGenericInConstContainer, * NamedConstGenericContainer: test_types_NamedConstGenericContainer, * InlineConstGenericContainer: test_types_InlineConstGenericContainer, * InlineRecursiveConstGenericContainer: test_types_InlineRecursiveConstGenericContainer, * TestCollectionRegister: test_types_TestCollectionRegister, * TestCollectionRegister: test_types_TestCollectionRegister, * }} Primitives * @property {number} i8 * @property {number} i16 * @property {number} i32 * @property {number} u8 * @property {number} u16 * @property {number} u32 * @property {number} f32 * @property {number} f64 * @property {boolean} bool * @property {string} char * @property {std_ops_Range} "Range" * @property {std_ops_RangeInclusive} "RangeInclusive" * @property {null} "()" * @property {[string, number]} "(String, i32)" * @property {[string, number, boolean]} "(String, i32, bool)" * @property {[[string, number], [boolean, string, boolean], null]} "((String, i32), (bool, char, bool), ())" * @property {[boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean]} "(bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool)" * @property {[number[], boolean[]]} "(Vec, Vec)" * @property {string} String * @property {string} PathBuf * @property {string} IpAddr * @property {string} Ipv4Addr * @property {string} Ipv6Addr * @property {string} SocketAddr * @property {string} SocketAddrV4 * @property {string} SocketAddrV6 * @property {string} "Cow<'static, str>" * @property {number} "Cow<'static, i32>" * @property {string} "&'static str" * @property {boolean} "&'static bool" * @property {number} "&'static i32" * @property {number[]} "Vec" * @property {number[]} "&'static [i32]" * @property {[number, number, number]} "&'static [i32; 3]" * @property {[number, number, number]} "[i32; 3]" * @property {test_types_MyEnum[]} "Vec" * @property {test_types_MyEnum[]} "&'static [MyEnum]" * @property {[test_types_MyEnum, test_types_MyEnum, test_types_MyEnum, test_types_MyEnum, test_types_MyEnum, test_types_MyEnum]} "&'static [MyEnum; 6]" * @property {[test_types_MyEnum, test_types_MyEnum]} "[MyEnum; 2]" * @property {[number]} "&'static [i32; 1]" * @property {[]} "&'static [i32; 0]" * @property {number | null} "Option" * @property {null} "Option<()>" * @property {number[] | null} "Option>" * @property {std_result_Result} "Result" * @property {(number | null)[]} "Vec>>" * @property {number[] | null} "Option>>" * @property {[string[], string[], string[]]} "[Vec; 3]" * @property {string | null} "Option>" * @property {string | null} "Option>>" * @property {null} "PhantomData<()>" * @property {null} "PhantomData" * @property {never} Infallible * @property {test_types_Unit1} Unit1 * @property {test_types_Unit2} Unit2 * @property {test_types_Unit3} Unit3 * @property {test_types_Unit4} Unit4 * @property {test_types_Unit5} Unit5 * @property {test_types_Unit6} Unit6 * @property {test_types_Unit7} Unit7 * @property {test_types_SimpleStruct} SimpleStruct * @property {test_types_TupleStruct1} TupleStruct1 * @property {test_types_TupleStruct3} TupleStruct3 * @property {test_types_TestEnum} TestEnum * @property {test_types_RefStruct} RefStruct * @property {test_types_InlinerStruct} InlinerStruct * @property {test_types_GenericStruct} "GenericStruct" * @property {test_types_GenericStruct} "GenericStruct" * @property {test_types_FlattenEnumStruct} FlattenEnumStruct * @property {test_types_OverridenStruct} OverridenStruct * @property {test_types_HasGenericAlias} HasGenericAlias * @property {test_types_EnumMacroAttributes} EnumMacroAttributes * @property {test_types_InlineEnumField} InlineEnumField * @property {test_types_InlineOptionalType} InlineOptionalType * @property {test_types_Rename} Rename * @property {test_types_TransparentType} TransparentType * @property {test_types_TransparentType2} TransparentType2 * @property {test_types_TransparentTypeWithOverride} TransparentTypeWithOverride * @property {[(number | null), (number | null), (number | null)]} "[Option; 3]" * @property {Partial<{ [key in test_types_BasicEnum]: null }>} "HashMap" * @property {Partial<{ [key in test_types_BasicEnum]: number }>} "HashMap" * @property {number | null} "Option>>>" * @property {test_types_PlaceholderInnerField[]} "Vec" * @property {test_types_EnumReferenceRecordKey} EnumReferenceRecordKey * @property {test_types_FlattenOnNestedEnum} FlattenOnNestedEnum * @property {test_types_MyEmptyInput} MyEmptyInput * @property {string} "(String)" * @property {[string]} "(String,)" * @property {test_types_ExtraBracketsInTupleVariant} ExtraBracketsInTupleVariant * @property {test_types_ExtraBracketsInUnnamedStruct} ExtraBracketsInUnnamedStruct * @property {test_types_MyEnum[]} "Vec" * @property {test_types_InlineTuple} InlineTuple * @property {test_types_InlineTuple2} InlineTuple2 * @property {string} "Box" * @property {string} "Box" * @property {test_types_SkippedFieldWithinVariant} SkippedFieldWithinVariant * @property {test_types_KebabCase} KebabCase * @property {string[]} "&[&str]" * @property {test_types_Issue281} "Issue281<'_>" * @property {test_types_LifetimeGenericStruct} "LifetimeGenericStruct<'_, i32>" * @property {test_types_LifetimeGenericEnum} "LifetimeGenericEnum<'_, i32>" * @property {test_types_RenameWithWeirdCharsField} RenameWithWeirdCharsField * @property {test_types_RenameWithWeirdCharsVariant} RenameWithWeirdCharsVariant * @property {test_types_RenamedFieldKeys} RenamedFieldKeys * @property {test_types_RenamedVariantWithSkippedPayload} RenamedVariantWithSkippedPayload * @property {test_types_type_type_Type} "type_type::Type" * @property {test_types_ActualType} ActualType * @property {test_types_SpectaTypeOverride} SpectaTypeOverride * @property {test_types_ContainerTypeOverrideStruct} ContainerTypeOverrideStruct * @property {test_types_ContainerTypeOverrideEnum} ContainerTypeOverrideEnum * @property {test_types_ContainerTypeOverrideGeneric} "ContainerTypeOverrideGeneric>" * @property {test_types_ContainerTypeOverrideToGeneric} "ContainerTypeOverrideToGeneric" * @property {test_types_ContainerTypeOverrideTuple} ContainerTypeOverrideTuple * @property {test_types_ContainerTypeOverrideTupleGeneric} "ContainerTypeOverrideTupleGeneric" * @property {test_types_InvalidToValidType} InvalidToValidType * @property {test_types_TupleStruct} TupleStruct * @property {test_types_TupleStructWithRep} TupleStructWithRep * @property {test_types_GenericTupleStruct} "GenericTupleStruct" * @property {test_types_BracedStruct} BracedStruct * @property {test_types_StructNew} Struct * @property {test_types_Struct2} Struct2 * @property {test_types_Enum} Enum * @property {test_types_Enum2} Enum2 * @property {test_types_Enum3} Enum3 * @property {test_types_StructRenameAllUppercase} StructRenameAllUppercase * @property {test_types_RenameSerdeSpecialChar} RenameSerdeSpecialChar * @property {test_types_EnumRenameAllUppercase} EnumRenameAllUppercase * @property {test_types_Recursive} Recursive * @property {test_types_RecursiveMapValue} RecursiveMapValue * @property {test_types_RecursiveTransparent} RecursiveTransparent * @property {test_types_RecursiveInEnum} RecursiveInEnum * @property {test_types_NonOptional} NonOptional * @property {test_types_OptionalOnNamedField} OptionalOnNamedField * @property {test_types_OptionalOnTransparentNamedField} OptionalOnTransparentNamedField * @property {test_types_OptionalInEnum} OptionalInEnum * @property {test_types_UntaggedVariants} UntaggedVariants * @property {test_types_UntaggedVariantsWithoutValue} UntaggedVariantsWithoutValue * @property {test_types_UntaggedVariantsWithDuplicateBranches} UntaggedVariantsWithDuplicateBranches * @property {{ [key in string]: null }} "HashMap" * @property {test_types_Regular} Regular * @property {{ [key in never]: null }} "HashMap" * @property {{ [key in test_types_TransparentStruct]: null }} "HashMap" * @property {Partial<{ [key in test_types_UnitVariants]: null }>} "HashMap" * @property {Partial<{ [key in test_types_UntaggedVariantsKey]: null }>} "HashMap" * @property {test_types_ValidMaybeValidKey} ValidMaybeValidKey * @property {test_types_ValidMaybeValidKeyNested} ValidMaybeValidKeyNested * @property {test_types_MacroStruct} MacroStruct * @property {test_types_MacroStruct2} MacroStruct2 * @property {test_types_MacroEnum} MacroEnum * @property {test_types_DeprecatedType} DeprecatedType * @property {test_types_DeprecatedTypeWithMsg} DeprecatedTypeWithMsg * @property {test_types_DeprecatedTypeWithMsg2} DeprecatedTypeWithMsg2 * @property {test_types_DeprecatedFields} DeprecatedFields * @property {test_types_DeprecatedTupleVariant} DeprecatedTupleVariant * @property {test_types_DeprecatedEnumVariants} DeprecatedEnumVariants * @property {test_types_CommentedStruct} CommentedStruct * @property {test_types_CommentedEnum} CommentedEnum * @property {test_types_SingleLineComment} SingleLineComment * @property {test_types_Demo} NonGeneric * @property {test_types_Demo} "HalfGenericA" * @property {test_types_Demo} "HalfGenericB" * @property {test_types_Demo} "FullGeneric" * @property {test_types_Demo} "Another" * @property {{ [key in string]: number }} "MapA" * @property {{ [key in number]: string }} "MapB" * @property {{ [key in string]: test_types_AGenericStruct }} "MapC" * @property {test_types_AGenericStruct} "AGenericStruct" * @property {test_types_A} A * @property {test_types_DoubleFlattened} DoubleFlattened * @property {test_types_FlattenedInner} FlattenedInner * @property {test_types_BoxFlattened} BoxFlattened * @property {test_types_BoxInline} BoxInline * @property {test_types_First} First * @property {test_types_Second} Second * @property {test_types_Third} Third * @property {test_types_Fourth} Fourth * @property {test_types_TagOnStructWithInline} TagOnStructWithInline * @property {test_types_Sixth} Sixth * @property {test_types_Seventh} Seventh * @property {test_types_Eight} Eight * @property {test_types_Ninth} Ninth * @property {test_types_Tenth} Tenth * @property {test_types_MyEnumTagged} MyEnumTagged * @property {test_types_MyEnumExternal} MyEnumExternal * @property {test_types_MyEnumAdjacent} MyEnumAdjacent * @property {test_types_MyEnumUntagged} MyEnumUntagged * @property {test_types_EmptyStruct} EmptyStruct * @property {test_types_EmptyStructWithTag} EmptyStructWithTag * @property {test_types_AdjacentlyTagged} AdjacentlyTagged * @property {test_types_LoadProjectEvent} LoadProjectEvent * @property {test_types_ExternallyTagged} ExternallyTagged * @property {test_types_Issue221External} Issue221External * @property {test_types_InternallyTaggedD} InternallyTaggedD * @property {test_types_InternallyTaggedE} InternallyTaggedE * @property {test_types_InternallyTaggedF} InternallyTaggedF * @property {test_types_InternallyTaggedH} InternallyTaggedH * @property {test_types_InternallyTaggedL} InternallyTaggedL * @property {test_types_InternallyTaggedM} InternallyTaggedM * @property {test_types_StructWithAlias} StructWithAlias * @property {test_types_StructWithMultipleAliases} StructWithMultipleAliases * @property {test_types_StructWithAliasAndRename} StructWithAliasAndRename * @property {test_types_EnumWithVariantAlias} EnumWithVariantAlias * @property {test_types_EnumWithMultipleVariantAliases} EnumWithMultipleVariantAliases * @property {test_types_EnumWithVariantAliasAndRename} EnumWithVariantAliasAndRename * @property {test_types_InternallyTaggedWithAlias} InternallyTaggedWithAlias * @property {test_types_AdjacentlyTaggedWithAlias} AdjacentlyTaggedWithAlias * @property {test_types_UntaggedWithAlias} UntaggedWithAlias * @property {test_types_Issue221UntaggedSafe} Issue221UntaggedSafe * @property {test_types_Issue221UntaggedMixed} Issue221UntaggedMixed * @property {test_types_EmptyEnum} EmptyEnum * @property {test_types_EmptyEnumTagged} EmptyEnumTagged * @property {test_types_EmptyEnumTaggedWContent} EmptyEnumTaggedWContent * @property {test_types_EmptyEnumUntagged} EmptyEnumUntagged * @property {test_types_SkipOnlyField} SkipOnlyField * @property {test_types_SkipField} SkipField * @property {test_types_SkipVariant} SkipVariant * @property {test_types_SkipUnnamedFieldInVariant} SkipUnnamedFieldInVariant * @property {test_types_SkipNamedFieldInVariant} SkipNamedFieldInVariant * @property {test_types_TransparentWithSkip} TransparentWithSkip * @property {test_types_TransparentWithSkip2} TransparentWithSkip2 * @property {test_types_TransparentWithSkip3} TransparentWithSkip3 * @property {test_types_SkipVariant2} SkipVariant2 * @property {test_types_SkipVariant3} SkipVariant3 * @property {test_types_SkipStructFields} SkipStructFields * @property {test_types_SpectaSkipNonTypeField} SpectaSkipNonTypeField * @property {test_types_FlattenA} FlattenA * @property {test_types_FlattenB} FlattenB * @property {test_types_FlattenC} FlattenC * @property {test_types_FlattenD} FlattenD * @property {test_types_FlattenE} FlattenE * @property {test_types_FlattenF} FlattenF * @property {test_types_FlattenG} FlattenG * @property {test_types_TupleNested} TupleNested * @property {test_types_Generic1} "Generic1<()>" * @property {test_types_GenericAutoBound} "GenericAutoBound<()>" * @property {test_types_GenericAutoBound2} "GenericAutoBound2<()>" * @property {test_types_Container1} Container1 * @property {test_types_Generic2} "Generic2<(), String, i32>" * @property {test_types_GenericNewType1} "GenericNewType1<()>" * @property {test_types_GenericTuple} "GenericTuple<()>" * @property {test_types_GenericStruct2} "GenericStruct2<()>" * @property {string} "InlineGenericNewtype" * @property {[string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | ({ Unnamed: string }) & { Named?: never } | ({ Named: { * value: string, * } }) & { Unnamed?: never }]} "InlineGenericNested" * @property {test_types_InlineFlattenGenericsG} "InlineFlattenGenericsG<()>" * @property {test_types_InlineFlattenGenerics} InlineFlattenGenerics * @property {test_types_GenericDefault} GenericDefault * @property {test_types_ChainedGenericDefault} ChainedGenericDefault * @property {test_types_ChainedGenericDefault} "ChainedGenericDefault" * @property {test_types_ChainedGenericDefault} "ChainedGenericDefault" * @property {test_types_ChainedGenericDefault} "ChainedGenericDefault" * @property {test_types_GenericDefaultSkipped} GenericDefaultSkipped * @property {test_types_GenericDefaultSkippedNonType} GenericDefaultSkippedNonType * @property {test_types_GenericParameterOrderPreserved} GenericParameterOrderPreserved * @property {test_types_ConstGenericInNonConstContainer} ConstGenericInNonConstContainer * @property {test_types_ConstGenericInConstContainer} ConstGenericInConstContainer * @property {test_types_NamedConstGenericContainer} NamedConstGenericContainer * @property {test_types_InlineConstGenericContainer} InlineConstGenericContainer * @property {test_types_InlineRecursiveConstGenericContainer} InlineRecursiveConstGenericContainer * @property {test_types_TestCollectionRegister} TestCollectionRegister * @property {test_types_TestCollectionRegister} TestCollectionRegister * * @typedef {{ * start: T, * end: T, * }} Range * @property {T} start * @property {T} end * * @typedef {{ * start: T, * end: T, * }} RangeInclusive * @property {T} start * @property {T} end * * @typedef {{ * demo: test_types_Recursive, * }} Recursive * @property {test_types_Recursive} demo * * @typedef {{ A: { * demo: test_types_RecursiveInEnum, * } }} RecursiveInEnum * @property {{ A: { * demo: test_types_RecursiveInEnum, * } }} A * * @typedef {test_types_RecursiveInline} RecursiveInline * * @typedef {{ * demo: { [key in string]: test_types_RecursiveMapValue }, * }} RecursiveMapValue * @property {{ [key in string]: test_types_RecursiveMapValue }} demo * * @typedef {test_types_RecursiveInline} RecursiveTransparent * @property {test_types_RecursiveInline} "0" * * @typedef {test_types_TestEnum} RefStruct * @property {test_types_TestEnum} "0" * * @typedef {{ [key in string]: null }} Regular * @property {{ [key in string]: null }} "0" * * @typedef {"OneWord" | "Two words"} Rename * @property {"OneWord"} OneWord * @property {"Two words"} "Two words" * * @typedef {{ * "a/b": number, * }} RenameSerdeSpecialChar * @property {number} "a/b" * * @typedef {{ * "@odata.context": string, * }} RenameWithWeirdCharsField * @property {string} "@odata.context" * * @typedef {{ "@odata.context": string }} RenameWithWeirdCharsVariant * @property {{ "@odata.context": string }} "@odata.context" * * @typedef {{ * "": string, * "a\"b": string, * "a\\b": string, * "line\nbreak": string, * "line\u2028break": string, * "line\u2029break": string, * }} RenamedFieldKeys * @property {string} "" * @property {string} "a\"b" * @property {string} "a\\b" * @property {string} "line\nbreak" * @property {string} "line\u2028break" * @property {string} "line\u2029break" * * @typedef {"a-b"} RenamedVariantWithSkippedPayload * @property {"a-b"} "a-b" * * @typedef {{ * ok: T, * err: E, * }} Result * @property {T} ok * @property {E} err * * @typedef {{ * a: number, * }} Second * @property {number} a * * @typedef {{ * a: test_types_First, * b: test_types_Second, * }} Seventh * @property {test_types_First} a * @property {test_types_Second} b * * @typedef {{ * a: number, * b: string, * c: [number, string, number], * d: string[], * e: string | null, * }} SimpleStruct * @property {number} a * @property {string} b * @property {[number, string, number]} c * @property {string[]} d * @property {string | null} e * * Some single-line comment * * @typedef { * /** Some single-line comment */ * ({ A: number }) & { B?: never } | * /** Some single-line comment */ * ({ B: { * /** Some single-line comment */ * a: number, * } }) & { A?: never }} SingleLineComment * @property { * /** Some single-line comment */ * { A: number }} A - Some single-line comment * @property { * /** Some single-line comment */ * { B: { * /** Some single-line comment */ * a: number, * } }} B - Some single-line comment * * @typedef {{ * a: test_types_First, * b: test_types_First, * }} Sixth * @property {test_types_First} a * @property {test_types_First} b * * @typedef {{ * b: number, * }} SkipField * @property {number} b * * @typedef {({ A: Record }) & { B?: never } | ({ B: { * b: number, * } }) & { A?: never }} SkipNamedFieldInVariant * @property {{ A: Record }} A * @property {{ B: { * b: number, * } }} B * * @typedef {Record} SkipOnlyField * * @typedef {{ * a: number, * }} SkipStructFields * @property {number} a * * @typedef {"A" | { B: [number] }} SkipUnnamedFieldInVariant * @property {"A"} A * @property {{ B: [number] }} B * * @typedef {{ A: string }} SkipVariant * @property {{ A: string }} A * * @typedef {{ tag: "A"; data: string }} SkipVariant2 * @property {{ tag: "A"; data: string }} A * * @typedef {{ A: { * a: string, * } }} SkipVariant3 * @property {{ A: { * a: string, * } }} A * * @typedef {{ type: "A" } | { type: "B"; data: string }} SkippedFieldWithinVariant * @property {{ type: "A" }} A * @property {{ type: "B"; data: string }} B * * @typedef {{ * a: number, * }} SpectaSkipNonTypeField * @property {number} a * * @typedef {{ * string_ident: string, * u32_ident: number, * path: string, * tuple: [string, number], * }} SpectaTypeOverride * @property {string} string_ident * @property {number} u32_ident * @property {string} path * @property {[string, number]} tuple * * @typedef {{ * b: string, * }} Struct2 * @property {string} b * * @typedef {{ * t: "StructNew", * a: string, * }} StructNew * @property {"StructNew"} t * @property {string} a * * @typedef {test_types_StructPhaseSpecificRenameSerialize | test_types_StructPhaseSpecificRenameDeserialize} StructPhaseSpecificRename * @property {test_types_StructPhaseSpecificRenameSerialize} Serialize * @property {test_types_StructPhaseSpecificRenameDeserialize} Deserialize * * @typedef {{ * kind: "StructPhaseSpecificRenameDeserialize", * der: string, * }} StructPhaseSpecificRenameDeserialize * @property {"StructPhaseSpecificRenameDeserialize"} kind * @property {string} der * * @typedef {{ * kind: "StructPhaseSpecificRenameSerialize", * ser: string, * }} StructPhaseSpecificRenameSerialize * @property {"StructPhaseSpecificRenameSerialize"} kind * @property {string} ser * * @typedef {{ * A: number, * B: number, * }} StructRenameAllUppercase * @property {number} A * @property {number} B * * @typedef {{ * field: string, * }} StructWithAlias * @property {string} field * * @typedef {{ * renamed_field: string, * }} StructWithAliasAndRename * @property {string} renamed_field * * @typedef {{ * field: string, * }} StructWithMultipleAliases * @property {string} field * * @typedef {{ * type: "TagOnStructWithInline", * a: test_types_First, * b: { * a: string, * }, * }} TagOnStructWithInline * @property {"TagOnStructWithInline"} type * @property {test_types_First} a * @property {{ * a: string, * }} b * * @typedef {string | "B" | { * a: string, * } | test_types_First} Tenth * @property {string} A * @property {"B"} B * @property {{ * a: string, * }} C * @property {test_types_First} D * * @typedef {never} TestCollectionRegister * * @typedef {"Unit" | ({ Single: number }) & { Multiple?: never; Struct?: never } | ({ Multiple: [number, number] }) & { Single?: never; Struct?: never } | ({ Struct: { * a: number, * } }) & { Multiple?: never; Single?: never }} TestEnum * @property {"Unit"} Unit * @property {{ Single: number }} Single * @property {{ Multiple: [number, number] }} Multiple * @property {{ Struct: { * a: number, * } }} Struct * * @typedef {{ * b: { [key in string]: string }, * c: test_types_First, * } & test_types_First} Third * @property {{ [key in string]: string }} b * @property {test_types_First} c * * @typedef {{ * a: string, * }} ToBeFlattened * @property {string} a * * @typedef {string} TransparentStruct * @property {string} "0" * * @typedef {test_types_TransparentTypeInner} TransparentType * @property {test_types_TransparentTypeInner} "0" * * @typedef {null} TransparentType2 * @property {null} "0" * * @typedef {{ * inner: string, * }} TransparentTypeInner * @property {string} inner * * @typedef {string} TransparentTypeWithOverride * @property {string} "0" * * @typedef {null} TransparentWithSkip * @property {null} "0" * * @typedef {string} TransparentWithSkip2 * @property {string} "0" * * @typedef {string} TransparentWithSkip3 * @property {string} "0" * * @typedef {[number[], [number[], number[]], [number[], number[], number[]]]} TupleNested * @property {number[]} "0" * @property {[number[], number[]]} "1" * @property {[number[], number[], number[]]} "2" * * @typedef {string} TupleStruct * @property {string} "0" * * @typedef {number} TupleStruct1 * @property {number} "0" * * @typedef {[number, boolean, string]} TupleStruct3 * @property {number} "0" * @property {boolean} "1" * @property {string} "2" * * @typedef {string} TupleStructWithRep * @property {string} "0" * * @typedef {never} Type * * @typedef {null} Unit1 * * @typedef {Record} Unit2 * * @typedef {[]} Unit3 * * @typedef {null} Unit4 * @property {null} "0" * * @typedef {"A"} Unit5 * @property {"A"} A * * @typedef {{ A: null }} Unit6 * @property {{ A: null }} A * * @typedef {{ A: Record }} Unit7 * @property {{ A: Record }} A * * @typedef {"A" | "B" | "C"} UnitVariants * @property {"A"} A * @property {"B"} B * @property {"C"} C * * @typedef {string | number | { id: string } | [string, boolean]} UntaggedVariants * @property {string} A * @property {number} B * @property {number} C * @property {{ id: string }} D * @property {[string, boolean]} E * * @typedef {string | number} UntaggedVariantsKey * @property {string} A * @property {number} B * @property {number} C * * @typedef {null | number} UntaggedVariantsWithDuplicateBranches * @property {null} A * @property {number} B * @property {null} C * * @typedef {string | [number, string] | number} UntaggedVariantsWithoutValue * @property {string} A * @property {[number, string]} B * @property {number} C * * @typedef {({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }} UntaggedWithAlias * @property {{ field: string }} A * @property {{ other: number }} B * * @typedef {{ [key in test_types_MaybeValidKey]: null }} ValidMaybeValidKey * @property {{ [key in test_types_MaybeValidKey]: null }} "0" * * @typedef {{ [key in test_types_MaybeValidKey>]: null }} ValidMaybeValidKeyNested * @property {{ [key in test_types_MaybeValidKey>]: null }} "0" */ ════════════════════════════════════════ ================================================ FILE: tests/tests/snapshots/test__jsdoc__jsdoc-export-to-namespaces-raw.snap ================================================ --- source: tests/tests/jsdoc.rs expression: output --- jsdoc-export-to-namespaces-raw (65864 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. namespace $s$ { export namespace std { export namespace ops { /** * @typedef {{ * start: T, * end: T, * }} Range * @property {T} start * @property {T} end * * @typedef {{ * start: T, * end: T, * }} RangeInclusive * @property {T} start * @property {T} end */ } export namespace result { /** * @typedef {{ * ok: T, * err: E, * }} Result * @property {T} ok * @property {E} err */ } } export namespace test { export namespace types { /** * @typedef {{ * a: $s$.test.types.B, * b: { * b: number, * }, * c: $s$.test.types.B, * d: { * flattened: number, * }, * e: { * generic_flattened: number, * }, * }} A * @property {$s$.test.types.B} a * @property {{ * b: number, * }} b * @property {$s$.test.types.B} c * @property {{ * flattened: number, * }} d * @property {{ * generic_flattened: number, * }} e * * @typedef {{ * field: $s$.test.types.Demo, * }} AGenericStruct * @property {$s$.test.types.Demo} field * * @typedef {{ * a: $s$.test.types.GenericType, * }} ActualType * @property {$s$.test.types.GenericType} a * * @typedef {"A" | { id: string; method: string } | string} AdjacentlyTagged * @property {"A"} A * @property {{ id: string; method: string }} B * @property {string} C * * @typedef {({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }} AdjacentlyTaggedWithAlias * @property {{ field: string }} A * @property {{ other: number }} B * * @typedef {{ * b: number, * }} B * @property {number} b * * @typedef {"A" | "B"} BasicEnum * @property {"A"} A * @property {"B"} B * * @typedef {{ * b: $s$.test.types.BoxedInner, * }} BoxFlattened * @property {$s$.test.types.BoxedInner} b * * @typedef {{ * c: { * a: number, * }, * }} BoxInline * @property {{ * a: number, * }} c * * @typedef {{ * a: number, * }} BoxedInner * @property {number} a * * @typedef {string} BracedStruct * @property {string} "0" * * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second * * Some triple-slash comment * Some more triple-slash comment * * @typedef { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * number | * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number }} CommentedEnum * @property { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * number} A - Some triple-slash comment Some more triple-slash comment * @property { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number }} B - Some triple-slash comment Some more triple-slash comment * * Some triple-slash comment * Some more triple-slash comment * * @typedef {{ * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * }} CommentedStruct * @property {number} a - Some triple-slash comment Some more triple-slash comment * * @typedef {{ * data: number[], * a: number[], * d: [number, number], * }} ConstGenericInConstContainer * @property {number[]} data * @property {number[]} a * @property {[number, number]} d * * @typedef {{ * data: [number], * a: [number, number], * d: [number, number], * }} ConstGenericInNonConstContainer * @property {[number]} data * @property {[number, number]} a * @property {[number, number]} d * * @typedef {{ * foo: $s$.test.types.Generic1, * bar: $s$.test.types.Generic1[], * baz: { [key in string]: $s$.test.types.Generic1 }, * }} Container1 * @property {$s$.test.types.Generic1} foo * @property {$s$.test.types.Generic1[]} bar * @property {{ [key in string]: $s$.test.types.Generic1 }} baz * * @typedef {string} ContainerTypeOverrideEnum * * @typedef {string} ContainerTypeOverrideGeneric * * @typedef {string} ContainerTypeOverrideStruct * * @typedef {T} ContainerTypeOverrideToGeneric * * @typedef {[string, number]} ContainerTypeOverrideTuple * * @typedef {[T, string]} ContainerTypeOverrideTupleGeneric * * @typedef {{ * flattened: number, * }} D * @property {number} flattened * * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b * * @typedef { * /** * * @deprecated * */ * "A" | * /** * * @deprecated Nope * */ * "B" | * /** * * @deprecated Nope * */ * "C"} DeprecatedEnumVariants * @property { * /** * * @deprecated * */ * "A"} A - @deprecated * @property { * /** * * @deprecated Nope * */ * "B"} B - @deprecated Nope * @property { * /** * * @deprecated Nope * */ * "C"} C - @deprecated Nope * * @typedef {{ * a: number, * /** * * @deprecated * */ * b: string, * /** * * @deprecated This field is cringe! * */ * c: string, * /** * * @deprecated This field is cringe! * */ * d: string, * }} DeprecatedFields * @property {number} a * @property {string} b - @deprecated * @property {string} c - @deprecated This field is cringe! * @property {string} d - @deprecated This field is cringe! * * @typedef {[ * /** * * @deprecated * */ * string, * /** * * @deprecated Nope * */ * string, * /** * * @deprecated Nope * */ * number]} DeprecatedTupleVariant * @property {string} "0" - @deprecated * @property {string} "1" - @deprecated Nope * @property {number} "2" - @deprecated Nope * * @deprecated * @typedef {{ * a: number, * }} DeprecatedType * @property {number} a * * @deprecated Look at you big man using a deprecation message * @typedef {{ * a: number, * }} DeprecatedTypeWithMsg * @property {number} a * * @deprecated Look at you big man using a deprecation message * @typedef {{ * a: number, * }} DeprecatedTypeWithMsg2 * @property {number} a * * @typedef {{ * a: $s$.test.types.ToBeFlattened, * b: $s$.test.types.ToBeFlattened, * }} DoubleFlattened * @property {$s$.test.types.ToBeFlattened} a * @property {$s$.test.types.ToBeFlattened} b * * @typedef {string | "B"} Eight * @property {string} A * @property {"B"} B * * @typedef {never} EmptyEnum * * @typedef {never} EmptyEnumTagged * * @typedef {never} EmptyEnumTaggedWContent * * @typedef {never} EmptyEnumUntagged * * @typedef {Record} EmptyStruct * * @typedef {Record} EmptyStructWithTag * * @typedef {"A" | "B"} Enum * @property {"A"} A * @property {"B"} B * * @typedef {"A" | "B" | { enum_field: null }} Enum2 * @property {"A"} A * @property {"B"} B * @property {{ enum_field: null }} D * * @typedef {{ a: string }} Enum3 * @property {{ a: string }} A * * @typedef {string | number | { a: string; b: number }} EnumMacroAttributes * @property {string} A * @property {number} B * @property {number} C * @property {{ a: string; b: number }} D * * @typedef {{ * a: Partial<{ [key in $s$.test.types.BasicEnum]: number }>, * }} EnumReferenceRecordKey * @property {Partial<{ [key in $s$.test.types.BasicEnum]: number }>} a * * @typedef {"HelloWorld" | "VariantB" | "TestingWords"} EnumRenameAllUppercase * @property {"HelloWorld"} HelloWorld * @property {"VariantB"} VariantB * @property {"TestingWords"} TestingWords * * @typedef {"Variant" | "Other"} EnumWithMultipleVariantAliases * @property {"Variant"} Variant * @property {"Other"} Other * * @typedef {"Variant" | "Other"} EnumWithVariantAlias * @property {"Variant"} Variant * @property {"Other"} Other * * @typedef {"Variant" | "Other"} EnumWithVariantAliasAndRename * @property {"Variant"} Variant * @property {"Other"} Other * * @typedef {"A" | { id: string; method: string } | string} ExternallyTagged * @property {"A"} A * @property {{ id: string; method: string }} B * @property {string} C * * @typedef {string} ExtraBracketsInTupleVariant * @property {string} A * * @typedef {string} ExtraBracketsInUnnamedStruct * @property {string} "0" * * @typedef {{ * a: string, * }} First * @property {string} a * * @typedef {{ * a: number, * b: number, * }} FlattenA * @property {number} a * @property {number} b * * @typedef {{ * a: $s$.test.types.FlattenA, * c: number, * }} FlattenB * @property {$s$.test.types.FlattenA} a * @property {number} c * * @typedef {{ * a: $s$.test.types.FlattenA, * c: number, * }} FlattenC * @property {$s$.test.types.FlattenA} a * @property {number} c * * @typedef {{ * a: $s$.test.types.FlattenA, * c: number, * }} FlattenD * @property {$s$.test.types.FlattenA} a * @property {number} c * * @typedef {{ * b: { * a: $s$.test.types.FlattenA, * c: number, * }, * d: number, * }} FlattenE * @property {{ * a: $s$.test.types.FlattenA, * c: number, * }} b * @property {number} d * * @typedef {"One" | "Two" | "Three"} FlattenEnum * @property {"One"} One * @property {"Two"} Two * @property {"Three"} Three * * @typedef {{ * outer: string, * inner: $s$.test.types.FlattenEnum, * }} FlattenEnumStruct * @property {string} outer * @property {$s$.test.types.FlattenEnum} inner * * @typedef {{ * b: { * a: $s$.test.types.FlattenA, * c: number, * }, * d: number, * }} FlattenF * @property {{ * a: $s$.test.types.FlattenA, * c: number, * }} b * @property {number} d * * @typedef {{ * b: $s$.test.types.FlattenB, * d: number, * }} FlattenG * @property {$s$.test.types.FlattenB} b * @property {number} d * * @typedef {{ * id: string, * result: $s$.test.types.NestedEnum, * }} FlattenOnNestedEnum * @property {string} id * @property {$s$.test.types.NestedEnum} result * * @typedef {{ * c: $s$.test.types.Inner, * }} FlattenedInner * @property {$s$.test.types.Inner} c * * @typedef {{ * a: $s$.test.types.First, * b: { * a: string, * }, * }} Fourth * @property {$s$.test.types.First} a * @property {{ * a: string, * }} b * * @typedef {{ * value: T, * values: T[], * }} Generic1 * @property {T} value * @property {T[]} values * * @typedef {A | [B, B, B] | C[] | A[][][] | { a: A; b: B; c: C } | number[] | number | number[][]} Generic2 * @property {A} A * @property {[B, B, B]} B * @property {C[]} C * @property {A[][][]} D * @property {{ a: A; b: B; c: C }} E * @property {number[]} X * @property {number} Y * @property {number[][]} Z * * @typedef {{ * value: T, * values: T[], * }} GenericAutoBound * @property {T} value * @property {T[]} values * * @typedef {{ * value: T, * values: T[], * }} GenericAutoBound2 * @property {T} value * @property {T[]} values * * @typedef {{ * value: T, * }} GenericDefault * @property {T} value * * @typedef {{ * value: T, * }} GenericDefaultSkipped * @property {T} value * * @typedef {{ * value: number, * }} GenericDefaultSkippedNonType * @property {number} value * * @typedef {{ * generic_flattened: T, * }} GenericFlattened * @property {T} generic_flattened * * @typedef {T[][]} GenericNewType1 * @property {T[][]} "0" * * @typedef {{ * pair: $s$.test.types.Pair, * }} GenericParameterOrderPreserved * @property {$s$.test.types.Pair} pair * * @typedef {{ * arg: T, * }} GenericStruct * @property {T} arg * * @typedef {{ * a: T, * b: [T, T], * c: [T, [T, T]], * d: [T, T, T], * e: [([T, T]), ([T, T]), ([T, T])], * f: T[], * g: T[][], * h: ([([T, T]), ([T, T]), ([T, T])])[], * }} GenericStruct2 * @property {T} a * @property {[T, T]} b * @property {[T, [T, T]]} c * @property {[T, T, T]} d * @property {[([T, T]), ([T, T]), ([T, T])]} e * @property {T[]} f * @property {T[][]} g * @property {([([T, T]), ([T, T]), ([T, T])])[]} h * * @typedef {[T, T[], T[][]]} GenericTuple * @property {T} "0" * @property {T[]} "1" * @property {T[][]} "2" * * @typedef {T} GenericTupleStruct * @property {T} "0" * * @typedef {"Undefined" | T} GenericType * @property {"Undefined"} Undefined * @property {T} Value * * @typedef {{ [key in number]: string }} HasGenericAlias * @property {{ [key in number]: string }} "0" * * @typedef {{ * b: { * data: [number, number], * a: [number, number], * d: [number, number, number], * }, * c: { * data: [number, number, number], * a: [number, number], * d: [number, number, number], * }, * d: [number, number], * }} InlineConstGenericContainer * @property {{ * data: [number, number], * a: [number, number], * d: [number, number, number], * }} b * @property {{ * data: [number, number, number], * a: [number, number], * d: [number, number, number], * }} c * @property {[number, number]} d * * @typedef {{ * a: string, * }} InlineEnumField * @property {{ * a: string, * }} A * * @typedef {{ * g: $s$.test.types.InlineFlattenGenericsG, * gi: { * t: string, * }, * t: $s$.test.types.InlineFlattenGenericsG, * }} InlineFlattenGenerics * @property {$s$.test.types.InlineFlattenGenericsG} g * @property {{ * t: string, * }} gi * @property {$s$.test.types.InlineFlattenGenericsG} t * * @typedef {{ * t: T, * }} InlineFlattenGenericsG * @property {T} t * * @typedef {{ * optional_field: { * a: string, * } | null, * }} InlineOptionalType * @property {{ * a: string, * } | null} optional_field * * @typedef {{ * data: number[], * a: number[], * d: [number, number, number], * e: $s$.test.types.InlineRecursiveConstGeneric, * }} InlineRecursiveConstGeneric * @property {number[]} data * @property {number[]} a * @property {[number, number, number]} d * @property {$s$.test.types.InlineRecursiveConstGeneric} e * * @typedef {{ * b: { * data: [number, number], * a: [number, number], * d: [number, number, number], * e: $s$.test.types.InlineRecursiveConstGeneric, * }, * c: { * data: [number, number, number], * a: [number, number], * d: [number, number, number], * e: $s$.test.types.InlineRecursiveConstGeneric, * }, * d: [number, number], * }} InlineRecursiveConstGenericContainer * @property {{ * data: [number, number], * a: [number, number], * d: [number, number, number], * e: $s$.test.types.InlineRecursiveConstGeneric, * }} b * @property {{ * data: [number, number, number], * a: [number, number], * d: [number, number, number], * e: $s$.test.types.InlineRecursiveConstGeneric, * }} c * @property {[number, number]} d * * @typedef {{ * ref_struct: $s$.test.types.SimpleStruct, * val: number, * }} InlineStruct * @property {$s$.test.types.SimpleStruct} ref_struct * @property {number} val * * @typedef {{ * demo: [string, boolean], * }} InlineTuple * @property {[string, boolean]} demo * * @typedef {{ * demo: [{ * demo: [string, boolean], * }, boolean], * }} InlineTuple2 * @property {[{ * demo: [string, boolean], * }, boolean]} demo * * @typedef {{ * inline_this: { * ref_struct: $s$.test.types.SimpleStruct, * val: number, * }, * dont_inline_this: $s$.test.types.RefStruct, * }} InlinerStruct * @property {{ * ref_struct: $s$.test.types.SimpleStruct, * val: number, * }} inline_this * @property {$s$.test.types.RefStruct} dont_inline_this * * @typedef {{ * a: number, * b: $s$.test.types.FlattenedInner, * }} Inner * @property {number} a * @property {$s$.test.types.FlattenedInner} b * * @typedef {{ [key in string]: string }} InternallyTaggedD * @property {{ [key in string]: string }} A * * @typedef {null} InternallyTaggedE * @property {null} A * * @typedef {$s$.test.types.InternallyTaggedFInner} InternallyTaggedF * @property {$s$.test.types.InternallyTaggedFInner} A * * @typedef {null} InternallyTaggedFInner * @property {null} A * * @typedef {$s$.test.types.InternallyTaggedHInner} InternallyTaggedH * @property {$s$.test.types.InternallyTaggedHInner} A * * @typedef {null} InternallyTaggedHInner * @property {null} "0" * * @typedef {"A" | "B"} InternallyTaggedL * @property {"A" | "B"} A * * @typedef {"A" | "B"} InternallyTaggedLInner * @property {"A"} A * @property {"B"} B * * @typedef {"A" | "B"} InternallyTaggedM * @property {"A" | "B"} A * * @typedef {"A" | "B"} InternallyTaggedMInner * @property {"A"} A * @property {"B"} B * * @typedef {({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }} InternallyTaggedWithAlias * @property {{ field: string }} A * @property {{ other: number }} B * * @typedef {{ * cause: null, * }} InvalidToValidType * @property {null} cause * * @typedef {({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }} Issue221External * @property {{ a: string }} A * @property {{ b: string }} B * * @typedef {({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never }} Issue221UntaggedMixed * @property {{ a: string }} A * @property {{ b: string }} B * @property {{ values: { [key in string]: string } }} Unsafe * * @typedef {({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }} Issue221UntaggedSafe * @property {{ a: string }} A * @property {{ b: string }} B * * @typedef {{ * default_unity_arguments: string[], * }} Issue281 * @property {string[]} default_unity_arguments * * @typedef {{ * test_ing: string, * }} KebabCase * @property {string} test_ing * * @typedef {T} LifetimeGenericEnum * @property {T} Borrowed * @property {T} Owned * * @typedef {{ * borrowed: T[], * owned: T[], * }} LifetimeGenericStruct * @property {T[]} borrowed * @property {T[]} owned * * @typedef {({ project_name: string }) & { progress?: never; status?: never } | { project_name: string; status: string; progress: number }} LoadProjectEvent * @property {{ project_name: string }} Started * @property {{ project_name: string; status: string; progress: number }} ProgressTest * @property {{ project_name: string }} Finished * * @typedef {string | { demo2: string }} MacroEnum * @property {string} Demo * @property {{ demo2: string }} Demo2 * * @typedef {string} MacroStruct * @property {string} "0" * * @typedef {{ * demo: string, * }} MacroStruct2 * @property {string} demo * * @typedef {T} MaybeValidKey * @property {T} "0" * * @typedef {Record} MyEmptyInput * * @typedef {string | number} MyEnum * @property {string} A * @property {number} B * * @typedef {{ inner: $s$.test.types.First }} MyEnumAdjacent * @property {{ inner: $s$.test.types.First }} Variant * * @typedef {{ inner: $s$.test.types.First }} MyEnumExternal * @property {{ inner: $s$.test.types.First }} Variant * * @typedef {{ inner: $s$.test.types.First }} MyEnumTagged * @property {{ inner: $s$.test.types.First }} Variant * * @typedef {{ inner: $s$.test.types.First }} MyEnumUntagged * @property {{ inner: $s$.test.types.First }} Variant * * @typedef {{ * data: number[], * a: number[], * d: [number, number], * }} NamedConstGeneric * @property {number[]} data * @property {number[]} a * @property {[number, number]} d * * @typedef {{ * a: $s$.test.types.NamedConstGeneric, * b: $s$.test.types.NamedConstGeneric, * d: [number, number], * }} NamedConstGenericContainer * @property {$s$.test.types.NamedConstGeneric} a * @property {$s$.test.types.NamedConstGeneric} b * @property {[number, number]} d * * @typedef {string | number} NestedEnum * @property {string} A * @property {number} B * * @typedef {string | "B" | { * a: string, * } | $s$.test.types.First} Ninth * @property {string} A * @property {"B"} B * @property {{ * a: string, * }} C * @property {$s$.test.types.First} D * * @typedef {string | null} NonOptional * @property {string | null} "0" * * @typedef {string | null | { a: string | null } | { a?: string | null }} OptionalInEnum * @property {string | null} A * @property {{ a: string | null }} B * @property {{ a?: string | null }} C * * @typedef {string | null} OptionalOnNamedField * @property {string | null} ["0"] * * @typedef {{ * b: string | null, * }} OptionalOnTransparentNamedField * @property {string | null} b * * @typedef {{ * overriden_field: string, * }} OverridenStruct * @property {string} overriden_field * * @typedef {{ * first: Z, * second: A, * }} Pair * @property {Z} first * @property {A} second * * @typedef {{ * a: string, * }} PlaceholderInnerField * @property {string} a * * @typedef {{ * demo: $s$.test.types.Recursive, * }} Recursive * @property {$s$.test.types.Recursive} demo * * @typedef {{ demo: $s$.test.types.RecursiveInEnum }} RecursiveInEnum * @property {{ demo: $s$.test.types.RecursiveInEnum }} A * * @typedef {{ * demo: $s$.test.types.RecursiveInline, * }} RecursiveInline * @property {$s$.test.types.RecursiveInline} demo * * @typedef {{ * demo: { [key in string]: $s$.test.types.RecursiveMapValue }, * }} RecursiveMapValue * @property {{ [key in string]: $s$.test.types.RecursiveMapValue }} demo * * @typedef {$s$.test.types.RecursiveInline} RecursiveTransparent * @property {$s$.test.types.RecursiveInline} "0" * * @typedef {$s$.test.types.TestEnum} RefStruct * @property {$s$.test.types.TestEnum} "0" * * @typedef {{ [key in string]: null }} Regular * @property {{ [key in string]: null }} "0" * * @typedef {"OneWord" | "TwoWords"} Rename * @property {"OneWord"} OneWord * @property {"TwoWords"} TwoWords * * @typedef {{ * b: number, * }} RenameSerdeSpecialChar * @property {number} b * * @typedef {{ * odata_context: string, * }} RenameWithWeirdCharsField * @property {string} odata_context * * @typedef {string} RenameWithWeirdCharsVariant * @property {string} A * * @typedef {{ * empty: string, * quote: string, * backslash: string, * newline: string, * line_separator: string, * paragraph_separator: string, * }} RenamedFieldKeys * @property {string} empty * @property {string} quote * @property {string} backslash * @property {string} newline * @property {string} line_separator * @property {string} paragraph_separator * * @typedef {never} RenamedVariantWithSkippedPayload * @property {never} A * * @typedef {{ * a: number, * }} Second * @property {number} a * * @typedef {{ * a: $s$.test.types.First, * b: $s$.test.types.Second, * }} Seventh * @property {$s$.test.types.First} a * @property {$s$.test.types.Second} b * * @typedef {{ * a: number, * b: string, * c: [number, string, number], * d: string[], * e: string | null, * }} SimpleStruct * @property {number} a * @property {string} b * @property {[number, string, number]} c * @property {string[]} d * @property {string | null} e * * Some single-line comment * * @typedef { * /** Some single-line comment */ * number | * /** Some single-line comment */ * { * /** Some single-line comment */ * a: number }} SingleLineComment * @property { * /** Some single-line comment */ * number} A - Some single-line comment * @property { * /** Some single-line comment */ * { * /** Some single-line comment */ * a: number }} B - Some single-line comment * * @typedef {{ * a: $s$.test.types.First, * b: $s$.test.types.First, * }} Sixth * @property {$s$.test.types.First} a * @property {$s$.test.types.First} b * * @typedef {{ * b: number, * }} SkipField * @property {number} b * * @typedef {Record | { b: number }} SkipNamedFieldInVariant * @property {Record} A * @property {{ b: number }} B * * @typedef {Record} SkipOnlyField * * @typedef {{ * a: number, * }} SkipStructFields * @property {number} a * * @typedef {never | [number]} SkipUnnamedFieldInVariant * @property {never} A * @property {[number]} B * * @typedef {string} SkipVariant * @property {string} A * * @typedef {string} SkipVariant2 * @property {string} A * * @typedef {{ a: string }} SkipVariant3 * @property {{ a: string }} A * * @typedef {never | string} SkippedFieldWithinVariant * @property {never} A * @property {string} B * * @typedef {{ * a: number, * }} SpectaSkipNonTypeField * @property {number} a * * @typedef {{ * string_ident: string, * u32_ident: number, * path: string, * tuple: [string, number], * }} SpectaTypeOverride * @property {string} string_ident * @property {number} u32_ident * @property {string} path * @property {[string, number]} tuple * * @typedef {{ * a: string, * }} Struct * @property {string} a * * @typedef {{ * a: string, * }} Struct2 * @property {string} a * * @typedef {{ * a: number, * b: number, * }} StructRenameAllUppercase * @property {number} a * @property {number} b * * @typedef {{ * field: string, * }} StructWithAlias * @property {string} field * * @typedef {{ * field: string, * }} StructWithAliasAndRename * @property {string} field * * @typedef {{ * field: string, * }} StructWithMultipleAliases * @property {string} field * * @typedef {{ * a: $s$.test.types.First, * b: { * a: string, * }, * }} TagOnStructWithInline * @property {$s$.test.types.First} a * @property {{ * a: string, * }} b * * @typedef {string | "B" | { * a: string, * } | $s$.test.types.First} Tenth * @property {string} A * @property {"B"} B * @property {{ * a: string, * }} C * @property {$s$.test.types.First} D * * @typedef {never} TestCollectionRegister * * @typedef {"Unit" | number | [number, number] | { a: number }} TestEnum * @property {"Unit"} Unit * @property {number} Single * @property {[number, number]} Multiple * @property {{ a: number }} Struct * * @typedef {{ * a: $s$.test.types.First, * b: { [key in string]: string }, * c: $s$.test.types.First, * }} Third * @property {$s$.test.types.First} a * @property {{ [key in string]: string }} b * @property {$s$.test.types.First} c * * @typedef {{ * a: string, * }} ToBeFlattened * @property {string} a * * @typedef {string} TransparentStruct * @property {string} "0" * * @typedef {$s$.test.types.TransparentTypeInner} TransparentType * @property {$s$.test.types.TransparentTypeInner} "0" * * @typedef {null} TransparentType2 * @property {null} "0" * * @typedef {{ * inner: string, * }} TransparentTypeInner * @property {string} inner * * @typedef {string} TransparentTypeWithOverride * @property {string} "0" * * @typedef {null} TransparentWithSkip * @property {null} "0" * * @typedef {string} TransparentWithSkip2 * @property {string} "0" * * @typedef {string} TransparentWithSkip3 * @property {string} "0" * * @typedef {[number[], [number[], number[]], [number[], number[], number[]]]} TupleNested * @property {number[]} "0" * @property {[number[], number[]]} "1" * @property {[number[], number[], number[]]} "2" * * @typedef {string} TupleStruct * @property {string} "0" * * @typedef {number} TupleStruct1 * @property {number} "0" * * @typedef {[number, boolean, string]} TupleStruct3 * @property {number} "0" * @property {boolean} "1" * @property {string} "2" * * @typedef {string} TupleStructWithRep * @property {string} "0" * * @typedef {null} Unit1 * * @typedef {Record} Unit2 * * @typedef {[]} Unit3 * * @typedef {null} Unit4 * @property {null} "0" * * @typedef {"A"} Unit5 * @property {"A"} A * * @typedef {[]} Unit6 * @property {[]} A * * @typedef {Record} Unit7 * @property {Record} A * * @typedef {"A" | "B" | "C"} UnitVariants * @property {"A"} A * @property {"B"} B * @property {"C"} C * * @typedef {string | number | { id: string } | [string, boolean]} UntaggedVariants * @property {string} A * @property {number} B * @property {number} C * @property {{ id: string }} D * @property {[string, boolean]} E * * @typedef {string | number} UntaggedVariantsKey * @property {string} A * @property {number} B * @property {number} C * * @typedef {null | number} UntaggedVariantsWithDuplicateBranches * @property {null} A * @property {number} B * @property {null} C * * @typedef {string | [number, string] | number} UntaggedVariantsWithoutValue * @property {string} A * @property {[number, string]} B * @property {number} C * * @typedef {({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }} UntaggedWithAlias * @property {{ field: string }} A * @property {{ other: number }} B * * @typedef {{ [key in $s$.test.types.MaybeValidKey]: null }} ValidMaybeValidKey * @property {{ [key in $s$.test.types.MaybeValidKey]: null }} "0" * * @typedef {{ [key in $s$.test.types.MaybeValidKey<$s$.test.types.MaybeValidKey>]: null }} ValidMaybeValidKeyNested * @property {{ [key in $s$.test.types.MaybeValidKey<$s$.test.types.MaybeValidKey>]: null }} "0" */ export namespace type_type { /** * @typedef {never} Type */ } } } export namespace tests { export namespace tests { export namespace types { /** * @typedef {{ * i8: number, * i16: number, * i32: number, * u8: number, * u16: number, * u32: number, * f32: number, * f64: number, * bool: boolean, * char: string, * "Range": $s$.std.ops.Range, * "RangeInclusive": $s$.std.ops.RangeInclusive, * "()": null, * "(String, i32)": [string, number], * "(String, i32, bool)": [string, number, boolean], * "((String, i32), (bool, char, bool), ())": [[string, number], [boolean, string, boolean], null], * "(bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool)": [boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean], * "(Vec, Vec)": [number[], boolean[]], * String: string, * PathBuf: string, * IpAddr: string, * Ipv4Addr: string, * Ipv6Addr: string, * SocketAddr: string, * SocketAddrV4: string, * SocketAddrV6: string, * "Cow<'static, str>": string, * "Cow<'static, i32>": number, * "&'static str": string, * "&'static bool": boolean, * "&'static i32": number, * "Vec": number[], * "&'static [i32]": number[], * "&'static [i32; 3]": [number, number, number], * "[i32; 3]": [number, number, number], * "Vec": $s$.test.types.MyEnum[], * "&'static [MyEnum]": $s$.test.types.MyEnum[], * "&'static [MyEnum; 6]": [$s$.test.types.MyEnum, $s$.test.types.MyEnum, $s$.test.types.MyEnum, $s$.test.types.MyEnum, $s$.test.types.MyEnum, $s$.test.types.MyEnum], * "[MyEnum; 2]": [$s$.test.types.MyEnum, $s$.test.types.MyEnum], * "&'static [i32; 1]": [number], * "&'static [i32; 0]": [], * "Option": number | null, * "Option<()>": null, * "Option>": number[] | null, * "Result": $s$.std.result.Result, * "Vec>>": (number | null)[], * "Option>>": number[] | null, * "[Vec; 3]": [string[], string[], string[]], * "Option>": string | null, * "Option>>": string | null, * "PhantomData<()>": null, * "PhantomData": null, * Infallible: never, * Unit1: $s$.test.types.Unit1, * Unit2: $s$.test.types.Unit2, * Unit3: $s$.test.types.Unit3, * Unit4: $s$.test.types.Unit4, * Unit5: $s$.test.types.Unit5, * Unit6: $s$.test.types.Unit6, * Unit7: $s$.test.types.Unit7, * SimpleStruct: $s$.test.types.SimpleStruct, * TupleStruct1: $s$.test.types.TupleStruct1, * TupleStruct3: $s$.test.types.TupleStruct3, * TestEnum: $s$.test.types.TestEnum, * RefStruct: $s$.test.types.RefStruct, * InlinerStruct: $s$.test.types.InlinerStruct, * "GenericStruct": $s$.test.types.GenericStruct, * "GenericStruct": $s$.test.types.GenericStruct, * FlattenEnumStruct: $s$.test.types.FlattenEnumStruct, * OverridenStruct: $s$.test.types.OverridenStruct, * HasGenericAlias: $s$.test.types.HasGenericAlias, * EnumMacroAttributes: $s$.test.types.EnumMacroAttributes, * InlineEnumField: $s$.test.types.InlineEnumField, * InlineOptionalType: $s$.test.types.InlineOptionalType, * Rename: $s$.test.types.Rename, * TransparentType: $s$.test.types.TransparentType, * TransparentType2: $s$.test.types.TransparentType2, * TransparentTypeWithOverride: $s$.test.types.TransparentTypeWithOverride, * "[Option; 3]": [(number | null), (number | null), (number | null)], * "HashMap": Partial<{ [key in $s$.test.types.BasicEnum]: null }>, * "HashMap": Partial<{ [key in $s$.test.types.BasicEnum]: number }>, * "Option>>>": number | null, * "Vec": $s$.test.types.PlaceholderInnerField[], * EnumReferenceRecordKey: $s$.test.types.EnumReferenceRecordKey, * FlattenOnNestedEnum: $s$.test.types.FlattenOnNestedEnum, * MyEmptyInput: $s$.test.types.MyEmptyInput, * "(String)": string, * "(String,)": [string], * ExtraBracketsInTupleVariant: $s$.test.types.ExtraBracketsInTupleVariant, * ExtraBracketsInUnnamedStruct: $s$.test.types.ExtraBracketsInUnnamedStruct, * "Vec": $s$.test.types.MyEnum[], * InlineTuple: $s$.test.types.InlineTuple, * InlineTuple2: $s$.test.types.InlineTuple2, * "Box": string, * "Box": string, * SkippedFieldWithinVariant: $s$.test.types.SkippedFieldWithinVariant, * KebabCase: $s$.test.types.KebabCase, * "&[&str]": string[], * "Issue281<'_>": $s$.test.types.Issue281, * "LifetimeGenericStruct<'_, i32>": $s$.test.types.LifetimeGenericStruct, * "LifetimeGenericEnum<'_, i32>": $s$.test.types.LifetimeGenericEnum, * RenameWithWeirdCharsField: $s$.test.types.RenameWithWeirdCharsField, * RenameWithWeirdCharsVariant: $s$.test.types.RenameWithWeirdCharsVariant, * RenamedFieldKeys: $s$.test.types.RenamedFieldKeys, * RenamedVariantWithSkippedPayload: $s$.test.types.RenamedVariantWithSkippedPayload, * "type_type::Type": $s$.test.types.type_type.Type, * ActualType: $s$.test.types.ActualType, * SpectaTypeOverride: $s$.test.types.SpectaTypeOverride, * ContainerTypeOverrideStruct: $s$.test.types.ContainerTypeOverrideStruct, * ContainerTypeOverrideEnum: $s$.test.types.ContainerTypeOverrideEnum, * "ContainerTypeOverrideGeneric>": $s$.test.types.ContainerTypeOverrideGeneric, * "ContainerTypeOverrideToGeneric": $s$.test.types.ContainerTypeOverrideToGeneric, * ContainerTypeOverrideTuple: $s$.test.types.ContainerTypeOverrideTuple, * "ContainerTypeOverrideTupleGeneric": $s$.test.types.ContainerTypeOverrideTupleGeneric, * InvalidToValidType: $s$.test.types.InvalidToValidType, * TupleStruct: $s$.test.types.TupleStruct, * TupleStructWithRep: $s$.test.types.TupleStructWithRep, * "GenericTupleStruct": $s$.test.types.GenericTupleStruct, * BracedStruct: $s$.test.types.BracedStruct, * Struct: $s$.test.types.Struct, * Struct2: $s$.test.types.Struct2, * Enum: $s$.test.types.Enum, * Enum2: $s$.test.types.Enum2, * Enum3: $s$.test.types.Enum3, * StructRenameAllUppercase: $s$.test.types.StructRenameAllUppercase, * RenameSerdeSpecialChar: $s$.test.types.RenameSerdeSpecialChar, * EnumRenameAllUppercase: $s$.test.types.EnumRenameAllUppercase, * Recursive: $s$.test.types.Recursive, * RecursiveMapValue: $s$.test.types.RecursiveMapValue, * RecursiveTransparent: $s$.test.types.RecursiveTransparent, * RecursiveInEnum: $s$.test.types.RecursiveInEnum, * NonOptional: $s$.test.types.NonOptional, * OptionalOnNamedField: $s$.test.types.OptionalOnNamedField, * OptionalOnTransparentNamedField: $s$.test.types.OptionalOnTransparentNamedField, * OptionalInEnum: $s$.test.types.OptionalInEnum, * UntaggedVariants: $s$.test.types.UntaggedVariants, * UntaggedVariantsWithoutValue: $s$.test.types.UntaggedVariantsWithoutValue, * UntaggedVariantsWithDuplicateBranches: $s$.test.types.UntaggedVariantsWithDuplicateBranches, * "HashMap": { [key in string]: null }, * Regular: $s$.test.types.Regular, * "HashMap": { [key in never]: null }, * "HashMap": { [key in $s$.test.types.TransparentStruct]: null }, * "HashMap": Partial<{ [key in $s$.test.types.UnitVariants]: null }>, * "HashMap": Partial<{ [key in $s$.test.types.UntaggedVariantsKey]: null }>, * ValidMaybeValidKey: $s$.test.types.ValidMaybeValidKey, * ValidMaybeValidKeyNested: $s$.test.types.ValidMaybeValidKeyNested, * MacroStruct: $s$.test.types.MacroStruct, * MacroStruct2: $s$.test.types.MacroStruct2, * MacroEnum: $s$.test.types.MacroEnum, * DeprecatedType: $s$.test.types.DeprecatedType, * DeprecatedTypeWithMsg: $s$.test.types.DeprecatedTypeWithMsg, * DeprecatedTypeWithMsg2: $s$.test.types.DeprecatedTypeWithMsg2, * DeprecatedFields: $s$.test.types.DeprecatedFields, * DeprecatedTupleVariant: $s$.test.types.DeprecatedTupleVariant, * DeprecatedEnumVariants: $s$.test.types.DeprecatedEnumVariants, * CommentedStruct: $s$.test.types.CommentedStruct, * CommentedEnum: $s$.test.types.CommentedEnum, * SingleLineComment: $s$.test.types.SingleLineComment, * NonGeneric: $s$.test.types.Demo, * "HalfGenericA": $s$.test.types.Demo, * "HalfGenericB": $s$.test.types.Demo, * "FullGeneric": $s$.test.types.Demo, * "Another": $s$.test.types.Demo, * "MapA": { [key in string]: number }, * "MapB": { [key in number]: string }, * "MapC": { [key in string]: $s$.test.types.AGenericStruct }, * "AGenericStruct": $s$.test.types.AGenericStruct, * A: $s$.test.types.A, * DoubleFlattened: $s$.test.types.DoubleFlattened, * FlattenedInner: $s$.test.types.FlattenedInner, * BoxFlattened: $s$.test.types.BoxFlattened, * BoxInline: $s$.test.types.BoxInline, * First: $s$.test.types.First, * Second: $s$.test.types.Second, * Third: $s$.test.types.Third, * Fourth: $s$.test.types.Fourth, * TagOnStructWithInline: $s$.test.types.TagOnStructWithInline, * Sixth: $s$.test.types.Sixth, * Seventh: $s$.test.types.Seventh, * Eight: $s$.test.types.Eight, * Ninth: $s$.test.types.Ninth, * Tenth: $s$.test.types.Tenth, * MyEnumTagged: $s$.test.types.MyEnumTagged, * MyEnumExternal: $s$.test.types.MyEnumExternal, * MyEnumAdjacent: $s$.test.types.MyEnumAdjacent, * MyEnumUntagged: $s$.test.types.MyEnumUntagged, * EmptyStruct: $s$.test.types.EmptyStruct, * EmptyStructWithTag: $s$.test.types.EmptyStructWithTag, * AdjacentlyTagged: $s$.test.types.AdjacentlyTagged, * LoadProjectEvent: $s$.test.types.LoadProjectEvent, * ExternallyTagged: $s$.test.types.ExternallyTagged, * Issue221External: $s$.test.types.Issue221External, * InternallyTaggedD: $s$.test.types.InternallyTaggedD, * InternallyTaggedE: $s$.test.types.InternallyTaggedE, * InternallyTaggedF: $s$.test.types.InternallyTaggedF, * InternallyTaggedH: $s$.test.types.InternallyTaggedH, * InternallyTaggedL: $s$.test.types.InternallyTaggedL, * InternallyTaggedM: $s$.test.types.InternallyTaggedM, * StructWithAlias: $s$.test.types.StructWithAlias, * StructWithMultipleAliases: $s$.test.types.StructWithMultipleAliases, * StructWithAliasAndRename: $s$.test.types.StructWithAliasAndRename, * EnumWithVariantAlias: $s$.test.types.EnumWithVariantAlias, * EnumWithMultipleVariantAliases: $s$.test.types.EnumWithMultipleVariantAliases, * EnumWithVariantAliasAndRename: $s$.test.types.EnumWithVariantAliasAndRename, * InternallyTaggedWithAlias: $s$.test.types.InternallyTaggedWithAlias, * AdjacentlyTaggedWithAlias: $s$.test.types.AdjacentlyTaggedWithAlias, * UntaggedWithAlias: $s$.test.types.UntaggedWithAlias, * Issue221UntaggedSafe: $s$.test.types.Issue221UntaggedSafe, * Issue221UntaggedMixed: $s$.test.types.Issue221UntaggedMixed, * EmptyEnum: $s$.test.types.EmptyEnum, * EmptyEnumTagged: $s$.test.types.EmptyEnumTagged, * EmptyEnumTaggedWContent: $s$.test.types.EmptyEnumTaggedWContent, * EmptyEnumUntagged: $s$.test.types.EmptyEnumUntagged, * SkipOnlyField: $s$.test.types.SkipOnlyField, * SkipField: $s$.test.types.SkipField, * SkipVariant: $s$.test.types.SkipVariant, * SkipUnnamedFieldInVariant: $s$.test.types.SkipUnnamedFieldInVariant, * SkipNamedFieldInVariant: $s$.test.types.SkipNamedFieldInVariant, * TransparentWithSkip: $s$.test.types.TransparentWithSkip, * TransparentWithSkip2: $s$.test.types.TransparentWithSkip2, * TransparentWithSkip3: $s$.test.types.TransparentWithSkip3, * SkipVariant2: $s$.test.types.SkipVariant2, * SkipVariant3: $s$.test.types.SkipVariant3, * SkipStructFields: $s$.test.types.SkipStructFields, * SpectaSkipNonTypeField: $s$.test.types.SpectaSkipNonTypeField, * FlattenA: $s$.test.types.FlattenA, * FlattenB: $s$.test.types.FlattenB, * FlattenC: $s$.test.types.FlattenC, * FlattenD: $s$.test.types.FlattenD, * FlattenE: $s$.test.types.FlattenE, * FlattenF: $s$.test.types.FlattenF, * FlattenG: $s$.test.types.FlattenG, * TupleNested: $s$.test.types.TupleNested, * "Generic1<()>": $s$.test.types.Generic1, * "GenericAutoBound<()>": $s$.test.types.GenericAutoBound, * "GenericAutoBound2<()>": $s$.test.types.GenericAutoBound2, * Container1: $s$.test.types.Container1, * "Generic2<(), String, i32>": $s$.test.types.Generic2, * "GenericNewType1<()>": $s$.test.types.GenericNewType1, * "GenericTuple<()>": $s$.test.types.GenericTuple, * "GenericStruct2<()>": $s$.test.types.GenericStruct2, * "InlineGenericNewtype": string, * "InlineGenericNested": [string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | string | { value: string }], * "InlineFlattenGenericsG<()>": $s$.test.types.InlineFlattenGenericsG, * InlineFlattenGenerics: $s$.test.types.InlineFlattenGenerics, * GenericDefault: $s$.test.types.GenericDefault, * ChainedGenericDefault: $s$.test.types.ChainedGenericDefault, * "ChainedGenericDefault": $s$.test.types.ChainedGenericDefault, * "ChainedGenericDefault": $s$.test.types.ChainedGenericDefault, * "ChainedGenericDefault": $s$.test.types.ChainedGenericDefault, * GenericDefaultSkipped: $s$.test.types.GenericDefaultSkipped, * GenericDefaultSkippedNonType: $s$.test.types.GenericDefaultSkippedNonType, * GenericParameterOrderPreserved: $s$.test.types.GenericParameterOrderPreserved, * ConstGenericInNonConstContainer: $s$.test.types.ConstGenericInNonConstContainer, * ConstGenericInConstContainer: $s$.test.types.ConstGenericInConstContainer, * NamedConstGenericContainer: $s$.test.types.NamedConstGenericContainer, * InlineConstGenericContainer: $s$.test.types.InlineConstGenericContainer, * InlineRecursiveConstGenericContainer: $s$.test.types.InlineRecursiveConstGenericContainer, * TestCollectionRegister: $s$.test.types.TestCollectionRegister, * TestCollectionRegister: $s$.test.types.TestCollectionRegister, * }} Primitives * @property {number} i8 * @property {number} i16 * @property {number} i32 * @property {number} u8 * @property {number} u16 * @property {number} u32 * @property {number} f32 * @property {number} f64 * @property {boolean} bool * @property {string} char * @property {$s$.std.ops.Range} "Range" * @property {$s$.std.ops.RangeInclusive} "RangeInclusive" * @property {null} "()" * @property {[string, number]} "(String, i32)" * @property {[string, number, boolean]} "(String, i32, bool)" * @property {[[string, number], [boolean, string, boolean], null]} "((String, i32), (bool, char, bool), ())" * @property {[boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean]} "(bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool)" * @property {[number[], boolean[]]} "(Vec, Vec)" * @property {string} String * @property {string} PathBuf * @property {string} IpAddr * @property {string} Ipv4Addr * @property {string} Ipv6Addr * @property {string} SocketAddr * @property {string} SocketAddrV4 * @property {string} SocketAddrV6 * @property {string} "Cow<'static, str>" * @property {number} "Cow<'static, i32>" * @property {string} "&'static str" * @property {boolean} "&'static bool" * @property {number} "&'static i32" * @property {number[]} "Vec" * @property {number[]} "&'static [i32]" * @property {[number, number, number]} "&'static [i32; 3]" * @property {[number, number, number]} "[i32; 3]" * @property {$s$.test.types.MyEnum[]} "Vec" * @property {$s$.test.types.MyEnum[]} "&'static [MyEnum]" * @property {[$s$.test.types.MyEnum, $s$.test.types.MyEnum, $s$.test.types.MyEnum, $s$.test.types.MyEnum, $s$.test.types.MyEnum, $s$.test.types.MyEnum]} "&'static [MyEnum; 6]" * @property {[$s$.test.types.MyEnum, $s$.test.types.MyEnum]} "[MyEnum; 2]" * @property {[number]} "&'static [i32; 1]" * @property {[]} "&'static [i32; 0]" * @property {number | null} "Option" * @property {null} "Option<()>" * @property {number[] | null} "Option>" * @property {$s$.std.result.Result} "Result" * @property {(number | null)[]} "Vec>>" * @property {number[] | null} "Option>>" * @property {[string[], string[], string[]]} "[Vec; 3]" * @property {string | null} "Option>" * @property {string | null} "Option>>" * @property {null} "PhantomData<()>" * @property {null} "PhantomData" * @property {never} Infallible * @property {$s$.test.types.Unit1} Unit1 * @property {$s$.test.types.Unit2} Unit2 * @property {$s$.test.types.Unit3} Unit3 * @property {$s$.test.types.Unit4} Unit4 * @property {$s$.test.types.Unit5} Unit5 * @property {$s$.test.types.Unit6} Unit6 * @property {$s$.test.types.Unit7} Unit7 * @property {$s$.test.types.SimpleStruct} SimpleStruct * @property {$s$.test.types.TupleStruct1} TupleStruct1 * @property {$s$.test.types.TupleStruct3} TupleStruct3 * @property {$s$.test.types.TestEnum} TestEnum * @property {$s$.test.types.RefStruct} RefStruct * @property {$s$.test.types.InlinerStruct} InlinerStruct * @property {$s$.test.types.GenericStruct} "GenericStruct" * @property {$s$.test.types.GenericStruct} "GenericStruct" * @property {$s$.test.types.FlattenEnumStruct} FlattenEnumStruct * @property {$s$.test.types.OverridenStruct} OverridenStruct * @property {$s$.test.types.HasGenericAlias} HasGenericAlias * @property {$s$.test.types.EnumMacroAttributes} EnumMacroAttributes * @property {$s$.test.types.InlineEnumField} InlineEnumField * @property {$s$.test.types.InlineOptionalType} InlineOptionalType * @property {$s$.test.types.Rename} Rename * @property {$s$.test.types.TransparentType} TransparentType * @property {$s$.test.types.TransparentType2} TransparentType2 * @property {$s$.test.types.TransparentTypeWithOverride} TransparentTypeWithOverride * @property {[(number | null), (number | null), (number | null)]} "[Option; 3]" * @property {Partial<{ [key in $s$.test.types.BasicEnum]: null }>} "HashMap" * @property {Partial<{ [key in $s$.test.types.BasicEnum]: number }>} "HashMap" * @property {number | null} "Option>>>" * @property {$s$.test.types.PlaceholderInnerField[]} "Vec" * @property {$s$.test.types.EnumReferenceRecordKey} EnumReferenceRecordKey * @property {$s$.test.types.FlattenOnNestedEnum} FlattenOnNestedEnum * @property {$s$.test.types.MyEmptyInput} MyEmptyInput * @property {string} "(String)" * @property {[string]} "(String,)" * @property {$s$.test.types.ExtraBracketsInTupleVariant} ExtraBracketsInTupleVariant * @property {$s$.test.types.ExtraBracketsInUnnamedStruct} ExtraBracketsInUnnamedStruct * @property {$s$.test.types.MyEnum[]} "Vec" * @property {$s$.test.types.InlineTuple} InlineTuple * @property {$s$.test.types.InlineTuple2} InlineTuple2 * @property {string} "Box" * @property {string} "Box" * @property {$s$.test.types.SkippedFieldWithinVariant} SkippedFieldWithinVariant * @property {$s$.test.types.KebabCase} KebabCase * @property {string[]} "&[&str]" * @property {$s$.test.types.Issue281} "Issue281<'_>" * @property {$s$.test.types.LifetimeGenericStruct} "LifetimeGenericStruct<'_, i32>" * @property {$s$.test.types.LifetimeGenericEnum} "LifetimeGenericEnum<'_, i32>" * @property {$s$.test.types.RenameWithWeirdCharsField} RenameWithWeirdCharsField * @property {$s$.test.types.RenameWithWeirdCharsVariant} RenameWithWeirdCharsVariant * @property {$s$.test.types.RenamedFieldKeys} RenamedFieldKeys * @property {$s$.test.types.RenamedVariantWithSkippedPayload} RenamedVariantWithSkippedPayload * @property {$s$.test.types.type_type.Type} "type_type::Type" * @property {$s$.test.types.ActualType} ActualType * @property {$s$.test.types.SpectaTypeOverride} SpectaTypeOverride * @property {$s$.test.types.ContainerTypeOverrideStruct} ContainerTypeOverrideStruct * @property {$s$.test.types.ContainerTypeOverrideEnum} ContainerTypeOverrideEnum * @property {$s$.test.types.ContainerTypeOverrideGeneric} "ContainerTypeOverrideGeneric>" * @property {$s$.test.types.ContainerTypeOverrideToGeneric} "ContainerTypeOverrideToGeneric" * @property {$s$.test.types.ContainerTypeOverrideTuple} ContainerTypeOverrideTuple * @property {$s$.test.types.ContainerTypeOverrideTupleGeneric} "ContainerTypeOverrideTupleGeneric" * @property {$s$.test.types.InvalidToValidType} InvalidToValidType * @property {$s$.test.types.TupleStruct} TupleStruct * @property {$s$.test.types.TupleStructWithRep} TupleStructWithRep * @property {$s$.test.types.GenericTupleStruct} "GenericTupleStruct" * @property {$s$.test.types.BracedStruct} BracedStruct * @property {$s$.test.types.Struct} Struct * @property {$s$.test.types.Struct2} Struct2 * @property {$s$.test.types.Enum} Enum * @property {$s$.test.types.Enum2} Enum2 * @property {$s$.test.types.Enum3} Enum3 * @property {$s$.test.types.StructRenameAllUppercase} StructRenameAllUppercase * @property {$s$.test.types.RenameSerdeSpecialChar} RenameSerdeSpecialChar * @property {$s$.test.types.EnumRenameAllUppercase} EnumRenameAllUppercase * @property {$s$.test.types.Recursive} Recursive * @property {$s$.test.types.RecursiveMapValue} RecursiveMapValue * @property {$s$.test.types.RecursiveTransparent} RecursiveTransparent * @property {$s$.test.types.RecursiveInEnum} RecursiveInEnum * @property {$s$.test.types.NonOptional} NonOptional * @property {$s$.test.types.OptionalOnNamedField} OptionalOnNamedField * @property {$s$.test.types.OptionalOnTransparentNamedField} OptionalOnTransparentNamedField * @property {$s$.test.types.OptionalInEnum} OptionalInEnum * @property {$s$.test.types.UntaggedVariants} UntaggedVariants * @property {$s$.test.types.UntaggedVariantsWithoutValue} UntaggedVariantsWithoutValue * @property {$s$.test.types.UntaggedVariantsWithDuplicateBranches} UntaggedVariantsWithDuplicateBranches * @property {{ [key in string]: null }} "HashMap" * @property {$s$.test.types.Regular} Regular * @property {{ [key in never]: null }} "HashMap" * @property {{ [key in $s$.test.types.TransparentStruct]: null }} "HashMap" * @property {Partial<{ [key in $s$.test.types.UnitVariants]: null }>} "HashMap" * @property {Partial<{ [key in $s$.test.types.UntaggedVariantsKey]: null }>} "HashMap" * @property {$s$.test.types.ValidMaybeValidKey} ValidMaybeValidKey * @property {$s$.test.types.ValidMaybeValidKeyNested} ValidMaybeValidKeyNested * @property {$s$.test.types.MacroStruct} MacroStruct * @property {$s$.test.types.MacroStruct2} MacroStruct2 * @property {$s$.test.types.MacroEnum} MacroEnum * @property {$s$.test.types.DeprecatedType} DeprecatedType * @property {$s$.test.types.DeprecatedTypeWithMsg} DeprecatedTypeWithMsg * @property {$s$.test.types.DeprecatedTypeWithMsg2} DeprecatedTypeWithMsg2 * @property {$s$.test.types.DeprecatedFields} DeprecatedFields * @property {$s$.test.types.DeprecatedTupleVariant} DeprecatedTupleVariant * @property {$s$.test.types.DeprecatedEnumVariants} DeprecatedEnumVariants * @property {$s$.test.types.CommentedStruct} CommentedStruct * @property {$s$.test.types.CommentedEnum} CommentedEnum * @property {$s$.test.types.SingleLineComment} SingleLineComment * @property {$s$.test.types.Demo} NonGeneric * @property {$s$.test.types.Demo} "HalfGenericA" * @property {$s$.test.types.Demo} "HalfGenericB" * @property {$s$.test.types.Demo} "FullGeneric" * @property {$s$.test.types.Demo} "Another" * @property {{ [key in string]: number }} "MapA" * @property {{ [key in number]: string }} "MapB" * @property {{ [key in string]: $s$.test.types.AGenericStruct }} "MapC" * @property {$s$.test.types.AGenericStruct} "AGenericStruct" * @property {$s$.test.types.A} A * @property {$s$.test.types.DoubleFlattened} DoubleFlattened * @property {$s$.test.types.FlattenedInner} FlattenedInner * @property {$s$.test.types.BoxFlattened} BoxFlattened * @property {$s$.test.types.BoxInline} BoxInline * @property {$s$.test.types.First} First * @property {$s$.test.types.Second} Second * @property {$s$.test.types.Third} Third * @property {$s$.test.types.Fourth} Fourth * @property {$s$.test.types.TagOnStructWithInline} TagOnStructWithInline * @property {$s$.test.types.Sixth} Sixth * @property {$s$.test.types.Seventh} Seventh * @property {$s$.test.types.Eight} Eight * @property {$s$.test.types.Ninth} Ninth * @property {$s$.test.types.Tenth} Tenth * @property {$s$.test.types.MyEnumTagged} MyEnumTagged * @property {$s$.test.types.MyEnumExternal} MyEnumExternal * @property {$s$.test.types.MyEnumAdjacent} MyEnumAdjacent * @property {$s$.test.types.MyEnumUntagged} MyEnumUntagged * @property {$s$.test.types.EmptyStruct} EmptyStruct * @property {$s$.test.types.EmptyStructWithTag} EmptyStructWithTag * @property {$s$.test.types.AdjacentlyTagged} AdjacentlyTagged * @property {$s$.test.types.LoadProjectEvent} LoadProjectEvent * @property {$s$.test.types.ExternallyTagged} ExternallyTagged * @property {$s$.test.types.Issue221External} Issue221External * @property {$s$.test.types.InternallyTaggedD} InternallyTaggedD * @property {$s$.test.types.InternallyTaggedE} InternallyTaggedE * @property {$s$.test.types.InternallyTaggedF} InternallyTaggedF * @property {$s$.test.types.InternallyTaggedH} InternallyTaggedH * @property {$s$.test.types.InternallyTaggedL} InternallyTaggedL * @property {$s$.test.types.InternallyTaggedM} InternallyTaggedM * @property {$s$.test.types.StructWithAlias} StructWithAlias * @property {$s$.test.types.StructWithMultipleAliases} StructWithMultipleAliases * @property {$s$.test.types.StructWithAliasAndRename} StructWithAliasAndRename * @property {$s$.test.types.EnumWithVariantAlias} EnumWithVariantAlias * @property {$s$.test.types.EnumWithMultipleVariantAliases} EnumWithMultipleVariantAliases * @property {$s$.test.types.EnumWithVariantAliasAndRename} EnumWithVariantAliasAndRename * @property {$s$.test.types.InternallyTaggedWithAlias} InternallyTaggedWithAlias * @property {$s$.test.types.AdjacentlyTaggedWithAlias} AdjacentlyTaggedWithAlias * @property {$s$.test.types.UntaggedWithAlias} UntaggedWithAlias * @property {$s$.test.types.Issue221UntaggedSafe} Issue221UntaggedSafe * @property {$s$.test.types.Issue221UntaggedMixed} Issue221UntaggedMixed * @property {$s$.test.types.EmptyEnum} EmptyEnum * @property {$s$.test.types.EmptyEnumTagged} EmptyEnumTagged * @property {$s$.test.types.EmptyEnumTaggedWContent} EmptyEnumTaggedWContent * @property {$s$.test.types.EmptyEnumUntagged} EmptyEnumUntagged * @property {$s$.test.types.SkipOnlyField} SkipOnlyField * @property {$s$.test.types.SkipField} SkipField * @property {$s$.test.types.SkipVariant} SkipVariant * @property {$s$.test.types.SkipUnnamedFieldInVariant} SkipUnnamedFieldInVariant * @property {$s$.test.types.SkipNamedFieldInVariant} SkipNamedFieldInVariant * @property {$s$.test.types.TransparentWithSkip} TransparentWithSkip * @property {$s$.test.types.TransparentWithSkip2} TransparentWithSkip2 * @property {$s$.test.types.TransparentWithSkip3} TransparentWithSkip3 * @property {$s$.test.types.SkipVariant2} SkipVariant2 * @property {$s$.test.types.SkipVariant3} SkipVariant3 * @property {$s$.test.types.SkipStructFields} SkipStructFields * @property {$s$.test.types.SpectaSkipNonTypeField} SpectaSkipNonTypeField * @property {$s$.test.types.FlattenA} FlattenA * @property {$s$.test.types.FlattenB} FlattenB * @property {$s$.test.types.FlattenC} FlattenC * @property {$s$.test.types.FlattenD} FlattenD * @property {$s$.test.types.FlattenE} FlattenE * @property {$s$.test.types.FlattenF} FlattenF * @property {$s$.test.types.FlattenG} FlattenG * @property {$s$.test.types.TupleNested} TupleNested * @property {$s$.test.types.Generic1} "Generic1<()>" * @property {$s$.test.types.GenericAutoBound} "GenericAutoBound<()>" * @property {$s$.test.types.GenericAutoBound2} "GenericAutoBound2<()>" * @property {$s$.test.types.Container1} Container1 * @property {$s$.test.types.Generic2} "Generic2<(), String, i32>" * @property {$s$.test.types.GenericNewType1} "GenericNewType1<()>" * @property {$s$.test.types.GenericTuple} "GenericTuple<()>" * @property {$s$.test.types.GenericStruct2} "GenericStruct2<()>" * @property {string} "InlineGenericNewtype" * @property {[string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | string | { value: string }]} "InlineGenericNested" * @property {$s$.test.types.InlineFlattenGenericsG} "InlineFlattenGenericsG<()>" * @property {$s$.test.types.InlineFlattenGenerics} InlineFlattenGenerics * @property {$s$.test.types.GenericDefault} GenericDefault * @property {$s$.test.types.ChainedGenericDefault} ChainedGenericDefault * @property {$s$.test.types.ChainedGenericDefault} "ChainedGenericDefault" * @property {$s$.test.types.ChainedGenericDefault} "ChainedGenericDefault" * @property {$s$.test.types.ChainedGenericDefault} "ChainedGenericDefault" * @property {$s$.test.types.GenericDefaultSkipped} GenericDefaultSkipped * @property {$s$.test.types.GenericDefaultSkippedNonType} GenericDefaultSkippedNonType * @property {$s$.test.types.GenericParameterOrderPreserved} GenericParameterOrderPreserved * @property {$s$.test.types.ConstGenericInNonConstContainer} ConstGenericInNonConstContainer * @property {$s$.test.types.ConstGenericInConstContainer} ConstGenericInConstContainer * @property {$s$.test.types.NamedConstGenericContainer} NamedConstGenericContainer * @property {$s$.test.types.InlineConstGenericContainer} InlineConstGenericContainer * @property {$s$.test.types.InlineRecursiveConstGenericContainer} InlineRecursiveConstGenericContainer * @property {$s$.test.types.TestCollectionRegister} TestCollectionRegister * @property {$s$.test.types.TestCollectionRegister} TestCollectionRegister */ } } } } export import std = $s$.std; export import test = $s$.test; export import tests = $s$.tests; ════════════════════════════════════════ ================================================ FILE: tests/tests/snapshots/test__jsdoc__jsdoc-export-to-namespaces-serde.snap ================================================ --- source: tests/tests/jsdoc.rs expression: output --- jsdoc-export-to-namespaces-serde (69397 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. namespace $s$ { export namespace std { export namespace ops { /** * @typedef {{ * start: T, * end: T, * }} Range * @property {T} start * @property {T} end * * @typedef {{ * start: T, * end: T, * }} RangeInclusive * @property {T} start * @property {T} end */ } export namespace result { /** * @typedef {{ * ok: T, * err: E, * }} Result * @property {T} ok * @property {E} err */ } } export namespace test { export namespace types { /** * @typedef {{ * a: $s$.test.types.B, * b: { * b: number, * }, * c: $s$.test.types.B, * d: { * flattened: number, * }, * e: { * generic_flattened: number, * }, * }} A * @property {$s$.test.types.B} a * @property {{ * b: number, * }} b * @property {$s$.test.types.B} c * @property {{ * flattened: number, * }} d * @property {{ * generic_flattened: number, * }} e * * @typedef {{ * field: $s$.test.types.Demo, * }} AGenericStruct * @property {$s$.test.types.Demo} field * * @typedef {{ * a: $s$.test.types.GenericType, * }} ActualType * @property {$s$.test.types.GenericType} a * * @typedef {{ t: "A" } | { t: "B"; c: { * id: string, * method: string, * } } | { t: "C"; c: string }} AdjacentlyTagged * @property {{ t: "A" }} A * @property {{ t: "B"; c: { * id: string, * method: string, * } }} B * @property {{ t: "C"; c: string }} C * * @typedef {{ type: "A"; data: { * field: string, * } } | { type: "B"; data: { * other: number, * } }} AdjacentlyTaggedWithAlias * @property {{ type: "A"; data: { * field: string, * } }} A * @property {{ type: "B"; data: { * other: number, * } }} B * * @typedef {{ * b: number, * }} B * @property {number} b * * @typedef {"A" | "B"} BasicEnum * @property {"A"} A * @property {"B"} B * * @typedef {$s$.test.types.BoxedInner} BoxFlattened * * @typedef {{ * c: { * a: number, * }, * }} BoxInline * @property {{ * a: number, * }} c * * @typedef {{ * a: number, * }} BoxedInner * @property {number} a * * @typedef {string} BracedStruct * @property {string} "0" * * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second * * Some triple-slash comment * Some more triple-slash comment * * @typedef { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * ({ A: number }) & { B?: never } | * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * ({ B: { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * } }) & { A?: never }} CommentedEnum * @property { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * { A: number }} A - Some triple-slash comment Some more triple-slash comment * @property { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * { B: { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * } }} B - Some triple-slash comment Some more triple-slash comment * * Some triple-slash comment * Some more triple-slash comment * * @typedef {{ * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * }} CommentedStruct * @property {number} a - Some triple-slash comment Some more triple-slash comment * * @typedef {{ * data: number[], * a: number[], * d: [number, number], * }} ConstGenericInConstContainer * @property {number[]} data * @property {number[]} a * @property {[number, number]} d * * @typedef {{ * data: [number], * a: [number, number], * d: [number, number], * }} ConstGenericInNonConstContainer * @property {[number]} data * @property {[number, number]} a * @property {[number, number]} d * * @typedef {{ * foo: $s$.test.types.Generic1, * bar: $s$.test.types.Generic1[], * baz: { [key in string]: $s$.test.types.Generic1 }, * }} Container1 * @property {$s$.test.types.Generic1} foo * @property {$s$.test.types.Generic1[]} bar * @property {{ [key in string]: $s$.test.types.Generic1 }} baz * * @typedef {string} ContainerTypeOverrideEnum * * @typedef {string} ContainerTypeOverrideGeneric * * @typedef {string} ContainerTypeOverrideStruct * * @typedef {T} ContainerTypeOverrideToGeneric * * @typedef {[string, number]} ContainerTypeOverrideTuple * * @typedef {[T, string]} ContainerTypeOverrideTupleGeneric * * @typedef {{ * flattened: number, * }} D * @property {number} flattened * * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b * * @typedef { * /** * * @deprecated * */ * "A" | * /** * * @deprecated Nope * */ * "B" | * /** * * @deprecated Nope * */ * "C"} DeprecatedEnumVariants * @property { * /** * * @deprecated * */ * "A"} A - @deprecated * @property { * /** * * @deprecated Nope * */ * "B"} B - @deprecated Nope * @property { * /** * * @deprecated Nope * */ * "C"} C - @deprecated Nope * * @typedef {{ * a: number, * /** * * @deprecated * */ * b: string, * /** * * @deprecated This field is cringe! * */ * c: string, * /** * * @deprecated This field is cringe! * */ * d: string, * }} DeprecatedFields * @property {number} a * @property {string} b - @deprecated * @property {string} c - @deprecated This field is cringe! * @property {string} d - @deprecated This field is cringe! * * @typedef {[ * /** * * @deprecated * */ * string, * /** * * @deprecated Nope * */ * string, * /** * * @deprecated Nope * */ * number]} DeprecatedTupleVariant * @property {string} "0" - @deprecated * @property {string} "1" - @deprecated Nope * @property {number} "2" - @deprecated Nope * * @deprecated * @typedef {{ * a: number, * }} DeprecatedType * @property {number} a * * @deprecated Look at you big man using a deprecation message * @typedef {{ * a: number, * }} DeprecatedTypeWithMsg * @property {number} a * * @deprecated Look at you big man using a deprecation message * @typedef {{ * a: number, * }} DeprecatedTypeWithMsg2 * @property {number} a * * @typedef {{ * a: $s$.test.types.ToBeFlattened, * b: $s$.test.types.ToBeFlattened, * }} DoubleFlattened * @property {$s$.test.types.ToBeFlattened} a * @property {$s$.test.types.ToBeFlattened} b * * @typedef {{ A: string } | "B"} Eight * @property {{ A: string }} A * @property {"B"} B * * @typedef {never} EmptyEnum * * @typedef {never} EmptyEnumTagged * * @typedef {never} EmptyEnumTaggedWContent * * @typedef {never} EmptyEnumUntagged * * @typedef {Record} EmptyStruct * * @typedef {{ * a: "EmptyStructWithTag", * }} EmptyStructWithTag * @property {"EmptyStructWithTag"} a * * @typedef {{ t: "A" } | { t: "B" }} Enum * @property {{ t: "A" }} A * @property {{ t: "B" }} B * * @typedef {{ t: "C" } | { t: "B" } | { t: "D"; enumField: null }} Enum2 * @property {{ t: "C" }} C * @property {{ t: "B" }} B * @property {{ t: "D"; enumField: null }} D * * @typedef {{ t: "A"; b: string }} Enum3 * @property {{ t: "A"; b: string }} A * * @typedef {({ A: string }) & { D?: never; bbb?: never; cccc?: never } | ({ bbb: number }) & { A?: never; D?: never; cccc?: never } | ({ cccc: number }) & { A?: never; D?: never; bbb?: never } | ({ D: { * a: string, * bbbbbb: number, * } }) & { A?: never; bbb?: never; cccc?: never }} EnumMacroAttributes * @property {{ A: string }} A * @property {{ bbb: number }} bbb * @property {{ cccc: number }} cccc * @property {{ D: { * a: string, * bbbbbb: number, * } }} D * * @typedef {{ * a: Partial<{ [key in $s$.test.types.BasicEnum]: number }>, * }} EnumReferenceRecordKey * @property {Partial<{ [key in $s$.test.types.BasicEnum]: number }>} a * * @typedef {"HELLOWORLD" | "VARIANTB" | "TESTINGWORDS"} EnumRenameAllUppercase * @property {"HELLOWORLD"} HELLOWORLD * @property {"VARIANTB"} VARIANTB * @property {"TESTINGWORDS"} TESTINGWORDS * * @typedef {"Variant" | "Other"} EnumWithMultipleVariantAliases * @property {"Variant"} Variant * @property {"Other"} Other * * @typedef {"Variant" | "Other"} EnumWithVariantAlias * @property {"Variant"} Variant * @property {"Other"} Other * * @typedef {"renamed_variant" | "Other"} EnumWithVariantAliasAndRename * @property {"renamed_variant"} renamed_variant * @property {"Other"} Other * * @typedef {"A" | ({ B: { * id: string, * method: string, * } }) & { C?: never } | ({ C: string }) & { B?: never }} ExternallyTagged * @property {"A"} A * @property {{ B: { * id: string, * method: string, * } }} B * @property {{ C: string }} C * * @typedef {{ A: string }} ExtraBracketsInTupleVariant * @property {{ A: string }} A * * @typedef {string} ExtraBracketsInUnnamedStruct * @property {string} "0" * * @typedef {{ * a: string, * }} First * @property {string} a * * @typedef {{ * a: number, * b: number, * }} FlattenA * @property {number} a * @property {number} b * * @typedef {{ * c: number, * } & $s$.test.types.FlattenA} FlattenB * @property {number} c * * @typedef {{ * c: number, * } & $s$.test.types.FlattenA} FlattenC * @property {number} c * * @typedef {{ * a: $s$.test.types.FlattenA, * c: number, * }} FlattenD * @property {$s$.test.types.FlattenA} a * @property {number} c * * @typedef {{ * b: ({ * c: number, * }) & ($s$.test.types.FlattenA), * d: number, * }} FlattenE * @property {({ * c: number, * }) & ($s$.test.types.FlattenA)} b * @property {number} d * * @typedef {{ tag: "One" } | { tag: "Two" } | { tag: "Three" }} FlattenEnum * @property {{ tag: "One" }} One * @property {{ tag: "Two" }} Two * @property {{ tag: "Three" }} Three * * @typedef {{ * outer: string, * } & $s$.test.types.FlattenEnum} FlattenEnumStruct * @property {string} outer * * @typedef {{ * b: ({ * c: number, * }) & ($s$.test.types.FlattenA), * d: number, * }} FlattenF * @property {({ * c: number, * }) & ($s$.test.types.FlattenA)} b * @property {number} d * * @typedef {{ * b: $s$.test.types.FlattenB, * d: number, * }} FlattenG * @property {$s$.test.types.FlattenB} b * @property {number} d * * @typedef {{ * id: string, * } & $s$.test.types.NestedEnum} FlattenOnNestedEnum * @property {string} id * * @typedef {$s$.test.types.Inner} FlattenedInner * * @typedef {{ * a: $s$.test.types.First, * b: { * a: string, * }, * }} Fourth * @property {$s$.test.types.First} a * @property {{ * a: string, * }} b * * @typedef {{ * value: T, * values: T[], * }} Generic1 * @property {T} value * @property {T[]} values * * @typedef {({ A: A }) & { B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ B: [B, B, B] }) & { A?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ C: C[] }) & { A?: never; B?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ D: A[][][] }) & { A?: never; B?: never; C?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ E: { * a: A, * b: B, * c: C, * } }) & { A?: never; B?: never; C?: never; D?: never; X?: never; Y?: never; Z?: never } | ({ X: number[] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; Y?: never; Z?: never } | ({ Y: number }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Z?: never } | ({ Z: number[][] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never }} Generic2 * @property {{ A: A }} A * @property {{ B: [B, B, B] }} B * @property {{ C: C[] }} C * @property {{ D: A[][][] }} D * @property {{ E: { * a: A, * b: B, * c: C, * } }} E * @property {{ X: number[] }} X * @property {{ Y: number }} Y * @property {{ Z: number[][] }} Z * * @typedef {{ * value: T, * values: T[], * }} GenericAutoBound * @property {T} value * @property {T[]} values * * @typedef {{ * value: T, * values: T[], * }} GenericAutoBound2 * @property {T} value * @property {T[]} values * * @typedef {{ * value: T, * }} GenericDefault * @property {T} value * * @typedef {{ * value: T, * }} GenericDefaultSkipped * @property {T} value * * @typedef {{ * value: number, * }} GenericDefaultSkippedNonType * @property {number} value * * @typedef {{ * generic_flattened: T, * }} GenericFlattened * @property {T} generic_flattened * * @typedef {T[][]} GenericNewType1 * @property {T[][]} "0" * * @typedef {{ * pair: $s$.test.types.Pair, * }} GenericParameterOrderPreserved * @property {$s$.test.types.Pair} pair * * @typedef {{ * arg: T, * }} GenericStruct * @property {T} arg * * @typedef {{ * a: T, * b: [T, T], * c: [T, [T, T]], * d: [T, T, T], * e: [([T, T]), ([T, T]), ([T, T])], * f: T[], * g: T[][], * h: ([([T, T]), ([T, T]), ([T, T])])[], * }} GenericStruct2 * @property {T} a * @property {[T, T]} b * @property {[T, [T, T]]} c * @property {[T, T, T]} d * @property {[([T, T]), ([T, T]), ([T, T])]} e * @property {T[]} f * @property {T[][]} g * @property {([([T, T]), ([T, T]), ([T, T])])[]} h * * @typedef {[T, T[], T[][]]} GenericTuple * @property {T} "0" * @property {T[]} "1" * @property {T[][]} "2" * * @typedef {T} GenericTupleStruct * @property {T} "0" * * @typedef {"Undefined" | T} GenericType * @property {"Undefined"} Undefined * @property {T} Value * * @typedef {{ [key in number]: string }} HasGenericAlias * @property {{ [key in number]: string }} "0" * * @typedef {{ * b: { * data: [number, number], * a: [number, number], * d: [number, number, number], * }, * c: { * data: [number, number, number], * a: [number, number], * d: [number, number, number], * }, * d: [number, number], * }} InlineConstGenericContainer * @property {{ * data: [number, number], * a: [number, number], * d: [number, number, number], * }} b * @property {{ * data: [number, number, number], * a: [number, number], * d: [number, number, number], * }} c * @property {[number, number]} d * * @typedef {{ A: { * a: string, * } }} InlineEnumField * @property {{ A: { * a: string, * } }} A * * @typedef {{ * g: $s$.test.types.InlineFlattenGenericsG, * gi: { * t: string, * }, * } & $s$.test.types.InlineFlattenGenericsG} InlineFlattenGenerics * @property {$s$.test.types.InlineFlattenGenericsG} g * @property {{ * t: string, * }} gi * * @typedef {{ * t: T, * }} InlineFlattenGenericsG * @property {T} t * * @typedef {{ * optional_field: { * a: string, * } | null, * }} InlineOptionalType * @property {{ * a: string, * } | null} optional_field * * @typedef {{ * data: number[], * a: number[], * d: [number, number, number], * e: $s$.test.types.InlineRecursiveConstGeneric, * }} InlineRecursiveConstGeneric * @property {number[]} data * @property {number[]} a * @property {[number, number, number]} d * @property {$s$.test.types.InlineRecursiveConstGeneric} e * * @typedef {{ * b: { * data: [number, number], * a: [number, number], * d: [number, number, number], * e: $s$.test.types.InlineRecursiveConstGeneric, * }, * c: { * data: [number, number, number], * a: [number, number], * d: [number, number, number], * e: $s$.test.types.InlineRecursiveConstGeneric, * }, * d: [number, number], * }} InlineRecursiveConstGenericContainer * @property {{ * data: [number, number], * a: [number, number], * d: [number, number, number], * e: $s$.test.types.InlineRecursiveConstGeneric, * }} b * @property {{ * data: [number, number, number], * a: [number, number], * d: [number, number, number], * e: $s$.test.types.InlineRecursiveConstGeneric, * }} c * @property {[number, number]} d * * @typedef {{ * ref_struct: $s$.test.types.SimpleStruct, * val: number, * }} InlineStruct * @property {$s$.test.types.SimpleStruct} ref_struct * @property {number} val * * @typedef {{ * demo: [string, boolean], * }} InlineTuple * @property {[string, boolean]} demo * * @typedef {{ * demo: [{ * demo: [string, boolean], * }, boolean], * }} InlineTuple2 * @property {[{ * demo: [string, boolean], * }, boolean]} demo * * @typedef {{ * inline_this: { * ref_struct: $s$.test.types.SimpleStruct, * val: number, * }, * dont_inline_this: $s$.test.types.RefStruct, * }} InlinerStruct * @property {{ * ref_struct: $s$.test.types.SimpleStruct, * val: number, * }} inline_this * @property {$s$.test.types.RefStruct} dont_inline_this * * @typedef {{ * a: number, * } & $s$.test.types.FlattenedInner} Inner * @property {number} a * * @typedef {{ * type: "A", * } & { [key in string]: string }} InternallyTaggedD * @property {{ * type: "A", * } & { [key in string]: string }} A * * @typedef {{ type: "A" }} InternallyTaggedE * @property {{ type: "A" }} A * * @typedef {{ type: "A" }} InternallyTaggedF * @property {{ type: "A" }} A * * @typedef {null} InternallyTaggedFInner * @property {null} A * * @typedef {{ type: "A" }} InternallyTaggedH * @property {{ type: "A" }} A * * @typedef {null} InternallyTaggedHInner * @property {null} "0" * * @typedef {{ * type: "A", * } & { type: "A" } | { type: "B" }} InternallyTaggedL * @property {{ * type: "A", * } & { type: "A" } | { type: "B" }} A * * @typedef {{ type: "A" } | { type: "B" }} InternallyTaggedLInner * @property {{ type: "A" }} A * @property {{ type: "B" }} B * * @typedef {{ type: "A" }} InternallyTaggedM * @property {{ type: "A" }} A * * @typedef {"A" | "B"} InternallyTaggedMInner * @property {"A"} A * @property {"B"} B * * @typedef {{ type: "A"; field: string } | { type: "B"; other: number }} InternallyTaggedWithAlias * @property {{ type: "A"; field: string }} A * @property {{ type: "B"; other: number }} B * * @typedef {{ * cause: null, * }} InvalidToValidType * @property {null} cause * * @typedef {({ A: { * a: string, * } }) & { B?: never } | ({ B: { * b: string, * } }) & { A?: never }} Issue221External * @property {{ A: { * a: string, * } }} A * @property {{ B: { * b: string, * } }} B * * @typedef {({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never }} Issue221UntaggedMixed * @property {{ a: string }} A * @property {{ b: string }} B * @property {{ values: { [key in string]: string } }} Unsafe * * @typedef {({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }} Issue221UntaggedSafe * @property {{ a: string }} A * @property {{ b: string }} B * * @typedef {{ * default_unity_arguments: string[], * }} Issue281 * @property {string[]} default_unity_arguments * * @typedef {{ * "test-ing": string, * }} KebabCase * @property {string} "test-ing" * * @typedef {({ Borrowed: T }) & { Owned?: never } | ({ Owned: T }) & { Borrowed?: never }} LifetimeGenericEnum * @property {{ Borrowed: T }} Borrowed * @property {{ Owned: T }} Owned * * @typedef {{ * borrowed: T[], * owned: T[], * }} LifetimeGenericStruct * @property {T[]} borrowed * @property {T[]} owned * * @typedef {{ event: "started"; data: { * projectName: string, * } } | { event: "progressTest"; data: { * projectName: string, * status: string, * progress: number, * } } | { event: "finished"; data: { * projectName: string, * } }} LoadProjectEvent * @property {{ event: "started"; data: { * projectName: string, * } }} started * @property {{ event: "progressTest"; data: { * projectName: string, * status: string, * progress: number, * } }} progressTest * @property {{ event: "finished"; data: { * projectName: string, * } }} finished * * @typedef {({ Demo: string }) & { Demo2?: never } | ({ Demo2: { * demo2: string, * } }) & { Demo?: never }} MacroEnum * @property {{ Demo: string }} Demo * @property {{ Demo2: { * demo2: string, * } }} Demo2 * * @typedef {string} MacroStruct * @property {string} "0" * * @typedef {{ * demo: string, * }} MacroStruct2 * @property {string} demo * * @typedef {T} MaybeValidKey * @property {T} "0" * * @typedef {Record} MyEmptyInput * * @typedef {({ A: string }) & { B?: never } | ({ B: number }) & { A?: never }} MyEnum * @property {{ A: string }} A * @property {{ B: number }} B * * @typedef {{ t: "Variant"; c: { * inner: $s$.test.types.First, * } }} MyEnumAdjacent * @property {{ t: "Variant"; c: { * inner: $s$.test.types.First, * } }} Variant * * @typedef {{ Variant: { * inner: $s$.test.types.First, * } }} MyEnumExternal * @property {{ Variant: { * inner: $s$.test.types.First, * } }} Variant * * @typedef {{ type: "Variant"; inner: $s$.test.types.First }} MyEnumTagged * @property {{ type: "Variant"; inner: $s$.test.types.First }} Variant * * @typedef {{ inner: $s$.test.types.First }} MyEnumUntagged * @property {{ inner: $s$.test.types.First }} Variant * * @typedef {{ * data: number[], * a: number[], * d: [number, number], * }} NamedConstGeneric * @property {number[]} data * @property {number[]} a * @property {[number, number]} d * * @typedef {{ * a: $s$.test.types.NamedConstGeneric, * b: $s$.test.types.NamedConstGeneric, * d: [number, number], * }} NamedConstGenericContainer * @property {$s$.test.types.NamedConstGeneric} a * @property {$s$.test.types.NamedConstGeneric} b * @property {[number, number]} d * * @typedef {{ type: "a"; value: string } | { type: "b"; value: number }} NestedEnum * @property {{ type: "a"; value: string }} a * @property {{ type: "b"; value: number }} b * * @typedef {{ t: "A"; c: string } | { t: "B" } | { t: "C"; c: { * a: string, * } } | { t: "D"; c: $s$.test.types.First }} Ninth * @property {{ t: "A"; c: string }} A * @property {{ t: "B" }} B * @property {{ t: "C"; c: { * a: string, * } }} C * @property {{ t: "D"; c: $s$.test.types.First }} D * * @typedef {string | null} NonOptional * @property {string | null} "0" * * @typedef {({ A?: string | null }) & { B?: never; C?: never } | ({ B: { * a: string | null, * } }) & { A?: never; C?: never } | ({ C: { * a?: string | null, * } }) & { A?: never; B?: never }} OptionalInEnum * @property {{ A?: string | null }} A * @property {{ B: { * a: string | null, * } }} B * @property {{ C: { * a?: string | null, * } }} C * * @typedef {string | null} OptionalOnNamedField * @property {string | null} ["0"] * * @typedef {{ * b: string | null, * }} OptionalOnTransparentNamedField * @property {string | null} b * * @typedef {{ * overriden_field: string, * }} OverridenStruct * @property {string} overriden_field * * @typedef {{ * first: Z, * second: A, * }} Pair * @property {Z} first * @property {A} second * * @typedef {{ * a: string, * }} PlaceholderInnerField * @property {string} a * * @typedef {{ * demo: $s$.test.types.Recursive, * }} Recursive * @property {$s$.test.types.Recursive} demo * * @typedef {{ A: { * demo: $s$.test.types.RecursiveInEnum, * } }} RecursiveInEnum * @property {{ A: { * demo: $s$.test.types.RecursiveInEnum, * } }} A * * @typedef {$s$.test.types.RecursiveInline} RecursiveInline * * @typedef {{ * demo: { [key in string]: $s$.test.types.RecursiveMapValue }, * }} RecursiveMapValue * @property {{ [key in string]: $s$.test.types.RecursiveMapValue }} demo * * @typedef {$s$.test.types.RecursiveInline} RecursiveTransparent * @property {$s$.test.types.RecursiveInline} "0" * * @typedef {$s$.test.types.TestEnum} RefStruct * @property {$s$.test.types.TestEnum} "0" * * @typedef {{ [key in string]: null }} Regular * @property {{ [key in string]: null }} "0" * * @typedef {"OneWord" | "Two words"} Rename * @property {"OneWord"} OneWord * @property {"Two words"} "Two words" * * @typedef {{ * "a/b": number, * }} RenameSerdeSpecialChar * @property {number} "a/b" * * @typedef {{ * "@odata.context": string, * }} RenameWithWeirdCharsField * @property {string} "@odata.context" * * @typedef {{ "@odata.context": string }} RenameWithWeirdCharsVariant * @property {{ "@odata.context": string }} "@odata.context" * * @typedef {{ * "": string, * "a\"b": string, * "a\\b": string, * "line\nbreak": string, * "line\u2028break": string, * "line\u2029break": string, * }} RenamedFieldKeys * @property {string} "" * @property {string} "a\"b" * @property {string} "a\\b" * @property {string} "line\nbreak" * @property {string} "line\u2028break" * @property {string} "line\u2029break" * * @typedef {"a-b"} RenamedVariantWithSkippedPayload * @property {"a-b"} "a-b" * * @typedef {{ * a: number, * }} Second * @property {number} a * * @typedef {{ * a: $s$.test.types.First, * b: $s$.test.types.Second, * }} Seventh * @property {$s$.test.types.First} a * @property {$s$.test.types.Second} b * * @typedef {{ * a: number, * b: string, * c: [number, string, number], * d: string[], * e: string | null, * }} SimpleStruct * @property {number} a * @property {string} b * @property {[number, string, number]} c * @property {string[]} d * @property {string | null} e * * Some single-line comment * * @typedef { * /** Some single-line comment */ * ({ A: number }) & { B?: never } | * /** Some single-line comment */ * ({ B: { * /** Some single-line comment */ * a: number, * } }) & { A?: never }} SingleLineComment * @property { * /** Some single-line comment */ * { A: number }} A - Some single-line comment * @property { * /** Some single-line comment */ * { B: { * /** Some single-line comment */ * a: number, * } }} B - Some single-line comment * * @typedef {{ * a: $s$.test.types.First, * b: $s$.test.types.First, * }} Sixth * @property {$s$.test.types.First} a * @property {$s$.test.types.First} b * * @typedef {{ * b: number, * }} SkipField * @property {number} b * * @typedef {({ A: Record }) & { B?: never } | ({ B: { * b: number, * } }) & { A?: never }} SkipNamedFieldInVariant * @property {{ A: Record }} A * @property {{ B: { * b: number, * } }} B * * @typedef {Record} SkipOnlyField * * @typedef {{ * a: number, * }} SkipStructFields * @property {number} a * * @typedef {"A" | { B: [number] }} SkipUnnamedFieldInVariant * @property {"A"} A * @property {{ B: [number] }} B * * @typedef {{ A: string }} SkipVariant * @property {{ A: string }} A * * @typedef {{ tag: "A"; data: string }} SkipVariant2 * @property {{ tag: "A"; data: string }} A * * @typedef {{ A: { * a: string, * } }} SkipVariant3 * @property {{ A: { * a: string, * } }} A * * @typedef {{ type: "A" } | { type: "B"; data: string }} SkippedFieldWithinVariant * @property {{ type: "A" }} A * @property {{ type: "B"; data: string }} B * * @typedef {{ * a: number, * }} SpectaSkipNonTypeField * @property {number} a * * @typedef {{ * string_ident: string, * u32_ident: number, * path: string, * tuple: [string, number], * }} SpectaTypeOverride * @property {string} string_ident * @property {number} u32_ident * @property {string} path * @property {[string, number]} tuple * * @typedef {{ * b: string, * }} Struct2 * @property {string} b * * @typedef {{ * t: "StructNew", * a: string, * }} StructNew * @property {"StructNew"} t * @property {string} a * * @typedef {{ * A: number, * B: number, * }} StructRenameAllUppercase * @property {number} A * @property {number} B * * @typedef {{ * field: string, * }} StructWithAlias * @property {string} field * * @typedef {{ * renamed_field: string, * }} StructWithAliasAndRename * @property {string} renamed_field * * @typedef {{ * field: string, * }} StructWithMultipleAliases * @property {string} field * * @typedef {{ * type: "TagOnStructWithInline", * a: $s$.test.types.First, * b: { * a: string, * }, * }} TagOnStructWithInline * @property {"TagOnStructWithInline"} type * @property {$s$.test.types.First} a * @property {{ * a: string, * }} b * * @typedef {string | "B" | { * a: string, * } | $s$.test.types.First} Tenth * @property {string} A * @property {"B"} B * @property {{ * a: string, * }} C * @property {$s$.test.types.First} D * * @typedef {never} TestCollectionRegister * * @typedef {"Unit" | ({ Single: number }) & { Multiple?: never; Struct?: never } | ({ Multiple: [number, number] }) & { Single?: never; Struct?: never } | ({ Struct: { * a: number, * } }) & { Multiple?: never; Single?: never }} TestEnum * @property {"Unit"} Unit * @property {{ Single: number }} Single * @property {{ Multiple: [number, number] }} Multiple * @property {{ Struct: { * a: number, * } }} Struct * * @typedef {{ * b: { [key in string]: string }, * c: $s$.test.types.First, * } & $s$.test.types.First} Third * @property {{ [key in string]: string }} b * @property {$s$.test.types.First} c * * @typedef {{ * a: string, * }} ToBeFlattened * @property {string} a * * @typedef {string} TransparentStruct * @property {string} "0" * * @typedef {$s$.test.types.TransparentTypeInner} TransparentType * @property {$s$.test.types.TransparentTypeInner} "0" * * @typedef {null} TransparentType2 * @property {null} "0" * * @typedef {{ * inner: string, * }} TransparentTypeInner * @property {string} inner * * @typedef {string} TransparentTypeWithOverride * @property {string} "0" * * @typedef {null} TransparentWithSkip * @property {null} "0" * * @typedef {string} TransparentWithSkip2 * @property {string} "0" * * @typedef {string} TransparentWithSkip3 * @property {string} "0" * * @typedef {[number[], [number[], number[]], [number[], number[], number[]]]} TupleNested * @property {number[]} "0" * @property {[number[], number[]]} "1" * @property {[number[], number[], number[]]} "2" * * @typedef {string} TupleStruct * @property {string} "0" * * @typedef {number} TupleStruct1 * @property {number} "0" * * @typedef {[number, boolean, string]} TupleStruct3 * @property {number} "0" * @property {boolean} "1" * @property {string} "2" * * @typedef {string} TupleStructWithRep * @property {string} "0" * * @typedef {null} Unit1 * * @typedef {Record} Unit2 * * @typedef {[]} Unit3 * * @typedef {null} Unit4 * @property {null} "0" * * @typedef {"A"} Unit5 * @property {"A"} A * * @typedef {{ A: null }} Unit6 * @property {{ A: null }} A * * @typedef {{ A: Record }} Unit7 * @property {{ A: Record }} A * * @typedef {"A" | "B" | "C"} UnitVariants * @property {"A"} A * @property {"B"} B * @property {"C"} C * * @typedef {string | number | { id: string } | [string, boolean]} UntaggedVariants * @property {string} A * @property {number} B * @property {number} C * @property {{ id: string }} D * @property {[string, boolean]} E * * @typedef {string | number} UntaggedVariantsKey * @property {string} A * @property {number} B * @property {number} C * * @typedef {null | number} UntaggedVariantsWithDuplicateBranches * @property {null} A * @property {number} B * @property {null} C * * @typedef {string | [number, string] | number} UntaggedVariantsWithoutValue * @property {string} A * @property {[number, string]} B * @property {number} C * * @typedef {({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }} UntaggedWithAlias * @property {{ field: string }} A * @property {{ other: number }} B * * @typedef {{ [key in $s$.test.types.MaybeValidKey]: null }} ValidMaybeValidKey * @property {{ [key in $s$.test.types.MaybeValidKey]: null }} "0" * * @typedef {{ [key in $s$.test.types.MaybeValidKey<$s$.test.types.MaybeValidKey>]: null }} ValidMaybeValidKeyNested * @property {{ [key in $s$.test.types.MaybeValidKey<$s$.test.types.MaybeValidKey>]: null }} "0" */ export namespace type_type { /** * @typedef {never} Type */ } } } export namespace tests { export namespace tests { export namespace types { /** * @typedef {{ * i8: number, * i16: number, * i32: number, * u8: number, * u16: number, * u32: number, * f32: number, * f64: number, * bool: boolean, * char: string, * "Range": $s$.std.ops.Range, * "RangeInclusive": $s$.std.ops.RangeInclusive, * "()": null, * "(String, i32)": [string, number], * "(String, i32, bool)": [string, number, boolean], * "((String, i32), (bool, char, bool), ())": [[string, number], [boolean, string, boolean], null], * "(bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool)": [boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean], * "(Vec, Vec)": [number[], boolean[]], * String: string, * PathBuf: string, * IpAddr: string, * Ipv4Addr: string, * Ipv6Addr: string, * SocketAddr: string, * SocketAddrV4: string, * SocketAddrV6: string, * "Cow<'static, str>": string, * "Cow<'static, i32>": number, * "&'static str": string, * "&'static bool": boolean, * "&'static i32": number, * "Vec": number[], * "&'static [i32]": number[], * "&'static [i32; 3]": [number, number, number], * "[i32; 3]": [number, number, number], * "Vec": $s$.test.types.MyEnum[], * "&'static [MyEnum]": $s$.test.types.MyEnum[], * "&'static [MyEnum; 6]": [$s$.test.types.MyEnum, $s$.test.types.MyEnum, $s$.test.types.MyEnum, $s$.test.types.MyEnum, $s$.test.types.MyEnum, $s$.test.types.MyEnum], * "[MyEnum; 2]": [$s$.test.types.MyEnum, $s$.test.types.MyEnum], * "&'static [i32; 1]": [number], * "&'static [i32; 0]": [], * "Option": number | null, * "Option<()>": null, * "Option>": number[] | null, * "Result": $s$.std.result.Result, * "Vec>>": (number | null)[], * "Option>>": number[] | null, * "[Vec; 3]": [string[], string[], string[]], * "Option>": string | null, * "Option>>": string | null, * "PhantomData<()>": null, * "PhantomData": null, * Infallible: never, * Unit1: $s$.test.types.Unit1, * Unit2: $s$.test.types.Unit2, * Unit3: $s$.test.types.Unit3, * Unit4: $s$.test.types.Unit4, * Unit5: $s$.test.types.Unit5, * Unit6: $s$.test.types.Unit6, * Unit7: $s$.test.types.Unit7, * SimpleStruct: $s$.test.types.SimpleStruct, * TupleStruct1: $s$.test.types.TupleStruct1, * TupleStruct3: $s$.test.types.TupleStruct3, * TestEnum: $s$.test.types.TestEnum, * RefStruct: $s$.test.types.RefStruct, * InlinerStruct: $s$.test.types.InlinerStruct, * "GenericStruct": $s$.test.types.GenericStruct, * "GenericStruct": $s$.test.types.GenericStruct, * FlattenEnumStruct: $s$.test.types.FlattenEnumStruct, * OverridenStruct: $s$.test.types.OverridenStruct, * HasGenericAlias: $s$.test.types.HasGenericAlias, * EnumMacroAttributes: $s$.test.types.EnumMacroAttributes, * InlineEnumField: $s$.test.types.InlineEnumField, * InlineOptionalType: $s$.test.types.InlineOptionalType, * Rename: $s$.test.types.Rename, * TransparentType: $s$.test.types.TransparentType, * TransparentType2: $s$.test.types.TransparentType2, * TransparentTypeWithOverride: $s$.test.types.TransparentTypeWithOverride, * "[Option; 3]": [(number | null), (number | null), (number | null)], * "HashMap": Partial<{ [key in $s$.test.types.BasicEnum]: null }>, * "HashMap": Partial<{ [key in $s$.test.types.BasicEnum]: number }>, * "Option>>>": number | null, * "Vec": $s$.test.types.PlaceholderInnerField[], * EnumReferenceRecordKey: $s$.test.types.EnumReferenceRecordKey, * FlattenOnNestedEnum: $s$.test.types.FlattenOnNestedEnum, * MyEmptyInput: $s$.test.types.MyEmptyInput, * "(String)": string, * "(String,)": [string], * ExtraBracketsInTupleVariant: $s$.test.types.ExtraBracketsInTupleVariant, * ExtraBracketsInUnnamedStruct: $s$.test.types.ExtraBracketsInUnnamedStruct, * "Vec": $s$.test.types.MyEnum[], * InlineTuple: $s$.test.types.InlineTuple, * InlineTuple2: $s$.test.types.InlineTuple2, * "Box": string, * "Box": string, * SkippedFieldWithinVariant: $s$.test.types.SkippedFieldWithinVariant, * KebabCase: $s$.test.types.KebabCase, * "&[&str]": string[], * "Issue281<'_>": $s$.test.types.Issue281, * "LifetimeGenericStruct<'_, i32>": $s$.test.types.LifetimeGenericStruct, * "LifetimeGenericEnum<'_, i32>": $s$.test.types.LifetimeGenericEnum, * RenameWithWeirdCharsField: $s$.test.types.RenameWithWeirdCharsField, * RenameWithWeirdCharsVariant: $s$.test.types.RenameWithWeirdCharsVariant, * RenamedFieldKeys: $s$.test.types.RenamedFieldKeys, * RenamedVariantWithSkippedPayload: $s$.test.types.RenamedVariantWithSkippedPayload, * "type_type::Type": $s$.test.types.type_type.Type, * ActualType: $s$.test.types.ActualType, * SpectaTypeOverride: $s$.test.types.SpectaTypeOverride, * ContainerTypeOverrideStruct: $s$.test.types.ContainerTypeOverrideStruct, * ContainerTypeOverrideEnum: $s$.test.types.ContainerTypeOverrideEnum, * "ContainerTypeOverrideGeneric>": $s$.test.types.ContainerTypeOverrideGeneric, * "ContainerTypeOverrideToGeneric": $s$.test.types.ContainerTypeOverrideToGeneric, * ContainerTypeOverrideTuple: $s$.test.types.ContainerTypeOverrideTuple, * "ContainerTypeOverrideTupleGeneric": $s$.test.types.ContainerTypeOverrideTupleGeneric, * InvalidToValidType: $s$.test.types.InvalidToValidType, * TupleStruct: $s$.test.types.TupleStruct, * TupleStructWithRep: $s$.test.types.TupleStructWithRep, * "GenericTupleStruct": $s$.test.types.GenericTupleStruct, * BracedStruct: $s$.test.types.BracedStruct, * Struct: $s$.test.types.StructNew, * Struct2: $s$.test.types.Struct2, * Enum: $s$.test.types.Enum, * Enum2: $s$.test.types.Enum2, * Enum3: $s$.test.types.Enum3, * StructRenameAllUppercase: $s$.test.types.StructRenameAllUppercase, * RenameSerdeSpecialChar: $s$.test.types.RenameSerdeSpecialChar, * EnumRenameAllUppercase: $s$.test.types.EnumRenameAllUppercase, * Recursive: $s$.test.types.Recursive, * RecursiveMapValue: $s$.test.types.RecursiveMapValue, * RecursiveTransparent: $s$.test.types.RecursiveTransparent, * RecursiveInEnum: $s$.test.types.RecursiveInEnum, * NonOptional: $s$.test.types.NonOptional, * OptionalOnNamedField: $s$.test.types.OptionalOnNamedField, * OptionalOnTransparentNamedField: $s$.test.types.OptionalOnTransparentNamedField, * OptionalInEnum: $s$.test.types.OptionalInEnum, * UntaggedVariants: $s$.test.types.UntaggedVariants, * UntaggedVariantsWithoutValue: $s$.test.types.UntaggedVariantsWithoutValue, * UntaggedVariantsWithDuplicateBranches: $s$.test.types.UntaggedVariantsWithDuplicateBranches, * "HashMap": { [key in string]: null }, * Regular: $s$.test.types.Regular, * "HashMap": { [key in never]: null }, * "HashMap": { [key in $s$.test.types.TransparentStruct]: null }, * "HashMap": Partial<{ [key in $s$.test.types.UnitVariants]: null }>, * "HashMap": Partial<{ [key in $s$.test.types.UntaggedVariantsKey]: null }>, * ValidMaybeValidKey: $s$.test.types.ValidMaybeValidKey, * ValidMaybeValidKeyNested: $s$.test.types.ValidMaybeValidKeyNested, * MacroStruct: $s$.test.types.MacroStruct, * MacroStruct2: $s$.test.types.MacroStruct2, * MacroEnum: $s$.test.types.MacroEnum, * DeprecatedType: $s$.test.types.DeprecatedType, * DeprecatedTypeWithMsg: $s$.test.types.DeprecatedTypeWithMsg, * DeprecatedTypeWithMsg2: $s$.test.types.DeprecatedTypeWithMsg2, * DeprecatedFields: $s$.test.types.DeprecatedFields, * DeprecatedTupleVariant: $s$.test.types.DeprecatedTupleVariant, * DeprecatedEnumVariants: $s$.test.types.DeprecatedEnumVariants, * CommentedStruct: $s$.test.types.CommentedStruct, * CommentedEnum: $s$.test.types.CommentedEnum, * SingleLineComment: $s$.test.types.SingleLineComment, * NonGeneric: $s$.test.types.Demo, * "HalfGenericA": $s$.test.types.Demo, * "HalfGenericB": $s$.test.types.Demo, * "FullGeneric": $s$.test.types.Demo, * "Another": $s$.test.types.Demo, * "MapA": { [key in string]: number }, * "MapB": { [key in number]: string }, * "MapC": { [key in string]: $s$.test.types.AGenericStruct }, * "AGenericStruct": $s$.test.types.AGenericStruct, * A: $s$.test.types.A, * DoubleFlattened: $s$.test.types.DoubleFlattened, * FlattenedInner: $s$.test.types.FlattenedInner, * BoxFlattened: $s$.test.types.BoxFlattened, * BoxInline: $s$.test.types.BoxInline, * First: $s$.test.types.First, * Second: $s$.test.types.Second, * Third: $s$.test.types.Third, * Fourth: $s$.test.types.Fourth, * TagOnStructWithInline: $s$.test.types.TagOnStructWithInline, * Sixth: $s$.test.types.Sixth, * Seventh: $s$.test.types.Seventh, * Eight: $s$.test.types.Eight, * Ninth: $s$.test.types.Ninth, * Tenth: $s$.test.types.Tenth, * MyEnumTagged: $s$.test.types.MyEnumTagged, * MyEnumExternal: $s$.test.types.MyEnumExternal, * MyEnumAdjacent: $s$.test.types.MyEnumAdjacent, * MyEnumUntagged: $s$.test.types.MyEnumUntagged, * EmptyStruct: $s$.test.types.EmptyStruct, * EmptyStructWithTag: $s$.test.types.EmptyStructWithTag, * AdjacentlyTagged: $s$.test.types.AdjacentlyTagged, * LoadProjectEvent: $s$.test.types.LoadProjectEvent, * ExternallyTagged: $s$.test.types.ExternallyTagged, * Issue221External: $s$.test.types.Issue221External, * InternallyTaggedD: $s$.test.types.InternallyTaggedD, * InternallyTaggedE: $s$.test.types.InternallyTaggedE, * InternallyTaggedF: $s$.test.types.InternallyTaggedF, * InternallyTaggedH: $s$.test.types.InternallyTaggedH, * InternallyTaggedL: $s$.test.types.InternallyTaggedL, * InternallyTaggedM: $s$.test.types.InternallyTaggedM, * StructWithAlias: $s$.test.types.StructWithAlias, * StructWithMultipleAliases: $s$.test.types.StructWithMultipleAliases, * StructWithAliasAndRename: $s$.test.types.StructWithAliasAndRename, * EnumWithVariantAlias: $s$.test.types.EnumWithVariantAlias, * EnumWithMultipleVariantAliases: $s$.test.types.EnumWithMultipleVariantAliases, * EnumWithVariantAliasAndRename: $s$.test.types.EnumWithVariantAliasAndRename, * InternallyTaggedWithAlias: $s$.test.types.InternallyTaggedWithAlias, * AdjacentlyTaggedWithAlias: $s$.test.types.AdjacentlyTaggedWithAlias, * UntaggedWithAlias: $s$.test.types.UntaggedWithAlias, * Issue221UntaggedSafe: $s$.test.types.Issue221UntaggedSafe, * Issue221UntaggedMixed: $s$.test.types.Issue221UntaggedMixed, * EmptyEnum: $s$.test.types.EmptyEnum, * EmptyEnumTagged: $s$.test.types.EmptyEnumTagged, * EmptyEnumTaggedWContent: $s$.test.types.EmptyEnumTaggedWContent, * EmptyEnumUntagged: $s$.test.types.EmptyEnumUntagged, * SkipOnlyField: $s$.test.types.SkipOnlyField, * SkipField: $s$.test.types.SkipField, * SkipVariant: $s$.test.types.SkipVariant, * SkipUnnamedFieldInVariant: $s$.test.types.SkipUnnamedFieldInVariant, * SkipNamedFieldInVariant: $s$.test.types.SkipNamedFieldInVariant, * TransparentWithSkip: $s$.test.types.TransparentWithSkip, * TransparentWithSkip2: $s$.test.types.TransparentWithSkip2, * TransparentWithSkip3: $s$.test.types.TransparentWithSkip3, * SkipVariant2: $s$.test.types.SkipVariant2, * SkipVariant3: $s$.test.types.SkipVariant3, * SkipStructFields: $s$.test.types.SkipStructFields, * SpectaSkipNonTypeField: $s$.test.types.SpectaSkipNonTypeField, * FlattenA: $s$.test.types.FlattenA, * FlattenB: $s$.test.types.FlattenB, * FlattenC: $s$.test.types.FlattenC, * FlattenD: $s$.test.types.FlattenD, * FlattenE: $s$.test.types.FlattenE, * FlattenF: $s$.test.types.FlattenF, * FlattenG: $s$.test.types.FlattenG, * TupleNested: $s$.test.types.TupleNested, * "Generic1<()>": $s$.test.types.Generic1, * "GenericAutoBound<()>": $s$.test.types.GenericAutoBound, * "GenericAutoBound2<()>": $s$.test.types.GenericAutoBound2, * Container1: $s$.test.types.Container1, * "Generic2<(), String, i32>": $s$.test.types.Generic2, * "GenericNewType1<()>": $s$.test.types.GenericNewType1, * "GenericTuple<()>": $s$.test.types.GenericTuple, * "GenericStruct2<()>": $s$.test.types.GenericStruct2, * "InlineGenericNewtype": string, * "InlineGenericNested": [string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | ({ Unnamed: string }) & { Named?: never } | ({ Named: { * value: string, * } }) & { Unnamed?: never }], * "InlineFlattenGenericsG<()>": $s$.test.types.InlineFlattenGenericsG, * InlineFlattenGenerics: $s$.test.types.InlineFlattenGenerics, * GenericDefault: $s$.test.types.GenericDefault, * ChainedGenericDefault: $s$.test.types.ChainedGenericDefault, * "ChainedGenericDefault": $s$.test.types.ChainedGenericDefault, * "ChainedGenericDefault": $s$.test.types.ChainedGenericDefault, * "ChainedGenericDefault": $s$.test.types.ChainedGenericDefault, * GenericDefaultSkipped: $s$.test.types.GenericDefaultSkipped, * GenericDefaultSkippedNonType: $s$.test.types.GenericDefaultSkippedNonType, * GenericParameterOrderPreserved: $s$.test.types.GenericParameterOrderPreserved, * ConstGenericInNonConstContainer: $s$.test.types.ConstGenericInNonConstContainer, * ConstGenericInConstContainer: $s$.test.types.ConstGenericInConstContainer, * NamedConstGenericContainer: $s$.test.types.NamedConstGenericContainer, * InlineConstGenericContainer: $s$.test.types.InlineConstGenericContainer, * InlineRecursiveConstGenericContainer: $s$.test.types.InlineRecursiveConstGenericContainer, * TestCollectionRegister: $s$.test.types.TestCollectionRegister, * TestCollectionRegister: $s$.test.types.TestCollectionRegister, * }} Primitives * @property {number} i8 * @property {number} i16 * @property {number} i32 * @property {number} u8 * @property {number} u16 * @property {number} u32 * @property {number} f32 * @property {number} f64 * @property {boolean} bool * @property {string} char * @property {$s$.std.ops.Range} "Range" * @property {$s$.std.ops.RangeInclusive} "RangeInclusive" * @property {null} "()" * @property {[string, number]} "(String, i32)" * @property {[string, number, boolean]} "(String, i32, bool)" * @property {[[string, number], [boolean, string, boolean], null]} "((String, i32), (bool, char, bool), ())" * @property {[boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean]} "(bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool)" * @property {[number[], boolean[]]} "(Vec, Vec)" * @property {string} String * @property {string} PathBuf * @property {string} IpAddr * @property {string} Ipv4Addr * @property {string} Ipv6Addr * @property {string} SocketAddr * @property {string} SocketAddrV4 * @property {string} SocketAddrV6 * @property {string} "Cow<'static, str>" * @property {number} "Cow<'static, i32>" * @property {string} "&'static str" * @property {boolean} "&'static bool" * @property {number} "&'static i32" * @property {number[]} "Vec" * @property {number[]} "&'static [i32]" * @property {[number, number, number]} "&'static [i32; 3]" * @property {[number, number, number]} "[i32; 3]" * @property {$s$.test.types.MyEnum[]} "Vec" * @property {$s$.test.types.MyEnum[]} "&'static [MyEnum]" * @property {[$s$.test.types.MyEnum, $s$.test.types.MyEnum, $s$.test.types.MyEnum, $s$.test.types.MyEnum, $s$.test.types.MyEnum, $s$.test.types.MyEnum]} "&'static [MyEnum; 6]" * @property {[$s$.test.types.MyEnum, $s$.test.types.MyEnum]} "[MyEnum; 2]" * @property {[number]} "&'static [i32; 1]" * @property {[]} "&'static [i32; 0]" * @property {number | null} "Option" * @property {null} "Option<()>" * @property {number[] | null} "Option>" * @property {$s$.std.result.Result} "Result" * @property {(number | null)[]} "Vec>>" * @property {number[] | null} "Option>>" * @property {[string[], string[], string[]]} "[Vec; 3]" * @property {string | null} "Option>" * @property {string | null} "Option>>" * @property {null} "PhantomData<()>" * @property {null} "PhantomData" * @property {never} Infallible * @property {$s$.test.types.Unit1} Unit1 * @property {$s$.test.types.Unit2} Unit2 * @property {$s$.test.types.Unit3} Unit3 * @property {$s$.test.types.Unit4} Unit4 * @property {$s$.test.types.Unit5} Unit5 * @property {$s$.test.types.Unit6} Unit6 * @property {$s$.test.types.Unit7} Unit7 * @property {$s$.test.types.SimpleStruct} SimpleStruct * @property {$s$.test.types.TupleStruct1} TupleStruct1 * @property {$s$.test.types.TupleStruct3} TupleStruct3 * @property {$s$.test.types.TestEnum} TestEnum * @property {$s$.test.types.RefStruct} RefStruct * @property {$s$.test.types.InlinerStruct} InlinerStruct * @property {$s$.test.types.GenericStruct} "GenericStruct" * @property {$s$.test.types.GenericStruct} "GenericStruct" * @property {$s$.test.types.FlattenEnumStruct} FlattenEnumStruct * @property {$s$.test.types.OverridenStruct} OverridenStruct * @property {$s$.test.types.HasGenericAlias} HasGenericAlias * @property {$s$.test.types.EnumMacroAttributes} EnumMacroAttributes * @property {$s$.test.types.InlineEnumField} InlineEnumField * @property {$s$.test.types.InlineOptionalType} InlineOptionalType * @property {$s$.test.types.Rename} Rename * @property {$s$.test.types.TransparentType} TransparentType * @property {$s$.test.types.TransparentType2} TransparentType2 * @property {$s$.test.types.TransparentTypeWithOverride} TransparentTypeWithOverride * @property {[(number | null), (number | null), (number | null)]} "[Option; 3]" * @property {Partial<{ [key in $s$.test.types.BasicEnum]: null }>} "HashMap" * @property {Partial<{ [key in $s$.test.types.BasicEnum]: number }>} "HashMap" * @property {number | null} "Option>>>" * @property {$s$.test.types.PlaceholderInnerField[]} "Vec" * @property {$s$.test.types.EnumReferenceRecordKey} EnumReferenceRecordKey * @property {$s$.test.types.FlattenOnNestedEnum} FlattenOnNestedEnum * @property {$s$.test.types.MyEmptyInput} MyEmptyInput * @property {string} "(String)" * @property {[string]} "(String,)" * @property {$s$.test.types.ExtraBracketsInTupleVariant} ExtraBracketsInTupleVariant * @property {$s$.test.types.ExtraBracketsInUnnamedStruct} ExtraBracketsInUnnamedStruct * @property {$s$.test.types.MyEnum[]} "Vec" * @property {$s$.test.types.InlineTuple} InlineTuple * @property {$s$.test.types.InlineTuple2} InlineTuple2 * @property {string} "Box" * @property {string} "Box" * @property {$s$.test.types.SkippedFieldWithinVariant} SkippedFieldWithinVariant * @property {$s$.test.types.KebabCase} KebabCase * @property {string[]} "&[&str]" * @property {$s$.test.types.Issue281} "Issue281<'_>" * @property {$s$.test.types.LifetimeGenericStruct} "LifetimeGenericStruct<'_, i32>" * @property {$s$.test.types.LifetimeGenericEnum} "LifetimeGenericEnum<'_, i32>" * @property {$s$.test.types.RenameWithWeirdCharsField} RenameWithWeirdCharsField * @property {$s$.test.types.RenameWithWeirdCharsVariant} RenameWithWeirdCharsVariant * @property {$s$.test.types.RenamedFieldKeys} RenamedFieldKeys * @property {$s$.test.types.RenamedVariantWithSkippedPayload} RenamedVariantWithSkippedPayload * @property {$s$.test.types.type_type.Type} "type_type::Type" * @property {$s$.test.types.ActualType} ActualType * @property {$s$.test.types.SpectaTypeOverride} SpectaTypeOverride * @property {$s$.test.types.ContainerTypeOverrideStruct} ContainerTypeOverrideStruct * @property {$s$.test.types.ContainerTypeOverrideEnum} ContainerTypeOverrideEnum * @property {$s$.test.types.ContainerTypeOverrideGeneric} "ContainerTypeOverrideGeneric>" * @property {$s$.test.types.ContainerTypeOverrideToGeneric} "ContainerTypeOverrideToGeneric" * @property {$s$.test.types.ContainerTypeOverrideTuple} ContainerTypeOverrideTuple * @property {$s$.test.types.ContainerTypeOverrideTupleGeneric} "ContainerTypeOverrideTupleGeneric" * @property {$s$.test.types.InvalidToValidType} InvalidToValidType * @property {$s$.test.types.TupleStruct} TupleStruct * @property {$s$.test.types.TupleStructWithRep} TupleStructWithRep * @property {$s$.test.types.GenericTupleStruct} "GenericTupleStruct" * @property {$s$.test.types.BracedStruct} BracedStruct * @property {$s$.test.types.StructNew} Struct * @property {$s$.test.types.Struct2} Struct2 * @property {$s$.test.types.Enum} Enum * @property {$s$.test.types.Enum2} Enum2 * @property {$s$.test.types.Enum3} Enum3 * @property {$s$.test.types.StructRenameAllUppercase} StructRenameAllUppercase * @property {$s$.test.types.RenameSerdeSpecialChar} RenameSerdeSpecialChar * @property {$s$.test.types.EnumRenameAllUppercase} EnumRenameAllUppercase * @property {$s$.test.types.Recursive} Recursive * @property {$s$.test.types.RecursiveMapValue} RecursiveMapValue * @property {$s$.test.types.RecursiveTransparent} RecursiveTransparent * @property {$s$.test.types.RecursiveInEnum} RecursiveInEnum * @property {$s$.test.types.NonOptional} NonOptional * @property {$s$.test.types.OptionalOnNamedField} OptionalOnNamedField * @property {$s$.test.types.OptionalOnTransparentNamedField} OptionalOnTransparentNamedField * @property {$s$.test.types.OptionalInEnum} OptionalInEnum * @property {$s$.test.types.UntaggedVariants} UntaggedVariants * @property {$s$.test.types.UntaggedVariantsWithoutValue} UntaggedVariantsWithoutValue * @property {$s$.test.types.UntaggedVariantsWithDuplicateBranches} UntaggedVariantsWithDuplicateBranches * @property {{ [key in string]: null }} "HashMap" * @property {$s$.test.types.Regular} Regular * @property {{ [key in never]: null }} "HashMap" * @property {{ [key in $s$.test.types.TransparentStruct]: null }} "HashMap" * @property {Partial<{ [key in $s$.test.types.UnitVariants]: null }>} "HashMap" * @property {Partial<{ [key in $s$.test.types.UntaggedVariantsKey]: null }>} "HashMap" * @property {$s$.test.types.ValidMaybeValidKey} ValidMaybeValidKey * @property {$s$.test.types.ValidMaybeValidKeyNested} ValidMaybeValidKeyNested * @property {$s$.test.types.MacroStruct} MacroStruct * @property {$s$.test.types.MacroStruct2} MacroStruct2 * @property {$s$.test.types.MacroEnum} MacroEnum * @property {$s$.test.types.DeprecatedType} DeprecatedType * @property {$s$.test.types.DeprecatedTypeWithMsg} DeprecatedTypeWithMsg * @property {$s$.test.types.DeprecatedTypeWithMsg2} DeprecatedTypeWithMsg2 * @property {$s$.test.types.DeprecatedFields} DeprecatedFields * @property {$s$.test.types.DeprecatedTupleVariant} DeprecatedTupleVariant * @property {$s$.test.types.DeprecatedEnumVariants} DeprecatedEnumVariants * @property {$s$.test.types.CommentedStruct} CommentedStruct * @property {$s$.test.types.CommentedEnum} CommentedEnum * @property {$s$.test.types.SingleLineComment} SingleLineComment * @property {$s$.test.types.Demo} NonGeneric * @property {$s$.test.types.Demo} "HalfGenericA" * @property {$s$.test.types.Demo} "HalfGenericB" * @property {$s$.test.types.Demo} "FullGeneric" * @property {$s$.test.types.Demo} "Another" * @property {{ [key in string]: number }} "MapA" * @property {{ [key in number]: string }} "MapB" * @property {{ [key in string]: $s$.test.types.AGenericStruct }} "MapC" * @property {$s$.test.types.AGenericStruct} "AGenericStruct" * @property {$s$.test.types.A} A * @property {$s$.test.types.DoubleFlattened} DoubleFlattened * @property {$s$.test.types.FlattenedInner} FlattenedInner * @property {$s$.test.types.BoxFlattened} BoxFlattened * @property {$s$.test.types.BoxInline} BoxInline * @property {$s$.test.types.First} First * @property {$s$.test.types.Second} Second * @property {$s$.test.types.Third} Third * @property {$s$.test.types.Fourth} Fourth * @property {$s$.test.types.TagOnStructWithInline} TagOnStructWithInline * @property {$s$.test.types.Sixth} Sixth * @property {$s$.test.types.Seventh} Seventh * @property {$s$.test.types.Eight} Eight * @property {$s$.test.types.Ninth} Ninth * @property {$s$.test.types.Tenth} Tenth * @property {$s$.test.types.MyEnumTagged} MyEnumTagged * @property {$s$.test.types.MyEnumExternal} MyEnumExternal * @property {$s$.test.types.MyEnumAdjacent} MyEnumAdjacent * @property {$s$.test.types.MyEnumUntagged} MyEnumUntagged * @property {$s$.test.types.EmptyStruct} EmptyStruct * @property {$s$.test.types.EmptyStructWithTag} EmptyStructWithTag * @property {$s$.test.types.AdjacentlyTagged} AdjacentlyTagged * @property {$s$.test.types.LoadProjectEvent} LoadProjectEvent * @property {$s$.test.types.ExternallyTagged} ExternallyTagged * @property {$s$.test.types.Issue221External} Issue221External * @property {$s$.test.types.InternallyTaggedD} InternallyTaggedD * @property {$s$.test.types.InternallyTaggedE} InternallyTaggedE * @property {$s$.test.types.InternallyTaggedF} InternallyTaggedF * @property {$s$.test.types.InternallyTaggedH} InternallyTaggedH * @property {$s$.test.types.InternallyTaggedL} InternallyTaggedL * @property {$s$.test.types.InternallyTaggedM} InternallyTaggedM * @property {$s$.test.types.StructWithAlias} StructWithAlias * @property {$s$.test.types.StructWithMultipleAliases} StructWithMultipleAliases * @property {$s$.test.types.StructWithAliasAndRename} StructWithAliasAndRename * @property {$s$.test.types.EnumWithVariantAlias} EnumWithVariantAlias * @property {$s$.test.types.EnumWithMultipleVariantAliases} EnumWithMultipleVariantAliases * @property {$s$.test.types.EnumWithVariantAliasAndRename} EnumWithVariantAliasAndRename * @property {$s$.test.types.InternallyTaggedWithAlias} InternallyTaggedWithAlias * @property {$s$.test.types.AdjacentlyTaggedWithAlias} AdjacentlyTaggedWithAlias * @property {$s$.test.types.UntaggedWithAlias} UntaggedWithAlias * @property {$s$.test.types.Issue221UntaggedSafe} Issue221UntaggedSafe * @property {$s$.test.types.Issue221UntaggedMixed} Issue221UntaggedMixed * @property {$s$.test.types.EmptyEnum} EmptyEnum * @property {$s$.test.types.EmptyEnumTagged} EmptyEnumTagged * @property {$s$.test.types.EmptyEnumTaggedWContent} EmptyEnumTaggedWContent * @property {$s$.test.types.EmptyEnumUntagged} EmptyEnumUntagged * @property {$s$.test.types.SkipOnlyField} SkipOnlyField * @property {$s$.test.types.SkipField} SkipField * @property {$s$.test.types.SkipVariant} SkipVariant * @property {$s$.test.types.SkipUnnamedFieldInVariant} SkipUnnamedFieldInVariant * @property {$s$.test.types.SkipNamedFieldInVariant} SkipNamedFieldInVariant * @property {$s$.test.types.TransparentWithSkip} TransparentWithSkip * @property {$s$.test.types.TransparentWithSkip2} TransparentWithSkip2 * @property {$s$.test.types.TransparentWithSkip3} TransparentWithSkip3 * @property {$s$.test.types.SkipVariant2} SkipVariant2 * @property {$s$.test.types.SkipVariant3} SkipVariant3 * @property {$s$.test.types.SkipStructFields} SkipStructFields * @property {$s$.test.types.SpectaSkipNonTypeField} SpectaSkipNonTypeField * @property {$s$.test.types.FlattenA} FlattenA * @property {$s$.test.types.FlattenB} FlattenB * @property {$s$.test.types.FlattenC} FlattenC * @property {$s$.test.types.FlattenD} FlattenD * @property {$s$.test.types.FlattenE} FlattenE * @property {$s$.test.types.FlattenF} FlattenF * @property {$s$.test.types.FlattenG} FlattenG * @property {$s$.test.types.TupleNested} TupleNested * @property {$s$.test.types.Generic1} "Generic1<()>" * @property {$s$.test.types.GenericAutoBound} "GenericAutoBound<()>" * @property {$s$.test.types.GenericAutoBound2} "GenericAutoBound2<()>" * @property {$s$.test.types.Container1} Container1 * @property {$s$.test.types.Generic2} "Generic2<(), String, i32>" * @property {$s$.test.types.GenericNewType1} "GenericNewType1<()>" * @property {$s$.test.types.GenericTuple} "GenericTuple<()>" * @property {$s$.test.types.GenericStruct2} "GenericStruct2<()>" * @property {string} "InlineGenericNewtype" * @property {[string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | ({ Unnamed: string }) & { Named?: never } | ({ Named: { * value: string, * } }) & { Unnamed?: never }]} "InlineGenericNested" * @property {$s$.test.types.InlineFlattenGenericsG} "InlineFlattenGenericsG<()>" * @property {$s$.test.types.InlineFlattenGenerics} InlineFlattenGenerics * @property {$s$.test.types.GenericDefault} GenericDefault * @property {$s$.test.types.ChainedGenericDefault} ChainedGenericDefault * @property {$s$.test.types.ChainedGenericDefault} "ChainedGenericDefault" * @property {$s$.test.types.ChainedGenericDefault} "ChainedGenericDefault" * @property {$s$.test.types.ChainedGenericDefault} "ChainedGenericDefault" * @property {$s$.test.types.GenericDefaultSkipped} GenericDefaultSkipped * @property {$s$.test.types.GenericDefaultSkippedNonType} GenericDefaultSkippedNonType * @property {$s$.test.types.GenericParameterOrderPreserved} GenericParameterOrderPreserved * @property {$s$.test.types.ConstGenericInNonConstContainer} ConstGenericInNonConstContainer * @property {$s$.test.types.ConstGenericInConstContainer} ConstGenericInConstContainer * @property {$s$.test.types.NamedConstGenericContainer} NamedConstGenericContainer * @property {$s$.test.types.InlineConstGenericContainer} InlineConstGenericContainer * @property {$s$.test.types.InlineRecursiveConstGenericContainer} InlineRecursiveConstGenericContainer * @property {$s$.test.types.TestCollectionRegister} TestCollectionRegister * @property {$s$.test.types.TestCollectionRegister} TestCollectionRegister */ } } } } export import std = $s$.std; export import test = $s$.test; export import tests = $s$.tests; ════════════════════════════════════════ ================================================ FILE: tests/tests/snapshots/test__jsdoc__jsdoc-export-to-namespaces-serde_phases.snap ================================================ --- source: tests/tests/jsdoc.rs expression: output --- jsdoc-export-to-namespaces-serde_phases (71704 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. namespace $s$ { export namespace std { export namespace ops { /** * @typedef {{ * start: T, * end: T, * }} Range * @property {T} start * @property {T} end * * @typedef {{ * start: T, * end: T, * }} RangeInclusive * @property {T} start * @property {T} end */ } export namespace result { /** * @typedef {{ * ok: T, * err: E, * }} Result * @property {T} ok * @property {E} err */ } } export namespace test { export namespace types { /** * @typedef {{ * a: $s$.test.types.B, * b: { * b: number, * }, * c: $s$.test.types.B, * d: { * flattened: number, * }, * e: { * generic_flattened: number, * }, * }} A * @property {$s$.test.types.B} a * @property {{ * b: number, * }} b * @property {$s$.test.types.B} c * @property {{ * flattened: number, * }} d * @property {{ * generic_flattened: number, * }} e * * @typedef {{ * field: $s$.test.types.Demo, * }} AGenericStruct * @property {$s$.test.types.Demo} field * * @typedef {{ * a: $s$.test.types.GenericType, * }} ActualType * @property {$s$.test.types.GenericType} a * * @typedef {{ t: "A" } | { t: "B"; c: { * id: string, * method: string, * } } | { t: "C"; c: string }} AdjacentlyTagged * @property {{ t: "A" }} A * @property {{ t: "B"; c: { * id: string, * method: string, * } }} B * @property {{ t: "C"; c: string }} C * * @typedef {{ type: "A"; data: { * field: string, * } } | { type: "B"; data: { * other: number, * } }} AdjacentlyTaggedWithAlias * @property {{ type: "A"; data: { * field: string, * } }} A * @property {{ type: "B"; data: { * other: number, * } }} B * * @typedef {{ * b: number, * }} B * @property {number} b * * @typedef {"A" | "B"} BasicEnum * @property {"A"} A * @property {"B"} B * * @typedef {$s$.test.types.BoxedInner} BoxFlattened * * @typedef {{ * c: { * a: number, * }, * }} BoxInline * @property {{ * a: number, * }} c * * @typedef {{ * a: number, * }} BoxedInner * @property {number} a * * @typedef {string} BracedStruct * @property {string} "0" * * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second * * Some triple-slash comment * Some more triple-slash comment * * @typedef { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * ({ A: number }) & { B?: never } | * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * ({ B: { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * } }) & { A?: never }} CommentedEnum * @property { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * { A: number }} A - Some triple-slash comment Some more triple-slash comment * @property { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * { B: { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * } }} B - Some triple-slash comment Some more triple-slash comment * * Some triple-slash comment * Some more triple-slash comment * * @typedef {{ * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * }} CommentedStruct * @property {number} a - Some triple-slash comment Some more triple-slash comment * * @typedef {{ * data: number[], * a: number[], * d: [number, number], * }} ConstGenericInConstContainer * @property {number[]} data * @property {number[]} a * @property {[number, number]} d * * @typedef {{ * data: [number], * a: [number, number], * d: [number, number], * }} ConstGenericInNonConstContainer * @property {[number]} data * @property {[number, number]} a * @property {[number, number]} d * * @typedef {{ * foo: $s$.test.types.Generic1, * bar: $s$.test.types.Generic1[], * baz: { [key in string]: $s$.test.types.Generic1 }, * }} Container1 * @property {$s$.test.types.Generic1} foo * @property {$s$.test.types.Generic1[]} bar * @property {{ [key in string]: $s$.test.types.Generic1 }} baz * * @typedef {string} ContainerTypeOverrideEnum * * @typedef {string} ContainerTypeOverrideGeneric * * @typedef {string} ContainerTypeOverrideStruct * * @typedef {T} ContainerTypeOverrideToGeneric * * @typedef {[string, number]} ContainerTypeOverrideTuple * * @typedef {[T, string]} ContainerTypeOverrideTupleGeneric * * @typedef {{ * flattened: number, * }} D * @property {number} flattened * * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b * * @typedef { * /** * * @deprecated * */ * "A" | * /** * * @deprecated Nope * */ * "B" | * /** * * @deprecated Nope * */ * "C"} DeprecatedEnumVariants * @property { * /** * * @deprecated * */ * "A"} A - @deprecated * @property { * /** * * @deprecated Nope * */ * "B"} B - @deprecated Nope * @property { * /** * * @deprecated Nope * */ * "C"} C - @deprecated Nope * * @typedef {{ * a: number, * /** * * @deprecated * */ * b: string, * /** * * @deprecated This field is cringe! * */ * c: string, * /** * * @deprecated This field is cringe! * */ * d: string, * }} DeprecatedFields * @property {number} a * @property {string} b - @deprecated * @property {string} c - @deprecated This field is cringe! * @property {string} d - @deprecated This field is cringe! * * @typedef {[ * /** * * @deprecated * */ * string, * /** * * @deprecated Nope * */ * string, * /** * * @deprecated Nope * */ * number]} DeprecatedTupleVariant * @property {string} "0" - @deprecated * @property {string} "1" - @deprecated Nope * @property {number} "2" - @deprecated Nope * * @deprecated * @typedef {{ * a: number, * }} DeprecatedType * @property {number} a * * @deprecated Look at you big man using a deprecation message * @typedef {{ * a: number, * }} DeprecatedTypeWithMsg * @property {number} a * * @deprecated Look at you big man using a deprecation message * @typedef {{ * a: number, * }} DeprecatedTypeWithMsg2 * @property {number} a * * @typedef {{ * a: $s$.test.types.ToBeFlattened, * b: $s$.test.types.ToBeFlattened, * }} DoubleFlattened * @property {$s$.test.types.ToBeFlattened} a * @property {$s$.test.types.ToBeFlattened} b * * @typedef {{ A: string } | "B"} Eight * @property {{ A: string }} A * @property {"B"} B * * @typedef {never} EmptyEnum * * @typedef {never} EmptyEnumTagged * * @typedef {never} EmptyEnumTaggedWContent * * @typedef {never} EmptyEnumUntagged * * @typedef {Record} EmptyStruct * * @typedef {{ * a: "EmptyStructWithTag", * }} EmptyStructWithTag * @property {"EmptyStructWithTag"} a * * @typedef {{ t: "A" } | { t: "B" }} Enum * @property {{ t: "A" }} A * @property {{ t: "B" }} B * * @typedef {{ t: "C" } | { t: "B" } | { t: "D"; enumField: null }} Enum2 * @property {{ t: "C" }} C * @property {{ t: "B" }} B * @property {{ t: "D"; enumField: null }} D * * @typedef {{ t: "A"; b: string }} Enum3 * @property {{ t: "A"; b: string }} A * * @typedef {({ A: string }) & { D?: never; bbb?: never; cccc?: never } | ({ bbb: number }) & { A?: never; D?: never; cccc?: never } | ({ cccc: number }) & { A?: never; D?: never; bbb?: never } | ({ D: { * a: string, * bbbbbb: number, * } }) & { A?: never; bbb?: never; cccc?: never }} EnumMacroAttributes * @property {{ A: string }} A * @property {{ bbb: number }} bbb * @property {{ cccc: number }} cccc * @property {{ D: { * a: string, * bbbbbb: number, * } }} D * * @typedef {{ * a: Partial<{ [key in $s$.test.types.BasicEnum]: number }>, * }} EnumReferenceRecordKey * @property {Partial<{ [key in $s$.test.types.BasicEnum]: number }>} a * * @typedef {"HELLOWORLD" | "VARIANTB" | "TESTINGWORDS"} EnumRenameAllUppercase * @property {"HELLOWORLD"} HELLOWORLD * @property {"VARIANTB"} VARIANTB * @property {"TESTINGWORDS"} TESTINGWORDS * * @typedef {"Variant" | "Other"} EnumWithMultipleVariantAliases * @property {"Variant"} Variant * @property {"Other"} Other * * @typedef {"Variant" | "Other"} EnumWithVariantAlias * @property {"Variant"} Variant * @property {"Other"} Other * * @typedef {"renamed_variant" | "Other"} EnumWithVariantAliasAndRename * @property {"renamed_variant"} renamed_variant * @property {"Other"} Other * * @typedef {"A" | ({ B: { * id: string, * method: string, * } }) & { C?: never } | ({ C: string }) & { B?: never }} ExternallyTagged * @property {"A"} A * @property {{ B: { * id: string, * method: string, * } }} B * @property {{ C: string }} C * * @typedef {{ A: string }} ExtraBracketsInTupleVariant * @property {{ A: string }} A * * @typedef {string} ExtraBracketsInUnnamedStruct * @property {string} "0" * * @typedef {{ * a: string, * }} First * @property {string} a * * @typedef {{ * a: number, * b: number, * }} FlattenA * @property {number} a * @property {number} b * * @typedef {{ * c: number, * } & $s$.test.types.FlattenA} FlattenB * @property {number} c * * @typedef {{ * c: number, * } & $s$.test.types.FlattenA} FlattenC * @property {number} c * * @typedef {{ * a: $s$.test.types.FlattenA, * c: number, * }} FlattenD * @property {$s$.test.types.FlattenA} a * @property {number} c * * @typedef {{ * b: ({ * c: number, * }) & ($s$.test.types.FlattenA), * d: number, * }} FlattenE * @property {({ * c: number, * }) & ($s$.test.types.FlattenA)} b * @property {number} d * * @typedef {{ tag: "One" } | { tag: "Two" } | { tag: "Three" }} FlattenEnum * @property {{ tag: "One" }} One * @property {{ tag: "Two" }} Two * @property {{ tag: "Three" }} Three * * @typedef {{ * outer: string, * } & $s$.test.types.FlattenEnum} FlattenEnumStruct * @property {string} outer * * @typedef {{ * b: ({ * c: number, * }) & ($s$.test.types.FlattenA), * d: number, * }} FlattenF * @property {({ * c: number, * }) & ($s$.test.types.FlattenA)} b * @property {number} d * * @typedef {{ * b: $s$.test.types.FlattenB, * d: number, * }} FlattenG * @property {$s$.test.types.FlattenB} b * @property {number} d * * @typedef {{ * id: string, * } & $s$.test.types.NestedEnum} FlattenOnNestedEnum * @property {string} id * * @typedef {$s$.test.types.Inner} FlattenedInner * * @typedef {{ * a: $s$.test.types.First, * b: { * a: string, * }, * }} Fourth * @property {$s$.test.types.First} a * @property {{ * a: string, * }} b * * @typedef {{ * value: T, * values: T[], * }} Generic1 * @property {T} value * @property {T[]} values * * @typedef {({ A: A }) & { B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ B: [B, B, B] }) & { A?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ C: C[] }) & { A?: never; B?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ D: A[][][] }) & { A?: never; B?: never; C?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ E: { * a: A, * b: B, * c: C, * } }) & { A?: never; B?: never; C?: never; D?: never; X?: never; Y?: never; Z?: never } | ({ X: number[] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; Y?: never; Z?: never } | ({ Y: number }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Z?: never } | ({ Z: number[][] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never }} Generic2 * @property {{ A: A }} A * @property {{ B: [B, B, B] }} B * @property {{ C: C[] }} C * @property {{ D: A[][][] }} D * @property {{ E: { * a: A, * b: B, * c: C, * } }} E * @property {{ X: number[] }} X * @property {{ Y: number }} Y * @property {{ Z: number[][] }} Z * * @typedef {{ * value: T, * values: T[], * }} GenericAutoBound * @property {T} value * @property {T[]} values * * @typedef {{ * value: T, * values: T[], * }} GenericAutoBound2 * @property {T} value * @property {T[]} values * * @typedef {{ * value: T, * }} GenericDefault * @property {T} value * * @typedef {{ * value: T, * }} GenericDefaultSkipped * @property {T} value * * @typedef {{ * value: number, * }} GenericDefaultSkippedNonType * @property {number} value * * @typedef {{ * generic_flattened: T, * }} GenericFlattened * @property {T} generic_flattened * * @typedef {T[][]} GenericNewType1 * @property {T[][]} "0" * * @typedef {{ * pair: $s$.test.types.Pair, * }} GenericParameterOrderPreserved * @property {$s$.test.types.Pair} pair * * @typedef {{ * arg: T, * }} GenericStruct * @property {T} arg * * @typedef {{ * a: T, * b: [T, T], * c: [T, [T, T]], * d: [T, T, T], * e: [([T, T]), ([T, T]), ([T, T])], * f: T[], * g: T[][], * h: ([([T, T]), ([T, T]), ([T, T])])[], * }} GenericStruct2 * @property {T} a * @property {[T, T]} b * @property {[T, [T, T]]} c * @property {[T, T, T]} d * @property {[([T, T]), ([T, T]), ([T, T])]} e * @property {T[]} f * @property {T[][]} g * @property {([([T, T]), ([T, T]), ([T, T])])[]} h * * @typedef {[T, T[], T[][]]} GenericTuple * @property {T} "0" * @property {T[]} "1" * @property {T[][]} "2" * * @typedef {T} GenericTupleStruct * @property {T} "0" * * @typedef {"Undefined" | T} GenericType * @property {"Undefined"} Undefined * @property {T} Value * * @typedef {{ [key in number]: string }} HasGenericAlias * @property {{ [key in number]: string }} "0" * * @typedef {{ * b: { * data: [number, number], * a: [number, number], * d: [number, number, number], * }, * c: { * data: [number, number, number], * a: [number, number], * d: [number, number, number], * }, * d: [number, number], * }} InlineConstGenericContainer * @property {{ * data: [number, number], * a: [number, number], * d: [number, number, number], * }} b * @property {{ * data: [number, number, number], * a: [number, number], * d: [number, number, number], * }} c * @property {[number, number]} d * * @typedef {{ A: { * a: string, * } }} InlineEnumField * @property {{ A: { * a: string, * } }} A * * @typedef {{ * g: $s$.test.types.InlineFlattenGenericsG, * gi: { * t: string, * }, * } & $s$.test.types.InlineFlattenGenericsG} InlineFlattenGenerics * @property {$s$.test.types.InlineFlattenGenericsG} g * @property {{ * t: string, * }} gi * * @typedef {{ * t: T, * }} InlineFlattenGenericsG * @property {T} t * * @typedef {{ * optional_field: { * a: string, * } | null, * }} InlineOptionalType * @property {{ * a: string, * } | null} optional_field * * @typedef {{ * data: number[], * a: number[], * d: [number, number, number], * e: $s$.test.types.InlineRecursiveConstGeneric, * }} InlineRecursiveConstGeneric * @property {number[]} data * @property {number[]} a * @property {[number, number, number]} d * @property {$s$.test.types.InlineRecursiveConstGeneric} e * * @typedef {{ * b: { * data: [number, number], * a: [number, number], * d: [number, number, number], * e: $s$.test.types.InlineRecursiveConstGeneric, * }, * c: { * data: [number, number, number], * a: [number, number], * d: [number, number, number], * e: $s$.test.types.InlineRecursiveConstGeneric, * }, * d: [number, number], * }} InlineRecursiveConstGenericContainer * @property {{ * data: [number, number], * a: [number, number], * d: [number, number, number], * e: $s$.test.types.InlineRecursiveConstGeneric, * }} b * @property {{ * data: [number, number, number], * a: [number, number], * d: [number, number, number], * e: $s$.test.types.InlineRecursiveConstGeneric, * }} c * @property {[number, number]} d * * @typedef {{ * ref_struct: $s$.test.types.SimpleStruct, * val: number, * }} InlineStruct * @property {$s$.test.types.SimpleStruct} ref_struct * @property {number} val * * @typedef {{ * demo: [string, boolean], * }} InlineTuple * @property {[string, boolean]} demo * * @typedef {{ * demo: [{ * demo: [string, boolean], * }, boolean], * }} InlineTuple2 * @property {[{ * demo: [string, boolean], * }, boolean]} demo * * @typedef {{ * inline_this: { * ref_struct: $s$.test.types.SimpleStruct, * val: number, * }, * dont_inline_this: $s$.test.types.RefStruct, * }} InlinerStruct * @property {{ * ref_struct: $s$.test.types.SimpleStruct, * val: number, * }} inline_this * @property {$s$.test.types.RefStruct} dont_inline_this * * @typedef {{ * a: number, * } & $s$.test.types.FlattenedInner} Inner * @property {number} a * * @typedef {{ * type: "A", * } & { [key in string]: string }} InternallyTaggedD * @property {{ * type: "A", * } & { [key in string]: string }} A * * @typedef {{ type: "A" }} InternallyTaggedE * @property {{ type: "A" }} A * * @typedef {{ type: "A" }} InternallyTaggedF * @property {{ type: "A" }} A * * @typedef {null} InternallyTaggedFInner * @property {null} A * * @typedef {{ type: "A" }} InternallyTaggedH * @property {{ type: "A" }} A * * @typedef {null} InternallyTaggedHInner * @property {null} "0" * * @typedef {{ * type: "A", * } & { type: "A" } | { type: "B" }} InternallyTaggedL * @property {{ * type: "A", * } & { type: "A" } | { type: "B" }} A * * @typedef {{ type: "A" } | { type: "B" }} InternallyTaggedLInner * @property {{ type: "A" }} A * @property {{ type: "B" }} B * * @typedef {{ type: "A" }} InternallyTaggedM * @property {{ type: "A" }} A * * @typedef {"A" | "B"} InternallyTaggedMInner * @property {"A"} A * @property {"B"} B * * @typedef {{ type: "A"; field: string } | { type: "B"; other: number }} InternallyTaggedWithAlias * @property {{ type: "A"; field: string }} A * @property {{ type: "B"; other: number }} B * * @typedef {{ * cause: null, * }} InvalidToValidType * @property {null} cause * * @typedef {({ A: { * a: string, * } }) & { B?: never } | ({ B: { * b: string, * } }) & { A?: never }} Issue221External * @property {{ A: { * a: string, * } }} A * @property {{ B: { * b: string, * } }} B * * @typedef {({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never }} Issue221UntaggedMixed * @property {{ a: string }} A * @property {{ b: string }} B * @property {{ values: { [key in string]: string } }} Unsafe * * @typedef {({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }} Issue221UntaggedSafe * @property {{ a: string }} A * @property {{ b: string }} B * * @typedef {{ * default_unity_arguments: string[], * }} Issue281 * @property {string[]} default_unity_arguments * * https://github.com/specta-rs/specta/issues/374 * * @typedef {$s$.test.types.Issue374_Serialize | $s$.test.types.Issue374_Deserialize} Issue374 * @property {$s$.test.types.Issue374_Serialize} Serialize * @property {$s$.test.types.Issue374_Deserialize} Deserialize * * https://github.com/specta-rs/specta/issues/374 * * @typedef {{ * foo?: boolean, * bar?: boolean, * }} Issue374_Deserialize * @property {boolean} [foo] * @property {boolean} [bar] * * https://github.com/specta-rs/specta/issues/374 * * @typedef {{ * foo?: boolean, * bar?: boolean, * }} Issue374_Serialize * @property {boolean} [foo] * @property {boolean} [bar] * * @typedef {{ * "test-ing": string, * }} KebabCase * @property {string} "test-ing" * * @typedef {({ Borrowed: T }) & { Owned?: never } | ({ Owned: T }) & { Borrowed?: never }} LifetimeGenericEnum * @property {{ Borrowed: T }} Borrowed * @property {{ Owned: T }} Owned * * @typedef {{ * borrowed: T[], * owned: T[], * }} LifetimeGenericStruct * @property {T[]} borrowed * @property {T[]} owned * * @typedef {{ event: "started"; data: { * projectName: string, * } } | { event: "progressTest"; data: { * projectName: string, * status: string, * progress: number, * } } | { event: "finished"; data: { * projectName: string, * } }} LoadProjectEvent * @property {{ event: "started"; data: { * projectName: string, * } }} started * @property {{ event: "progressTest"; data: { * projectName: string, * status: string, * progress: number, * } }} progressTest * @property {{ event: "finished"; data: { * projectName: string, * } }} finished * * @typedef {({ Demo: string }) & { Demo2?: never } | ({ Demo2: { * demo2: string, * } }) & { Demo?: never }} MacroEnum * @property {{ Demo: string }} Demo * @property {{ Demo2: { * demo2: string, * } }} Demo2 * * @typedef {string} MacroStruct * @property {string} "0" * * @typedef {{ * demo: string, * }} MacroStruct2 * @property {string} demo * * @typedef {T} MaybeValidKey * @property {T} "0" * * @typedef {Record} MyEmptyInput * * @typedef {({ A: string }) & { B?: never } | ({ B: number }) & { A?: never }} MyEnum * @property {{ A: string }} A * @property {{ B: number }} B * * @typedef {{ t: "Variant"; c: { * inner: $s$.test.types.First, * } }} MyEnumAdjacent * @property {{ t: "Variant"; c: { * inner: $s$.test.types.First, * } }} Variant * * @typedef {{ Variant: { * inner: $s$.test.types.First, * } }} MyEnumExternal * @property {{ Variant: { * inner: $s$.test.types.First, * } }} Variant * * @typedef {{ type: "Variant"; inner: $s$.test.types.First }} MyEnumTagged * @property {{ type: "Variant"; inner: $s$.test.types.First }} Variant * * @typedef {{ inner: $s$.test.types.First }} MyEnumUntagged * @property {{ inner: $s$.test.types.First }} Variant * * @typedef {{ * data: number[], * a: number[], * d: [number, number], * }} NamedConstGeneric * @property {number[]} data * @property {number[]} a * @property {[number, number]} d * * @typedef {{ * a: $s$.test.types.NamedConstGeneric, * b: $s$.test.types.NamedConstGeneric, * d: [number, number], * }} NamedConstGenericContainer * @property {$s$.test.types.NamedConstGeneric} a * @property {$s$.test.types.NamedConstGeneric} b * @property {[number, number]} d * * @typedef {{ type: "a"; value: string } | { type: "b"; value: number }} NestedEnum * @property {{ type: "a"; value: string }} a * @property {{ type: "b"; value: number }} b * * @typedef {{ t: "A"; c: string } | { t: "B" } | { t: "C"; c: { * a: string, * } } | { t: "D"; c: $s$.test.types.First }} Ninth * @property {{ t: "A"; c: string }} A * @property {{ t: "B" }} B * @property {{ t: "C"; c: { * a: string, * } }} C * @property {{ t: "D"; c: $s$.test.types.First }} D * * @typedef {string | null} NonOptional * @property {string | null} "0" * * @typedef {$s$.test.types.Optional_Serialize | $s$.test.types.Optional_Deserialize} Optional * @property {$s$.test.types.Optional_Serialize} Serialize * @property {$s$.test.types.Optional_Deserialize} Deserialize * * @typedef {({ A?: string | null }) & { B?: never; C?: never } | ({ B: { * a: string | null, * } }) & { A?: never; C?: never } | ({ C: { * a?: string | null, * } }) & { A?: never; B?: never }} OptionalInEnum * @property {{ A?: string | null }} A * @property {{ B: { * a: string | null, * } }} B * @property {{ C: { * a?: string | null, * } }} C * * @typedef {string | null} OptionalOnNamedField * @property {string | null} ["0"] * * @typedef {{ * b: string | null, * }} OptionalOnTransparentNamedField * @property {string | null} b * * @typedef {{ * a: number | null, * b?: number | null, * c: string | null, * d?: boolean, * }} Optional_Deserialize * @property {number | null} a * @property {number | null} [b] * @property {string | null} c * @property {boolean} [d] * * @typedef {{ * a: number | null, * b?: number | null, * c?: string | null, * d: boolean, * }} Optional_Serialize * @property {number | null} a * @property {number | null} [b] * @property {string | null} [c] * @property {boolean} d * * @typedef {{ * overriden_field: string, * }} OverridenStruct * @property {string} overriden_field * * @typedef {{ * first: Z, * second: A, * }} Pair * @property {Z} first * @property {A} second * * @typedef {{ * a: string, * }} PlaceholderInnerField * @property {string} a * * @typedef {{ * demo: $s$.test.types.Recursive, * }} Recursive * @property {$s$.test.types.Recursive} demo * * @typedef {{ A: { * demo: $s$.test.types.RecursiveInEnum, * } }} RecursiveInEnum * @property {{ A: { * demo: $s$.test.types.RecursiveInEnum, * } }} A * * @typedef {$s$.test.types.RecursiveInline} RecursiveInline * * @typedef {{ * demo: { [key in string]: $s$.test.types.RecursiveMapValue }, * }} RecursiveMapValue * @property {{ [key in string]: $s$.test.types.RecursiveMapValue }} demo * * @typedef {$s$.test.types.RecursiveInline} RecursiveTransparent * @property {$s$.test.types.RecursiveInline} "0" * * @typedef {$s$.test.types.TestEnum} RefStruct * @property {$s$.test.types.TestEnum} "0" * * @typedef {{ [key in string]: null }} Regular * @property {{ [key in string]: null }} "0" * * @typedef {"OneWord" | "Two words"} Rename * @property {"OneWord"} OneWord * @property {"Two words"} "Two words" * * @typedef {{ * "a/b": number, * }} RenameSerdeSpecialChar * @property {number} "a/b" * * @typedef {{ * "@odata.context": string, * }} RenameWithWeirdCharsField * @property {string} "@odata.context" * * @typedef {{ "@odata.context": string }} RenameWithWeirdCharsVariant * @property {{ "@odata.context": string }} "@odata.context" * * @typedef {{ * "": string, * "a\"b": string, * "a\\b": string, * "line\nbreak": string, * "line\u2028break": string, * "line\u2029break": string, * }} RenamedFieldKeys * @property {string} "" * @property {string} "a\"b" * @property {string} "a\\b" * @property {string} "line\nbreak" * @property {string} "line\u2028break" * @property {string} "line\u2029break" * * @typedef {"a-b"} RenamedVariantWithSkippedPayload * @property {"a-b"} "a-b" * * @typedef {{ * a: number, * }} Second * @property {number} a * * @typedef {{ * a: $s$.test.types.First, * b: $s$.test.types.Second, * }} Seventh * @property {$s$.test.types.First} a * @property {$s$.test.types.Second} b * * @typedef {{ * a: number, * b: string, * c: [number, string, number], * d: string[], * e: string | null, * }} SimpleStruct * @property {number} a * @property {string} b * @property {[number, string, number]} c * @property {string[]} d * @property {string | null} e * * Some single-line comment * * @typedef { * /** Some single-line comment */ * ({ A: number }) & { B?: never } | * /** Some single-line comment */ * ({ B: { * /** Some single-line comment */ * a: number, * } }) & { A?: never }} SingleLineComment * @property { * /** Some single-line comment */ * { A: number }} A - Some single-line comment * @property { * /** Some single-line comment */ * { B: { * /** Some single-line comment */ * a: number, * } }} B - Some single-line comment * * @typedef {{ * a: $s$.test.types.First, * b: $s$.test.types.First, * }} Sixth * @property {$s$.test.types.First} a * @property {$s$.test.types.First} b * * @typedef {{ * b: number, * }} SkipField * @property {number} b * * @typedef {({ A: Record }) & { B?: never } | ({ B: { * b: number, * } }) & { A?: never }} SkipNamedFieldInVariant * @property {{ A: Record }} A * @property {{ B: { * b: number, * } }} B * * @typedef {Record} SkipOnlyField * * @typedef {{ * a: number, * }} SkipStructFields * @property {number} a * * @typedef {"A" | { B: [number] }} SkipUnnamedFieldInVariant * @property {"A"} A * @property {{ B: [number] }} B * * @typedef {{ A: string }} SkipVariant * @property {{ A: string }} A * * @typedef {{ tag: "A"; data: string }} SkipVariant2 * @property {{ tag: "A"; data: string }} A * * @typedef {{ A: { * a: string, * } }} SkipVariant3 * @property {{ A: { * a: string, * } }} A * * @typedef {{ type: "A" } | { type: "B"; data: string }} SkippedFieldWithinVariant * @property {{ type: "A" }} A * @property {{ type: "B"; data: string }} B * * @typedef {{ * a: number, * }} SpectaSkipNonTypeField * @property {number} a * * @typedef {{ * string_ident: string, * u32_ident: number, * path: string, * tuple: [string, number], * }} SpectaTypeOverride * @property {string} string_ident * @property {number} u32_ident * @property {string} path * @property {[string, number]} tuple * * @typedef {{ * b: string, * }} Struct2 * @property {string} b * * @typedef {{ * t: "StructNew", * a: string, * }} StructNew * @property {"StructNew"} t * @property {string} a * * @typedef {$s$.test.types.StructPhaseSpecificRenameSerialize | $s$.test.types.StructPhaseSpecificRenameDeserialize} StructPhaseSpecificRename * @property {$s$.test.types.StructPhaseSpecificRenameSerialize} Serialize * @property {$s$.test.types.StructPhaseSpecificRenameDeserialize} Deserialize * * @typedef {{ * kind: "StructPhaseSpecificRenameDeserialize", * der: string, * }} StructPhaseSpecificRenameDeserialize * @property {"StructPhaseSpecificRenameDeserialize"} kind * @property {string} der * * @typedef {{ * kind: "StructPhaseSpecificRenameSerialize", * ser: string, * }} StructPhaseSpecificRenameSerialize * @property {"StructPhaseSpecificRenameSerialize"} kind * @property {string} ser * * @typedef {{ * A: number, * B: number, * }} StructRenameAllUppercase * @property {number} A * @property {number} B * * @typedef {{ * field: string, * }} StructWithAlias * @property {string} field * * @typedef {{ * renamed_field: string, * }} StructWithAliasAndRename * @property {string} renamed_field * * @typedef {{ * field: string, * }} StructWithMultipleAliases * @property {string} field * * @typedef {{ * type: "TagOnStructWithInline", * a: $s$.test.types.First, * b: { * a: string, * }, * }} TagOnStructWithInline * @property {"TagOnStructWithInline"} type * @property {$s$.test.types.First} a * @property {{ * a: string, * }} b * * @typedef {string | "B" | { * a: string, * } | $s$.test.types.First} Tenth * @property {string} A * @property {"B"} B * @property {{ * a: string, * }} C * @property {$s$.test.types.First} D * * @typedef {never} TestCollectionRegister * * @typedef {"Unit" | ({ Single: number }) & { Multiple?: never; Struct?: never } | ({ Multiple: [number, number] }) & { Single?: never; Struct?: never } | ({ Struct: { * a: number, * } }) & { Multiple?: never; Single?: never }} TestEnum * @property {"Unit"} Unit * @property {{ Single: number }} Single * @property {{ Multiple: [number, number] }} Multiple * @property {{ Struct: { * a: number, * } }} Struct * * @typedef {{ * b: { [key in string]: string }, * c: $s$.test.types.First, * } & $s$.test.types.First} Third * @property {{ [key in string]: string }} b * @property {$s$.test.types.First} c * * @typedef {{ * a: string, * }} ToBeFlattened * @property {string} a * * @typedef {string} TransparentStruct * @property {string} "0" * * @typedef {$s$.test.types.TransparentTypeInner} TransparentType * @property {$s$.test.types.TransparentTypeInner} "0" * * @typedef {null} TransparentType2 * @property {null} "0" * * @typedef {{ * inner: string, * }} TransparentTypeInner * @property {string} inner * * @typedef {string} TransparentTypeWithOverride * @property {string} "0" * * @typedef {null} TransparentWithSkip * @property {null} "0" * * @typedef {string} TransparentWithSkip2 * @property {string} "0" * * @typedef {string} TransparentWithSkip3 * @property {string} "0" * * @typedef {[number[], [number[], number[]], [number[], number[], number[]]]} TupleNested * @property {number[]} "0" * @property {[number[], number[]]} "1" * @property {[number[], number[], number[]]} "2" * * @typedef {string} TupleStruct * @property {string} "0" * * @typedef {number} TupleStruct1 * @property {number} "0" * * @typedef {[number, boolean, string]} TupleStruct3 * @property {number} "0" * @property {boolean} "1" * @property {string} "2" * * @typedef {string} TupleStructWithRep * @property {string} "0" * * @typedef {null} Unit1 * * @typedef {Record} Unit2 * * @typedef {[]} Unit3 * * @typedef {null} Unit4 * @property {null} "0" * * @typedef {"A"} Unit5 * @property {"A"} A * * @typedef {{ A: null }} Unit6 * @property {{ A: null }} A * * @typedef {{ A: Record }} Unit7 * @property {{ A: Record }} A * * @typedef {"A" | "B" | "C"} UnitVariants * @property {"A"} A * @property {"B"} B * @property {"C"} C * * @typedef {string | number | { id: string } | [string, boolean]} UntaggedVariants * @property {string} A * @property {number} B * @property {number} C * @property {{ id: string }} D * @property {[string, boolean]} E * * @typedef {string | number} UntaggedVariantsKey * @property {string} A * @property {number} B * @property {number} C * * @typedef {null | number} UntaggedVariantsWithDuplicateBranches * @property {null} A * @property {number} B * @property {null} C * * @typedef {string | [number, string] | number} UntaggedVariantsWithoutValue * @property {string} A * @property {[number, string]} B * @property {number} C * * @typedef {({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }} UntaggedWithAlias * @property {{ field: string }} A * @property {{ other: number }} B * * @typedef {{ [key in $s$.test.types.MaybeValidKey]: null }} ValidMaybeValidKey * @property {{ [key in $s$.test.types.MaybeValidKey]: null }} "0" * * @typedef {{ [key in $s$.test.types.MaybeValidKey<$s$.test.types.MaybeValidKey>]: null }} ValidMaybeValidKeyNested * @property {{ [key in $s$.test.types.MaybeValidKey<$s$.test.types.MaybeValidKey>]: null }} "0" */ export namespace type_type { /** * @typedef {never} Type */ } } } export namespace tests { export namespace tests { export namespace types { /** * @typedef {{ * i8: number, * i16: number, * i32: number, * u8: number, * u16: number, * u32: number, * f32: number, * f64: number, * bool: boolean, * char: string, * "Range": $s$.std.ops.Range, * "RangeInclusive": $s$.std.ops.RangeInclusive, * "()": null, * "(String, i32)": [string, number], * "(String, i32, bool)": [string, number, boolean], * "((String, i32), (bool, char, bool), ())": [[string, number], [boolean, string, boolean], null], * "(bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool)": [boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean], * "(Vec, Vec)": [number[], boolean[]], * String: string, * PathBuf: string, * IpAddr: string, * Ipv4Addr: string, * Ipv6Addr: string, * SocketAddr: string, * SocketAddrV4: string, * SocketAddrV6: string, * "Cow<'static, str>": string, * "Cow<'static, i32>": number, * "&'static str": string, * "&'static bool": boolean, * "&'static i32": number, * "Vec": number[], * "&'static [i32]": number[], * "&'static [i32; 3]": [number, number, number], * "[i32; 3]": [number, number, number], * "Vec": $s$.test.types.MyEnum[], * "&'static [MyEnum]": $s$.test.types.MyEnum[], * "&'static [MyEnum; 6]": [$s$.test.types.MyEnum, $s$.test.types.MyEnum, $s$.test.types.MyEnum, $s$.test.types.MyEnum, $s$.test.types.MyEnum, $s$.test.types.MyEnum], * "[MyEnum; 2]": [$s$.test.types.MyEnum, $s$.test.types.MyEnum], * "&'static [i32; 1]": [number], * "&'static [i32; 0]": [], * "Option": number | null, * "Option<()>": null, * "Option>": number[] | null, * "Result": $s$.std.result.Result, * "Vec>>": (number | null)[], * "Option>>": number[] | null, * "[Vec; 3]": [string[], string[], string[]], * "Option>": string | null, * "Option>>": string | null, * "PhantomData<()>": null, * "PhantomData": null, * Infallible: never, * Unit1: $s$.test.types.Unit1, * Unit2: $s$.test.types.Unit2, * Unit3: $s$.test.types.Unit3, * Unit4: $s$.test.types.Unit4, * Unit5: $s$.test.types.Unit5, * Unit6: $s$.test.types.Unit6, * Unit7: $s$.test.types.Unit7, * SimpleStruct: $s$.test.types.SimpleStruct, * TupleStruct1: $s$.test.types.TupleStruct1, * TupleStruct3: $s$.test.types.TupleStruct3, * TestEnum: $s$.test.types.TestEnum, * RefStruct: $s$.test.types.RefStruct, * InlinerStruct: $s$.test.types.InlinerStruct, * "GenericStruct": $s$.test.types.GenericStruct, * "GenericStruct": $s$.test.types.GenericStruct, * FlattenEnumStruct: $s$.test.types.FlattenEnumStruct, * OverridenStruct: $s$.test.types.OverridenStruct, * HasGenericAlias: $s$.test.types.HasGenericAlias, * EnumMacroAttributes: $s$.test.types.EnumMacroAttributes, * InlineEnumField: $s$.test.types.InlineEnumField, * InlineOptionalType: $s$.test.types.InlineOptionalType, * Rename: $s$.test.types.Rename, * TransparentType: $s$.test.types.TransparentType, * TransparentType2: $s$.test.types.TransparentType2, * TransparentTypeWithOverride: $s$.test.types.TransparentTypeWithOverride, * "[Option; 3]": [(number | null), (number | null), (number | null)], * "HashMap": Partial<{ [key in $s$.test.types.BasicEnum]: null }>, * "HashMap": Partial<{ [key in $s$.test.types.BasicEnum]: number }>, * "Option>>>": number | null, * "Vec": $s$.test.types.PlaceholderInnerField[], * EnumReferenceRecordKey: $s$.test.types.EnumReferenceRecordKey, * FlattenOnNestedEnum: $s$.test.types.FlattenOnNestedEnum, * MyEmptyInput: $s$.test.types.MyEmptyInput, * "(String)": string, * "(String,)": [string], * ExtraBracketsInTupleVariant: $s$.test.types.ExtraBracketsInTupleVariant, * ExtraBracketsInUnnamedStruct: $s$.test.types.ExtraBracketsInUnnamedStruct, * "Vec": $s$.test.types.MyEnum[], * InlineTuple: $s$.test.types.InlineTuple, * InlineTuple2: $s$.test.types.InlineTuple2, * "Box": string, * "Box": string, * SkippedFieldWithinVariant: $s$.test.types.SkippedFieldWithinVariant, * KebabCase: $s$.test.types.KebabCase, * "&[&str]": string[], * "Issue281<'_>": $s$.test.types.Issue281, * "LifetimeGenericStruct<'_, i32>": $s$.test.types.LifetimeGenericStruct, * "LifetimeGenericEnum<'_, i32>": $s$.test.types.LifetimeGenericEnum, * RenameWithWeirdCharsField: $s$.test.types.RenameWithWeirdCharsField, * RenameWithWeirdCharsVariant: $s$.test.types.RenameWithWeirdCharsVariant, * RenamedFieldKeys: $s$.test.types.RenamedFieldKeys, * RenamedVariantWithSkippedPayload: $s$.test.types.RenamedVariantWithSkippedPayload, * "type_type::Type": $s$.test.types.type_type.Type, * ActualType: $s$.test.types.ActualType, * SpectaTypeOverride: $s$.test.types.SpectaTypeOverride, * ContainerTypeOverrideStruct: $s$.test.types.ContainerTypeOverrideStruct, * ContainerTypeOverrideEnum: $s$.test.types.ContainerTypeOverrideEnum, * "ContainerTypeOverrideGeneric>": $s$.test.types.ContainerTypeOverrideGeneric, * "ContainerTypeOverrideToGeneric": $s$.test.types.ContainerTypeOverrideToGeneric, * ContainerTypeOverrideTuple: $s$.test.types.ContainerTypeOverrideTuple, * "ContainerTypeOverrideTupleGeneric": $s$.test.types.ContainerTypeOverrideTupleGeneric, * InvalidToValidType: $s$.test.types.InvalidToValidType, * TupleStruct: $s$.test.types.TupleStruct, * TupleStructWithRep: $s$.test.types.TupleStructWithRep, * "GenericTupleStruct": $s$.test.types.GenericTupleStruct, * BracedStruct: $s$.test.types.BracedStruct, * Struct: $s$.test.types.StructNew, * Struct2: $s$.test.types.Struct2, * Enum: $s$.test.types.Enum, * Enum2: $s$.test.types.Enum2, * Enum3: $s$.test.types.Enum3, * StructRenameAllUppercase: $s$.test.types.StructRenameAllUppercase, * RenameSerdeSpecialChar: $s$.test.types.RenameSerdeSpecialChar, * EnumRenameAllUppercase: $s$.test.types.EnumRenameAllUppercase, * Recursive: $s$.test.types.Recursive, * RecursiveMapValue: $s$.test.types.RecursiveMapValue, * RecursiveTransparent: $s$.test.types.RecursiveTransparent, * RecursiveInEnum: $s$.test.types.RecursiveInEnum, * NonOptional: $s$.test.types.NonOptional, * OptionalOnNamedField: $s$.test.types.OptionalOnNamedField, * OptionalOnTransparentNamedField: $s$.test.types.OptionalOnTransparentNamedField, * OptionalInEnum: $s$.test.types.OptionalInEnum, * UntaggedVariants: $s$.test.types.UntaggedVariants, * UntaggedVariantsWithoutValue: $s$.test.types.UntaggedVariantsWithoutValue, * UntaggedVariantsWithDuplicateBranches: $s$.test.types.UntaggedVariantsWithDuplicateBranches, * "HashMap": { [key in string]: null }, * Regular: $s$.test.types.Regular, * "HashMap": { [key in never]: null }, * "HashMap": { [key in $s$.test.types.TransparentStruct]: null }, * "HashMap": Partial<{ [key in $s$.test.types.UnitVariants]: null }>, * "HashMap": Partial<{ [key in $s$.test.types.UntaggedVariantsKey]: null }>, * ValidMaybeValidKey: $s$.test.types.ValidMaybeValidKey, * ValidMaybeValidKeyNested: $s$.test.types.ValidMaybeValidKeyNested, * MacroStruct: $s$.test.types.MacroStruct, * MacroStruct2: $s$.test.types.MacroStruct2, * MacroEnum: $s$.test.types.MacroEnum, * DeprecatedType: $s$.test.types.DeprecatedType, * DeprecatedTypeWithMsg: $s$.test.types.DeprecatedTypeWithMsg, * DeprecatedTypeWithMsg2: $s$.test.types.DeprecatedTypeWithMsg2, * DeprecatedFields: $s$.test.types.DeprecatedFields, * DeprecatedTupleVariant: $s$.test.types.DeprecatedTupleVariant, * DeprecatedEnumVariants: $s$.test.types.DeprecatedEnumVariants, * CommentedStruct: $s$.test.types.CommentedStruct, * CommentedEnum: $s$.test.types.CommentedEnum, * SingleLineComment: $s$.test.types.SingleLineComment, * NonGeneric: $s$.test.types.Demo, * "HalfGenericA": $s$.test.types.Demo, * "HalfGenericB": $s$.test.types.Demo, * "FullGeneric": $s$.test.types.Demo, * "Another": $s$.test.types.Demo, * "MapA": { [key in string]: number }, * "MapB": { [key in number]: string }, * "MapC": { [key in string]: $s$.test.types.AGenericStruct }, * "AGenericStruct": $s$.test.types.AGenericStruct, * A: $s$.test.types.A, * DoubleFlattened: $s$.test.types.DoubleFlattened, * FlattenedInner: $s$.test.types.FlattenedInner, * BoxFlattened: $s$.test.types.BoxFlattened, * BoxInline: $s$.test.types.BoxInline, * First: $s$.test.types.First, * Second: $s$.test.types.Second, * Third: $s$.test.types.Third, * Fourth: $s$.test.types.Fourth, * TagOnStructWithInline: $s$.test.types.TagOnStructWithInline, * Sixth: $s$.test.types.Sixth, * Seventh: $s$.test.types.Seventh, * Eight: $s$.test.types.Eight, * Ninth: $s$.test.types.Ninth, * Tenth: $s$.test.types.Tenth, * MyEnumTagged: $s$.test.types.MyEnumTagged, * MyEnumExternal: $s$.test.types.MyEnumExternal, * MyEnumAdjacent: $s$.test.types.MyEnumAdjacent, * MyEnumUntagged: $s$.test.types.MyEnumUntagged, * EmptyStruct: $s$.test.types.EmptyStruct, * EmptyStructWithTag: $s$.test.types.EmptyStructWithTag, * AdjacentlyTagged: $s$.test.types.AdjacentlyTagged, * LoadProjectEvent: $s$.test.types.LoadProjectEvent, * ExternallyTagged: $s$.test.types.ExternallyTagged, * Issue221External: $s$.test.types.Issue221External, * InternallyTaggedD: $s$.test.types.InternallyTaggedD, * InternallyTaggedE: $s$.test.types.InternallyTaggedE, * InternallyTaggedF: $s$.test.types.InternallyTaggedF, * InternallyTaggedH: $s$.test.types.InternallyTaggedH, * InternallyTaggedL: $s$.test.types.InternallyTaggedL, * InternallyTaggedM: $s$.test.types.InternallyTaggedM, * StructWithAlias: $s$.test.types.StructWithAlias, * StructWithMultipleAliases: $s$.test.types.StructWithMultipleAliases, * StructWithAliasAndRename: $s$.test.types.StructWithAliasAndRename, * EnumWithVariantAlias: $s$.test.types.EnumWithVariantAlias, * EnumWithMultipleVariantAliases: $s$.test.types.EnumWithMultipleVariantAliases, * EnumWithVariantAliasAndRename: $s$.test.types.EnumWithVariantAliasAndRename, * InternallyTaggedWithAlias: $s$.test.types.InternallyTaggedWithAlias, * AdjacentlyTaggedWithAlias: $s$.test.types.AdjacentlyTaggedWithAlias, * UntaggedWithAlias: $s$.test.types.UntaggedWithAlias, * Issue221UntaggedSafe: $s$.test.types.Issue221UntaggedSafe, * Issue221UntaggedMixed: $s$.test.types.Issue221UntaggedMixed, * EmptyEnum: $s$.test.types.EmptyEnum, * EmptyEnumTagged: $s$.test.types.EmptyEnumTagged, * EmptyEnumTaggedWContent: $s$.test.types.EmptyEnumTaggedWContent, * EmptyEnumUntagged: $s$.test.types.EmptyEnumUntagged, * SkipOnlyField: $s$.test.types.SkipOnlyField, * SkipField: $s$.test.types.SkipField, * SkipVariant: $s$.test.types.SkipVariant, * SkipUnnamedFieldInVariant: $s$.test.types.SkipUnnamedFieldInVariant, * SkipNamedFieldInVariant: $s$.test.types.SkipNamedFieldInVariant, * TransparentWithSkip: $s$.test.types.TransparentWithSkip, * TransparentWithSkip2: $s$.test.types.TransparentWithSkip2, * TransparentWithSkip3: $s$.test.types.TransparentWithSkip3, * SkipVariant2: $s$.test.types.SkipVariant2, * SkipVariant3: $s$.test.types.SkipVariant3, * SkipStructFields: $s$.test.types.SkipStructFields, * SpectaSkipNonTypeField: $s$.test.types.SpectaSkipNonTypeField, * FlattenA: $s$.test.types.FlattenA, * FlattenB: $s$.test.types.FlattenB, * FlattenC: $s$.test.types.FlattenC, * FlattenD: $s$.test.types.FlattenD, * FlattenE: $s$.test.types.FlattenE, * FlattenF: $s$.test.types.FlattenF, * FlattenG: $s$.test.types.FlattenG, * TupleNested: $s$.test.types.TupleNested, * "Generic1<()>": $s$.test.types.Generic1, * "GenericAutoBound<()>": $s$.test.types.GenericAutoBound, * "GenericAutoBound2<()>": $s$.test.types.GenericAutoBound2, * Container1: $s$.test.types.Container1, * "Generic2<(), String, i32>": $s$.test.types.Generic2, * "GenericNewType1<()>": $s$.test.types.GenericNewType1, * "GenericTuple<()>": $s$.test.types.GenericTuple, * "GenericStruct2<()>": $s$.test.types.GenericStruct2, * "InlineGenericNewtype": string, * "InlineGenericNested": [string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | ({ Unnamed: string }) & { Named?: never } | ({ Named: { * value: string, * } }) & { Unnamed?: never }], * "InlineFlattenGenericsG<()>": $s$.test.types.InlineFlattenGenericsG, * InlineFlattenGenerics: $s$.test.types.InlineFlattenGenerics, * GenericDefault: $s$.test.types.GenericDefault, * ChainedGenericDefault: $s$.test.types.ChainedGenericDefault, * "ChainedGenericDefault": $s$.test.types.ChainedGenericDefault, * "ChainedGenericDefault": $s$.test.types.ChainedGenericDefault, * "ChainedGenericDefault": $s$.test.types.ChainedGenericDefault, * GenericDefaultSkipped: $s$.test.types.GenericDefaultSkipped, * GenericDefaultSkippedNonType: $s$.test.types.GenericDefaultSkippedNonType, * GenericParameterOrderPreserved: $s$.test.types.GenericParameterOrderPreserved, * ConstGenericInNonConstContainer: $s$.test.types.ConstGenericInNonConstContainer, * ConstGenericInConstContainer: $s$.test.types.ConstGenericInConstContainer, * NamedConstGenericContainer: $s$.test.types.NamedConstGenericContainer, * InlineConstGenericContainer: $s$.test.types.InlineConstGenericContainer, * InlineRecursiveConstGenericContainer: $s$.test.types.InlineRecursiveConstGenericContainer, * TestCollectionRegister: $s$.test.types.TestCollectionRegister, * TestCollectionRegister: $s$.test.types.TestCollectionRegister, * }} Primitives * @property {number} i8 * @property {number} i16 * @property {number} i32 * @property {number} u8 * @property {number} u16 * @property {number} u32 * @property {number} f32 * @property {number} f64 * @property {boolean} bool * @property {string} char * @property {$s$.std.ops.Range} "Range" * @property {$s$.std.ops.RangeInclusive} "RangeInclusive" * @property {null} "()" * @property {[string, number]} "(String, i32)" * @property {[string, number, boolean]} "(String, i32, bool)" * @property {[[string, number], [boolean, string, boolean], null]} "((String, i32), (bool, char, bool), ())" * @property {[boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean]} "(bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool)" * @property {[number[], boolean[]]} "(Vec, Vec)" * @property {string} String * @property {string} PathBuf * @property {string} IpAddr * @property {string} Ipv4Addr * @property {string} Ipv6Addr * @property {string} SocketAddr * @property {string} SocketAddrV4 * @property {string} SocketAddrV6 * @property {string} "Cow<'static, str>" * @property {number} "Cow<'static, i32>" * @property {string} "&'static str" * @property {boolean} "&'static bool" * @property {number} "&'static i32" * @property {number[]} "Vec" * @property {number[]} "&'static [i32]" * @property {[number, number, number]} "&'static [i32; 3]" * @property {[number, number, number]} "[i32; 3]" * @property {$s$.test.types.MyEnum[]} "Vec" * @property {$s$.test.types.MyEnum[]} "&'static [MyEnum]" * @property {[$s$.test.types.MyEnum, $s$.test.types.MyEnum, $s$.test.types.MyEnum, $s$.test.types.MyEnum, $s$.test.types.MyEnum, $s$.test.types.MyEnum]} "&'static [MyEnum; 6]" * @property {[$s$.test.types.MyEnum, $s$.test.types.MyEnum]} "[MyEnum; 2]" * @property {[number]} "&'static [i32; 1]" * @property {[]} "&'static [i32; 0]" * @property {number | null} "Option" * @property {null} "Option<()>" * @property {number[] | null} "Option>" * @property {$s$.std.result.Result} "Result" * @property {(number | null)[]} "Vec>>" * @property {number[] | null} "Option>>" * @property {[string[], string[], string[]]} "[Vec; 3]" * @property {string | null} "Option>" * @property {string | null} "Option>>" * @property {null} "PhantomData<()>" * @property {null} "PhantomData" * @property {never} Infallible * @property {$s$.test.types.Unit1} Unit1 * @property {$s$.test.types.Unit2} Unit2 * @property {$s$.test.types.Unit3} Unit3 * @property {$s$.test.types.Unit4} Unit4 * @property {$s$.test.types.Unit5} Unit5 * @property {$s$.test.types.Unit6} Unit6 * @property {$s$.test.types.Unit7} Unit7 * @property {$s$.test.types.SimpleStruct} SimpleStruct * @property {$s$.test.types.TupleStruct1} TupleStruct1 * @property {$s$.test.types.TupleStruct3} TupleStruct3 * @property {$s$.test.types.TestEnum} TestEnum * @property {$s$.test.types.RefStruct} RefStruct * @property {$s$.test.types.InlinerStruct} InlinerStruct * @property {$s$.test.types.GenericStruct} "GenericStruct" * @property {$s$.test.types.GenericStruct} "GenericStruct" * @property {$s$.test.types.FlattenEnumStruct} FlattenEnumStruct * @property {$s$.test.types.OverridenStruct} OverridenStruct * @property {$s$.test.types.HasGenericAlias} HasGenericAlias * @property {$s$.test.types.EnumMacroAttributes} EnumMacroAttributes * @property {$s$.test.types.InlineEnumField} InlineEnumField * @property {$s$.test.types.InlineOptionalType} InlineOptionalType * @property {$s$.test.types.Rename} Rename * @property {$s$.test.types.TransparentType} TransparentType * @property {$s$.test.types.TransparentType2} TransparentType2 * @property {$s$.test.types.TransparentTypeWithOverride} TransparentTypeWithOverride * @property {[(number | null), (number | null), (number | null)]} "[Option; 3]" * @property {Partial<{ [key in $s$.test.types.BasicEnum]: null }>} "HashMap" * @property {Partial<{ [key in $s$.test.types.BasicEnum]: number }>} "HashMap" * @property {number | null} "Option>>>" * @property {$s$.test.types.PlaceholderInnerField[]} "Vec" * @property {$s$.test.types.EnumReferenceRecordKey} EnumReferenceRecordKey * @property {$s$.test.types.FlattenOnNestedEnum} FlattenOnNestedEnum * @property {$s$.test.types.MyEmptyInput} MyEmptyInput * @property {string} "(String)" * @property {[string]} "(String,)" * @property {$s$.test.types.ExtraBracketsInTupleVariant} ExtraBracketsInTupleVariant * @property {$s$.test.types.ExtraBracketsInUnnamedStruct} ExtraBracketsInUnnamedStruct * @property {$s$.test.types.MyEnum[]} "Vec" * @property {$s$.test.types.InlineTuple} InlineTuple * @property {$s$.test.types.InlineTuple2} InlineTuple2 * @property {string} "Box" * @property {string} "Box" * @property {$s$.test.types.SkippedFieldWithinVariant} SkippedFieldWithinVariant * @property {$s$.test.types.KebabCase} KebabCase * @property {string[]} "&[&str]" * @property {$s$.test.types.Issue281} "Issue281<'_>" * @property {$s$.test.types.LifetimeGenericStruct} "LifetimeGenericStruct<'_, i32>" * @property {$s$.test.types.LifetimeGenericEnum} "LifetimeGenericEnum<'_, i32>" * @property {$s$.test.types.RenameWithWeirdCharsField} RenameWithWeirdCharsField * @property {$s$.test.types.RenameWithWeirdCharsVariant} RenameWithWeirdCharsVariant * @property {$s$.test.types.RenamedFieldKeys} RenamedFieldKeys * @property {$s$.test.types.RenamedVariantWithSkippedPayload} RenamedVariantWithSkippedPayload * @property {$s$.test.types.type_type.Type} "type_type::Type" * @property {$s$.test.types.ActualType} ActualType * @property {$s$.test.types.SpectaTypeOverride} SpectaTypeOverride * @property {$s$.test.types.ContainerTypeOverrideStruct} ContainerTypeOverrideStruct * @property {$s$.test.types.ContainerTypeOverrideEnum} ContainerTypeOverrideEnum * @property {$s$.test.types.ContainerTypeOverrideGeneric} "ContainerTypeOverrideGeneric>" * @property {$s$.test.types.ContainerTypeOverrideToGeneric} "ContainerTypeOverrideToGeneric" * @property {$s$.test.types.ContainerTypeOverrideTuple} ContainerTypeOverrideTuple * @property {$s$.test.types.ContainerTypeOverrideTupleGeneric} "ContainerTypeOverrideTupleGeneric" * @property {$s$.test.types.InvalidToValidType} InvalidToValidType * @property {$s$.test.types.TupleStruct} TupleStruct * @property {$s$.test.types.TupleStructWithRep} TupleStructWithRep * @property {$s$.test.types.GenericTupleStruct} "GenericTupleStruct" * @property {$s$.test.types.BracedStruct} BracedStruct * @property {$s$.test.types.StructNew} Struct * @property {$s$.test.types.Struct2} Struct2 * @property {$s$.test.types.Enum} Enum * @property {$s$.test.types.Enum2} Enum2 * @property {$s$.test.types.Enum3} Enum3 * @property {$s$.test.types.StructRenameAllUppercase} StructRenameAllUppercase * @property {$s$.test.types.RenameSerdeSpecialChar} RenameSerdeSpecialChar * @property {$s$.test.types.EnumRenameAllUppercase} EnumRenameAllUppercase * @property {$s$.test.types.Recursive} Recursive * @property {$s$.test.types.RecursiveMapValue} RecursiveMapValue * @property {$s$.test.types.RecursiveTransparent} RecursiveTransparent * @property {$s$.test.types.RecursiveInEnum} RecursiveInEnum * @property {$s$.test.types.NonOptional} NonOptional * @property {$s$.test.types.OptionalOnNamedField} OptionalOnNamedField * @property {$s$.test.types.OptionalOnTransparentNamedField} OptionalOnTransparentNamedField * @property {$s$.test.types.OptionalInEnum} OptionalInEnum * @property {$s$.test.types.UntaggedVariants} UntaggedVariants * @property {$s$.test.types.UntaggedVariantsWithoutValue} UntaggedVariantsWithoutValue * @property {$s$.test.types.UntaggedVariantsWithDuplicateBranches} UntaggedVariantsWithDuplicateBranches * @property {{ [key in string]: null }} "HashMap" * @property {$s$.test.types.Regular} Regular * @property {{ [key in never]: null }} "HashMap" * @property {{ [key in $s$.test.types.TransparentStruct]: null }} "HashMap" * @property {Partial<{ [key in $s$.test.types.UnitVariants]: null }>} "HashMap" * @property {Partial<{ [key in $s$.test.types.UntaggedVariantsKey]: null }>} "HashMap" * @property {$s$.test.types.ValidMaybeValidKey} ValidMaybeValidKey * @property {$s$.test.types.ValidMaybeValidKeyNested} ValidMaybeValidKeyNested * @property {$s$.test.types.MacroStruct} MacroStruct * @property {$s$.test.types.MacroStruct2} MacroStruct2 * @property {$s$.test.types.MacroEnum} MacroEnum * @property {$s$.test.types.DeprecatedType} DeprecatedType * @property {$s$.test.types.DeprecatedTypeWithMsg} DeprecatedTypeWithMsg * @property {$s$.test.types.DeprecatedTypeWithMsg2} DeprecatedTypeWithMsg2 * @property {$s$.test.types.DeprecatedFields} DeprecatedFields * @property {$s$.test.types.DeprecatedTupleVariant} DeprecatedTupleVariant * @property {$s$.test.types.DeprecatedEnumVariants} DeprecatedEnumVariants * @property {$s$.test.types.CommentedStruct} CommentedStruct * @property {$s$.test.types.CommentedEnum} CommentedEnum * @property {$s$.test.types.SingleLineComment} SingleLineComment * @property {$s$.test.types.Demo} NonGeneric * @property {$s$.test.types.Demo} "HalfGenericA" * @property {$s$.test.types.Demo} "HalfGenericB" * @property {$s$.test.types.Demo} "FullGeneric" * @property {$s$.test.types.Demo} "Another" * @property {{ [key in string]: number }} "MapA" * @property {{ [key in number]: string }} "MapB" * @property {{ [key in string]: $s$.test.types.AGenericStruct }} "MapC" * @property {$s$.test.types.AGenericStruct} "AGenericStruct" * @property {$s$.test.types.A} A * @property {$s$.test.types.DoubleFlattened} DoubleFlattened * @property {$s$.test.types.FlattenedInner} FlattenedInner * @property {$s$.test.types.BoxFlattened} BoxFlattened * @property {$s$.test.types.BoxInline} BoxInline * @property {$s$.test.types.First} First * @property {$s$.test.types.Second} Second * @property {$s$.test.types.Third} Third * @property {$s$.test.types.Fourth} Fourth * @property {$s$.test.types.TagOnStructWithInline} TagOnStructWithInline * @property {$s$.test.types.Sixth} Sixth * @property {$s$.test.types.Seventh} Seventh * @property {$s$.test.types.Eight} Eight * @property {$s$.test.types.Ninth} Ninth * @property {$s$.test.types.Tenth} Tenth * @property {$s$.test.types.MyEnumTagged} MyEnumTagged * @property {$s$.test.types.MyEnumExternal} MyEnumExternal * @property {$s$.test.types.MyEnumAdjacent} MyEnumAdjacent * @property {$s$.test.types.MyEnumUntagged} MyEnumUntagged * @property {$s$.test.types.EmptyStruct} EmptyStruct * @property {$s$.test.types.EmptyStructWithTag} EmptyStructWithTag * @property {$s$.test.types.AdjacentlyTagged} AdjacentlyTagged * @property {$s$.test.types.LoadProjectEvent} LoadProjectEvent * @property {$s$.test.types.ExternallyTagged} ExternallyTagged * @property {$s$.test.types.Issue221External} Issue221External * @property {$s$.test.types.InternallyTaggedD} InternallyTaggedD * @property {$s$.test.types.InternallyTaggedE} InternallyTaggedE * @property {$s$.test.types.InternallyTaggedF} InternallyTaggedF * @property {$s$.test.types.InternallyTaggedH} InternallyTaggedH * @property {$s$.test.types.InternallyTaggedL} InternallyTaggedL * @property {$s$.test.types.InternallyTaggedM} InternallyTaggedM * @property {$s$.test.types.StructWithAlias} StructWithAlias * @property {$s$.test.types.StructWithMultipleAliases} StructWithMultipleAliases * @property {$s$.test.types.StructWithAliasAndRename} StructWithAliasAndRename * @property {$s$.test.types.EnumWithVariantAlias} EnumWithVariantAlias * @property {$s$.test.types.EnumWithMultipleVariantAliases} EnumWithMultipleVariantAliases * @property {$s$.test.types.EnumWithVariantAliasAndRename} EnumWithVariantAliasAndRename * @property {$s$.test.types.InternallyTaggedWithAlias} InternallyTaggedWithAlias * @property {$s$.test.types.AdjacentlyTaggedWithAlias} AdjacentlyTaggedWithAlias * @property {$s$.test.types.UntaggedWithAlias} UntaggedWithAlias * @property {$s$.test.types.Issue221UntaggedSafe} Issue221UntaggedSafe * @property {$s$.test.types.Issue221UntaggedMixed} Issue221UntaggedMixed * @property {$s$.test.types.EmptyEnum} EmptyEnum * @property {$s$.test.types.EmptyEnumTagged} EmptyEnumTagged * @property {$s$.test.types.EmptyEnumTaggedWContent} EmptyEnumTaggedWContent * @property {$s$.test.types.EmptyEnumUntagged} EmptyEnumUntagged * @property {$s$.test.types.SkipOnlyField} SkipOnlyField * @property {$s$.test.types.SkipField} SkipField * @property {$s$.test.types.SkipVariant} SkipVariant * @property {$s$.test.types.SkipUnnamedFieldInVariant} SkipUnnamedFieldInVariant * @property {$s$.test.types.SkipNamedFieldInVariant} SkipNamedFieldInVariant * @property {$s$.test.types.TransparentWithSkip} TransparentWithSkip * @property {$s$.test.types.TransparentWithSkip2} TransparentWithSkip2 * @property {$s$.test.types.TransparentWithSkip3} TransparentWithSkip3 * @property {$s$.test.types.SkipVariant2} SkipVariant2 * @property {$s$.test.types.SkipVariant3} SkipVariant3 * @property {$s$.test.types.SkipStructFields} SkipStructFields * @property {$s$.test.types.SpectaSkipNonTypeField} SpectaSkipNonTypeField * @property {$s$.test.types.FlattenA} FlattenA * @property {$s$.test.types.FlattenB} FlattenB * @property {$s$.test.types.FlattenC} FlattenC * @property {$s$.test.types.FlattenD} FlattenD * @property {$s$.test.types.FlattenE} FlattenE * @property {$s$.test.types.FlattenF} FlattenF * @property {$s$.test.types.FlattenG} FlattenG * @property {$s$.test.types.TupleNested} TupleNested * @property {$s$.test.types.Generic1} "Generic1<()>" * @property {$s$.test.types.GenericAutoBound} "GenericAutoBound<()>" * @property {$s$.test.types.GenericAutoBound2} "GenericAutoBound2<()>" * @property {$s$.test.types.Container1} Container1 * @property {$s$.test.types.Generic2} "Generic2<(), String, i32>" * @property {$s$.test.types.GenericNewType1} "GenericNewType1<()>" * @property {$s$.test.types.GenericTuple} "GenericTuple<()>" * @property {$s$.test.types.GenericStruct2} "GenericStruct2<()>" * @property {string} "InlineGenericNewtype" * @property {[string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | ({ Unnamed: string }) & { Named?: never } | ({ Named: { * value: string, * } }) & { Unnamed?: never }]} "InlineGenericNested" * @property {$s$.test.types.InlineFlattenGenericsG} "InlineFlattenGenericsG<()>" * @property {$s$.test.types.InlineFlattenGenerics} InlineFlattenGenerics * @property {$s$.test.types.GenericDefault} GenericDefault * @property {$s$.test.types.ChainedGenericDefault} ChainedGenericDefault * @property {$s$.test.types.ChainedGenericDefault} "ChainedGenericDefault" * @property {$s$.test.types.ChainedGenericDefault} "ChainedGenericDefault" * @property {$s$.test.types.ChainedGenericDefault} "ChainedGenericDefault" * @property {$s$.test.types.GenericDefaultSkipped} GenericDefaultSkipped * @property {$s$.test.types.GenericDefaultSkippedNonType} GenericDefaultSkippedNonType * @property {$s$.test.types.GenericParameterOrderPreserved} GenericParameterOrderPreserved * @property {$s$.test.types.ConstGenericInNonConstContainer} ConstGenericInNonConstContainer * @property {$s$.test.types.ConstGenericInConstContainer} ConstGenericInConstContainer * @property {$s$.test.types.NamedConstGenericContainer} NamedConstGenericContainer * @property {$s$.test.types.InlineConstGenericContainer} InlineConstGenericContainer * @property {$s$.test.types.InlineRecursiveConstGenericContainer} InlineRecursiveConstGenericContainer * @property {$s$.test.types.TestCollectionRegister} TestCollectionRegister * @property {$s$.test.types.TestCollectionRegister} TestCollectionRegister */ } } } } export import std = $s$.std; export import test = $s$.test; export import tests = $s$.tests; ════════════════════════════════════════ ================================================ FILE: tests/tests/snapshots/test__jsdoc__primitives-many-inline-raw.snap ================================================ --- source: tests/tests/jsdoc.rs expression: output --- /** * @typedef {{ * start: T, * end: T, * }} Range * @property {T} start * @property {T} end * * @typedef {{ * start: T, * end: T, * }} RangeInclusive * @property {T} start * @property {T} end * * @typedef {string} String * * @typedef {string} PathBuf * * @typedef {string} IpAddr * * @typedef {string} Ipv4Addr * * @typedef {string} Ipv6Addr * * @typedef {string} SocketAddr * * @typedef {string} SocketAddrV4 * * @typedef {string} SocketAddrV6 * * @typedef {T} Cow * * @typedef {T} Cow * * @typedef {T[]} Vec * * @typedef {T[]} Vec * * @typedef {T | E} Result * @property {T} Ok * @property {E} Err * * @typedef {T[]} Vec * * @typedef {null} PhantomData * * @typedef {null} PhantomData * * @typedef {never} Infallible * * @typedef {null} Unit1 * * @typedef {Record} Unit2 * * @typedef {[]} Unit3 * * @typedef {null} Unit4 * @property {null} "0" * * @typedef {"A"} Unit5 * @property {"A"} A * * @typedef {[]} Unit6 * @property {[]} A * * @typedef {Record} Unit7 * @property {Record} A * * @typedef {{ * a: number, * b: string, * c: [number, string, number], * d: string[], * e: string | null, * }} SimpleStruct * @property {number} a * @property {string} b * @property {[number, string, number]} c * @property {string[]} d * @property {string | null} e * * @typedef {number} TupleStruct1 * @property {number} "0" * * @typedef {[number, boolean, string]} TupleStruct3 * @property {number} "0" * @property {boolean} "1" * @property {string} "2" * * @typedef {"Unit" | number | [number, number] | { a: number }} TestEnum * @property {"Unit"} Unit * @property {number} Single * @property {[number, number]} Multiple * @property {{ a: number }} Struct * * @typedef {TestEnum} RefStruct * @property {TestEnum} "0" * * @typedef {{ * inline_this: { * ref_struct: SimpleStruct, * val: number, * }, * dont_inline_this: RefStruct, * }} InlinerStruct * @property {InlineStruct} inline_this * @property {RefStruct} dont_inline_this * * @typedef {{ * arg: T, * }} GenericStruct * @property {T} arg * * @typedef {{ * arg: T, * }} GenericStruct * @property {T} arg * * @typedef {{ * outer: string, * inner: FlattenEnum, * }} FlattenEnumStruct * @property {string} outer * @property {FlattenEnum} inner * * @typedef {{ * overriden_field: string, * }} OverridenStruct * @property {string} overriden_field * * @typedef {{ [key in number]: string }} HasGenericAlias * @property {{ [key in number]: string }} "0" * * @typedef {string | number | { a: string; b: number }} EnumMacroAttributes * @property {string} A * @property {number} B * @property {number} C * @property {{ a: string; b: number }} D * * @typedef {{ * a: string, * }} InlineEnumField * @property {{ * a: string, * }} A * * @typedef {{ * optional_field: { * a: string, * } | null, * }} InlineOptionalType * @property {PlaceholderInnerField | null} optional_field * * @typedef {"OneWord" | "TwoWords"} Rename * @property {"OneWord"} OneWord * @property {"TwoWords"} TwoWords * * @typedef {TransparentTypeInner} TransparentType * @property {TransparentTypeInner} "0" * * @typedef {null} TransparentType2 * @property {null} "0" * * @typedef {string} TransparentTypeWithOverride * @property {string} "0" * * @typedef {{ [key in K]: V }} HashMap * * @typedef {{ [key in K]: V }} HashMap * * @typedef {T[]} Vec * * @typedef {{ * a: Partial<{ [key in BasicEnum]: number }>, * }} EnumReferenceRecordKey * @property {Partial<{ [key in BasicEnum]: number }>} a * * @typedef {{ * id: string, * result: NestedEnum, * }} FlattenOnNestedEnum * @property {string} id * @property {NestedEnum} result * * @typedef {Record} MyEmptyInput * * @typedef {string} String * * @typedef {string} ExtraBracketsInTupleVariant * @property {string} A * * @typedef {string} ExtraBracketsInUnnamedStruct * @property {string} "0" * * @typedef {T[]} Vec * * @typedef {{ * demo: [string, boolean], * }} InlineTuple * @property {[string, boolean]} demo * * @typedef {{ * demo: [{ * demo: [string, boolean], * }, boolean], * }} InlineTuple2 * @property {[InlineTuple, boolean]} demo * * @typedef {T} Box * * @typedef {T} Box * * @typedef {never | string} SkippedFieldWithinVariant * @property {never} A * @property {string} B * * @typedef {{ * test_ing: string, * }} KebabCase * @property {string} test_ing * * @typedef {{ * default_unity_arguments: string[], * }} Issue281 * @property {string[]} default_unity_arguments * * @typedef {{ * borrowed: T[], * owned: T[], * }} LifetimeGenericStruct * @property {T[]} borrowed * @property {T[]} owned * * @typedef {T} LifetimeGenericEnum * @property {T} Borrowed * @property {T} Owned * * @typedef {{ * odata_context: string, * }} RenameWithWeirdCharsField * @property {string} odata_context * * @typedef {string} RenameWithWeirdCharsVariant * @property {string} A * * @typedef {{ * empty: string, * quote: string, * backslash: string, * newline: string, * line_separator: string, * paragraph_separator: string, * }} RenamedFieldKeys * @property {string} empty * @property {string} quote * @property {string} backslash * @property {string} newline * @property {string} line_separator * @property {string} paragraph_separator * * @typedef {never} RenamedVariantWithSkippedPayload * @property {never} A * * @typedef {never} Type * * @typedef {{ * a: GenericType, * }} ActualType * @property {GenericType} a * * @typedef {{ * string_ident: string, * u32_ident: number, * path: string, * tuple: [string, number], * }} SpectaTypeOverride * @property {string} string_ident * @property {number} u32_ident * @property {string} path * @property {[string, number]} tuple * * @typedef {string} ContainerTypeOverrideStruct * * @typedef {string} ContainerTypeOverrideEnum * * @typedef {string} ContainerTypeOverrideGeneric * * @typedef {T} ContainerTypeOverrideToGeneric * * @typedef {[string, number]} ContainerTypeOverrideTuple * * @typedef {[T, string]} ContainerTypeOverrideTupleGeneric * * @typedef {{ * cause: null, * }} InvalidToValidType * @property {null} cause * * @typedef {string} TupleStruct * @property {string} "0" * * @typedef {string} TupleStructWithRep * @property {string} "0" * * @typedef {T} GenericTupleStruct * @property {T} "0" * * @typedef {string} BracedStruct * @property {string} "0" * * @typedef {{ * a: string, * }} Struct * @property {string} a * * @typedef {{ * a: string, * }} Struct2 * @property {string} a * * @typedef {"A" | "B"} Enum * @property {"A"} A * @property {"B"} B * * @typedef {"A" | "B" | { enum_field: null }} Enum2 * @property {"A"} A * @property {"B"} B * @property {{ enum_field: null }} D * * @typedef {{ a: string }} Enum3 * @property {{ a: string }} A * * @typedef {{ * a: number, * b: number, * }} StructRenameAllUppercase * @property {number} a * @property {number} b * * @typedef {{ * b: number, * }} RenameSerdeSpecialChar * @property {number} b * * @typedef {"HelloWorld" | "VariantB" | "TestingWords"} EnumRenameAllUppercase * @property {"HelloWorld"} HelloWorld * @property {"VariantB"} VariantB * @property {"TestingWords"} TestingWords * * @typedef {{ * demo: Recursive, * }} Recursive * @property {Recursive} demo * * @typedef {{ * demo: { [key in string]: RecursiveMapValue }, * }} RecursiveMapValue * @property {{ [key in string]: RecursiveMapValue }} demo * * @typedef {RecursiveInline} RecursiveTransparent * @property {RecursiveInline} "0" * * @typedef {{ demo: RecursiveInEnum }} RecursiveInEnum * @property {{ demo: RecursiveInEnum }} A * * @typedef {string | null} NonOptional * @property {string | null} "0" * * @typedef {string | null} OptionalOnNamedField * @property {string | null} ["0"] * * @typedef {{ * b: string | null, * }} OptionalOnTransparentNamedField * @property {string | null} b * * @typedef {string | null | { a: string | null } | { a?: string | null }} OptionalInEnum * @property {string | null} A * @property {{ a: string | null }} B * @property {{ a?: string | null }} C * * @typedef {string | number | { id: string } | [string, boolean]} UntaggedVariants * @property {string} A * @property {number} B * @property {number} C * @property {{ id: string }} D * @property {[string, boolean]} E * * @typedef {string | [number, string] | number} UntaggedVariantsWithoutValue * @property {string} A * @property {[number, string]} B * @property {number} C * * @typedef {null | number} UntaggedVariantsWithDuplicateBranches * @property {null} A * @property {number} B * @property {null} C * * @typedef {{ [key in K]: V }} HashMap * * @typedef {{ [key in string]: null }} Regular * @property {{ [key in string]: null }} "0" * * @typedef {{ [key in K]: V }} HashMap * * @typedef {{ [key in K]: V }} HashMap * * @typedef {{ [key in K]: V }} HashMap * * @typedef {{ [key in K]: V }} HashMap * * @typedef {{ [key in MaybeValidKey]: null }} ValidMaybeValidKey * @property {{ [key in MaybeValidKey]: null }} "0" * * @typedef {{ [key in MaybeValidKey>]: null }} ValidMaybeValidKeyNested * @property {{ [key in MaybeValidKey>]: null }} "0" * * @typedef {string} MacroStruct * @property {string} "0" * * @typedef {{ * demo: string, * }} MacroStruct2 * @property {string} demo * * @typedef {string | { demo2: string }} MacroEnum * @property {string} Demo * @property {{ demo2: string }} Demo2 * * @deprecated * @typedef {{ * a: number, * }} DeprecatedType * @property {number} a * * @deprecated Look at you big man using a deprecation message * @typedef {{ * a: number, * }} DeprecatedTypeWithMsg * @property {number} a * * @deprecated Look at you big man using a deprecation message * @typedef {{ * a: number, * }} DeprecatedTypeWithMsg2 * @property {number} a * * @typedef {{ * a: number, * /** * * @deprecated * */ * b: string, * /** * * @deprecated This field is cringe! * */ * c: string, * /** * * @deprecated This field is cringe! * */ * d: string, * }} DeprecatedFields * @property {number} a * @property {string} b - @deprecated * @property {string} c - @deprecated This field is cringe! * @property {string} d - @deprecated This field is cringe! * * @typedef {[ * /** * * @deprecated * */ * string, * /** * * @deprecated Nope * */ * string, * /** * * @deprecated Nope * */ * number]} DeprecatedTupleVariant * @property {string} "0" - @deprecated * @property {string} "1" - @deprecated Nope * @property {number} "2" - @deprecated Nope * * @typedef { * /** * * @deprecated * */ * "A" | * /** * * @deprecated Nope * */ * "B" | * /** * * @deprecated Nope * */ * "C"} DeprecatedEnumVariants * @property { * /** * * @deprecated * */ * "A"} A - @deprecated * @property { * /** * * @deprecated Nope * */ * "B"} B - @deprecated Nope * @property { * /** * * @deprecated Nope * */ * "C"} C - @deprecated Nope * * Some triple-slash comment * Some more triple-slash comment * * @typedef {{ * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * }} CommentedStruct * @property {number} a - Some triple-slash comment Some more triple-slash comment * * Some triple-slash comment * Some more triple-slash comment * * @typedef { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * number | * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number }} CommentedEnum * @property { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * number} A - Some triple-slash comment Some more triple-slash comment * @property { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number }} B - Some triple-slash comment Some more triple-slash comment * * Some single-line comment * * @typedef { * /** * * Some single-line comment * */ * number | * /** * * Some single-line comment * */ * { * /** * * Some single-line comment * */ * a: number }} SingleLineComment * @property { * /** * * Some single-line comment * */ * number} A - Some single-line comment * @property { * /** * * Some single-line comment * */ * { * /** * * Some single-line comment * */ * a: number }} B - Some single-line comment * * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b * * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b * * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b * * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b * * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b * * @typedef {{ [key in K]: V }} HashMap * * @typedef {{ [key in K]: V }} HashMap * * @typedef {{ [key in K]: V }} HashMap * * @typedef {{ * field: Demo, * }} AGenericStruct * @property {Demo} field * * @typedef {{ * a: B, * b: { * b: number, * }, * c: B, * d: { * flattened: number, * }, * e: { * generic_flattened: number, * }, * }} A * @property {B} a * @property {B} b * @property {B} c * @property {D} d * @property {GenericFlattened} e * * @typedef {{ * a: ToBeFlattened, * b: ToBeFlattened, * }} DoubleFlattened * @property {ToBeFlattened} a * @property {ToBeFlattened} b * * @typedef {{ * c: Inner, * }} FlattenedInner * @property {Inner} c * * @typedef {{ * b: BoxedInner, * }} BoxFlattened * @property {BoxedInner} b * * @typedef {{ * c: { * a: number, * }, * }} BoxInline * @property {BoxedInner} c * * @typedef {{ * a: string, * }} First * @property {string} a * * @typedef {{ * a: number, * }} Second * @property {number} a * * @typedef {{ * a: First, * b: { [key in string]: string }, * c: First, * }} Third * @property {First} a * @property {{ [key in string]: string }} b * @property {First} c * * @typedef {{ * a: First, * b: { * a: string, * }, * }} Fourth * @property {First} a * @property {First} b * * @typedef {{ * a: First, * b: { * a: string, * }, * }} TagOnStructWithInline * @property {First} a * @property {First} b * * @typedef {{ * a: First, * b: First, * }} Sixth * @property {First} a * @property {First} b * * @typedef {{ * a: First, * b: Second, * }} Seventh * @property {First} a * @property {Second} b * * @typedef {string | "B"} Eight * @property {string} A * @property {"B"} B * * @typedef {string | "B" | { * a: string, * } | First} Ninth * @property {string} A * @property {"B"} B * @property {{ * a: string, * }} C * @property {First} D * * @typedef {string | "B" | { * a: string, * } | First} Tenth * @property {string} A * @property {"B"} B * @property {{ * a: string, * }} C * @property {First} D * * @typedef {{ inner: First }} MyEnumTagged * @property {{ inner: First }} Variant * * @typedef {{ inner: First }} MyEnumExternal * @property {{ inner: First }} Variant * * @typedef {{ inner: First }} MyEnumAdjacent * @property {{ inner: First }} Variant * * @typedef {{ inner: First }} MyEnumUntagged * @property {{ inner: First }} Variant * * @typedef {Record} EmptyStruct * * @typedef {Record} EmptyStructWithTag * * @typedef {"A" | { id: string; method: string } | string} AdjacentlyTagged * @property {"A"} A * @property {{ id: string; method: string }} B * @property {string} C * * @typedef {({ project_name: string }) & { progress?: never; status?: never } | { project_name: string; status: string; progress: number }} LoadProjectEvent * @property {{ project_name: string }} Started * @property {{ project_name: string; status: string; progress: number }} ProgressTest * @property {{ project_name: string }} Finished * * @typedef {"A" | { id: string; method: string } | string} ExternallyTagged * @property {"A"} A * @property {{ id: string; method: string }} B * @property {string} C * * @typedef {({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }} Issue221External * @property {{ a: string }} A * @property {{ b: string }} B * * @typedef {{ [key in string]: string }} InternallyTaggedD * @property {{ [key in string]: string }} A * * @typedef {null} InternallyTaggedE * @property {null} A * * @typedef {InternallyTaggedFInner} InternallyTaggedF * @property {InternallyTaggedFInner} A * * @typedef {InternallyTaggedHInner} InternallyTaggedH * @property {InternallyTaggedHInner} A * * @typedef {"A" | "B"} InternallyTaggedL * @property {"A" | "B"} A * * @typedef {"A" | "B"} InternallyTaggedM * @property {"A" | "B"} A * * @typedef {{ * field: string, * }} StructWithAlias * @property {string} field * * @typedef {{ * field: string, * }} StructWithMultipleAliases * @property {string} field * * @typedef {{ * field: string, * }} StructWithAliasAndRename * @property {string} field * * @typedef {"Variant" | "Other"} EnumWithVariantAlias * @property {"Variant"} Variant * @property {"Other"} Other * * @typedef {"Variant" | "Other"} EnumWithMultipleVariantAliases * @property {"Variant"} Variant * @property {"Other"} Other * * @typedef {"Variant" | "Other"} EnumWithVariantAliasAndRename * @property {"Variant"} Variant * @property {"Other"} Other * * @typedef {({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }} InternallyTaggedWithAlias * @property {{ field: string }} A * @property {{ other: number }} B * * @typedef {({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }} AdjacentlyTaggedWithAlias * @property {{ field: string }} A * @property {{ other: number }} B * * @typedef {({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }} UntaggedWithAlias * @property {{ field: string }} A * @property {{ other: number }} B * * @typedef {({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }} Issue221UntaggedSafe * @property {{ a: string }} A * @property {{ b: string }} B * * @typedef {({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never }} Issue221UntaggedMixed * @property {{ a: string }} A * @property {{ b: string }} B * @property {{ values: { [key in string]: string } }} Unsafe * * @typedef {never} EmptyEnum * * @typedef {never} EmptyEnumTagged * * @typedef {never} EmptyEnumTaggedWContent * * @typedef {never} EmptyEnumUntagged * * @typedef {Record} SkipOnlyField * * @typedef {{ * b: number, * }} SkipField * @property {number} b * * @typedef {string} SkipVariant * @property {string} A * * @typedef {never | [number]} SkipUnnamedFieldInVariant * @property {never} A * @property {[number]} B * * @typedef {Record | { b: number }} SkipNamedFieldInVariant * @property {Record} A * @property {{ b: number }} B * * @typedef {null} TransparentWithSkip * @property {null} "0" * * @typedef {string} TransparentWithSkip2 * @property {string} "0" * * @typedef {string} TransparentWithSkip3 * @property {string} "0" * * @typedef {string} SkipVariant2 * @property {string} A * * @typedef {{ a: string }} SkipVariant3 * @property {{ a: string }} A * * @typedef {{ * a: number, * }} SkipStructFields * @property {number} a * * @typedef {{ * a: number, * }} SpectaSkipNonTypeField * @property {number} a * * @typedef {{ * a: number, * b: number, * }} FlattenA * @property {number} a * @property {number} b * * @typedef {{ * a: FlattenA, * c: number, * }} FlattenB * @property {FlattenA} a * @property {number} c * * @typedef {{ * a: FlattenA, * c: number, * }} FlattenC * @property {FlattenA} a * @property {number} c * * @typedef {{ * a: FlattenA, * c: number, * }} FlattenD * @property {FlattenA} a * @property {number} c * * @typedef {{ * b: { * a: FlattenA, * c: number, * }, * d: number, * }} FlattenE * @property {FlattenB} b * @property {number} d * * @typedef {{ * b: { * a: FlattenA, * c: number, * }, * d: number, * }} FlattenF * @property {FlattenB} b * @property {number} d * * @typedef {{ * b: FlattenB, * d: number, * }} FlattenG * @property {FlattenB} b * @property {number} d * * @typedef {[number[], [number[], number[]], [number[], number[], number[]]]} TupleNested * @property {number[]} "0" * @property {[number[], number[]]} "1" * @property {[number[], number[], number[]]} "2" * * @typedef {{ * value: T, * values: T[], * }} Generic1 * @property {T} value * @property {T[]} values * * @typedef {{ * value: T, * values: T[], * }} GenericAutoBound * @property {T} value * @property {T[]} values * * @typedef {{ * value: T, * values: T[], * }} GenericAutoBound2 * @property {T} value * @property {T[]} values * * @typedef {{ * foo: Generic1, * bar: Generic1[], * baz: { [key in string]: Generic1 }, * }} Container1 * @property {Generic1} foo * @property {Generic1[]} bar * @property {{ [key in string]: Generic1 }} baz * * @typedef {A | [B, B, B] | C[] | A[][][] | { a: A; b: B; c: C } | number[] | number | number[][]} Generic2 * @property {A} A * @property {[B, B, B]} B * @property {C[]} C * @property {A[][][]} D * @property {{ a: A; b: B; c: C }} E * @property {number[]} X * @property {number} Y * @property {number[][]} Z * * @typedef {T[][]} GenericNewType1 * @property {T[][]} "0" * * @typedef {[T, T[], T[][]]} GenericTuple * @property {T} "0" * @property {T[]} "1" * @property {T[][]} "2" * * @typedef {{ * a: T, * b: [T, T], * c: [T, [T, T]], * d: [T, T, T], * e: [([T, T]), ([T, T]), ([T, T])], * f: T[], * g: T[][], * h: ([([T, T]), ([T, T]), ([T, T])])[], * }} GenericStruct2 * @property {T} a * @property {[T, T]} b * @property {[T, [T, T]]} c * @property {[T, T, T]} d * @property {[([T, T]), ([T, T]), ([T, T])]} e * @property {T[]} f * @property {T[][]} g * @property {([([T, T]), ([T, T]), ([T, T])])[]} h * * @typedef {T} InlineGenericNewtype * @property {T} "0" * * @typedef {[T, T[], [T, T], { [key in string]: T }, T | null, "Unit" | T | { value: T }]} InlineGenericNested * @property {T} "0" * @property {T[]} "1" * @property {[T, T]} "2" * @property {{ [key in string]: T }} "3" * @property {T | null} "4" * @property {"Unit" | T | { value: T }} "5" * * @typedef {{ * t: T, * }} InlineFlattenGenericsG * @property {T} t * * @typedef {{ * g: InlineFlattenGenericsG, * gi: { * t: string, * }, * t: InlineFlattenGenericsG, * }} InlineFlattenGenerics * @property {InlineFlattenGenericsG} g * @property {InlineFlattenGenericsG} gi * @property {InlineFlattenGenericsG} t * * @typedef {{ * value: T, * }} GenericDefault * @property {T} value * * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second * * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second * * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second * * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second * * @typedef {{ * value: T, * }} GenericDefaultSkipped * @property {T} value * * @typedef {{ * value: number, * }} GenericDefaultSkippedNonType * @property {number} value * * @typedef {{ * pair: Pair, * }} GenericParameterOrderPreserved * @property {Pair} pair * * @typedef {{ * data: [number], * a: [number, number], * d: [number, number], * }} ConstGenericInNonConstContainer * @property {[number]} data * @property {[number, number]} a * @property {[number, number]} d * * @typedef {{ * data: number[], * a: number[], * d: [number, number], * }} ConstGenericInConstContainer * @property {number[]} data * @property {number[]} a * @property {[number, number]} d * * @typedef {{ * a: NamedConstGeneric, * b: NamedConstGeneric, * d: [number, number], * }} NamedConstGenericContainer * @property {NamedConstGeneric} a * @property {NamedConstGeneric} b * @property {[number, number]} d * * @typedef {{ * b: { * data: [number, number], * a: [number, number], * d: [number, number, number], * }, * c: { * data: [number, number, number], * a: [number, number], * d: [number, number, number], * }, * d: [number, number], * }} InlineConstGenericContainer * @property {{ * data: number[], * a: number[], * d: [number, number, number], * }} b * @property {{ * data: number[], * a: number[], * d: [number, number, number], * }} c * @property {[number, number]} d * * @typedef {{ * b: { * data: [number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }, * c: { * data: [number, number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }, * d: [number, number], * }} InlineRecursiveConstGenericContainer * @property {InlineRecursiveConstGeneric} b * @property {InlineRecursiveConstGeneric} c * @property {[number, number]} d * * @typedef {never} TestCollectionRegister * * @typedef {never} TestCollectionRegister */ ================================================ FILE: tests/tests/snapshots/test__jsdoc__primitives-many-inline-serde.snap ================================================ --- source: tests/tests/jsdoc.rs expression: output --- /** * @typedef {{ * start: T, * end: T, * }} Range * @property {T} start * @property {T} end * * @typedef {{ * start: T, * end: T, * }} RangeInclusive * @property {T} start * @property {T} end * * @typedef {string} String * * @typedef {string} PathBuf * * @typedef {string} IpAddr * * @typedef {string} Ipv4Addr * * @typedef {string} Ipv6Addr * * @typedef {string} SocketAddr * * @typedef {string} SocketAddrV4 * * @typedef {string} SocketAddrV6 * * @typedef {T} Cow * * @typedef {T} Cow * * @typedef {T[]} Vec * * @typedef {T[]} Vec * * @typedef {({ Ok: T }) & { Err?: never } | ({ Err: E }) & { Ok?: never }} Result * @property {{ Ok: T }} Ok * @property {{ Err: E }} Err * * @typedef {T[]} Vec * * @typedef {null} PhantomData * * @typedef {null} PhantomData * * @typedef {never} Infallible * * @typedef {null} Unit1 * * @typedef {Record} Unit2 * * @typedef {[]} Unit3 * * @typedef {null} Unit4 * @property {null} "0" * * @typedef {"A"} Unit5 * @property {"A"} A * * @typedef {{ A: null }} Unit6 * @property {{ A: null }} A * * @typedef {{ A: Record }} Unit7 * @property {{ A: Record }} A * * @typedef {{ * a: number, * b: string, * c: [number, string, number], * d: string[], * e: string | null, * }} SimpleStruct * @property {number} a * @property {string} b * @property {[number, string, number]} c * @property {string[]} d * @property {string | null} e * * @typedef {number} TupleStruct1 * @property {number} "0" * * @typedef {[number, boolean, string]} TupleStruct3 * @property {number} "0" * @property {boolean} "1" * @property {string} "2" * * @typedef {"Unit" | ({ Single: number }) & { Multiple?: never; Struct?: never } | ({ Multiple: [number, number] }) & { Single?: never; Struct?: never } | ({ Struct: { * a: number, * } }) & { Multiple?: never; Single?: never }} TestEnum * @property {"Unit"} Unit * @property {{ Single: number }} Single * @property {{ Multiple: [number, number] }} Multiple * @property {{ Struct: { * a: number, * } }} Struct * * @typedef {TestEnum} RefStruct * @property {TestEnum} "0" * * @typedef {{ * inline_this: { * ref_struct: SimpleStruct, * val: number, * }, * dont_inline_this: RefStruct, * }} InlinerStruct * @property {InlineStruct} inline_this * @property {RefStruct} dont_inline_this * * @typedef {{ * arg: T, * }} GenericStruct * @property {T} arg * * @typedef {{ * arg: T, * }} GenericStruct * @property {T} arg * * @typedef {{ * outer: string, * } & (FlattenEnum)} FlattenEnumStruct * @property {string} outer * @property {FlattenEnum} inner * * @typedef {{ * overriden_field: string, * }} OverridenStruct * @property {string} overriden_field * * @typedef {{ [key in number]: string }} HasGenericAlias * @property {{ [key in number]: string }} "0" * * @typedef {({ A: string }) & { D?: never; bbb?: never; cccc?: never } | ({ bbb: number }) & { A?: never; D?: never; cccc?: never } | ({ cccc: number }) & { A?: never; D?: never; bbb?: never } | ({ D: { * a: string, * bbbbbb: number, * } }) & { A?: never; bbb?: never; cccc?: never }} EnumMacroAttributes * @property {{ A: string }} A * @property {{ bbb: number }} bbb * @property {{ cccc: number }} cccc * @property {{ D: { * a: string, * bbbbbb: number, * } }} D * * @typedef {{ A: { * a: string, * } }} InlineEnumField * @property {{ A: { * a: string, * } }} A * * @typedef {{ * optional_field: { * a: string, * } | null, * }} InlineOptionalType * @property {PlaceholderInnerField | null} optional_field * * @typedef {"OneWord" | "Two words"} Rename * @property {"OneWord"} OneWord * @property {"Two words"} "Two words" * * @typedef {TransparentTypeInner} TransparentType * @property {TransparentTypeInner} "0" * * @typedef {null} TransparentType2 * @property {null} "0" * * @typedef {string} TransparentTypeWithOverride * @property {string} "0" * * @typedef {{ [key in K]: V }} HashMap * * @typedef {{ [key in K]: V }} HashMap * * @typedef {T[]} Vec * * @typedef {{ * a: Partial<{ [key in BasicEnum]: number }>, * }} EnumReferenceRecordKey * @property {Partial<{ [key in BasicEnum]: number }>} a * * @typedef {{ * id: string, * } & (NestedEnum)} FlattenOnNestedEnum * @property {string} id * @property {NestedEnum} result * * @typedef {Record} MyEmptyInput * * @typedef {string} String * * @typedef {{ A: string }} ExtraBracketsInTupleVariant * @property {{ A: string }} A * * @typedef {string} ExtraBracketsInUnnamedStruct * @property {string} "0" * * @typedef {T[]} Vec * * @typedef {{ * demo: [string, boolean], * }} InlineTuple * @property {[string, boolean]} demo * * @typedef {{ * demo: [{ * demo: [string, boolean], * }, boolean], * }} InlineTuple2 * @property {[InlineTuple, boolean]} demo * * @typedef {T} Box * * @typedef {T} Box * * @typedef {{ type: "A" } | { type: "B"; data: string }} SkippedFieldWithinVariant * @property {{ type: "A" }} A * @property {{ type: "B"; data: string }} B * * @typedef {{ * "test-ing": string, * }} KebabCase * @property {string} "test-ing" * * @typedef {{ * default_unity_arguments: string[], * }} Issue281 * @property {string[]} default_unity_arguments * * @typedef {{ * borrowed: T[], * owned: T[], * }} LifetimeGenericStruct * @property {T[]} borrowed * @property {T[]} owned * * @typedef {({ Borrowed: T }) & { Owned?: never } | ({ Owned: T }) & { Borrowed?: never }} LifetimeGenericEnum * @property {{ Borrowed: T }} Borrowed * @property {{ Owned: T }} Owned * * @typedef {{ * "@odata.context": string, * }} RenameWithWeirdCharsField * @property {string} "@odata.context" * * @typedef {{ "@odata.context": string }} RenameWithWeirdCharsVariant * @property {{ "@odata.context": string }} "@odata.context" * * @typedef {{ * "": string, * "a\"b": string, * "a\\b": string, * "line\nbreak": string, * "line\u2028break": string, * "line\u2029break": string, * }} RenamedFieldKeys * @property {string} "" * @property {string} "a\"b" * @property {string} "a\\b" * @property {string} "line\nbreak" * @property {string} "line\u2028break" * @property {string} "line\u2029break" * * @typedef {"a-b"} RenamedVariantWithSkippedPayload * @property {"a-b"} "a-b" * * @typedef {never} Type * * @typedef {{ * a: GenericType, * }} ActualType * @property {GenericType} a * * @typedef {{ * string_ident: string, * u32_ident: number, * path: string, * tuple: [string, number], * }} SpectaTypeOverride * @property {string} string_ident * @property {number} u32_ident * @property {string} path * @property {[string, number]} tuple * * @typedef {string} ContainerTypeOverrideStruct * * @typedef {string} ContainerTypeOverrideEnum * * @typedef {string} ContainerTypeOverrideGeneric * * @typedef {T} ContainerTypeOverrideToGeneric * * @typedef {[string, number]} ContainerTypeOverrideTuple * * @typedef {[T, string]} ContainerTypeOverrideTupleGeneric * * @typedef {{ * cause: null, * }} InvalidToValidType * @property {null} cause * * @typedef {string} TupleStruct * @property {string} "0" * * @typedef {string} TupleStructWithRep * @property {string} "0" * * @typedef {T} GenericTupleStruct * @property {T} "0" * * @typedef {string} BracedStruct * @property {string} "0" * * @typedef {{ * t: "StructNew", * a: string, * }} StructNew * @property {"StructNew"} t * @property {string} a * * @typedef {{ * b: string, * }} Struct2 * @property {string} b * * @typedef {{ t: "A" } | { t: "B" }} Enum * @property {{ t: "A" }} A * @property {{ t: "B" }} B * * @typedef {{ t: "C" } | { t: "B" } | { t: "D"; enumField: null }} Enum2 * @property {{ t: "C" }} C * @property {{ t: "B" }} B * @property {{ t: "D"; enumField: null }} D * * @typedef {{ t: "A"; b: string }} Enum3 * @property {{ t: "A"; b: string }} A * * @typedef {{ * A: number, * B: number, * }} StructRenameAllUppercase * @property {number} A * @property {number} B * * @typedef {{ * "a/b": number, * }} RenameSerdeSpecialChar * @property {number} "a/b" * * @typedef {"HELLOWORLD" | "VARIANTB" | "TESTINGWORDS"} EnumRenameAllUppercase * @property {"HELLOWORLD"} HELLOWORLD * @property {"VARIANTB"} VARIANTB * @property {"TESTINGWORDS"} TESTINGWORDS * * @typedef {{ * demo: Recursive, * }} Recursive * @property {Recursive} demo * * @typedef {{ * demo: { [key in string]: RecursiveMapValue }, * }} RecursiveMapValue * @property {{ [key in string]: RecursiveMapValue }} demo * * @typedef {RecursiveInline} RecursiveTransparent * @property {RecursiveInline} "0" * * @typedef {{ A: (RecursiveInEnum) }} RecursiveInEnum * @property {{ A: (RecursiveInEnum) }} A * * @typedef {string | null} NonOptional * @property {string | null} "0" * * @typedef {string | null} OptionalOnNamedField * @property {string | null} ["0"] * * @typedef {{ * b: string | null, * }} OptionalOnTransparentNamedField * @property {string | null} b * * @typedef {({ A?: string | null }) & { B?: never; C?: never } | ({ B: { * a: string | null, * } }) & { A?: never; C?: never } | ({ C: { * a?: string | null, * } }) & { A?: never; B?: never }} OptionalInEnum * @property {{ A?: string | null }} A * @property {{ B: { * a: string | null, * } }} B * @property {{ C: { * a?: string | null, * } }} C * * @typedef {string | number | { id: string } | [string, boolean]} UntaggedVariants * @property {string} A * @property {number} B * @property {number} C * @property {{ id: string }} D * @property {[string, boolean]} E * * @typedef {string | [number, string] | number} UntaggedVariantsWithoutValue * @property {string} A * @property {[number, string]} B * @property {number} C * * @typedef {null | number} UntaggedVariantsWithDuplicateBranches * @property {null} A * @property {number} B * @property {null} C * * @typedef {{ [key in K]: V }} HashMap * * @typedef {{ [key in string]: null }} Regular * @property {{ [key in string]: null }} "0" * * @typedef {{ [key in K]: V }} HashMap * * @typedef {{ [key in K]: V }} HashMap * * @typedef {{ [key in K]: V }} HashMap * * @typedef {{ [key in K]: V }} HashMap * * @typedef {{ [key in MaybeValidKey]: null }} ValidMaybeValidKey * @property {{ [key in MaybeValidKey]: null }} "0" * * @typedef {{ [key in MaybeValidKey>]: null }} ValidMaybeValidKeyNested * @property {{ [key in MaybeValidKey>]: null }} "0" * * @typedef {string} MacroStruct * @property {string} "0" * * @typedef {{ * demo: string, * }} MacroStruct2 * @property {string} demo * * @typedef {({ Demo: string }) & { Demo2?: never } | ({ Demo2: { * demo2: string, * } }) & { Demo?: never }} MacroEnum * @property {{ Demo: string }} Demo * @property {{ Demo2: { * demo2: string, * } }} Demo2 * * @deprecated * @typedef {{ * a: number, * }} DeprecatedType * @property {number} a * * @deprecated Look at you big man using a deprecation message * @typedef {{ * a: number, * }} DeprecatedTypeWithMsg * @property {number} a * * @deprecated Look at you big man using a deprecation message * @typedef {{ * a: number, * }} DeprecatedTypeWithMsg2 * @property {number} a * * @typedef {{ * a: number, * /** * * @deprecated * */ * b: string, * /** * * @deprecated This field is cringe! * */ * c: string, * /** * * @deprecated This field is cringe! * */ * d: string, * }} DeprecatedFields * @property {number} a * @property {string} b - @deprecated * @property {string} c - @deprecated This field is cringe! * @property {string} d - @deprecated This field is cringe! * * @typedef {[ * /** * * @deprecated * */ * string, * /** * * @deprecated Nope * */ * string, * /** * * @deprecated Nope * */ * number]} DeprecatedTupleVariant * @property {string} "0" - @deprecated * @property {string} "1" - @deprecated Nope * @property {number} "2" - @deprecated Nope * * @typedef { * /** * * @deprecated * */ * "A" | * /** * * @deprecated Nope * */ * "B" | * /** * * @deprecated Nope * */ * "C"} DeprecatedEnumVariants * @property { * /** * * @deprecated * */ * "A"} A - @deprecated * @property { * /** * * @deprecated Nope * */ * "B"} B - @deprecated Nope * @property { * /** * * @deprecated Nope * */ * "C"} C - @deprecated Nope * * Some triple-slash comment * Some more triple-slash comment * * @typedef {{ * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * }} CommentedStruct * @property {number} a - Some triple-slash comment Some more triple-slash comment * * Some triple-slash comment * Some more triple-slash comment * * @typedef { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * ({ A: number }) & { B?: never } | * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * ({ B: { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * } }) & { A?: never }} CommentedEnum * @property { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * { A: number }} A - Some triple-slash comment Some more triple-slash comment * @property { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * { B: { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * } }} B - Some triple-slash comment Some more triple-slash comment * * Some single-line comment * * @typedef { * /** * * Some single-line comment * */ * ({ A: number }) & { B?: never } | * /** * * Some single-line comment * */ * ({ B: { * /** * * Some single-line comment * */ * a: number, * } }) & { A?: never }} SingleLineComment * @property { * /** * * Some single-line comment * */ * { A: number }} A - Some single-line comment * @property { * /** * * Some single-line comment * */ * { B: { * /** * * Some single-line comment * */ * a: number, * } }} B - Some single-line comment * * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b * * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b * * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b * * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b * * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b * * @typedef {{ [key in K]: V }} HashMap * * @typedef {{ [key in K]: V }} HashMap * * @typedef {{ [key in K]: V }} HashMap * * @typedef {{ * field: Demo, * }} AGenericStruct * @property {Demo} field * * @typedef {{ * a: B, * b: { * b: number, * }, * c: B, * d: { * flattened: number, * }, * e: { * generic_flattened: number, * }, * }} A * @property {B} a * @property {B} b * @property {B} c * @property {D} d * @property {GenericFlattened} e * * @typedef {{ * a: ToBeFlattened, * b: ToBeFlattened, * }} DoubleFlattened * @property {ToBeFlattened} a * @property {ToBeFlattened} b * * @typedef {(Inner)} FlattenedInner * @property {Inner} c * * @typedef {(BoxedInner)} BoxFlattened * @property {BoxedInner} b * * @typedef {{ * c: { * a: number, * }, * }} BoxInline * @property {BoxedInner} c * * @typedef {{ * a: string, * }} First * @property {string} a * * @typedef {{ * a: number, * }} Second * @property {number} a * * @typedef {{ * b: { [key in string]: string }, * c: First, * } & (First)} Third * @property {First} a * @property {{ [key in string]: string }} b * @property {First} c * * @typedef {{ * a: First, * b: { * a: string, * }, * }} Fourth * @property {First} a * @property {First} b * * @typedef {{ * type: "TagOnStructWithInline", * a: First, * b: { * a: string, * }, * }} TagOnStructWithInline * @property {"TagOnStructWithInline"} type * @property {First} a * @property {First} b * * @typedef {{ * a: First, * b: First, * }} Sixth * @property {First} a * @property {First} b * * @typedef {{ * a: First, * b: Second, * }} Seventh * @property {First} a * @property {Second} b * * @typedef {{ A: string } | "B"} Eight * @property {{ A: string }} A * @property {"B"} B * * @typedef {{ t: "A"; c: string } | { t: "B" } | { t: "C"; c: { * a: string, * } } | { t: "D"; c: First }} Ninth * @property {{ t: "A"; c: string }} A * @property {{ t: "B" }} B * @property {{ t: "C"; c: { * a: string, * } }} C * @property {{ t: "D"; c: First }} D * * @typedef {string | "B" | { * a: string, * } | First} Tenth * @property {string} A * @property {"B"} B * @property {{ * a: string, * }} C * @property {First} D * * @typedef {{ type: "Variant" } & (First)} MyEnumTagged * @property {{ type: "Variant" } & (First)} Variant * * @typedef {{ Variant: (First) }} MyEnumExternal * @property {{ Variant: (First) }} Variant * * @typedef {{ t: "Variant"; c: (First) }} MyEnumAdjacent * @property {{ t: "Variant"; c: (First) }} Variant * * @typedef {(First)} MyEnumUntagged * @property {(First)} Variant * * @typedef {Record} EmptyStruct * * @typedef {{ * a: "EmptyStructWithTag", * }} EmptyStructWithTag * @property {"EmptyStructWithTag"} a * * @typedef {{ t: "A" } | { t: "B"; c: { * id: string, * method: string, * } } | { t: "C"; c: string }} AdjacentlyTagged * @property {{ t: "A" }} A * @property {{ t: "B"; c: { * id: string, * method: string, * } }} B * @property {{ t: "C"; c: string }} C * * @typedef {{ event: "started"; data: { * projectName: string, * } } | { event: "progressTest"; data: { * projectName: string, * status: string, * progress: number, * } } | { event: "finished"; data: { * projectName: string, * } }} LoadProjectEvent * @property {{ event: "started"; data: { * projectName: string, * } }} started * @property {{ event: "progressTest"; data: { * projectName: string, * status: string, * progress: number, * } }} progressTest * @property {{ event: "finished"; data: { * projectName: string, * } }} finished * * @typedef {"A" | ({ B: { * id: string, * method: string, * } }) & { C?: never } | ({ C: string }) & { B?: never }} ExternallyTagged * @property {"A"} A * @property {{ B: { * id: string, * method: string, * } }} B * @property {{ C: string }} C * * @typedef {({ A: { * a: string, * } }) & { B?: never } | ({ B: { * b: string, * } }) & { A?: never }} Issue221External * @property {{ A: { * a: string, * } }} A * @property {{ B: { * b: string, * } }} B * * @typedef {{ type: "A" } & ({ [key in string]: string })} InternallyTaggedD * @property {{ type: "A" } & ({ [key in string]: string })} A * * @typedef {{ type: "A" }} InternallyTaggedE * @property {{ type: "A" }} A * * @typedef {{ type: "A" }} InternallyTaggedF * @property {{ type: "A" }} A * * @typedef {{ type: "A" }} InternallyTaggedH * @property {{ type: "A" }} A * * @typedef {{ type: "A" } & ({ type: "A" } | { type: "B" })} InternallyTaggedL * @property {{ type: "A" } & ({ type: "A" } | { type: "B" })} A * * @typedef {{ type: "A" }} InternallyTaggedM * @property {{ type: "A" }} A * * @typedef {{ * field: string, * }} StructWithAlias * @property {string} field * * @typedef {{ * field: string, * }} StructWithMultipleAliases * @property {string} field * * @typedef {{ * renamed_field: string, * }} StructWithAliasAndRename * @property {string} renamed_field * * @typedef {"Variant" | "Other"} EnumWithVariantAlias * @property {"Variant"} Variant * @property {"Other"} Other * * @typedef {"Variant" | "Other"} EnumWithMultipleVariantAliases * @property {"Variant"} Variant * @property {"Other"} Other * * @typedef {"renamed_variant" | "Other"} EnumWithVariantAliasAndRename * @property {"renamed_variant"} renamed_variant * @property {"Other"} Other * * @typedef {{ type: "A"; field: string } | { type: "B"; other: number }} InternallyTaggedWithAlias * @property {{ type: "A"; field: string }} A * @property {{ type: "B"; other: number }} B * * @typedef {{ type: "A"; data: { * field: string, * } } | { type: "B"; data: { * other: number, * } }} AdjacentlyTaggedWithAlias * @property {{ type: "A"; data: { * field: string, * } }} A * @property {{ type: "B"; data: { * other: number, * } }} B * * @typedef {({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }} UntaggedWithAlias * @property {{ field: string }} A * @property {{ other: number }} B * * @typedef {({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }} Issue221UntaggedSafe * @property {{ a: string }} A * @property {{ b: string }} B * * @typedef {({ a: string }) & { b?: never } | ({ b: string }) & { a?: never } | ({ [key in string]: string })} Issue221UntaggedMixed * @property {{ a: string }} A * @property {{ b: string }} B * @property {({ [key in string]: string })} Unsafe * * @typedef {never} EmptyEnum * * @typedef {never} EmptyEnumTagged * * @typedef {never} EmptyEnumTaggedWContent * * @typedef {never} EmptyEnumUntagged * * @typedef {Record} SkipOnlyField * * @typedef {{ * b: number, * }} SkipField * @property {number} b * * @typedef {{ A: string }} SkipVariant * @property {{ A: string }} A * * @typedef {"A" | { B: [number] }} SkipUnnamedFieldInVariant * @property {"A"} A * @property {{ B: [number] }} B * * @typedef {({ A: Record }) & { B?: never } | ({ B: { * b: number, * } }) & { A?: never }} SkipNamedFieldInVariant * @property {{ A: Record }} A * @property {{ B: { * b: number, * } }} B * * @typedef {null} TransparentWithSkip * @property {null} "0" * * @typedef {string} TransparentWithSkip2 * @property {string} "0" * * @typedef {string} TransparentWithSkip3 * @property {string} "0" * * @typedef {{ tag: "A"; data: string }} SkipVariant2 * @property {{ tag: "A"; data: string }} A * * @typedef {{ A: { * a: string, * } }} SkipVariant3 * @property {{ A: { * a: string, * } }} A * * @typedef {{ * a: number, * }} SkipStructFields * @property {number} a * * @typedef {{ * a: number, * }} SpectaSkipNonTypeField * @property {number} a * * @typedef {{ * a: number, * b: number, * }} FlattenA * @property {number} a * @property {number} b * * @typedef {{ * c: number, * } & (FlattenA)} FlattenB * @property {FlattenA} a * @property {number} c * * @typedef {{ * c: number, * } & (FlattenA)} FlattenC * @property {FlattenA} a * @property {number} c * * @typedef {{ * a: FlattenA, * c: number, * }} FlattenD * @property {FlattenA} a * @property {number} c * * @typedef {{ * b: { * c: number, * } & (FlattenA), * d: number, * }} FlattenE * @property {FlattenB} b * @property {number} d * * @typedef {{ * b: { * c: number, * } & (FlattenA), * d: number, * }} FlattenF * @property {FlattenB} b * @property {number} d * * @typedef {{ * b: FlattenB, * d: number, * }} FlattenG * @property {FlattenB} b * @property {number} d * * @typedef {[number[], [number[], number[]], [number[], number[], number[]]]} TupleNested * @property {number[]} "0" * @property {[number[], number[]]} "1" * @property {[number[], number[], number[]]} "2" * * @typedef {{ * value: T, * values: T[], * }} Generic1 * @property {T} value * @property {T[]} values * * @typedef {{ * value: T, * values: T[], * }} GenericAutoBound * @property {T} value * @property {T[]} values * * @typedef {{ * value: T, * values: T[], * }} GenericAutoBound2 * @property {T} value * @property {T[]} values * * @typedef {{ * foo: Generic1, * bar: Generic1[], * baz: { [key in string]: Generic1 }, * }} Container1 * @property {Generic1} foo * @property {Generic1[]} bar * @property {{ [key in string]: Generic1 }} baz * * @typedef {({ A: A }) & { B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ B: [B, B, B] }) & { A?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ C: C[] }) & { A?: never; B?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ D: A[][][] }) & { A?: never; B?: never; C?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ E: { * a: A, * b: B, * c: C, * } }) & { A?: never; B?: never; C?: never; D?: never; X?: never; Y?: never; Z?: never } | ({ X: number[] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; Y?: never; Z?: never } | ({ Y: number }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Z?: never } | ({ Z: number[][] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never }} Generic2 * @property {{ A: A }} A * @property {{ B: [B, B, B] }} B * @property {{ C: C[] }} C * @property {{ D: A[][][] }} D * @property {{ E: { * a: A, * b: B, * c: C, * } }} E * @property {{ X: number[] }} X * @property {{ Y: number }} Y * @property {{ Z: number[][] }} Z * * @typedef {T[][]} GenericNewType1 * @property {T[][]} "0" * * @typedef {[T, T[], T[][]]} GenericTuple * @property {T} "0" * @property {T[]} "1" * @property {T[][]} "2" * * @typedef {{ * a: T, * b: [T, T], * c: [T, [T, T]], * d: [T, T, T], * e: [([T, T]), ([T, T]), ([T, T])], * f: T[], * g: T[][], * h: ([([T, T]), ([T, T]), ([T, T])])[], * }} GenericStruct2 * @property {T} a * @property {[T, T]} b * @property {[T, [T, T]]} c * @property {[T, T, T]} d * @property {[([T, T]), ([T, T]), ([T, T])]} e * @property {T[]} f * @property {T[][]} g * @property {([([T, T]), ([T, T]), ([T, T])])[]} h * * @typedef {T} InlineGenericNewtype * @property {T} "0" * * @typedef {[T, T[], [T, T], { [key in string]: T }, T | null, "Unit" | ({ Unnamed: T }) & { Named?: never } | ({ Named: { * value: T, * } }) & { Unnamed?: never }]} InlineGenericNested * @property {T} "0" * @property {T[]} "1" * @property {[T, T]} "2" * @property {{ [key in string]: T }} "3" * @property {T | null} "4" * @property {"Unit" | ({ Unnamed: T }) & { Named?: never } | ({ Named: { * value: T, * } }) & { Unnamed?: never }} "5" * * @typedef {{ * t: T, * }} InlineFlattenGenericsG * @property {T} t * * @typedef {{ * g: InlineFlattenGenericsG, * gi: { * t: string, * }, * } & (InlineFlattenGenericsG)} InlineFlattenGenerics * @property {InlineFlattenGenericsG} g * @property {InlineFlattenGenericsG} gi * @property {InlineFlattenGenericsG} t * * @typedef {{ * value: T, * }} GenericDefault * @property {T} value * * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second * * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second * * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second * * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second * * @typedef {{ * value: T, * }} GenericDefaultSkipped * @property {T} value * * @typedef {{ * value: number, * }} GenericDefaultSkippedNonType * @property {number} value * * @typedef {{ * pair: Pair, * }} GenericParameterOrderPreserved * @property {Pair} pair * * @typedef {{ * data: [number], * a: [number, number], * d: [number, number], * }} ConstGenericInNonConstContainer * @property {[number]} data * @property {[number, number]} a * @property {[number, number]} d * * @typedef {{ * data: number[], * a: number[], * d: [number, number], * }} ConstGenericInConstContainer * @property {number[]} data * @property {number[]} a * @property {[number, number]} d * * @typedef {{ * a: NamedConstGeneric, * b: NamedConstGeneric, * d: [number, number], * }} NamedConstGenericContainer * @property {NamedConstGeneric} a * @property {NamedConstGeneric} b * @property {[number, number]} d * * @typedef {{ * b: { * data: [number, number], * a: [number, number], * d: [number, number, number], * }, * c: { * data: [number, number, number], * a: [number, number], * d: [number, number, number], * }, * d: [number, number], * }} InlineConstGenericContainer * @property {{ * data: number[], * a: number[], * d: [number, number, number], * }} b * @property {{ * data: number[], * a: number[], * d: [number, number, number], * }} c * @property {[number, number]} d * * @typedef {{ * b: { * data: [number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }, * c: { * data: [number, number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }, * d: [number, number], * }} InlineRecursiveConstGenericContainer * @property {InlineRecursiveConstGeneric} b * @property {InlineRecursiveConstGeneric} c * @property {[number, number]} d * * @typedef {never} TestCollectionRegister * * @typedef {never} TestCollectionRegister */ ================================================ FILE: tests/tests/snapshots/test__jsdoc__primitives-many-inline-serde_phases.snap ================================================ --- source: tests/tests/jsdoc.rs expression: output --- /** * https://github.com/specta-rs/specta/issues/374 * * @typedef {Issue374_Serialize | Issue374_Deserialize} Issue374 * @property {Issue374_Serialize} Serialize * @property {Issue374_Deserialize} Deserialize * * @typedef {Optional_Serialize | Optional_Deserialize} Optional * @property {Optional_Serialize} Serialize * @property {Optional_Deserialize} Deserialize * * @typedef {StructPhaseSpecificRenameSerialize | StructPhaseSpecificRenameDeserialize} StructPhaseSpecificRename * @property {StructPhaseSpecificRenameSerialize} Serialize * @property {StructPhaseSpecificRenameDeserialize} Deserialize * * @typedef {{ * start: T, * end: T, * }} Range * @property {T} start * @property {T} end * * @typedef {{ * start: T, * end: T, * }} RangeInclusive * @property {T} start * @property {T} end * * @typedef {string} String * * @typedef {string} PathBuf * * @typedef {string} IpAddr * * @typedef {string} Ipv4Addr * * @typedef {string} Ipv6Addr * * @typedef {string} SocketAddr * * @typedef {string} SocketAddrV4 * * @typedef {string} SocketAddrV6 * * @typedef {T} Cow * * @typedef {T} Cow * * @typedef {T[]} Vec * * @typedef {T[]} Vec * * @typedef {({ Ok: T }) & { Err?: never } | ({ Err: E }) & { Ok?: never }} Result * @property {{ Ok: T }} Ok * @property {{ Err: E }} Err * * @typedef {T[]} Vec * * @typedef {null} PhantomData * * @typedef {null} PhantomData * * @typedef {never} Infallible * * @typedef {null} Unit1 * * @typedef {Record} Unit2 * * @typedef {[]} Unit3 * * @typedef {null} Unit4 * @property {null} "0" * * @typedef {"A"} Unit5 * @property {"A"} A * * @typedef {{ A: null }} Unit6 * @property {{ A: null }} A * * @typedef {{ A: Record }} Unit7 * @property {{ A: Record }} A * * @typedef {{ * a: number, * b: string, * c: [number, string, number], * d: string[], * e: string | null, * }} SimpleStruct * @property {number} a * @property {string} b * @property {[number, string, number]} c * @property {string[]} d * @property {string | null} e * * @typedef {number} TupleStruct1 * @property {number} "0" * * @typedef {[number, boolean, string]} TupleStruct3 * @property {number} "0" * @property {boolean} "1" * @property {string} "2" * * @typedef {"Unit" | ({ Single: number }) & { Multiple?: never; Struct?: never } | ({ Multiple: [number, number] }) & { Single?: never; Struct?: never } | ({ Struct: { * a: number, * } }) & { Multiple?: never; Single?: never }} TestEnum * @property {"Unit"} Unit * @property {{ Single: number }} Single * @property {{ Multiple: [number, number] }} Multiple * @property {{ Struct: { * a: number, * } }} Struct * * @typedef {TestEnum} RefStruct * @property {TestEnum} "0" * * @typedef {{ * inline_this: { * ref_struct: SimpleStruct, * val: number, * }, * dont_inline_this: RefStruct, * }} InlinerStruct * @property {InlineStruct} inline_this * @property {RefStruct} dont_inline_this * * @typedef {{ * arg: T, * }} GenericStruct * @property {T} arg * * @typedef {{ * arg: T, * }} GenericStruct * @property {T} arg * * @typedef {{ * outer: string, * } & (FlattenEnum)} FlattenEnumStruct * @property {string} outer * @property {FlattenEnum} inner * * @typedef {{ * overriden_field: string, * }} OverridenStruct * @property {string} overriden_field * * @typedef {{ [key in number]: string }} HasGenericAlias * @property {{ [key in number]: string }} "0" * * @typedef {({ A: string }) & { D?: never; bbb?: never; cccc?: never } | ({ bbb: number }) & { A?: never; D?: never; cccc?: never } | ({ cccc: number }) & { A?: never; D?: never; bbb?: never } | ({ D: { * a: string, * bbbbbb: number, * } }) & { A?: never; bbb?: never; cccc?: never }} EnumMacroAttributes * @property {{ A: string }} A * @property {{ bbb: number }} bbb * @property {{ cccc: number }} cccc * @property {{ D: { * a: string, * bbbbbb: number, * } }} D * * @typedef {{ A: { * a: string, * } }} InlineEnumField * @property {{ A: { * a: string, * } }} A * * @typedef {{ * optional_field: { * a: string, * } | null, * }} InlineOptionalType * @property {PlaceholderInnerField | null} optional_field * * @typedef {"OneWord" | "Two words"} Rename * @property {"OneWord"} OneWord * @property {"Two words"} "Two words" * * @typedef {TransparentTypeInner} TransparentType * @property {TransparentTypeInner} "0" * * @typedef {null} TransparentType2 * @property {null} "0" * * @typedef {string} TransparentTypeWithOverride * @property {string} "0" * * @typedef {{ [key in K]: V }} HashMap * * @typedef {{ [key in K]: V }} HashMap * * @typedef {T[]} Vec * * @typedef {{ * a: Partial<{ [key in BasicEnum]: number }>, * }} EnumReferenceRecordKey * @property {Partial<{ [key in BasicEnum]: number }>} a * * @typedef {{ * id: string, * } & (NestedEnum)} FlattenOnNestedEnum * @property {string} id * @property {NestedEnum} result * * @typedef {Record} MyEmptyInput * * @typedef {string} String * * @typedef {{ A: string }} ExtraBracketsInTupleVariant * @property {{ A: string }} A * * @typedef {string} ExtraBracketsInUnnamedStruct * @property {string} "0" * * @typedef {T[]} Vec * * @typedef {{ * demo: [string, boolean], * }} InlineTuple * @property {[string, boolean]} demo * * @typedef {{ * demo: [{ * demo: [string, boolean], * }, boolean], * }} InlineTuple2 * @property {[InlineTuple, boolean]} demo * * @typedef {T} Box * * @typedef {T} Box * * @typedef {{ type: "A" } | { type: "B"; data: string }} SkippedFieldWithinVariant * @property {{ type: "A" }} A * @property {{ type: "B"; data: string }} B * * @typedef {{ * "test-ing": string, * }} KebabCase * @property {string} "test-ing" * * @typedef {{ * default_unity_arguments: string[], * }} Issue281 * @property {string[]} default_unity_arguments * * @typedef {{ * borrowed: T[], * owned: T[], * }} LifetimeGenericStruct * @property {T[]} borrowed * @property {T[]} owned * * @typedef {({ Borrowed: T }) & { Owned?: never } | ({ Owned: T }) & { Borrowed?: never }} LifetimeGenericEnum * @property {{ Borrowed: T }} Borrowed * @property {{ Owned: T }} Owned * * @typedef {{ * "@odata.context": string, * }} RenameWithWeirdCharsField * @property {string} "@odata.context" * * @typedef {{ "@odata.context": string }} RenameWithWeirdCharsVariant * @property {{ "@odata.context": string }} "@odata.context" * * @typedef {{ * "": string, * "a\"b": string, * "a\\b": string, * "line\nbreak": string, * "line\u2028break": string, * "line\u2029break": string, * }} RenamedFieldKeys * @property {string} "" * @property {string} "a\"b" * @property {string} "a\\b" * @property {string} "line\nbreak" * @property {string} "line\u2028break" * @property {string} "line\u2029break" * * @typedef {"a-b"} RenamedVariantWithSkippedPayload * @property {"a-b"} "a-b" * * @typedef {never} Type * * @typedef {{ * a: GenericType, * }} ActualType * @property {GenericType} a * * @typedef {{ * string_ident: string, * u32_ident: number, * path: string, * tuple: [string, number], * }} SpectaTypeOverride * @property {string} string_ident * @property {number} u32_ident * @property {string} path * @property {[string, number]} tuple * * @typedef {string} ContainerTypeOverrideStruct * * @typedef {string} ContainerTypeOverrideEnum * * @typedef {string} ContainerTypeOverrideGeneric * * @typedef {T} ContainerTypeOverrideToGeneric * * @typedef {[string, number]} ContainerTypeOverrideTuple * * @typedef {[T, string]} ContainerTypeOverrideTupleGeneric * * @typedef {{ * cause: null, * }} InvalidToValidType * @property {null} cause * * @typedef {string} TupleStruct * @property {string} "0" * * @typedef {string} TupleStructWithRep * @property {string} "0" * * @typedef {T} GenericTupleStruct * @property {T} "0" * * @typedef {string} BracedStruct * @property {string} "0" * * @typedef {{ * t: "StructNew", * a: string, * }} StructNew * @property {"StructNew"} t * @property {string} a * * @typedef {{ * b: string, * }} Struct2 * @property {string} b * * @typedef {{ t: "A" } | { t: "B" }} Enum * @property {{ t: "A" }} A * @property {{ t: "B" }} B * * @typedef {{ t: "C" } | { t: "B" } | { t: "D"; enumField: null }} Enum2 * @property {{ t: "C" }} C * @property {{ t: "B" }} B * @property {{ t: "D"; enumField: null }} D * * @typedef {{ t: "A"; b: string }} Enum3 * @property {{ t: "A"; b: string }} A * * @typedef {{ * A: number, * B: number, * }} StructRenameAllUppercase * @property {number} A * @property {number} B * * @typedef {{ * "a/b": number, * }} RenameSerdeSpecialChar * @property {number} "a/b" * * @typedef {"HELLOWORLD" | "VARIANTB" | "TESTINGWORDS"} EnumRenameAllUppercase * @property {"HELLOWORLD"} HELLOWORLD * @property {"VARIANTB"} VARIANTB * @property {"TESTINGWORDS"} TESTINGWORDS * * @typedef {{ * demo: Recursive, * }} Recursive * @property {Recursive} demo * * @typedef {{ * demo: { [key in string]: RecursiveMapValue }, * }} RecursiveMapValue * @property {{ [key in string]: RecursiveMapValue }} demo * * @typedef {RecursiveInline} RecursiveTransparent * @property {RecursiveInline} "0" * * @typedef {{ A: (RecursiveInEnum) }} RecursiveInEnum * @property {{ A: (RecursiveInEnum) }} A * * @typedef {string | null} NonOptional * @property {string | null} "0" * * @typedef {string | null} OptionalOnNamedField * @property {string | null} ["0"] * * @typedef {{ * b: string | null, * }} OptionalOnTransparentNamedField * @property {string | null} b * * @typedef {({ A?: string | null }) & { B?: never; C?: never } | ({ B: { * a: string | null, * } }) & { A?: never; C?: never } | ({ C: { * a?: string | null, * } }) & { A?: never; B?: never }} OptionalInEnum * @property {{ A?: string | null }} A * @property {{ B: { * a: string | null, * } }} B * @property {{ C: { * a?: string | null, * } }} C * * @typedef {string | number | { id: string } | [string, boolean]} UntaggedVariants * @property {string} A * @property {number} B * @property {number} C * @property {{ id: string }} D * @property {[string, boolean]} E * * @typedef {string | [number, string] | number} UntaggedVariantsWithoutValue * @property {string} A * @property {[number, string]} B * @property {number} C * * @typedef {null | number} UntaggedVariantsWithDuplicateBranches * @property {null} A * @property {number} B * @property {null} C * * @typedef {{ [key in K]: V }} HashMap * * @typedef {{ [key in string]: null }} Regular * @property {{ [key in string]: null }} "0" * * @typedef {{ [key in K]: V }} HashMap * * @typedef {{ [key in K]: V }} HashMap * * @typedef {{ [key in K]: V }} HashMap * * @typedef {{ [key in K]: V }} HashMap * * @typedef {{ [key in MaybeValidKey]: null }} ValidMaybeValidKey * @property {{ [key in MaybeValidKey]: null }} "0" * * @typedef {{ [key in MaybeValidKey>]: null }} ValidMaybeValidKeyNested * @property {{ [key in MaybeValidKey>]: null }} "0" * * @typedef {string} MacroStruct * @property {string} "0" * * @typedef {{ * demo: string, * }} MacroStruct2 * @property {string} demo * * @typedef {({ Demo: string }) & { Demo2?: never } | ({ Demo2: { * demo2: string, * } }) & { Demo?: never }} MacroEnum * @property {{ Demo: string }} Demo * @property {{ Demo2: { * demo2: string, * } }} Demo2 * * @deprecated * @typedef {{ * a: number, * }} DeprecatedType * @property {number} a * * @deprecated Look at you big man using a deprecation message * @typedef {{ * a: number, * }} DeprecatedTypeWithMsg * @property {number} a * * @deprecated Look at you big man using a deprecation message * @typedef {{ * a: number, * }} DeprecatedTypeWithMsg2 * @property {number} a * * @typedef {{ * a: number, * /** * * @deprecated * */ * b: string, * /** * * @deprecated This field is cringe! * */ * c: string, * /** * * @deprecated This field is cringe! * */ * d: string, * }} DeprecatedFields * @property {number} a * @property {string} b - @deprecated * @property {string} c - @deprecated This field is cringe! * @property {string} d - @deprecated This field is cringe! * * @typedef {[ * /** * * @deprecated * */ * string, * /** * * @deprecated Nope * */ * string, * /** * * @deprecated Nope * */ * number]} DeprecatedTupleVariant * @property {string} "0" - @deprecated * @property {string} "1" - @deprecated Nope * @property {number} "2" - @deprecated Nope * * @typedef { * /** * * @deprecated * */ * "A" | * /** * * @deprecated Nope * */ * "B" | * /** * * @deprecated Nope * */ * "C"} DeprecatedEnumVariants * @property { * /** * * @deprecated * */ * "A"} A - @deprecated * @property { * /** * * @deprecated Nope * */ * "B"} B - @deprecated Nope * @property { * /** * * @deprecated Nope * */ * "C"} C - @deprecated Nope * * Some triple-slash comment * Some more triple-slash comment * * @typedef {{ * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * }} CommentedStruct * @property {number} a - Some triple-slash comment Some more triple-slash comment * * Some triple-slash comment * Some more triple-slash comment * * @typedef { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * ({ A: number }) & { B?: never } | * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * ({ B: { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * } }) & { A?: never }} CommentedEnum * @property { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * { A: number }} A - Some triple-slash comment Some more triple-slash comment * @property { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * { B: { * /** * * Some triple-slash comment * * Some more triple-slash comment * */ * a: number, * } }} B - Some triple-slash comment Some more triple-slash comment * * Some single-line comment * * @typedef { * /** * * Some single-line comment * */ * ({ A: number }) & { B?: never } | * /** * * Some single-line comment * */ * ({ B: { * /** * * Some single-line comment * */ * a: number, * } }) & { A?: never }} SingleLineComment * @property { * /** * * Some single-line comment * */ * { A: number }} A - Some single-line comment * @property { * /** * * Some single-line comment * */ * { B: { * /** * * Some single-line comment * */ * a: number, * } }} B - Some single-line comment * * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b * * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b * * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b * * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b * * @typedef {{ * a: A, * b: B, * }} Demo * @property {A} a * @property {B} b * * @typedef {{ [key in K]: V }} HashMap * * @typedef {{ [key in K]: V }} HashMap * * @typedef {{ [key in K]: V }} HashMap * * @typedef {{ * field: Demo, * }} AGenericStruct * @property {Demo} field * * @typedef {{ * a: B, * b: { * b: number, * }, * c: B, * d: { * flattened: number, * }, * e: { * generic_flattened: number, * }, * }} A * @property {B} a * @property {B} b * @property {B} c * @property {D} d * @property {GenericFlattened} e * * @typedef {{ * a: ToBeFlattened, * b: ToBeFlattened, * }} DoubleFlattened * @property {ToBeFlattened} a * @property {ToBeFlattened} b * * @typedef {(Inner)} FlattenedInner * @property {Inner} c * * @typedef {(BoxedInner)} BoxFlattened * @property {BoxedInner} b * * @typedef {{ * c: { * a: number, * }, * }} BoxInline * @property {BoxedInner} c * * @typedef {{ * a: string, * }} First * @property {string} a * * @typedef {{ * a: number, * }} Second * @property {number} a * * @typedef {{ * b: { [key in string]: string }, * c: First, * } & (First)} Third * @property {First} a * @property {{ [key in string]: string }} b * @property {First} c * * @typedef {{ * a: First, * b: { * a: string, * }, * }} Fourth * @property {First} a * @property {First} b * * @typedef {{ * type: "TagOnStructWithInline", * a: First, * b: { * a: string, * }, * }} TagOnStructWithInline * @property {"TagOnStructWithInline"} type * @property {First} a * @property {First} b * * @typedef {{ * a: First, * b: First, * }} Sixth * @property {First} a * @property {First} b * * @typedef {{ * a: First, * b: Second, * }} Seventh * @property {First} a * @property {Second} b * * @typedef {{ A: string } | "B"} Eight * @property {{ A: string }} A * @property {"B"} B * * @typedef {{ t: "A"; c: string } | { t: "B" } | { t: "C"; c: { * a: string, * } } | { t: "D"; c: First }} Ninth * @property {{ t: "A"; c: string }} A * @property {{ t: "B" }} B * @property {{ t: "C"; c: { * a: string, * } }} C * @property {{ t: "D"; c: First }} D * * @typedef {string | "B" | { * a: string, * } | First} Tenth * @property {string} A * @property {"B"} B * @property {{ * a: string, * }} C * @property {First} D * * @typedef {{ type: "Variant" } & (First)} MyEnumTagged * @property {{ type: "Variant" } & (First)} Variant * * @typedef {{ Variant: (First) }} MyEnumExternal * @property {{ Variant: (First) }} Variant * * @typedef {{ t: "Variant"; c: (First) }} MyEnumAdjacent * @property {{ t: "Variant"; c: (First) }} Variant * * @typedef {(First)} MyEnumUntagged * @property {(First)} Variant * * @typedef {Record} EmptyStruct * * @typedef {{ * a: "EmptyStructWithTag", * }} EmptyStructWithTag * @property {"EmptyStructWithTag"} a * * @typedef {{ t: "A" } | { t: "B"; c: { * id: string, * method: string, * } } | { t: "C"; c: string }} AdjacentlyTagged * @property {{ t: "A" }} A * @property {{ t: "B"; c: { * id: string, * method: string, * } }} B * @property {{ t: "C"; c: string }} C * * @typedef {{ event: "started"; data: { * projectName: string, * } } | { event: "progressTest"; data: { * projectName: string, * status: string, * progress: number, * } } | { event: "finished"; data: { * projectName: string, * } }} LoadProjectEvent * @property {{ event: "started"; data: { * projectName: string, * } }} started * @property {{ event: "progressTest"; data: { * projectName: string, * status: string, * progress: number, * } }} progressTest * @property {{ event: "finished"; data: { * projectName: string, * } }} finished * * @typedef {"A" | ({ B: { * id: string, * method: string, * } }) & { C?: never } | ({ C: string }) & { B?: never }} ExternallyTagged * @property {"A"} A * @property {{ B: { * id: string, * method: string, * } }} B * @property {{ C: string }} C * * @typedef {({ A: { * a: string, * } }) & { B?: never } | ({ B: { * b: string, * } }) & { A?: never }} Issue221External * @property {{ A: { * a: string, * } }} A * @property {{ B: { * b: string, * } }} B * * @typedef {{ type: "A" } & ({ [key in string]: string })} InternallyTaggedD * @property {{ type: "A" } & ({ [key in string]: string })} A * * @typedef {{ type: "A" }} InternallyTaggedE * @property {{ type: "A" }} A * * @typedef {{ type: "A" }} InternallyTaggedF * @property {{ type: "A" }} A * * @typedef {{ type: "A" }} InternallyTaggedH * @property {{ type: "A" }} A * * @typedef {{ type: "A" } & ({ type: "A" } | { type: "B" })} InternallyTaggedL * @property {{ type: "A" } & ({ type: "A" } | { type: "B" })} A * * @typedef {{ type: "A" }} InternallyTaggedM * @property {{ type: "A" }} A * * @typedef {{ * field: string, * }} StructWithAlias * @property {string} field * * @typedef {{ * field: string, * }} StructWithMultipleAliases * @property {string} field * * @typedef {{ * renamed_field: string, * }} StructWithAliasAndRename * @property {string} renamed_field * * @typedef {"Variant" | "Other"} EnumWithVariantAlias * @property {"Variant"} Variant * @property {"Other"} Other * * @typedef {"Variant" | "Other"} EnumWithMultipleVariantAliases * @property {"Variant"} Variant * @property {"Other"} Other * * @typedef {"renamed_variant" | "Other"} EnumWithVariantAliasAndRename * @property {"renamed_variant"} renamed_variant * @property {"Other"} Other * * @typedef {{ type: "A"; field: string } | { type: "B"; other: number }} InternallyTaggedWithAlias * @property {{ type: "A"; field: string }} A * @property {{ type: "B"; other: number }} B * * @typedef {{ type: "A"; data: { * field: string, * } } | { type: "B"; data: { * other: number, * } }} AdjacentlyTaggedWithAlias * @property {{ type: "A"; data: { * field: string, * } }} A * @property {{ type: "B"; data: { * other: number, * } }} B * * @typedef {({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }} UntaggedWithAlias * @property {{ field: string }} A * @property {{ other: number }} B * * @typedef {({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }} Issue221UntaggedSafe * @property {{ a: string }} A * @property {{ b: string }} B * * @typedef {({ a: string }) & { b?: never } | ({ b: string }) & { a?: never } | ({ [key in string]: string })} Issue221UntaggedMixed * @property {{ a: string }} A * @property {{ b: string }} B * @property {({ [key in string]: string })} Unsafe * * @typedef {never} EmptyEnum * * @typedef {never} EmptyEnumTagged * * @typedef {never} EmptyEnumTaggedWContent * * @typedef {never} EmptyEnumUntagged * * @typedef {Record} SkipOnlyField * * @typedef {{ * b: number, * }} SkipField * @property {number} b * * @typedef {{ A: string }} SkipVariant * @property {{ A: string }} A * * @typedef {"A" | { B: [number] }} SkipUnnamedFieldInVariant * @property {"A"} A * @property {{ B: [number] }} B * * @typedef {({ A: Record }) & { B?: never } | ({ B: { * b: number, * } }) & { A?: never }} SkipNamedFieldInVariant * @property {{ A: Record }} A * @property {{ B: { * b: number, * } }} B * * @typedef {null} TransparentWithSkip * @property {null} "0" * * @typedef {string} TransparentWithSkip2 * @property {string} "0" * * @typedef {string} TransparentWithSkip3 * @property {string} "0" * * @typedef {{ tag: "A"; data: string }} SkipVariant2 * @property {{ tag: "A"; data: string }} A * * @typedef {{ A: { * a: string, * } }} SkipVariant3 * @property {{ A: { * a: string, * } }} A * * @typedef {{ * a: number, * }} SkipStructFields * @property {number} a * * @typedef {{ * a: number, * }} SpectaSkipNonTypeField * @property {number} a * * @typedef {{ * a: number, * b: number, * }} FlattenA * @property {number} a * @property {number} b * * @typedef {{ * c: number, * } & (FlattenA)} FlattenB * @property {FlattenA} a * @property {number} c * * @typedef {{ * c: number, * } & (FlattenA)} FlattenC * @property {FlattenA} a * @property {number} c * * @typedef {{ * a: FlattenA, * c: number, * }} FlattenD * @property {FlattenA} a * @property {number} c * * @typedef {{ * b: { * c: number, * } & (FlattenA), * d: number, * }} FlattenE * @property {FlattenB} b * @property {number} d * * @typedef {{ * b: { * c: number, * } & (FlattenA), * d: number, * }} FlattenF * @property {FlattenB} b * @property {number} d * * @typedef {{ * b: FlattenB, * d: number, * }} FlattenG * @property {FlattenB} b * @property {number} d * * @typedef {[number[], [number[], number[]], [number[], number[], number[]]]} TupleNested * @property {number[]} "0" * @property {[number[], number[]]} "1" * @property {[number[], number[], number[]]} "2" * * @typedef {{ * value: T, * values: T[], * }} Generic1 * @property {T} value * @property {T[]} values * * @typedef {{ * value: T, * values: T[], * }} GenericAutoBound * @property {T} value * @property {T[]} values * * @typedef {{ * value: T, * values: T[], * }} GenericAutoBound2 * @property {T} value * @property {T[]} values * * @typedef {{ * foo: Generic1, * bar: Generic1[], * baz: { [key in string]: Generic1 }, * }} Container1 * @property {Generic1} foo * @property {Generic1[]} bar * @property {{ [key in string]: Generic1 }} baz * * @typedef {({ A: A }) & { B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ B: [B, B, B] }) & { A?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ C: C[] }) & { A?: never; B?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ D: A[][][] }) & { A?: never; B?: never; C?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ E: { * a: A, * b: B, * c: C, * } }) & { A?: never; B?: never; C?: never; D?: never; X?: never; Y?: never; Z?: never } | ({ X: number[] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; Y?: never; Z?: never } | ({ Y: number }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Z?: never } | ({ Z: number[][] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never }} Generic2 * @property {{ A: A }} A * @property {{ B: [B, B, B] }} B * @property {{ C: C[] }} C * @property {{ D: A[][][] }} D * @property {{ E: { * a: A, * b: B, * c: C, * } }} E * @property {{ X: number[] }} X * @property {{ Y: number }} Y * @property {{ Z: number[][] }} Z * * @typedef {T[][]} GenericNewType1 * @property {T[][]} "0" * * @typedef {[T, T[], T[][]]} GenericTuple * @property {T} "0" * @property {T[]} "1" * @property {T[][]} "2" * * @typedef {{ * a: T, * b: [T, T], * c: [T, [T, T]], * d: [T, T, T], * e: [([T, T]), ([T, T]), ([T, T])], * f: T[], * g: T[][], * h: ([([T, T]), ([T, T]), ([T, T])])[], * }} GenericStruct2 * @property {T} a * @property {[T, T]} b * @property {[T, [T, T]]} c * @property {[T, T, T]} d * @property {[([T, T]), ([T, T]), ([T, T])]} e * @property {T[]} f * @property {T[][]} g * @property {([([T, T]), ([T, T]), ([T, T])])[]} h * * @typedef {T} InlineGenericNewtype * @property {T} "0" * * @typedef {[T, T[], [T, T], { [key in string]: T }, T | null, "Unit" | ({ Unnamed: T }) & { Named?: never } | ({ Named: { * value: T, * } }) & { Unnamed?: never }]} InlineGenericNested * @property {T} "0" * @property {T[]} "1" * @property {[T, T]} "2" * @property {{ [key in string]: T }} "3" * @property {T | null} "4" * @property {"Unit" | ({ Unnamed: T }) & { Named?: never } | ({ Named: { * value: T, * } }) & { Unnamed?: never }} "5" * * @typedef {{ * t: T, * }} InlineFlattenGenericsG * @property {T} t * * @typedef {{ * g: InlineFlattenGenericsG, * gi: { * t: string, * }, * } & (InlineFlattenGenericsG)} InlineFlattenGenerics * @property {InlineFlattenGenericsG} g * @property {InlineFlattenGenericsG} gi * @property {InlineFlattenGenericsG} t * * @typedef {{ * value: T, * }} GenericDefault * @property {T} value * * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second * * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second * * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second * * @typedef {{ * first: T, * second: U, * }} ChainedGenericDefault * @property {T} first * @property {U} second * * @typedef {{ * value: T, * }} GenericDefaultSkipped * @property {T} value * * @typedef {{ * value: number, * }} GenericDefaultSkippedNonType * @property {number} value * * @typedef {{ * pair: Pair, * }} GenericParameterOrderPreserved * @property {Pair} pair * * @typedef {{ * data: [number], * a: [number, number], * d: [number, number], * }} ConstGenericInNonConstContainer * @property {[number]} data * @property {[number, number]} a * @property {[number, number]} d * * @typedef {{ * data: number[], * a: number[], * d: [number, number], * }} ConstGenericInConstContainer * @property {number[]} data * @property {number[]} a * @property {[number, number]} d * * @typedef {{ * a: NamedConstGeneric, * b: NamedConstGeneric, * d: [number, number], * }} NamedConstGenericContainer * @property {NamedConstGeneric} a * @property {NamedConstGeneric} b * @property {[number, number]} d * * @typedef {{ * b: { * data: [number, number], * a: [number, number], * d: [number, number, number], * }, * c: { * data: [number, number, number], * a: [number, number], * d: [number, number, number], * }, * d: [number, number], * }} InlineConstGenericContainer * @property {{ * data: number[], * a: number[], * d: [number, number, number], * }} b * @property {{ * data: number[], * a: number[], * d: [number, number, number], * }} c * @property {[number, number]} d * * @typedef {{ * b: { * data: [number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }, * c: { * data: [number, number, number], * a: [number, number], * d: [number, number, number], * e: InlineRecursiveConstGeneric, * }, * d: [number, number], * }} InlineRecursiveConstGenericContainer * @property {InlineRecursiveConstGeneric} b * @property {InlineRecursiveConstGeneric} c * @property {[number, number]} d * * @typedef {never} TestCollectionRegister * * @typedef {never} TestCollectionRegister */ ================================================ FILE: tests/tests/snapshots/test__jsdoc__reference-raw.snap ================================================ --- source: tests/tests/jsdoc.rs expression: output --- Range: Range RangeInclusive: RangeInclusive String: string PathBuf: string IpAddr: string Ipv4Addr: string Ipv6Addr: string SocketAddr: string SocketAddrV4: string SocketAddrV6: string Cow<'static, str>: string Cow<'static, i32>: number Vec: number[] Vec: MyEnum[] Result: Result Vec>>: (number | null)[] PhantomData<()>: null PhantomData: null Infallible: never Unit1: Unit1 Unit2: Unit2 Unit3: Unit3 Unit4: Unit4 Unit5: Unit5 Unit6: Unit6 Unit7: Unit7 SimpleStruct: SimpleStruct TupleStruct1: TupleStruct1 TupleStruct3: TupleStruct3 TestEnum: TestEnum RefStruct: RefStruct InlinerStruct: InlinerStruct GenericStruct: GenericStruct GenericStruct: GenericStruct FlattenEnumStruct: FlattenEnumStruct OverridenStruct: OverridenStruct HasGenericAlias: HasGenericAlias EnumMacroAttributes: EnumMacroAttributes InlineEnumField: InlineEnumField InlineOptionalType: InlineOptionalType Rename: Rename TransparentType: TransparentType TransparentType2: TransparentType2 TransparentTypeWithOverride: TransparentTypeWithOverride HashMap: Partial<{ [key in BasicEnum]: null }> HashMap: Partial<{ [key in BasicEnum]: number }> Vec: PlaceholderInnerField[] EnumReferenceRecordKey: EnumReferenceRecordKey FlattenOnNestedEnum: FlattenOnNestedEnum MyEmptyInput: MyEmptyInput (String): string ExtraBracketsInTupleVariant: ExtraBracketsInTupleVariant ExtraBracketsInUnnamedStruct: ExtraBracketsInUnnamedStruct Vec: MyEnum[] InlineTuple: InlineTuple InlineTuple2: InlineTuple2 Box: string Box: string SkippedFieldWithinVariant: SkippedFieldWithinVariant KebabCase: KebabCase Issue281<'_>: Issue281 LifetimeGenericStruct<'_, i32>: LifetimeGenericStruct LifetimeGenericEnum<'_, i32>: LifetimeGenericEnum RenameWithWeirdCharsField: RenameWithWeirdCharsField RenameWithWeirdCharsVariant: RenameWithWeirdCharsVariant RenamedFieldKeys: RenamedFieldKeys RenamedVariantWithSkippedPayload: RenamedVariantWithSkippedPayload type_type::Type: Type ActualType: ActualType SpectaTypeOverride: SpectaTypeOverride ContainerTypeOverrideStruct: ContainerTypeOverrideStruct ContainerTypeOverrideEnum: ContainerTypeOverrideEnum ContainerTypeOverrideGeneric>: ContainerTypeOverrideGeneric ContainerTypeOverrideToGeneric: ContainerTypeOverrideToGeneric ContainerTypeOverrideTuple: ContainerTypeOverrideTuple ContainerTypeOverrideTupleGeneric: ContainerTypeOverrideTupleGeneric InvalidToValidType: InvalidToValidType TupleStruct: TupleStruct TupleStructWithRep: TupleStructWithRep GenericTupleStruct: GenericTupleStruct BracedStruct: BracedStruct Struct: Struct Struct2: Struct2 Enum: Enum Enum2: Enum2 Enum3: Enum3 StructRenameAllUppercase: StructRenameAllUppercase RenameSerdeSpecialChar: RenameSerdeSpecialChar EnumRenameAllUppercase: EnumRenameAllUppercase Recursive: Recursive RecursiveMapValue: RecursiveMapValue RecursiveTransparent: RecursiveTransparent RecursiveInEnum: RecursiveInEnum NonOptional: NonOptional OptionalOnNamedField: OptionalOnNamedField OptionalOnTransparentNamedField: OptionalOnTransparentNamedField OptionalInEnum: OptionalInEnum UntaggedVariants: UntaggedVariants UntaggedVariantsWithoutValue: UntaggedVariantsWithoutValue UntaggedVariantsWithDuplicateBranches: UntaggedVariantsWithDuplicateBranches HashMap: { [key in string]: null } Regular: Regular HashMap: { [key in never]: null } HashMap: { [key in TransparentStruct]: null } HashMap: Partial<{ [key in UnitVariants]: null }> HashMap: Partial<{ [key in UntaggedVariantsKey]: null }> ValidMaybeValidKey: ValidMaybeValidKey ValidMaybeValidKeyNested: ValidMaybeValidKeyNested MacroStruct: MacroStruct MacroStruct2: MacroStruct2 MacroEnum: MacroEnum DeprecatedType: DeprecatedType DeprecatedTypeWithMsg: DeprecatedTypeWithMsg DeprecatedTypeWithMsg2: DeprecatedTypeWithMsg2 DeprecatedFields: DeprecatedFields DeprecatedTupleVariant: DeprecatedTupleVariant DeprecatedEnumVariants: DeprecatedEnumVariants CommentedStruct: CommentedStruct CommentedEnum: CommentedEnum SingleLineComment: SingleLineComment NonGeneric: Demo HalfGenericA: Demo HalfGenericB: Demo FullGeneric: Demo Another: Demo MapA: { [key in string]: number } MapB: { [key in number]: string } MapC: { [key in string]: AGenericStruct } AGenericStruct: AGenericStruct A: A DoubleFlattened: DoubleFlattened FlattenedInner: FlattenedInner BoxFlattened: BoxFlattened BoxInline: BoxInline First: First Second: Second Third: Third Fourth: Fourth TagOnStructWithInline: TagOnStructWithInline Sixth: Sixth Seventh: Seventh Eight: Eight Ninth: Ninth Tenth: Tenth MyEnumTagged: MyEnumTagged MyEnumExternal: MyEnumExternal MyEnumAdjacent: MyEnumAdjacent MyEnumUntagged: MyEnumUntagged EmptyStruct: EmptyStruct EmptyStructWithTag: EmptyStructWithTag AdjacentlyTagged: AdjacentlyTagged LoadProjectEvent: LoadProjectEvent ExternallyTagged: ExternallyTagged Issue221External: Issue221External InternallyTaggedD: InternallyTaggedD InternallyTaggedE: InternallyTaggedE InternallyTaggedF: InternallyTaggedF InternallyTaggedH: InternallyTaggedH InternallyTaggedL: InternallyTaggedL InternallyTaggedM: InternallyTaggedM StructWithAlias: StructWithAlias StructWithMultipleAliases: StructWithMultipleAliases StructWithAliasAndRename: StructWithAliasAndRename EnumWithVariantAlias: EnumWithVariantAlias EnumWithMultipleVariantAliases: EnumWithMultipleVariantAliases EnumWithVariantAliasAndRename: EnumWithVariantAliasAndRename InternallyTaggedWithAlias: InternallyTaggedWithAlias AdjacentlyTaggedWithAlias: AdjacentlyTaggedWithAlias UntaggedWithAlias: UntaggedWithAlias Issue221UntaggedSafe: Issue221UntaggedSafe Issue221UntaggedMixed: Issue221UntaggedMixed EmptyEnum: EmptyEnum EmptyEnumTagged: EmptyEnumTagged EmptyEnumTaggedWContent: EmptyEnumTaggedWContent EmptyEnumUntagged: EmptyEnumUntagged SkipOnlyField: SkipOnlyField SkipField: SkipField SkipVariant: SkipVariant SkipUnnamedFieldInVariant: SkipUnnamedFieldInVariant SkipNamedFieldInVariant: SkipNamedFieldInVariant TransparentWithSkip: TransparentWithSkip TransparentWithSkip2: TransparentWithSkip2 TransparentWithSkip3: TransparentWithSkip3 SkipVariant2: SkipVariant2 SkipVariant3: SkipVariant3 SkipStructFields: SkipStructFields SpectaSkipNonTypeField: SpectaSkipNonTypeField FlattenA: FlattenA FlattenB: FlattenB FlattenC: FlattenC FlattenD: FlattenD FlattenE: FlattenE FlattenF: FlattenF FlattenG: FlattenG TupleNested: TupleNested Generic1<()>: Generic1 GenericAutoBound<()>: GenericAutoBound GenericAutoBound2<()>: GenericAutoBound2 Container1: Container1 Generic2<(), String, i32>: Generic2 GenericNewType1<()>: GenericNewType1 GenericTuple<()>: GenericTuple GenericStruct2<()>: GenericStruct2 InlineGenericNewtype: string InlineGenericNested: [string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | string | { value: string }] InlineFlattenGenericsG<()>: InlineFlattenGenericsG InlineFlattenGenerics: InlineFlattenGenerics GenericDefault: GenericDefault ChainedGenericDefault: ChainedGenericDefault ChainedGenericDefault: ChainedGenericDefault ChainedGenericDefault: ChainedGenericDefault ChainedGenericDefault: ChainedGenericDefault GenericDefaultSkipped: GenericDefaultSkipped GenericDefaultSkippedNonType: GenericDefaultSkippedNonType GenericParameterOrderPreserved: GenericParameterOrderPreserved ConstGenericInNonConstContainer: ConstGenericInNonConstContainer ConstGenericInConstContainer: ConstGenericInConstContainer NamedConstGenericContainer: NamedConstGenericContainer InlineConstGenericContainer: InlineConstGenericContainer InlineRecursiveConstGenericContainer: InlineRecursiveConstGenericContainer TestCollectionRegister: TestCollectionRegister TestCollectionRegister: TestCollectionRegister specta_typescript::Any: any specta_typescript::Any: any specta_typescript::Unknown: unknown specta_typescript::Unknown: unknown specta_typescript::Never: never specta_typescript::Never: never ================================================ FILE: tests/tests/snapshots/test__jsdoc__reference-serde.snap ================================================ --- source: tests/tests/jsdoc.rs expression: output --- Range: Range RangeInclusive: RangeInclusive String: string PathBuf: string IpAddr: string Ipv4Addr: string Ipv6Addr: string SocketAddr: string SocketAddrV4: string SocketAddrV6: string Cow<'static, str>: string Cow<'static, i32>: number Vec: number[] Vec: MyEnum[] Result: Result Vec>>: (number | null)[] PhantomData<()>: null PhantomData: null Infallible: never Unit1: Unit1 Unit2: Unit2 Unit3: Unit3 Unit4: Unit4 Unit5: Unit5 Unit6: Unit6 Unit7: Unit7 SimpleStruct: SimpleStruct TupleStruct1: TupleStruct1 TupleStruct3: TupleStruct3 TestEnum: TestEnum RefStruct: RefStruct InlinerStruct: InlinerStruct GenericStruct: GenericStruct GenericStruct: GenericStruct FlattenEnumStruct: FlattenEnumStruct OverridenStruct: OverridenStruct HasGenericAlias: HasGenericAlias EnumMacroAttributes: EnumMacroAttributes InlineEnumField: InlineEnumField InlineOptionalType: InlineOptionalType Rename: Rename TransparentType: TransparentType TransparentType2: TransparentType2 TransparentTypeWithOverride: TransparentTypeWithOverride HashMap: Partial<{ [key in BasicEnum]: null }> HashMap: Partial<{ [key in BasicEnum]: number }> Vec: PlaceholderInnerField[] EnumReferenceRecordKey: EnumReferenceRecordKey FlattenOnNestedEnum: FlattenOnNestedEnum MyEmptyInput: MyEmptyInput (String): string ExtraBracketsInTupleVariant: ExtraBracketsInTupleVariant ExtraBracketsInUnnamedStruct: ExtraBracketsInUnnamedStruct Vec: MyEnum[] InlineTuple: InlineTuple InlineTuple2: InlineTuple2 Box: string Box: string SkippedFieldWithinVariant: SkippedFieldWithinVariant KebabCase: KebabCase Issue281<'_>: Issue281 LifetimeGenericStruct<'_, i32>: LifetimeGenericStruct LifetimeGenericEnum<'_, i32>: LifetimeGenericEnum RenameWithWeirdCharsField: RenameWithWeirdCharsField RenameWithWeirdCharsVariant: RenameWithWeirdCharsVariant RenamedFieldKeys: RenamedFieldKeys RenamedVariantWithSkippedPayload: RenamedVariantWithSkippedPayload type_type::Type: Type ActualType: ActualType SpectaTypeOverride: SpectaTypeOverride ContainerTypeOverrideStruct: ContainerTypeOverrideStruct ContainerTypeOverrideEnum: ContainerTypeOverrideEnum ContainerTypeOverrideGeneric>: ContainerTypeOverrideGeneric ContainerTypeOverrideToGeneric: ContainerTypeOverrideToGeneric ContainerTypeOverrideTuple: ContainerTypeOverrideTuple ContainerTypeOverrideTupleGeneric: ContainerTypeOverrideTupleGeneric InvalidToValidType: InvalidToValidType TupleStruct: TupleStruct TupleStructWithRep: TupleStructWithRep GenericTupleStruct: GenericTupleStruct BracedStruct: BracedStruct Struct: StructNew Struct2: Struct2 Enum: Enum Enum2: Enum2 Enum3: Enum3 StructRenameAllUppercase: StructRenameAllUppercase RenameSerdeSpecialChar: RenameSerdeSpecialChar EnumRenameAllUppercase: EnumRenameAllUppercase Recursive: Recursive RecursiveMapValue: RecursiveMapValue RecursiveTransparent: RecursiveTransparent RecursiveInEnum: RecursiveInEnum NonOptional: NonOptional OptionalOnNamedField: OptionalOnNamedField OptionalOnTransparentNamedField: OptionalOnTransparentNamedField OptionalInEnum: OptionalInEnum UntaggedVariants: UntaggedVariants UntaggedVariantsWithoutValue: UntaggedVariantsWithoutValue UntaggedVariantsWithDuplicateBranches: UntaggedVariantsWithDuplicateBranches HashMap: { [key in string]: null } Regular: Regular HashMap: { [key in never]: null } HashMap: { [key in TransparentStruct]: null } HashMap: Partial<{ [key in UnitVariants]: null }> HashMap: Partial<{ [key in UntaggedVariantsKey]: null }> ValidMaybeValidKey: ValidMaybeValidKey ValidMaybeValidKeyNested: ValidMaybeValidKeyNested MacroStruct: MacroStruct MacroStruct2: MacroStruct2 MacroEnum: MacroEnum DeprecatedType: DeprecatedType DeprecatedTypeWithMsg: DeprecatedTypeWithMsg DeprecatedTypeWithMsg2: DeprecatedTypeWithMsg2 DeprecatedFields: DeprecatedFields DeprecatedTupleVariant: DeprecatedTupleVariant DeprecatedEnumVariants: DeprecatedEnumVariants CommentedStruct: CommentedStruct CommentedEnum: CommentedEnum SingleLineComment: SingleLineComment NonGeneric: Demo HalfGenericA: Demo HalfGenericB: Demo FullGeneric: Demo Another: Demo MapA: { [key in string]: number } MapB: { [key in number]: string } MapC: { [key in string]: AGenericStruct } AGenericStruct: AGenericStruct A: A DoubleFlattened: DoubleFlattened FlattenedInner: FlattenedInner BoxFlattened: BoxFlattened BoxInline: BoxInline First: First Second: Second Third: Third Fourth: Fourth TagOnStructWithInline: TagOnStructWithInline Sixth: Sixth Seventh: Seventh Eight: Eight Ninth: Ninth Tenth: Tenth MyEnumTagged: MyEnumTagged MyEnumExternal: MyEnumExternal MyEnumAdjacent: MyEnumAdjacent MyEnumUntagged: MyEnumUntagged EmptyStruct: EmptyStruct EmptyStructWithTag: EmptyStructWithTag AdjacentlyTagged: AdjacentlyTagged LoadProjectEvent: LoadProjectEvent ExternallyTagged: ExternallyTagged Issue221External: Issue221External InternallyTaggedD: InternallyTaggedD InternallyTaggedE: InternallyTaggedE InternallyTaggedF: InternallyTaggedF InternallyTaggedH: InternallyTaggedH InternallyTaggedL: InternallyTaggedL InternallyTaggedM: InternallyTaggedM StructWithAlias: StructWithAlias StructWithMultipleAliases: StructWithMultipleAliases StructWithAliasAndRename: StructWithAliasAndRename EnumWithVariantAlias: EnumWithVariantAlias EnumWithMultipleVariantAliases: EnumWithMultipleVariantAliases EnumWithVariantAliasAndRename: EnumWithVariantAliasAndRename InternallyTaggedWithAlias: InternallyTaggedWithAlias AdjacentlyTaggedWithAlias: AdjacentlyTaggedWithAlias UntaggedWithAlias: UntaggedWithAlias Issue221UntaggedSafe: Issue221UntaggedSafe Issue221UntaggedMixed: Issue221UntaggedMixed EmptyEnum: EmptyEnum EmptyEnumTagged: EmptyEnumTagged EmptyEnumTaggedWContent: EmptyEnumTaggedWContent EmptyEnumUntagged: EmptyEnumUntagged SkipOnlyField: SkipOnlyField SkipField: SkipField SkipVariant: SkipVariant SkipUnnamedFieldInVariant: SkipUnnamedFieldInVariant SkipNamedFieldInVariant: SkipNamedFieldInVariant TransparentWithSkip: TransparentWithSkip TransparentWithSkip2: TransparentWithSkip2 TransparentWithSkip3: TransparentWithSkip3 SkipVariant2: SkipVariant2 SkipVariant3: SkipVariant3 SkipStructFields: SkipStructFields SpectaSkipNonTypeField: SpectaSkipNonTypeField FlattenA: FlattenA FlattenB: FlattenB FlattenC: FlattenC FlattenD: FlattenD FlattenE: FlattenE FlattenF: FlattenF FlattenG: FlattenG TupleNested: TupleNested Generic1<()>: Generic1 GenericAutoBound<()>: GenericAutoBound GenericAutoBound2<()>: GenericAutoBound2 Container1: Container1 Generic2<(), String, i32>: Generic2 GenericNewType1<()>: GenericNewType1 GenericTuple<()>: GenericTuple GenericStruct2<()>: GenericStruct2 InlineGenericNewtype: string InlineGenericNested: [string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | ({ Unnamed: string }) & { Named?: never } | ({ Named: { value: string, } }) & { Unnamed?: never }] InlineFlattenGenericsG<()>: InlineFlattenGenericsG InlineFlattenGenerics: InlineFlattenGenerics GenericDefault: GenericDefault ChainedGenericDefault: ChainedGenericDefault ChainedGenericDefault: ChainedGenericDefault ChainedGenericDefault: ChainedGenericDefault ChainedGenericDefault: ChainedGenericDefault GenericDefaultSkipped: GenericDefaultSkipped GenericDefaultSkippedNonType: GenericDefaultSkippedNonType GenericParameterOrderPreserved: GenericParameterOrderPreserved ConstGenericInNonConstContainer: ConstGenericInNonConstContainer ConstGenericInConstContainer: ConstGenericInConstContainer NamedConstGenericContainer: NamedConstGenericContainer InlineConstGenericContainer: InlineConstGenericContainer InlineRecursiveConstGenericContainer: InlineRecursiveConstGenericContainer TestCollectionRegister: TestCollectionRegister TestCollectionRegister: TestCollectionRegister specta_typescript::Any: any specta_typescript::Any: any specta_typescript::Unknown: unknown specta_typescript::Unknown: unknown specta_typescript::Never: never specta_typescript::Never: never ================================================ FILE: tests/tests/snapshots/test__jsdoc__reference-serde_phases.snap ================================================ --- source: tests/tests/jsdoc.rs expression: output --- Issue374: Issue374_Serialize Optional: Optional_Serialize StructPhaseSpecificRename: StructPhaseSpecificRenameSerialize Range: Range RangeInclusive: RangeInclusive String: string PathBuf: string IpAddr: string Ipv4Addr: string Ipv6Addr: string SocketAddr: string SocketAddrV4: string SocketAddrV6: string Cow<'static, str>: string Cow<'static, i32>: number Vec: number[] Vec: MyEnum[] Result: Result Vec>>: (number | null)[] PhantomData<()>: null PhantomData: null Infallible: never Unit1: Unit1 Unit2: Unit2 Unit3: Unit3 Unit4: Unit4 Unit5: Unit5 Unit6: Unit6 Unit7: Unit7 SimpleStruct: SimpleStruct TupleStruct1: TupleStruct1 TupleStruct3: TupleStruct3 TestEnum: TestEnum RefStruct: RefStruct InlinerStruct: InlinerStruct GenericStruct: GenericStruct GenericStruct: GenericStruct FlattenEnumStruct: FlattenEnumStruct OverridenStruct: OverridenStruct HasGenericAlias: HasGenericAlias EnumMacroAttributes: EnumMacroAttributes InlineEnumField: InlineEnumField InlineOptionalType: InlineOptionalType Rename: Rename TransparentType: TransparentType TransparentType2: TransparentType2 TransparentTypeWithOverride: TransparentTypeWithOverride HashMap: Partial<{ [key in BasicEnum]: null }> HashMap: Partial<{ [key in BasicEnum]: number }> Vec: PlaceholderInnerField[] EnumReferenceRecordKey: EnumReferenceRecordKey FlattenOnNestedEnum: FlattenOnNestedEnum MyEmptyInput: MyEmptyInput (String): string ExtraBracketsInTupleVariant: ExtraBracketsInTupleVariant ExtraBracketsInUnnamedStruct: ExtraBracketsInUnnamedStruct Vec: MyEnum[] InlineTuple: InlineTuple InlineTuple2: InlineTuple2 Box: string Box: string SkippedFieldWithinVariant: SkippedFieldWithinVariant KebabCase: KebabCase Issue281<'_>: Issue281 LifetimeGenericStruct<'_, i32>: LifetimeGenericStruct LifetimeGenericEnum<'_, i32>: LifetimeGenericEnum RenameWithWeirdCharsField: RenameWithWeirdCharsField RenameWithWeirdCharsVariant: RenameWithWeirdCharsVariant RenamedFieldKeys: RenamedFieldKeys RenamedVariantWithSkippedPayload: RenamedVariantWithSkippedPayload type_type::Type: Type ActualType: ActualType SpectaTypeOverride: SpectaTypeOverride ContainerTypeOverrideStruct: ContainerTypeOverrideStruct ContainerTypeOverrideEnum: ContainerTypeOverrideEnum ContainerTypeOverrideGeneric>: ContainerTypeOverrideGeneric ContainerTypeOverrideToGeneric: ContainerTypeOverrideToGeneric ContainerTypeOverrideTuple: ContainerTypeOverrideTuple ContainerTypeOverrideTupleGeneric: ContainerTypeOverrideTupleGeneric InvalidToValidType: InvalidToValidType TupleStruct: TupleStruct TupleStructWithRep: TupleStructWithRep GenericTupleStruct: GenericTupleStruct BracedStruct: BracedStruct Struct: StructNew Struct2: Struct2 Enum: Enum Enum2: Enum2 Enum3: Enum3 StructRenameAllUppercase: StructRenameAllUppercase RenameSerdeSpecialChar: RenameSerdeSpecialChar EnumRenameAllUppercase: EnumRenameAllUppercase Recursive: Recursive RecursiveMapValue: RecursiveMapValue RecursiveTransparent: RecursiveTransparent RecursiveInEnum: RecursiveInEnum NonOptional: NonOptional OptionalOnNamedField: OptionalOnNamedField OptionalOnTransparentNamedField: OptionalOnTransparentNamedField OptionalInEnum: OptionalInEnum UntaggedVariants: UntaggedVariants UntaggedVariantsWithoutValue: UntaggedVariantsWithoutValue UntaggedVariantsWithDuplicateBranches: UntaggedVariantsWithDuplicateBranches HashMap: { [key in string]: null } Regular: Regular HashMap: { [key in never]: null } HashMap: { [key in TransparentStruct]: null } HashMap: Partial<{ [key in UnitVariants]: null }> HashMap: Partial<{ [key in UntaggedVariantsKey]: null }> ValidMaybeValidKey: ValidMaybeValidKey ValidMaybeValidKeyNested: ValidMaybeValidKeyNested MacroStruct: MacroStruct MacroStruct2: MacroStruct2 MacroEnum: MacroEnum DeprecatedType: DeprecatedType DeprecatedTypeWithMsg: DeprecatedTypeWithMsg DeprecatedTypeWithMsg2: DeprecatedTypeWithMsg2 DeprecatedFields: DeprecatedFields DeprecatedTupleVariant: DeprecatedTupleVariant DeprecatedEnumVariants: DeprecatedEnumVariants CommentedStruct: CommentedStruct CommentedEnum: CommentedEnum SingleLineComment: SingleLineComment NonGeneric: Demo HalfGenericA: Demo HalfGenericB: Demo FullGeneric: Demo Another: Demo MapA: { [key in string]: number } MapB: { [key in number]: string } MapC: { [key in string]: AGenericStruct } AGenericStruct: AGenericStruct A: A DoubleFlattened: DoubleFlattened FlattenedInner: FlattenedInner BoxFlattened: BoxFlattened BoxInline: BoxInline First: First Second: Second Third: Third Fourth: Fourth TagOnStructWithInline: TagOnStructWithInline Sixth: Sixth Seventh: Seventh Eight: Eight Ninth: Ninth Tenth: Tenth MyEnumTagged: MyEnumTagged MyEnumExternal: MyEnumExternal MyEnumAdjacent: MyEnumAdjacent MyEnumUntagged: MyEnumUntagged EmptyStruct: EmptyStruct EmptyStructWithTag: EmptyStructWithTag AdjacentlyTagged: AdjacentlyTagged LoadProjectEvent: LoadProjectEvent ExternallyTagged: ExternallyTagged Issue221External: Issue221External InternallyTaggedD: InternallyTaggedD InternallyTaggedE: InternallyTaggedE InternallyTaggedF: InternallyTaggedF InternallyTaggedH: InternallyTaggedH InternallyTaggedL: InternallyTaggedL InternallyTaggedM: InternallyTaggedM StructWithAlias: StructWithAlias StructWithMultipleAliases: StructWithMultipleAliases StructWithAliasAndRename: StructWithAliasAndRename EnumWithVariantAlias: EnumWithVariantAlias EnumWithMultipleVariantAliases: EnumWithMultipleVariantAliases EnumWithVariantAliasAndRename: EnumWithVariantAliasAndRename InternallyTaggedWithAlias: InternallyTaggedWithAlias AdjacentlyTaggedWithAlias: AdjacentlyTaggedWithAlias UntaggedWithAlias: UntaggedWithAlias Issue221UntaggedSafe: Issue221UntaggedSafe Issue221UntaggedMixed: Issue221UntaggedMixed EmptyEnum: EmptyEnum EmptyEnumTagged: EmptyEnumTagged EmptyEnumTaggedWContent: EmptyEnumTaggedWContent EmptyEnumUntagged: EmptyEnumUntagged SkipOnlyField: SkipOnlyField SkipField: SkipField SkipVariant: SkipVariant SkipUnnamedFieldInVariant: SkipUnnamedFieldInVariant SkipNamedFieldInVariant: SkipNamedFieldInVariant TransparentWithSkip: TransparentWithSkip TransparentWithSkip2: TransparentWithSkip2 TransparentWithSkip3: TransparentWithSkip3 SkipVariant2: SkipVariant2 SkipVariant3: SkipVariant3 SkipStructFields: SkipStructFields SpectaSkipNonTypeField: SpectaSkipNonTypeField FlattenA: FlattenA FlattenB: FlattenB FlattenC: FlattenC FlattenD: FlattenD FlattenE: FlattenE FlattenF: FlattenF FlattenG: FlattenG TupleNested: TupleNested Generic1<()>: Generic1 GenericAutoBound<()>: GenericAutoBound GenericAutoBound2<()>: GenericAutoBound2 Container1: Container1 Generic2<(), String, i32>: Generic2 GenericNewType1<()>: GenericNewType1 GenericTuple<()>: GenericTuple GenericStruct2<()>: GenericStruct2 InlineGenericNewtype: string InlineGenericNested: [string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | ({ Unnamed: string }) & { Named?: never } | ({ Named: { value: string, } }) & { Unnamed?: never }] InlineFlattenGenericsG<()>: InlineFlattenGenericsG InlineFlattenGenerics: InlineFlattenGenerics GenericDefault: GenericDefault ChainedGenericDefault: ChainedGenericDefault ChainedGenericDefault: ChainedGenericDefault ChainedGenericDefault: ChainedGenericDefault ChainedGenericDefault: ChainedGenericDefault GenericDefaultSkipped: GenericDefaultSkipped GenericDefaultSkippedNonType: GenericDefaultSkippedNonType GenericParameterOrderPreserved: GenericParameterOrderPreserved ConstGenericInNonConstContainer: ConstGenericInNonConstContainer ConstGenericInConstContainer: ConstGenericInConstContainer NamedConstGenericContainer: NamedConstGenericContainer InlineConstGenericContainer: InlineConstGenericContainer InlineRecursiveConstGenericContainer: InlineRecursiveConstGenericContainer TestCollectionRegister: TestCollectionRegister TestCollectionRegister: TestCollectionRegister specta_typescript::Any: any specta_typescript::Any: any specta_typescript::Unknown: unknown specta_typescript::Unknown: unknown specta_typescript::Never: never specta_typescript::Never: never ================================================ FILE: tests/tests/snapshots/test__layouts__layouts-duplicate-files.snap ================================================ --- source: tests/tests/layouts.rs expression: output --- test/ layouts/ testing/ testing2.ts (114 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. export type Testing = { c: string, }; ════════════════════════════════════════ testing.ts (220 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. import type * as test$layouts$testing$testing2 from "./testing/testing2"; export type Testing = { b: test$layouts$testing$testing2.Testing, }; ════════════════════════════════════════ layouts.ts (285 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. import type * as test$layouts$testing from "./layouts/testing"; export type Another = { bruh: string, }; export type MoreType = { u: string, }; export type Testing = { a: test$layouts$testing.Testing, }; ════════════════════════════════════════ ================================================ FILE: tests/tests/snapshots/test__layouts__layouts-duplicate-module-prefixed.snap ================================================ --- source: tests/tests/layouts.rs expression: module_prefixed --- // This file has been generated by Specta. Do not edit this file manually. export type test_layouts_Another = { bruh: string, }; export type test_layouts_MoreType = { u: string, }; export type test_layouts_Testing = { a: test_layouts_testing_Testing, }; export type test_layouts_testing_Testing = { b: test_layouts_testing_testing2_Testing, }; export type test_layouts_testing_testing2_Testing = { c: string, }; ================================================ FILE: tests/tests/snapshots/test__layouts__layouts-duplicate-namespaces.snap ================================================ --- source: tests/tests/layouts.rs expression: namespaces --- // This file has been generated by Specta. Do not edit this file manually. namespace $s$ { export namespace test { export namespace layouts { export type Another = { bruh: string, }; export type MoreType = { u: string, }; export type Testing = { a: $s$.test.layouts.testing.Testing, }; export namespace testing { export type Testing = { b: $s$.test.layouts.testing.testing2.Testing, }; export namespace testing2 { export type Testing = { c: string, }; } } } } } export import test = $s$.test; ================================================ FILE: tests/tests/snapshots/test__layouts__layouts-empty-module-path-files.snap ================================================ --- source: tests/tests/layouts.rs expression: output --- tests/ tests/ layouts.ts (105 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. export type testing = number; ════════════════════════════════════════ ================================================ FILE: tests/tests/snapshots/test__layouts__layouts-empty-module-path-flat.snap ================================================ --- source: tests/tests/layouts.rs expression: flat --- // This file has been generated by Specta. Do not edit this file manually. export type testing = number; ================================================ FILE: tests/tests/snapshots/test__layouts__layouts-empty-module-path-module-prefixed.snap ================================================ --- source: tests/tests/layouts.rs expression: module_prefixed --- // This file has been generated by Specta. Do not edit this file manually. export type tests_tests_layouts_testing = number; ================================================ FILE: tests/tests/snapshots/test__layouts__layouts-empty-module-path-namespaces.snap ================================================ --- source: tests/tests/layouts.rs expression: namespaces --- // This file has been generated by Specta. Do not edit this file manually. namespace $s$ { export namespace tests { export namespace tests { export namespace layouts { export type testing = number; } } } } export import tests = $s$.tests; ================================================ FILE: tests/tests/snapshots/test__layouts__layouts-non-duplicate-default.snap ================================================ --- source: tests/tests/layouts.rs expression: default_output --- // This file has been generated by Specta. Do not edit this file manually. export type Another = { bruh: string, }; export type MoreType = { u: string, }; ================================================ FILE: tests/tests/snapshots/test__layouts__layouts-non-duplicate-files.snap ================================================ --- source: tests/tests/layouts.rs expression: output --- test/ layouts.ts (158 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. export type Another = { bruh: string, }; export type MoreType = { u: string, }; ════════════════════════════════════════ ================================================ FILE: tests/tests/snapshots/test__layouts__layouts-non-duplicate-flat.snap ================================================ --- source: tests/tests/layouts.rs expression: flat --- // This file has been generated by Specta. Do not edit this file manually. export type Another = { bruh: string, }; export type MoreType = { u: string, }; ================================================ FILE: tests/tests/snapshots/test__layouts__layouts-non-duplicate-module-prefixed.snap ================================================ --- source: tests/tests/layouts.rs expression: module_prefixed --- // This file has been generated by Specta. Do not edit this file manually. export type test_layouts_Another = { bruh: string, }; export type test_layouts_MoreType = { u: string, }; ================================================ FILE: tests/tests/snapshots/test__layouts__layouts-non-duplicate-namespaces.snap ================================================ --- source: tests/tests/layouts.rs expression: namespaces --- // This file has been generated by Specta. Do not edit this file manually. namespace $s$ { export namespace test { export namespace layouts { export type Another = { bruh: string, }; export type MoreType = { u: string, }; } } } export import test = $s$.test; ================================================ FILE: tests/tests/snapshots/test__legacy_impls__legacy_impls.snap ================================================ --- source: tests/tests/legacy_impls.rs expression: "Typescript::default().export(&Types::default().register::(),\nspecta_serde::Format).unwrap()" --- // This file has been generated by Specta. Do not edit this file manually. export type ErrorStackContext = { context: string, attachments: string[], sources: ErrorStackContext[], }; export type LegacyImpls = { ordered_f32: number, ordered_f64: number, heapless_vec: [number, number, number, number, number, number, number, number], semver: string, smol: string, array_vec: [number, number, number, number, number, number, number, number], array_string: string, smallvec: ([number, number, number, number, number, number, number, number])[], toml_datetime: { v: string, }, ulid: string, chrono_naive_datetime: string, chrono_naive_date: string, chrono_naive_time: string, chrono_duration: string, chrono_date: string, chrono_datetime: string, chrono_fixed_offset: string, chrono_utc: string, chrono_local: string, either: ({ Left: number }) & { Right?: never } | ({ Right: string }) & { Left?: never }, error_stack_report: Report, error_stack_multi_report: Report, glam_affine2: [number, number, number, number, number, number], glam_affine3a: [number, number, number, number, number, number, number, number, number, number, number, number], glam_mat2: [number, number, number, number], glam_mat3: [number, number, number, number, number, number, number, number, number], glam_mat3a: [number, number, number, number, number, number, number, number, number], glam_mat4: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number], glam_quat: [number, number, number, number], glam_vec2: [number, number], glam_vec3: [number, number, number], glam_vec3a: [number, number, number], glam_vec4: [number, number, number, number], glam_daffine2: [number, number, number, number, number, number], glam_daffine3: [number, number, number, number, number, number, number, number, number, number, number, number], glam_dmat2: [number, number, number, number], glam_dmat3: [number, number, number, number, number, number, number, number, number], glam_dmat4: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number], glam_dquat: [number, number, number, number], glam_dvec2: [number, number], glam_dvec3: [number, number, number], glam_dvec4: [number, number, number, number], glam_i8vec2: [number, number], glam_i8vec3: [number, number, number], glam_i8vec4: [number, number, number, number], glam_u8vec2: [number, number], glam_u8vec3: [number, number, number], glam_u8vec4: [number, number, number, number], glam_i16vec2: [number, number], glam_i16vec3: [number, number, number], glam_i16vec4: [number, number, number, number], glam_u16vec2: [number, number], glam_u16vec3: [number, number, number], glam_u16vec4: [number, number, number, number], glam_ivec2: [number, number], glam_ivec3: [number, number, number], glam_ivec4: [number, number, number, number], glam_uvec2: [number, number], glam_uvec3: [number, number, number], glam_uvec4: [number, number, number, number], glam_bvec2: [boolean, boolean], glam_bvec3: [boolean, boolean, boolean], glam_bvec4: [boolean, boolean, boolean, boolean], }; export type Report = ErrorStackContext[]; ================================================ FILE: tests/tests/snapshots/test__serde_conversions__serde-conversions-format-phases-exports-field-only-phased-override.snap ================================================ --- source: tests/tests/serde_conversions.rs expression: rendered --- // This file has been generated by Specta. Do not edit this file manually. export type FieldOnlyPhasedOverride = FieldOnlyPhasedOverride_Serialize | FieldOnlyPhasedOverride_Deserialize; export type FieldOnlyPhasedOverride_Deserialize = { value: number, }; export type FieldOnlyPhasedOverride_Serialize = { value: string, }; ================================================ FILE: tests/tests/snapshots/test__serde_conversions__serde-conversions-format-phases-splits-container-and-dependents.snap ================================================ --- source: tests/tests/serde_conversions.rs expression: rendered --- // This file has been generated by Specta. Do not edit this file manually. export type IntoOnly = IntoOnly_Serialize | IntoOnly_Deserialize; export type IntoOnly_Deserialize = { value: number, }; export type IntoOnly_Serialize = Wire; export type Parent = Parent_Serialize | Parent_Deserialize; export type Parent_Deserialize = { child: IntoOnly_Deserialize, }; export type Parent_Serialize = { child: IntoOnly_Serialize, }; export type Wire = { value: number, }; ================================================ FILE: tests/tests/snapshots/test__serde_identifiers__serde-identifiers-field-typescript.snap ================================================ --- source: tests/tests/serde_identifiers.rs expression: field_ts --- // This file has been generated by Specta. Do not edit this file manually. export type FieldIdentifier = FieldIdentifier_Serialize | FieldIdentifier_Deserialize; export type FieldIdentifier_Deserialize = "first_name" | "last_name" | "other" | number | boolean; export type FieldIdentifier_Serialize = "first_name" | "last_name" | { other: boolean }; ================================================ FILE: tests/tests/snapshots/test__serde_identifiers__serde-identifiers-variant-typescript.snap ================================================ --- source: tests/tests/serde_identifiers.rs expression: variant_ts --- // This file has been generated by Specta. Do not edit this file manually. export type VariantIdentifier = VariantIdentifier_Serialize | VariantIdentifier_Deserialize; export type VariantIdentifier_Deserialize = "http_status" | "legacy_name" | "legacy" | number; export type VariantIdentifier_Serialize = "http_status" | "legacy_name"; ================================================ FILE: tests/tests/snapshots/test__serde_other__serde-other-adjacent-tag-typescript.snap ================================================ --- source: tests/tests/serde_other.rs expression: ts --- // This file has been generated by Specta. Do not edit this file manually. export type AdjacentOther = AdjacentOther_Serialize | AdjacentOther_Deserialize; export type AdjacentOther_Deserialize = ({ known: { kind: "known", data: string, } }) & { Other?: never } | ({ Other: { kind: string, } }) & { known?: never }; export type AdjacentOther_Serialize = { kind: "known"; data: string } | ({ kind: "Other" }) & { data?: never }; ================================================ FILE: tests/tests/snapshots/test__serde_other__serde-other-internal-tag-typescript.snap ================================================ --- source: tests/tests/serde_other.rs expression: ts --- // This file has been generated by Specta. Do not edit this file manually. export type InternalOther = InternalOther_Serialize | InternalOther_Deserialize; export type InternalOther_Deserialize = ({ known: { kind: "known", } }) & { Other?: never } | ({ Other: { kind: string, } }) & { known?: never }; export type InternalOther_Serialize = { kind: "known" } | { kind: "Other" }; ================================================ FILE: tests/tests/snapshots/test__swift__swift-export-raw.snap ================================================ --- source: tests/tests/swift.rs expression: "phase_output(&types, format)" --- // This file has been generated by Specta. DO NOT EDIT. import Foundation public enum JobStatus: Codable { case queued case pendingApproval } public enum MixedEnum: Codable { case unit case withData(String) } public enum RegularEnum: Codable { case variantOne case variantTwo } ================================================ FILE: tests/tests/snapshots/test__swift__swift-export-serde.snap ================================================ --- source: tests/tests/swift.rs expression: "phase_output(&types, format)" --- // This file has been generated by Specta. DO NOT EDIT. import Foundation public enum JobStatus: String, Codable { case queued = "queued" case pendingApproval = "pending_approval" } public enum MixedEnum { case unit case withData(String) } // MARK: - MixedEnum Codable Implementation extension MixedEnum: Codable { private enum CodingKeys: String, CodingKey { case unit = "unit" case withData = "with_data" } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) if container.allKeys.count != 1 { throw DecodingError.dataCorrupted( DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Invalid number of keys found, expected one.") ) } let key = container.allKeys.first! switch key { case .unit: self = .unit case .withData: let data = try container.decode(String.self, forKey: .withData) self = .withData(data) } } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) switch self { case .unit: try container.encodeNil(forKey: .unit) case .withData(let data): try container.encode(data, forKey: .withData) } } } public enum RegularEnum: String, Codable { case variantOne = "VariantOne" case variantTwo = "VariantTwo" } ================================================ FILE: tests/tests/snapshots/test__swift__swift-export-serde_phases.snap ================================================ --- source: tests/tests/swift.rs expression: "phase_output(&types, format)" --- // This file has been generated by Specta. DO NOT EDIT. import Foundation public enum JobStatus: String, Codable { case queued = "queued" case pendingApproval = "pending_approval" } public enum MixedEnum { case unit case withData(String) } // MARK: - MixedEnum Codable Implementation extension MixedEnum: Codable { private enum CodingKeys: String, CodingKey { case unit = "unit" case withData = "with_data" } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) if container.allKeys.count != 1 { throw DecodingError.dataCorrupted( DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Invalid number of keys found, expected one.") ) } let key = container.allKeys.first! switch key { case .unit: self = .unit case .withData: let data = try container.decode(String.self, forKey: .withData) self = .withData(data) } } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) switch self { case .unit: try container.encodeNil(forKey: .unit) case .withData(let data): try container.encode(data, forKey: .withData) } } } public enum RegularEnum: String, Codable { case variantOne = "VariantOne" case variantTwo = "VariantTwo" } ================================================ FILE: tests/tests/snapshots/test__types__serde-default-container-typescript.snap ================================================ --- source: tests/tests/types.rs expression: ts --- // This file has been generated by Specta. Do not edit this file manually. export type ContainerDefault = { value?: string, flag?: boolean, }; ================================================ FILE: tests/tests/snapshots/test__types__serde-default-field-typescript.snap ================================================ --- source: tests/tests/types.rs expression: ts --- // This file has been generated by Specta. Do not edit this file manually. export type FieldDefault = { name: string, enabled?: boolean, }; ================================================ FILE: tests/tests/snapshots/test__types__serde-mixed-untagged-phased-typescript.snap ================================================ --- source: tests/tests/types.rs expression: ts --- // This file has been generated by Specta. Do not edit this file manually. export type MixedTaggedAndUntaggedPhased = MixedTaggedAndUntaggedPhased_Serialize | MixedTaggedAndUntaggedPhased_Deserialize; export type MixedTaggedAndUntaggedPhased_Deserialize = { Tagged: { kind: "Tagged", value: string, } } | string; export type MixedTaggedAndUntaggedPhased_Serialize = { Tagged: { kind: "Tagged", value: string, } } | boolean; ================================================ FILE: tests/tests/snapshots/test__types__serde-mixed-untagged-struct-typescript.snap ================================================ --- source: tests/tests/types.rs expression: ts --- // This file has been generated by Specta. Do not edit this file manually. export type MixedTaggedAndUntaggedStruct = { kind: "Tagged"; value: string } | { raw_value: string, }; ================================================ FILE: tests/tests/snapshots/test__types__serde-mixed-untagged-typescript.snap ================================================ --- source: tests/tests/types.rs expression: ts --- // This file has been generated by Specta. Do not edit this file manually. export type MixedTaggedAndUntagged = { kind: "Tagged"; value: string } | string | null; ================================================ FILE: tests/tests/snapshots/test__typescript__export-many-raw.snap ================================================ --- source: tests/tests/typescript.rs expression: output --- export type Range = { start: T, end: T, }; export type RangeInclusive = { start: T, end: T, }; export type Result = { ok: T, err: E, }; export type Unit1 = null; export type Unit2 = Record; export type Unit3 = []; export type Unit4 = null; export type Unit5 = "A"; export type Unit6 = []; export type Unit7 = Record; export type SimpleStruct = { a: number, b: string, c: [number, string, number], d: string[], e: string | null, }; export type TupleStruct1 = number; export type TupleStruct3 = [number, boolean, string]; export type TestEnum = "Unit" | number | [number, number] | { a: number }; export type RefStruct = TestEnum; export type InlinerStruct = { inline_this: { ref_struct: SimpleStruct, val: number, }, dont_inline_this: RefStruct, }; export type GenericStruct = { arg: T, }; export type GenericStruct = { arg: T, }; export type FlattenEnumStruct = { outer: string, inner: FlattenEnum, }; export type OverridenStruct = { overriden_field: string, }; export type HasGenericAlias = { [key in number]: string }; export type EnumMacroAttributes = string | number | { a: string; b: number }; export type InlineEnumField = { a: string, }; export type InlineOptionalType = { optional_field: { a: string, } | null, }; export type Rename = "OneWord" | "TwoWords"; export type TransparentType = TransparentTypeInner; export type TransparentType2 = null; export type TransparentTypeWithOverride = string; export type EnumReferenceRecordKey = { a: Partial<{ [key in BasicEnum]: number }>, }; export type FlattenOnNestedEnum = { id: string, result: NestedEnum, }; export type MyEmptyInput = Record; export type ExtraBracketsInTupleVariant = string; export type ExtraBracketsInUnnamedStruct = string; export type InlineTuple = { demo: [string, boolean], }; export type InlineTuple2 = { demo: [{ demo: [string, boolean], }, boolean], }; export type SkippedFieldWithinVariant = never | string; export type KebabCase = { test_ing: string, }; export type Issue281 = { default_unity_arguments: string[], }; export type LifetimeGenericStruct = { borrowed: T[], owned: T[], }; export type LifetimeGenericEnum = T; export type RenameWithWeirdCharsField = { odata_context: string, }; export type RenameWithWeirdCharsVariant = string; export type RenamedFieldKeys = { empty: string, quote: string, backslash: string, newline: string, line_separator: string, paragraph_separator: string, }; export type RenamedVariantWithSkippedPayload = never; export type Type = never; export type ActualType = { a: GenericType, }; export type SpectaTypeOverride = { string_ident: string, u32_ident: number, path: string, tuple: [string, number], }; export type ContainerTypeOverrideStruct = string; export type ContainerTypeOverrideEnum = string; export type ContainerTypeOverrideGeneric = string; export type ContainerTypeOverrideToGeneric = T; export type ContainerTypeOverrideTuple = [string, number]; export type ContainerTypeOverrideTupleGeneric = [T, string]; export type InvalidToValidType = { cause: null, }; export type TupleStruct = string; export type TupleStructWithRep = string; export type GenericTupleStruct = T; export type BracedStruct = string; export type Struct = { a: string, }; export type Struct2 = { a: string, }; export type Enum = "A" | "B"; export type Enum2 = "A" | "B" | { enum_field: null }; export type Enum3 = { a: string }; export type StructRenameAllUppercase = { a: number, b: number, }; export type RenameSerdeSpecialChar = { b: number, }; export type EnumRenameAllUppercase = "HelloWorld" | "VariantB" | "TestingWords"; export type Recursive = { demo: Recursive, }; export type RecursiveMapValue = { demo: { [key in string]: RecursiveMapValue }, }; export type RecursiveTransparent = RecursiveInline; export type RecursiveInEnum = { demo: RecursiveInEnum }; export type NonOptional = string | null; export type OptionalOnNamedField = string | null; export type OptionalOnTransparentNamedField = { b: string | null, }; export type OptionalInEnum = string | null | { a: string | null } | { a?: string | null }; export type UntaggedVariants = string | number | { id: string } | [string, boolean]; export type UntaggedVariantsWithoutValue = string | [number, string] | number; export type UntaggedVariantsWithDuplicateBranches = null | number; export type Regular = { [key in string]: null }; export type ValidMaybeValidKey = { [key in MaybeValidKey]: null }; export type ValidMaybeValidKeyNested = { [key in MaybeValidKey>]: null }; export type MacroStruct = string; export type MacroStruct2 = { demo: string, }; export type MacroEnum = string | { demo2: string }; /** * @deprecated */ export type DeprecatedType = { a: number, }; /** * @deprecated Look at you big man using a deprecation message */ export type DeprecatedTypeWithMsg = { a: number, }; /** * @deprecated Look at you big man using a deprecation message */ export type DeprecatedTypeWithMsg2 = { a: number, }; export type DeprecatedFields = { a: number, /** * @deprecated */ b: string, /** * @deprecated This field is cringe! */ c: string, /** * @deprecated This field is cringe! */ d: string, }; export type DeprecatedTupleVariant = [ /** * @deprecated */ string, /** * @deprecated Nope */ string, /** * @deprecated Nope */ number]; export type DeprecatedEnumVariants = /** * @deprecated */ "A" | /** * @deprecated Nope */ "B" | /** * @deprecated Nope */ "C"; /** * Some triple-slash comment * Some more triple-slash comment */ export type CommentedStruct = { /** * Some triple-slash comment * Some more triple-slash comment */ a: number, }; /** * Some triple-slash comment * Some more triple-slash comment */ export type CommentedEnum = /** * Some triple-slash comment * Some more triple-slash comment */ number | /** * Some triple-slash comment * Some more triple-slash comment */ { /** * Some triple-slash comment * Some more triple-slash comment */ a: number }; /** Some single-line comment */ export type SingleLineComment = /** Some single-line comment */ number | /** Some single-line comment */ { /** Some single-line comment */ a: number }; export type Demo = { a: A, b: B, }; export type Demo = { a: A, b: B, }; export type Demo = { a: A, b: B, }; export type Demo = { a: A, b: B, }; export type Demo = { a: A, b: B, }; export type AGenericStruct = { field: Demo, }; export type A = { a: B, b: { b: number, }, c: B, d: { flattened: number, }, e: { generic_flattened: number, }, }; export type DoubleFlattened = { a: ToBeFlattened, b: ToBeFlattened, }; export type FlattenedInner = { c: Inner, }; export type BoxFlattened = { b: BoxedInner, }; export type BoxInline = { c: { a: number, }, }; export type First = { a: string, }; export type Second = { a: number, }; export type Third = { a: First, b: { [key in string]: string }, c: First, }; export type Fourth = { a: First, b: { a: string, }, }; export type TagOnStructWithInline = { a: First, b: { a: string, }, }; export type Sixth = { a: First, b: First, }; export type Seventh = { a: First, b: Second, }; export type Eight = string | "B"; export type Ninth = string | "B" | { a: string, } | First; export type Tenth = string | "B" | { a: string, } | First; export type MyEnumTagged = { inner: First }; export type MyEnumExternal = { inner: First }; export type MyEnumAdjacent = { inner: First }; export type MyEnumUntagged = { inner: First }; export type EmptyStruct = Record; export type EmptyStructWithTag = Record; export type AdjacentlyTagged = "A" | { id: string; method: string } | string; export type LoadProjectEvent = ({ project_name: string }) & { progress?: never; status?: never } | { project_name: string; status: string; progress: number }; export type ExternallyTagged = "A" | { id: string; method: string } | string; export type Issue221External = ({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }; export type InternallyTaggedD = { [key in string]: string }; export type InternallyTaggedE = null; export type InternallyTaggedF = InternallyTaggedFInner; export type InternallyTaggedH = InternallyTaggedHInner; export type InternallyTaggedL = "A" | "B"; export type InternallyTaggedM = "A" | "B"; export type StructWithAlias = { field: string, }; export type StructWithMultipleAliases = { field: string, }; export type StructWithAliasAndRename = { field: string, }; export type EnumWithVariantAlias = "Variant" | "Other"; export type EnumWithMultipleVariantAliases = "Variant" | "Other"; export type EnumWithVariantAliasAndRename = "Variant" | "Other"; export type InternallyTaggedWithAlias = ({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }; export type AdjacentlyTaggedWithAlias = ({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }; export type UntaggedWithAlias = ({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }; export type Issue221UntaggedSafe = ({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }; export type Issue221UntaggedMixed = ({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never }; export type EmptyEnum = never; export type EmptyEnumTagged = never; export type EmptyEnumTaggedWContent = never; export type EmptyEnumUntagged = never; export type SkipOnlyField = Record; export type SkipField = { b: number, }; export type SkipVariant = string; export type SkipUnnamedFieldInVariant = never | [number]; export type SkipNamedFieldInVariant = Record | { b: number }; export type TransparentWithSkip = null; export type TransparentWithSkip2 = string; export type TransparentWithSkip3 = string; export type SkipVariant2 = string; export type SkipVariant3 = { a: string }; export type SkipStructFields = { a: number, }; export type SpectaSkipNonTypeField = { a: number, }; export type FlattenA = { a: number, b: number, }; export type FlattenB = { a: FlattenA, c: number, }; export type FlattenC = { a: FlattenA, c: number, }; export type FlattenD = { a: FlattenA, c: number, }; export type FlattenE = { b: { a: FlattenA, c: number, }, d: number, }; export type FlattenF = { b: { a: FlattenA, c: number, }, d: number, }; export type FlattenG = { b: FlattenB, d: number, }; export type TupleNested = [number[], [number[], number[]], [number[], number[], number[]]]; export type Generic1 = { value: T, values: T[], }; export type GenericAutoBound = { value: T, values: T[], }; export type GenericAutoBound2 = { value: T, values: T[], }; export type Container1 = { foo: Generic1, bar: Generic1[], baz: { [key in string]: Generic1 }, }; export type Generic2 = A | [B, B, B] | C[] | A[][][] | { a: A; b: B; c: C } | number[] | number | number[][]; export type GenericNewType1 = T[][]; export type GenericTuple = [T, T[], T[][]]; export type GenericStruct2 = { a: T, b: [T, T], c: [T, [T, T]], d: [T, T, T], e: [([T, T]), ([T, T]), ([T, T])], f: T[], g: T[][], h: ([([T, T]), ([T, T]), ([T, T])])[], }; export type InlineFlattenGenericsG = { t: T, }; export type InlineFlattenGenerics = { g: InlineFlattenGenericsG, gi: { t: string, }, t: InlineFlattenGenericsG, }; export type GenericDefault = { value: T, }; export type ChainedGenericDefault = { first: T, second: U, }; export type ChainedGenericDefault = { first: T, second: U, }; export type ChainedGenericDefault = { first: T, second: U, }; export type ChainedGenericDefault = { first: T, second: U, }; export type GenericDefaultSkipped = { value: T, }; export type GenericDefaultSkippedNonType = { value: number, }; export type GenericParameterOrderPreserved = { pair: Pair, }; export type ConstGenericInNonConstContainer = { data: [number], a: [number, number], d: [number, number], }; export type ConstGenericInConstContainer = { data: number[], a: number[], d: [number, number], }; export type NamedConstGenericContainer = { a: NamedConstGeneric, b: NamedConstGeneric, d: [number, number], }; export type InlineConstGenericContainer = { b: { data: [number, number], a: [number, number], d: [number, number, number], }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], }, d: [number, number], }; export type InlineRecursiveConstGenericContainer = { b: { data: [number, number], a: [number, number], d: [number, number, number], e: InlineRecursiveConstGeneric, }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], e: InlineRecursiveConstGeneric, }, d: [number, number], }; export type TestCollectionRegister = never; export type TestCollectionRegister = never; ================================================ FILE: tests/tests/snapshots/test__typescript__export-many-serde.snap ================================================ --- source: tests/tests/typescript.rs expression: output --- export type Range = { start: T, end: T, }; export type RangeInclusive = { start: T, end: T, }; export type Result = { ok: T, err: E, }; export type Unit1 = null; export type Unit2 = Record; export type Unit3 = []; export type Unit4 = null; export type Unit5 = "A"; export type Unit6 = { A: null }; export type Unit7 = { A: Record }; export type SimpleStruct = { a: number, b: string, c: [number, string, number], d: string[], e: string | null, }; export type TupleStruct1 = number; export type TupleStruct3 = [number, boolean, string]; export type TestEnum = "Unit" | ({ Single: number }) & { Multiple?: never; Struct?: never } | ({ Multiple: [number, number] }) & { Single?: never; Struct?: never } | ({ Struct: { a: number, } }) & { Multiple?: never; Single?: never }; export type RefStruct = TestEnum; export type InlinerStruct = { inline_this: { ref_struct: SimpleStruct, val: number, }, dont_inline_this: RefStruct, }; export type GenericStruct = { arg: T, }; export type GenericStruct = { arg: T, }; export type FlattenEnumStruct = { outer: string, } & FlattenEnum; export type OverridenStruct = { overriden_field: string, }; export type HasGenericAlias = { [key in number]: string }; export type EnumMacroAttributes = ({ A: string }) & { D?: never; bbb?: never; cccc?: never } | ({ bbb: number }) & { A?: never; D?: never; cccc?: never } | ({ cccc: number }) & { A?: never; D?: never; bbb?: never } | ({ D: { a: string, bbbbbb: number, } }) & { A?: never; bbb?: never; cccc?: never }; export type InlineEnumField = { A: { a: string, } }; export type InlineOptionalType = { optional_field: { a: string, } | null, }; export type Rename = "OneWord" | "Two words"; export type TransparentType = TransparentTypeInner; export type TransparentType2 = null; export type TransparentTypeWithOverride = string; export type EnumReferenceRecordKey = { a: Partial<{ [key in BasicEnum]: number }>, }; export type FlattenOnNestedEnum = { id: string, } & NestedEnum; export type MyEmptyInput = Record; export type ExtraBracketsInTupleVariant = { A: string }; export type ExtraBracketsInUnnamedStruct = string; export type InlineTuple = { demo: [string, boolean], }; export type InlineTuple2 = { demo: [{ demo: [string, boolean], }, boolean], }; export type SkippedFieldWithinVariant = { type: "A" } | { type: "B"; data: string }; export type KebabCase = { "test-ing": string, }; export type Issue281 = { default_unity_arguments: string[], }; export type LifetimeGenericStruct = { borrowed: T[], owned: T[], }; export type LifetimeGenericEnum = ({ Borrowed: T }) & { Owned?: never } | ({ Owned: T }) & { Borrowed?: never }; export type RenameWithWeirdCharsField = { "@odata.context": string, }; export type RenameWithWeirdCharsVariant = { "@odata.context": string }; export type RenamedFieldKeys = { "": string, "a\"b": string, "a\\b": string, "line\nbreak": string, "line\u2028break": string, "line\u2029break": string, }; export type RenamedVariantWithSkippedPayload = "a-b"; export type Type = never; export type ActualType = { a: GenericType, }; export type SpectaTypeOverride = { string_ident: string, u32_ident: number, path: string, tuple: [string, number], }; export type ContainerTypeOverrideStruct = string; export type ContainerTypeOverrideEnum = string; export type ContainerTypeOverrideGeneric = string; export type ContainerTypeOverrideToGeneric = T; export type ContainerTypeOverrideTuple = [string, number]; export type ContainerTypeOverrideTupleGeneric = [T, string]; export type InvalidToValidType = { cause: null, }; export type TupleStruct = string; export type TupleStructWithRep = string; export type GenericTupleStruct = T; export type BracedStruct = string; export type StructNew = { t: "StructNew", a: string, }; export type Struct2 = { b: string, }; export type Enum = { t: "A" } | { t: "B" }; export type Enum2 = { t: "C" } | { t: "B" } | { t: "D"; enumField: null }; export type Enum3 = { t: "A"; b: string }; export type StructRenameAllUppercase = { A: number, B: number, }; export type RenameSerdeSpecialChar = { "a/b": number, }; export type EnumRenameAllUppercase = "HELLOWORLD" | "VARIANTB" | "TESTINGWORDS"; export type Recursive = { demo: Recursive, }; export type RecursiveMapValue = { demo: { [key in string]: RecursiveMapValue }, }; export type RecursiveTransparent = RecursiveInline; export type RecursiveInEnum = { A: { demo: RecursiveInEnum, } }; export type NonOptional = string | null; export type OptionalOnNamedField = string | null; export type OptionalOnTransparentNamedField = { b: string | null, }; export type OptionalInEnum = ({ A?: string | null }) & { B?: never; C?: never } | ({ B: { a: string | null, } }) & { A?: never; C?: never } | ({ C: { a?: string | null, } }) & { A?: never; B?: never }; export type UntaggedVariants = string | number | { id: string } | [string, boolean]; export type UntaggedVariantsWithoutValue = string | [number, string] | number; export type UntaggedVariantsWithDuplicateBranches = null | number; export type Regular = { [key in string]: null }; export type ValidMaybeValidKey = { [key in MaybeValidKey]: null }; export type ValidMaybeValidKeyNested = { [key in MaybeValidKey>]: null }; export type MacroStruct = string; export type MacroStruct2 = { demo: string, }; export type MacroEnum = ({ Demo: string }) & { Demo2?: never } | ({ Demo2: { demo2: string, } }) & { Demo?: never }; /** * @deprecated */ export type DeprecatedType = { a: number, }; /** * @deprecated Look at you big man using a deprecation message */ export type DeprecatedTypeWithMsg = { a: number, }; /** * @deprecated Look at you big man using a deprecation message */ export type DeprecatedTypeWithMsg2 = { a: number, }; export type DeprecatedFields = { a: number, /** * @deprecated */ b: string, /** * @deprecated This field is cringe! */ c: string, /** * @deprecated This field is cringe! */ d: string, }; export type DeprecatedTupleVariant = [ /** * @deprecated */ string, /** * @deprecated Nope */ string, /** * @deprecated Nope */ number]; export type DeprecatedEnumVariants = /** * @deprecated */ "A" | /** * @deprecated Nope */ "B" | /** * @deprecated Nope */ "C"; /** * Some triple-slash comment * Some more triple-slash comment */ export type CommentedStruct = { /** * Some triple-slash comment * Some more triple-slash comment */ a: number, }; /** * Some triple-slash comment * Some more triple-slash comment */ export type CommentedEnum = /** * Some triple-slash comment * Some more triple-slash comment */ ({ A: number }) & { B?: never } | /** * Some triple-slash comment * Some more triple-slash comment */ ({ B: { /** * Some triple-slash comment * Some more triple-slash comment */ a: number, } }) & { A?: never }; /** Some single-line comment */ export type SingleLineComment = /** Some single-line comment */ ({ A: number }) & { B?: never } | /** Some single-line comment */ ({ B: { /** Some single-line comment */ a: number, } }) & { A?: never }; export type Demo = { a: A, b: B, }; export type Demo = { a: A, b: B, }; export type Demo = { a: A, b: B, }; export type Demo = { a: A, b: B, }; export type Demo = { a: A, b: B, }; export type AGenericStruct = { field: Demo, }; export type A = { a: B, b: { b: number, }, c: B, d: { flattened: number, }, e: { generic_flattened: number, }, }; export type DoubleFlattened = { a: ToBeFlattened, b: ToBeFlattened, }; export type FlattenedInner = Inner; export type BoxFlattened = BoxedInner; export type BoxInline = { c: { a: number, }, }; export type First = { a: string, }; export type Second = { a: number, }; export type Third = { b: { [key in string]: string }, c: First, } & First; export type Fourth = { a: First, b: { a: string, }, }; export type TagOnStructWithInline = { type: "TagOnStructWithInline", a: First, b: { a: string, }, }; export type Sixth = { a: First, b: First, }; export type Seventh = { a: First, b: Second, }; export type Eight = { A: string } | "B"; export type Ninth = { t: "A"; c: string } | { t: "B" } | { t: "C"; c: { a: string, } } | { t: "D"; c: First }; export type Tenth = string | "B" | { a: string, } | First; export type MyEnumTagged = { type: "Variant"; inner: First }; export type MyEnumExternal = { Variant: { inner: First, } }; export type MyEnumAdjacent = { t: "Variant"; c: { inner: First, } }; export type MyEnumUntagged = { inner: First }; export type EmptyStruct = Record; export type EmptyStructWithTag = { a: "EmptyStructWithTag", }; export type AdjacentlyTagged = { t: "A" } | { t: "B"; c: { id: string, method: string, } } | { t: "C"; c: string }; export type LoadProjectEvent = { event: "started"; data: { projectName: string, } } | { event: "progressTest"; data: { projectName: string, status: string, progress: number, } } | { event: "finished"; data: { projectName: string, } }; export type ExternallyTagged = "A" | ({ B: { id: string, method: string, } }) & { C?: never } | ({ C: string }) & { B?: never }; export type Issue221External = ({ A: { a: string, } }) & { B?: never } | ({ B: { b: string, } }) & { A?: never }; export type InternallyTaggedD = { type: "A", } & { [key in string]: string }; export type InternallyTaggedE = { type: "A" }; export type InternallyTaggedF = { type: "A" }; export type InternallyTaggedH = { type: "A" }; export type InternallyTaggedL = { type: "A", } & { type: "A" } | { type: "B" }; export type InternallyTaggedM = { type: "A" }; export type StructWithAlias = { field: string, }; export type StructWithMultipleAliases = { field: string, }; export type StructWithAliasAndRename = { renamed_field: string, }; export type EnumWithVariantAlias = "Variant" | "Other"; export type EnumWithMultipleVariantAliases = "Variant" | "Other"; export type EnumWithVariantAliasAndRename = "renamed_variant" | "Other"; export type InternallyTaggedWithAlias = { type: "A"; field: string } | { type: "B"; other: number }; export type AdjacentlyTaggedWithAlias = { type: "A"; data: { field: string, } } | { type: "B"; data: { other: number, } }; export type UntaggedWithAlias = ({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }; export type Issue221UntaggedSafe = ({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }; export type Issue221UntaggedMixed = ({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never }; export type EmptyEnum = never; export type EmptyEnumTagged = never; export type EmptyEnumTaggedWContent = never; export type EmptyEnumUntagged = never; export type SkipOnlyField = Record; export type SkipField = { b: number, }; export type SkipVariant = { A: string }; export type SkipUnnamedFieldInVariant = "A" | { B: [number] }; export type SkipNamedFieldInVariant = ({ A: Record }) & { B?: never } | ({ B: { b: number, } }) & { A?: never }; export type TransparentWithSkip = null; export type TransparentWithSkip2 = string; export type TransparentWithSkip3 = string; export type SkipVariant2 = { tag: "A"; data: string }; export type SkipVariant3 = { A: { a: string, } }; export type SkipStructFields = { a: number, }; export type SpectaSkipNonTypeField = { a: number, }; export type FlattenA = { a: number, b: number, }; export type FlattenB = { c: number, } & FlattenA; export type FlattenC = { c: number, } & FlattenA; export type FlattenD = { a: FlattenA, c: number, }; export type FlattenE = { b: ({ c: number, }) & (FlattenA), d: number, }; export type FlattenF = { b: ({ c: number, }) & (FlattenA), d: number, }; export type FlattenG = { b: FlattenB, d: number, }; export type TupleNested = [number[], [number[], number[]], [number[], number[], number[]]]; export type Generic1 = { value: T, values: T[], }; export type GenericAutoBound = { value: T, values: T[], }; export type GenericAutoBound2 = { value: T, values: T[], }; export type Container1 = { foo: Generic1, bar: Generic1[], baz: { [key in string]: Generic1 }, }; export type Generic2 = ({ A: A }) & { B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ B: [B, B, B] }) & { A?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ C: C[] }) & { A?: never; B?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ D: A[][][] }) & { A?: never; B?: never; C?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ E: { a: A, b: B, c: C, } }) & { A?: never; B?: never; C?: never; D?: never; X?: never; Y?: never; Z?: never } | ({ X: number[] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; Y?: never; Z?: never } | ({ Y: number }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Z?: never } | ({ Z: number[][] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never }; export type GenericNewType1 = T[][]; export type GenericTuple = [T, T[], T[][]]; export type GenericStruct2 = { a: T, b: [T, T], c: [T, [T, T]], d: [T, T, T], e: [([T, T]), ([T, T]), ([T, T])], f: T[], g: T[][], h: ([([T, T]), ([T, T]), ([T, T])])[], }; export type InlineFlattenGenericsG = { t: T, }; export type InlineFlattenGenerics = { g: InlineFlattenGenericsG, gi: { t: string, }, } & InlineFlattenGenericsG; export type GenericDefault = { value: T, }; export type ChainedGenericDefault = { first: T, second: U, }; export type ChainedGenericDefault = { first: T, second: U, }; export type ChainedGenericDefault = { first: T, second: U, }; export type ChainedGenericDefault = { first: T, second: U, }; export type GenericDefaultSkipped = { value: T, }; export type GenericDefaultSkippedNonType = { value: number, }; export type GenericParameterOrderPreserved = { pair: Pair, }; export type ConstGenericInNonConstContainer = { data: [number], a: [number, number], d: [number, number], }; export type ConstGenericInConstContainer = { data: number[], a: number[], d: [number, number], }; export type NamedConstGenericContainer = { a: NamedConstGeneric, b: NamedConstGeneric, d: [number, number], }; export type InlineConstGenericContainer = { b: { data: [number, number], a: [number, number], d: [number, number, number], }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], }, d: [number, number], }; export type InlineRecursiveConstGenericContainer = { b: { data: [number, number], a: [number, number], d: [number, number, number], e: InlineRecursiveConstGeneric, }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], e: InlineRecursiveConstGeneric, }, d: [number, number], }; export type TestCollectionRegister = never; export type TestCollectionRegister = never; ================================================ FILE: tests/tests/snapshots/test__typescript__export-many-serde_phases.snap ================================================ --- source: tests/tests/typescript.rs expression: output --- /** https://github.com/specta-rs/specta/issues/374 */ export type Issue374 = Issue374_Serialize | Issue374_Deserialize; export type Optional = Optional_Serialize | Optional_Deserialize; export type StructPhaseSpecificRename = StructPhaseSpecificRenameSerialize | StructPhaseSpecificRenameDeserialize; export type Range = { start: T, end: T, }; export type RangeInclusive = { start: T, end: T, }; export type Result = { ok: T, err: E, }; export type Unit1 = null; export type Unit2 = Record; export type Unit3 = []; export type Unit4 = null; export type Unit5 = "A"; export type Unit6 = { A: null }; export type Unit7 = { A: Record }; export type SimpleStruct = { a: number, b: string, c: [number, string, number], d: string[], e: string | null, }; export type TupleStruct1 = number; export type TupleStruct3 = [number, boolean, string]; export type TestEnum = "Unit" | ({ Single: number }) & { Multiple?: never; Struct?: never } | ({ Multiple: [number, number] }) & { Single?: never; Struct?: never } | ({ Struct: { a: number, } }) & { Multiple?: never; Single?: never }; export type RefStruct = TestEnum; export type InlinerStruct = { inline_this: { ref_struct: SimpleStruct, val: number, }, dont_inline_this: RefStruct, }; export type GenericStruct = { arg: T, }; export type GenericStruct = { arg: T, }; export type FlattenEnumStruct = { outer: string, } & FlattenEnum; export type OverridenStruct = { overriden_field: string, }; export type HasGenericAlias = { [key in number]: string }; export type EnumMacroAttributes = ({ A: string }) & { D?: never; bbb?: never; cccc?: never } | ({ bbb: number }) & { A?: never; D?: never; cccc?: never } | ({ cccc: number }) & { A?: never; D?: never; bbb?: never } | ({ D: { a: string, bbbbbb: number, } }) & { A?: never; bbb?: never; cccc?: never }; export type InlineEnumField = { A: { a: string, } }; export type InlineOptionalType = { optional_field: { a: string, } | null, }; export type Rename = "OneWord" | "Two words"; export type TransparentType = TransparentTypeInner; export type TransparentType2 = null; export type TransparentTypeWithOverride = string; export type EnumReferenceRecordKey = { a: Partial<{ [key in BasicEnum]: number }>, }; export type FlattenOnNestedEnum = { id: string, } & NestedEnum; export type MyEmptyInput = Record; export type ExtraBracketsInTupleVariant = { A: string }; export type ExtraBracketsInUnnamedStruct = string; export type InlineTuple = { demo: [string, boolean], }; export type InlineTuple2 = { demo: [{ demo: [string, boolean], }, boolean], }; export type SkippedFieldWithinVariant = { type: "A" } | { type: "B"; data: string }; export type KebabCase = { "test-ing": string, }; export type Issue281 = { default_unity_arguments: string[], }; export type LifetimeGenericStruct = { borrowed: T[], owned: T[], }; export type LifetimeGenericEnum = ({ Borrowed: T }) & { Owned?: never } | ({ Owned: T }) & { Borrowed?: never }; export type RenameWithWeirdCharsField = { "@odata.context": string, }; export type RenameWithWeirdCharsVariant = { "@odata.context": string }; export type RenamedFieldKeys = { "": string, "a\"b": string, "a\\b": string, "line\nbreak": string, "line\u2028break": string, "line\u2029break": string, }; export type RenamedVariantWithSkippedPayload = "a-b"; export type Type = never; export type ActualType = { a: GenericType, }; export type SpectaTypeOverride = { string_ident: string, u32_ident: number, path: string, tuple: [string, number], }; export type ContainerTypeOverrideStruct = string; export type ContainerTypeOverrideEnum = string; export type ContainerTypeOverrideGeneric = string; export type ContainerTypeOverrideToGeneric = T; export type ContainerTypeOverrideTuple = [string, number]; export type ContainerTypeOverrideTupleGeneric = [T, string]; export type InvalidToValidType = { cause: null, }; export type TupleStruct = string; export type TupleStructWithRep = string; export type GenericTupleStruct = T; export type BracedStruct = string; export type StructNew = { t: "StructNew", a: string, }; export type Struct2 = { b: string, }; export type Enum = { t: "A" } | { t: "B" }; export type Enum2 = { t: "C" } | { t: "B" } | { t: "D"; enumField: null }; export type Enum3 = { t: "A"; b: string }; export type StructRenameAllUppercase = { A: number, B: number, }; export type RenameSerdeSpecialChar = { "a/b": number, }; export type EnumRenameAllUppercase = "HELLOWORLD" | "VARIANTB" | "TESTINGWORDS"; export type Recursive = { demo: Recursive, }; export type RecursiveMapValue = { demo: { [key in string]: RecursiveMapValue }, }; export type RecursiveTransparent = RecursiveInline; export type RecursiveInEnum = { A: { demo: RecursiveInEnum, } }; export type NonOptional = string | null; export type OptionalOnNamedField = string | null; export type OptionalOnTransparentNamedField = { b: string | null, }; export type OptionalInEnum = ({ A?: string | null }) & { B?: never; C?: never } | ({ B: { a: string | null, } }) & { A?: never; C?: never } | ({ C: { a?: string | null, } }) & { A?: never; B?: never }; export type UntaggedVariants = string | number | { id: string } | [string, boolean]; export type UntaggedVariantsWithoutValue = string | [number, string] | number; export type UntaggedVariantsWithDuplicateBranches = null | number; export type Regular = { [key in string]: null }; export type ValidMaybeValidKey = { [key in MaybeValidKey]: null }; export type ValidMaybeValidKeyNested = { [key in MaybeValidKey>]: null }; export type MacroStruct = string; export type MacroStruct2 = { demo: string, }; export type MacroEnum = ({ Demo: string }) & { Demo2?: never } | ({ Demo2: { demo2: string, } }) & { Demo?: never }; /** * @deprecated */ export type DeprecatedType = { a: number, }; /** * @deprecated Look at you big man using a deprecation message */ export type DeprecatedTypeWithMsg = { a: number, }; /** * @deprecated Look at you big man using a deprecation message */ export type DeprecatedTypeWithMsg2 = { a: number, }; export type DeprecatedFields = { a: number, /** * @deprecated */ b: string, /** * @deprecated This field is cringe! */ c: string, /** * @deprecated This field is cringe! */ d: string, }; export type DeprecatedTupleVariant = [ /** * @deprecated */ string, /** * @deprecated Nope */ string, /** * @deprecated Nope */ number]; export type DeprecatedEnumVariants = /** * @deprecated */ "A" | /** * @deprecated Nope */ "B" | /** * @deprecated Nope */ "C"; /** * Some triple-slash comment * Some more triple-slash comment */ export type CommentedStruct = { /** * Some triple-slash comment * Some more triple-slash comment */ a: number, }; /** * Some triple-slash comment * Some more triple-slash comment */ export type CommentedEnum = /** * Some triple-slash comment * Some more triple-slash comment */ ({ A: number }) & { B?: never } | /** * Some triple-slash comment * Some more triple-slash comment */ ({ B: { /** * Some triple-slash comment * Some more triple-slash comment */ a: number, } }) & { A?: never }; /** Some single-line comment */ export type SingleLineComment = /** Some single-line comment */ ({ A: number }) & { B?: never } | /** Some single-line comment */ ({ B: { /** Some single-line comment */ a: number, } }) & { A?: never }; export type Demo = { a: A, b: B, }; export type Demo = { a: A, b: B, }; export type Demo = { a: A, b: B, }; export type Demo = { a: A, b: B, }; export type Demo = { a: A, b: B, }; export type AGenericStruct = { field: Demo, }; export type A = { a: B, b: { b: number, }, c: B, d: { flattened: number, }, e: { generic_flattened: number, }, }; export type DoubleFlattened = { a: ToBeFlattened, b: ToBeFlattened, }; export type FlattenedInner = Inner; export type BoxFlattened = BoxedInner; export type BoxInline = { c: { a: number, }, }; export type First = { a: string, }; export type Second = { a: number, }; export type Third = { b: { [key in string]: string }, c: First, } & First; export type Fourth = { a: First, b: { a: string, }, }; export type TagOnStructWithInline = { type: "TagOnStructWithInline", a: First, b: { a: string, }, }; export type Sixth = { a: First, b: First, }; export type Seventh = { a: First, b: Second, }; export type Eight = { A: string } | "B"; export type Ninth = { t: "A"; c: string } | { t: "B" } | { t: "C"; c: { a: string, } } | { t: "D"; c: First }; export type Tenth = string | "B" | { a: string, } | First; export type MyEnumTagged = { type: "Variant"; inner: First }; export type MyEnumExternal = { Variant: { inner: First, } }; export type MyEnumAdjacent = { t: "Variant"; c: { inner: First, } }; export type MyEnumUntagged = { inner: First }; export type EmptyStruct = Record; export type EmptyStructWithTag = { a: "EmptyStructWithTag", }; export type AdjacentlyTagged = { t: "A" } | { t: "B"; c: { id: string, method: string, } } | { t: "C"; c: string }; export type LoadProjectEvent = { event: "started"; data: { projectName: string, } } | { event: "progressTest"; data: { projectName: string, status: string, progress: number, } } | { event: "finished"; data: { projectName: string, } }; export type ExternallyTagged = "A" | ({ B: { id: string, method: string, } }) & { C?: never } | ({ C: string }) & { B?: never }; export type Issue221External = ({ A: { a: string, } }) & { B?: never } | ({ B: { b: string, } }) & { A?: never }; export type InternallyTaggedD = { type: "A", } & { [key in string]: string }; export type InternallyTaggedE = { type: "A" }; export type InternallyTaggedF = { type: "A" }; export type InternallyTaggedH = { type: "A" }; export type InternallyTaggedL = { type: "A", } & { type: "A" } | { type: "B" }; export type InternallyTaggedM = { type: "A" }; export type StructWithAlias = { field: string, }; export type StructWithMultipleAliases = { field: string, }; export type StructWithAliasAndRename = { renamed_field: string, }; export type EnumWithVariantAlias = "Variant" | "Other"; export type EnumWithMultipleVariantAliases = "Variant" | "Other"; export type EnumWithVariantAliasAndRename = "renamed_variant" | "Other"; export type InternallyTaggedWithAlias = { type: "A"; field: string } | { type: "B"; other: number }; export type AdjacentlyTaggedWithAlias = { type: "A"; data: { field: string, } } | { type: "B"; data: { other: number, } }; export type UntaggedWithAlias = ({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }; export type Issue221UntaggedSafe = ({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }; export type Issue221UntaggedMixed = ({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never }; export type EmptyEnum = never; export type EmptyEnumTagged = never; export type EmptyEnumTaggedWContent = never; export type EmptyEnumUntagged = never; export type SkipOnlyField = Record; export type SkipField = { b: number, }; export type SkipVariant = { A: string }; export type SkipUnnamedFieldInVariant = "A" | { B: [number] }; export type SkipNamedFieldInVariant = ({ A: Record }) & { B?: never } | ({ B: { b: number, } }) & { A?: never }; export type TransparentWithSkip = null; export type TransparentWithSkip2 = string; export type TransparentWithSkip3 = string; export type SkipVariant2 = { tag: "A"; data: string }; export type SkipVariant3 = { A: { a: string, } }; export type SkipStructFields = { a: number, }; export type SpectaSkipNonTypeField = { a: number, }; export type FlattenA = { a: number, b: number, }; export type FlattenB = { c: number, } & FlattenA; export type FlattenC = { c: number, } & FlattenA; export type FlattenD = { a: FlattenA, c: number, }; export type FlattenE = { b: ({ c: number, }) & (FlattenA), d: number, }; export type FlattenF = { b: ({ c: number, }) & (FlattenA), d: number, }; export type FlattenG = { b: FlattenB, d: number, }; export type TupleNested = [number[], [number[], number[]], [number[], number[], number[]]]; export type Generic1 = { value: T, values: T[], }; export type GenericAutoBound = { value: T, values: T[], }; export type GenericAutoBound2 = { value: T, values: T[], }; export type Container1 = { foo: Generic1, bar: Generic1[], baz: { [key in string]: Generic1 }, }; export type Generic2 = ({ A: A }) & { B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ B: [B, B, B] }) & { A?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ C: C[] }) & { A?: never; B?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ D: A[][][] }) & { A?: never; B?: never; C?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ E: { a: A, b: B, c: C, } }) & { A?: never; B?: never; C?: never; D?: never; X?: never; Y?: never; Z?: never } | ({ X: number[] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; Y?: never; Z?: never } | ({ Y: number }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Z?: never } | ({ Z: number[][] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never }; export type GenericNewType1 = T[][]; export type GenericTuple = [T, T[], T[][]]; export type GenericStruct2 = { a: T, b: [T, T], c: [T, [T, T]], d: [T, T, T], e: [([T, T]), ([T, T]), ([T, T])], f: T[], g: T[][], h: ([([T, T]), ([T, T]), ([T, T])])[], }; export type InlineFlattenGenericsG = { t: T, }; export type InlineFlattenGenerics = { g: InlineFlattenGenericsG, gi: { t: string, }, } & InlineFlattenGenericsG; export type GenericDefault = { value: T, }; export type ChainedGenericDefault = { first: T, second: U, }; export type ChainedGenericDefault = { first: T, second: U, }; export type ChainedGenericDefault = { first: T, second: U, }; export type ChainedGenericDefault = { first: T, second: U, }; export type GenericDefaultSkipped = { value: T, }; export type GenericDefaultSkippedNonType = { value: number, }; export type GenericParameterOrderPreserved = { pair: Pair, }; export type ConstGenericInNonConstContainer = { data: [number], a: [number, number], d: [number, number], }; export type ConstGenericInConstContainer = { data: number[], a: number[], d: [number, number], }; export type NamedConstGenericContainer = { a: NamedConstGeneric, b: NamedConstGeneric, d: [number, number], }; export type InlineConstGenericContainer = { b: { data: [number, number], a: [number, number], d: [number, number, number], }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], }, d: [number, number], }; export type InlineRecursiveConstGenericContainer = { b: { data: [number, number], a: [number, number], d: [number, number, number], e: InlineRecursiveConstGeneric, }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], e: InlineRecursiveConstGeneric, }, d: [number, number], }; export type TestCollectionRegister = never; export type TestCollectionRegister = never; ================================================ FILE: tests/tests/snapshots/test__typescript__export-raw.snap ================================================ --- source: tests/tests/typescript.rs expression: output --- Range: export type Range = { start: T, end: T, }; RangeInclusive: export type RangeInclusive = { start: T, end: T, }; String: PathBuf: IpAddr: Ipv4Addr: Ipv6Addr: SocketAddr: SocketAddrV4: SocketAddrV6: Cow<'static, str>: Cow<'static, i32>: Vec: Vec: Result: export type Result = { ok: T, err: E, }; Vec>>: PhantomData<()>: PhantomData: Infallible: Unit1: export type Unit1 = null; Unit2: export type Unit2 = Record; Unit3: export type Unit3 = []; Unit4: export type Unit4 = null; Unit5: export type Unit5 = "A"; Unit6: export type Unit6 = []; Unit7: export type Unit7 = Record; SimpleStruct: export type SimpleStruct = { a: number, b: string, c: [number, string, number], d: string[], e: string | null, }; TupleStruct1: export type TupleStruct1 = number; TupleStruct3: export type TupleStruct3 = [number, boolean, string]; TestEnum: export type TestEnum = "Unit" | number | [number, number] | { a: number }; RefStruct: export type RefStruct = TestEnum; InlinerStruct: export type InlinerStruct = { inline_this: { ref_struct: SimpleStruct, val: number, }, dont_inline_this: RefStruct, }; GenericStruct: export type GenericStruct = { arg: T, }; GenericStruct: export type GenericStruct = { arg: T, }; FlattenEnumStruct: export type FlattenEnumStruct = { outer: string, inner: FlattenEnum, }; OverridenStruct: export type OverridenStruct = { overriden_field: string, }; HasGenericAlias: export type HasGenericAlias = { [key in number]: string }; EnumMacroAttributes: export type EnumMacroAttributes = string | number | { a: string; b: number }; InlineEnumField: export type InlineEnumField = { a: string, }; InlineOptionalType: export type InlineOptionalType = { optional_field: { a: string, } | null, }; Rename: export type Rename = "OneWord" | "TwoWords"; TransparentType: export type TransparentType = TransparentTypeInner; TransparentType2: export type TransparentType2 = null; TransparentTypeWithOverride: export type TransparentTypeWithOverride = string; HashMap: HashMap: Vec: EnumReferenceRecordKey: export type EnumReferenceRecordKey = { a: Partial<{ [key in BasicEnum]: number }>, }; FlattenOnNestedEnum: export type FlattenOnNestedEnum = { id: string, result: NestedEnum, }; MyEmptyInput: export type MyEmptyInput = Record; (String): ExtraBracketsInTupleVariant: export type ExtraBracketsInTupleVariant = string; ExtraBracketsInUnnamedStruct: export type ExtraBracketsInUnnamedStruct = string; Vec: InlineTuple: export type InlineTuple = { demo: [string, boolean], }; InlineTuple2: export type InlineTuple2 = { demo: [{ demo: [string, boolean], }, boolean], }; Box: Box: SkippedFieldWithinVariant: export type SkippedFieldWithinVariant = never | string; KebabCase: export type KebabCase = { test_ing: string, }; Issue281<'_>: export type Issue281 = { default_unity_arguments: string[], }; LifetimeGenericStruct<'_, i32>: export type LifetimeGenericStruct = { borrowed: T[], owned: T[], }; LifetimeGenericEnum<'_, i32>: export type LifetimeGenericEnum = T; RenameWithWeirdCharsField: export type RenameWithWeirdCharsField = { odata_context: string, }; RenameWithWeirdCharsVariant: export type RenameWithWeirdCharsVariant = string; RenamedFieldKeys: export type RenamedFieldKeys = { empty: string, quote: string, backslash: string, newline: string, line_separator: string, paragraph_separator: string, }; RenamedVariantWithSkippedPayload: export type RenamedVariantWithSkippedPayload = never; type_type::Type: export type Type = never; ActualType: export type ActualType = { a: GenericType, }; SpectaTypeOverride: export type SpectaTypeOverride = { string_ident: string, u32_ident: number, path: string, tuple: [string, number], }; ContainerTypeOverrideStruct: export type ContainerTypeOverrideStruct = string; ContainerTypeOverrideEnum: export type ContainerTypeOverrideEnum = string; ContainerTypeOverrideGeneric>: export type ContainerTypeOverrideGeneric = string; ContainerTypeOverrideToGeneric: export type ContainerTypeOverrideToGeneric = T; ContainerTypeOverrideTuple: export type ContainerTypeOverrideTuple = [string, number]; ContainerTypeOverrideTupleGeneric: export type ContainerTypeOverrideTupleGeneric = [T, string]; InvalidToValidType: export type InvalidToValidType = { cause: null, }; TupleStruct: export type TupleStruct = string; TupleStructWithRep: export type TupleStructWithRep = string; GenericTupleStruct: export type GenericTupleStruct = T; BracedStruct: export type BracedStruct = string; Struct: export type Struct = { a: string, }; Struct2: export type Struct2 = { a: string, }; Enum: export type Enum = "A" | "B"; Enum2: export type Enum2 = "A" | "B" | { enum_field: null }; Enum3: export type Enum3 = { a: string }; StructRenameAllUppercase: export type StructRenameAllUppercase = { a: number, b: number, }; RenameSerdeSpecialChar: export type RenameSerdeSpecialChar = { b: number, }; EnumRenameAllUppercase: export type EnumRenameAllUppercase = "HelloWorld" | "VariantB" | "TestingWords"; Recursive: export type Recursive = { demo: Recursive, }; RecursiveMapValue: export type RecursiveMapValue = { demo: { [key in string]: RecursiveMapValue }, }; RecursiveTransparent: export type RecursiveTransparent = RecursiveInline; RecursiveInEnum: export type RecursiveInEnum = { demo: RecursiveInEnum }; NonOptional: export type NonOptional = string | null; OptionalOnNamedField: export type OptionalOnNamedField = string | null; OptionalOnTransparentNamedField: export type OptionalOnTransparentNamedField = { b: string | null, }; OptionalInEnum: export type OptionalInEnum = string | null | { a: string | null } | { a?: string | null }; UntaggedVariants: export type UntaggedVariants = string | number | { id: string } | [string, boolean]; UntaggedVariantsWithoutValue: export type UntaggedVariantsWithoutValue = string | [number, string] | number; UntaggedVariantsWithDuplicateBranches: export type UntaggedVariantsWithDuplicateBranches = null | number; HashMap: Regular: export type Regular = { [key in string]: null }; HashMap: HashMap: HashMap: HashMap: ValidMaybeValidKey: export type ValidMaybeValidKey = { [key in MaybeValidKey]: null }; ValidMaybeValidKeyNested: export type ValidMaybeValidKeyNested = { [key in MaybeValidKey>]: null }; MacroStruct: export type MacroStruct = string; MacroStruct2: export type MacroStruct2 = { demo: string, }; MacroEnum: export type MacroEnum = string | { demo2: string }; DeprecatedType: /** * @deprecated */ export type DeprecatedType = { a: number, }; DeprecatedTypeWithMsg: /** * @deprecated Look at you big man using a deprecation message */ export type DeprecatedTypeWithMsg = { a: number, }; DeprecatedTypeWithMsg2: /** * @deprecated Look at you big man using a deprecation message */ export type DeprecatedTypeWithMsg2 = { a: number, }; DeprecatedFields: export type DeprecatedFields = { a: number, /** * @deprecated */ b: string, /** * @deprecated This field is cringe! */ c: string, /** * @deprecated This field is cringe! */ d: string, }; DeprecatedTupleVariant: export type DeprecatedTupleVariant = [ /** * @deprecated */ string, /** * @deprecated Nope */ string, /** * @deprecated Nope */ number]; DeprecatedEnumVariants: export type DeprecatedEnumVariants = /** * @deprecated */ "A" | /** * @deprecated Nope */ "B" | /** * @deprecated Nope */ "C"; CommentedStruct: /** * Some triple-slash comment * Some more triple-slash comment */ export type CommentedStruct = { /** * Some triple-slash comment * Some more triple-slash comment */ a: number, }; CommentedEnum: /** * Some triple-slash comment * Some more triple-slash comment */ export type CommentedEnum = /** * Some triple-slash comment * Some more triple-slash comment */ number | /** * Some triple-slash comment * Some more triple-slash comment */ { /** * Some triple-slash comment * Some more triple-slash comment */ a: number }; SingleLineComment: /** Some single-line comment */ export type SingleLineComment = /** Some single-line comment */ number | /** Some single-line comment */ { /** Some single-line comment */ a: number }; NonGeneric: export type Demo = { a: A, b: B, }; HalfGenericA: export type Demo = { a: A, b: B, }; HalfGenericB: export type Demo = { a: A, b: B, }; FullGeneric: export type Demo = { a: A, b: B, }; Another: export type Demo = { a: A, b: B, }; MapA: MapB: MapC: AGenericStruct: export type AGenericStruct = { field: Demo, }; A: export type A = { a: B, b: { b: number, }, c: B, d: { flattened: number, }, e: { generic_flattened: number, }, }; DoubleFlattened: export type DoubleFlattened = { a: ToBeFlattened, b: ToBeFlattened, }; FlattenedInner: export type FlattenedInner = { c: Inner, }; BoxFlattened: export type BoxFlattened = { b: BoxedInner, }; BoxInline: export type BoxInline = { c: { a: number, }, }; First: export type First = { a: string, }; Second: export type Second = { a: number, }; Third: export type Third = { a: First, b: { [key in string]: string }, c: First, }; Fourth: export type Fourth = { a: First, b: { a: string, }, }; TagOnStructWithInline: export type TagOnStructWithInline = { a: First, b: { a: string, }, }; Sixth: export type Sixth = { a: First, b: First, }; Seventh: export type Seventh = { a: First, b: Second, }; Eight: export type Eight = string | "B"; Ninth: export type Ninth = string | "B" | { a: string, } | First; Tenth: export type Tenth = string | "B" | { a: string, } | First; MyEnumTagged: export type MyEnumTagged = { inner: First }; MyEnumExternal: export type MyEnumExternal = { inner: First }; MyEnumAdjacent: export type MyEnumAdjacent = { inner: First }; MyEnumUntagged: export type MyEnumUntagged = { inner: First }; EmptyStruct: export type EmptyStruct = Record; EmptyStructWithTag: export type EmptyStructWithTag = Record; AdjacentlyTagged: export type AdjacentlyTagged = "A" | { id: string; method: string } | string; LoadProjectEvent: export type LoadProjectEvent = ({ project_name: string }) & { progress?: never; status?: never } | { project_name: string; status: string; progress: number }; ExternallyTagged: export type ExternallyTagged = "A" | { id: string; method: string } | string; Issue221External: export type Issue221External = ({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }; InternallyTaggedD: export type InternallyTaggedD = { [key in string]: string }; InternallyTaggedE: export type InternallyTaggedE = null; InternallyTaggedF: export type InternallyTaggedF = InternallyTaggedFInner; InternallyTaggedH: export type InternallyTaggedH = InternallyTaggedHInner; InternallyTaggedL: export type InternallyTaggedL = "A" | "B"; InternallyTaggedM: export type InternallyTaggedM = "A" | "B"; StructWithAlias: export type StructWithAlias = { field: string, }; StructWithMultipleAliases: export type StructWithMultipleAliases = { field: string, }; StructWithAliasAndRename: export type StructWithAliasAndRename = { field: string, }; EnumWithVariantAlias: export type EnumWithVariantAlias = "Variant" | "Other"; EnumWithMultipleVariantAliases: export type EnumWithMultipleVariantAliases = "Variant" | "Other"; EnumWithVariantAliasAndRename: export type EnumWithVariantAliasAndRename = "Variant" | "Other"; InternallyTaggedWithAlias: export type InternallyTaggedWithAlias = ({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }; AdjacentlyTaggedWithAlias: export type AdjacentlyTaggedWithAlias = ({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }; UntaggedWithAlias: export type UntaggedWithAlias = ({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }; Issue221UntaggedSafe: export type Issue221UntaggedSafe = ({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }; Issue221UntaggedMixed: export type Issue221UntaggedMixed = ({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never }; EmptyEnum: export type EmptyEnum = never; EmptyEnumTagged: export type EmptyEnumTagged = never; EmptyEnumTaggedWContent: export type EmptyEnumTaggedWContent = never; EmptyEnumUntagged: export type EmptyEnumUntagged = never; SkipOnlyField: export type SkipOnlyField = Record; SkipField: export type SkipField = { b: number, }; SkipVariant: export type SkipVariant = string; SkipUnnamedFieldInVariant: export type SkipUnnamedFieldInVariant = never | [number]; SkipNamedFieldInVariant: export type SkipNamedFieldInVariant = Record | { b: number }; TransparentWithSkip: export type TransparentWithSkip = null; TransparentWithSkip2: export type TransparentWithSkip2 = string; TransparentWithSkip3: export type TransparentWithSkip3 = string; SkipVariant2: export type SkipVariant2 = string; SkipVariant3: export type SkipVariant3 = { a: string }; SkipStructFields: export type SkipStructFields = { a: number, }; SpectaSkipNonTypeField: export type SpectaSkipNonTypeField = { a: number, }; FlattenA: export type FlattenA = { a: number, b: number, }; FlattenB: export type FlattenB = { a: FlattenA, c: number, }; FlattenC: export type FlattenC = { a: FlattenA, c: number, }; FlattenD: export type FlattenD = { a: FlattenA, c: number, }; FlattenE: export type FlattenE = { b: { a: FlattenA, c: number, }, d: number, }; FlattenF: export type FlattenF = { b: { a: FlattenA, c: number, }, d: number, }; FlattenG: export type FlattenG = { b: FlattenB, d: number, }; TupleNested: export type TupleNested = [number[], [number[], number[]], [number[], number[], number[]]]; Generic1<()>: export type Generic1 = { value: T, values: T[], }; GenericAutoBound<()>: export type GenericAutoBound = { value: T, values: T[], }; GenericAutoBound2<()>: export type GenericAutoBound2 = { value: T, values: T[], }; Container1: export type Container1 = { foo: Generic1, bar: Generic1[], baz: { [key in string]: Generic1 }, }; Generic2<(), String, i32>: export type Generic2 = A | [B, B, B] | C[] | A[][][] | { a: A; b: B; c: C } | number[] | number | number[][]; GenericNewType1<()>: export type GenericNewType1 = T[][]; GenericTuple<()>: export type GenericTuple = [T, T[], T[][]]; GenericStruct2<()>: export type GenericStruct2 = { a: T, b: [T, T], c: [T, [T, T]], d: [T, T, T], e: [([T, T]), ([T, T]), ([T, T])], f: T[], g: T[][], h: ([([T, T]), ([T, T]), ([T, T])])[], }; InlineGenericNewtype: InlineGenericNested: InlineFlattenGenericsG<()>: export type InlineFlattenGenericsG = { t: T, }; InlineFlattenGenerics: export type InlineFlattenGenerics = { g: InlineFlattenGenericsG, gi: { t: string, }, t: InlineFlattenGenericsG, }; GenericDefault: export type GenericDefault = { value: T, }; ChainedGenericDefault: export type ChainedGenericDefault = { first: T, second: U, }; ChainedGenericDefault: export type ChainedGenericDefault = { first: T, second: U, }; ChainedGenericDefault: export type ChainedGenericDefault = { first: T, second: U, }; ChainedGenericDefault: export type ChainedGenericDefault = { first: T, second: U, }; GenericDefaultSkipped: export type GenericDefaultSkipped = { value: T, }; GenericDefaultSkippedNonType: export type GenericDefaultSkippedNonType = { value: number, }; GenericParameterOrderPreserved: export type GenericParameterOrderPreserved = { pair: Pair, }; ConstGenericInNonConstContainer: export type ConstGenericInNonConstContainer = { data: [number], a: [number, number], d: [number, number], }; ConstGenericInConstContainer: export type ConstGenericInConstContainer = { data: number[], a: number[], d: [number, number], }; NamedConstGenericContainer: export type NamedConstGenericContainer = { a: NamedConstGeneric, b: NamedConstGeneric, d: [number, number], }; InlineConstGenericContainer: export type InlineConstGenericContainer = { b: { data: [number, number], a: [number, number], d: [number, number, number], }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], }, d: [number, number], }; InlineRecursiveConstGenericContainer: export type InlineRecursiveConstGenericContainer = { b: { data: [number, number], a: [number, number], d: [number, number, number], e: InlineRecursiveConstGeneric, }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], e: InlineRecursiveConstGeneric, }, d: [number, number], }; TestCollectionRegister: export type TestCollectionRegister = never; TestCollectionRegister: export type TestCollectionRegister = never; ================================================ FILE: tests/tests/snapshots/test__typescript__export-serde.snap ================================================ --- source: tests/tests/typescript.rs expression: output --- Range: export type Range = { start: T, end: T, }; RangeInclusive: export type RangeInclusive = { start: T, end: T, }; String: PathBuf: IpAddr: Ipv4Addr: Ipv6Addr: SocketAddr: SocketAddrV4: SocketAddrV6: Cow<'static, str>: Cow<'static, i32>: Vec: Vec: Result: export type Result = { ok: T, err: E, }; Vec>>: PhantomData<()>: PhantomData: Infallible: Unit1: export type Unit1 = null; Unit2: export type Unit2 = Record; Unit3: export type Unit3 = []; Unit4: export type Unit4 = null; Unit5: export type Unit5 = "A"; Unit6: export type Unit6 = { A: null }; Unit7: export type Unit7 = { A: Record }; SimpleStruct: export type SimpleStruct = { a: number, b: string, c: [number, string, number], d: string[], e: string | null, }; TupleStruct1: export type TupleStruct1 = number; TupleStruct3: export type TupleStruct3 = [number, boolean, string]; TestEnum: export type TestEnum = "Unit" | ({ Single: number }) & { Multiple?: never; Struct?: never } | ({ Multiple: [number, number] }) & { Single?: never; Struct?: never } | ({ Struct: { a: number, } }) & { Multiple?: never; Single?: never }; RefStruct: export type RefStruct = TestEnum; InlinerStruct: export type InlinerStruct = { inline_this: { ref_struct: SimpleStruct, val: number, }, dont_inline_this: RefStruct, }; GenericStruct: export type GenericStruct = { arg: T, }; GenericStruct: export type GenericStruct = { arg: T, }; FlattenEnumStruct: export type FlattenEnumStruct = { outer: string, } & FlattenEnum; OverridenStruct: export type OverridenStruct = { overriden_field: string, }; HasGenericAlias: export type HasGenericAlias = { [key in number]: string }; EnumMacroAttributes: export type EnumMacroAttributes = ({ A: string }) & { D?: never; bbb?: never; cccc?: never } | ({ bbb: number }) & { A?: never; D?: never; cccc?: never } | ({ cccc: number }) & { A?: never; D?: never; bbb?: never } | ({ D: { a: string, bbbbbb: number, } }) & { A?: never; bbb?: never; cccc?: never }; InlineEnumField: export type InlineEnumField = { A: { a: string, } }; InlineOptionalType: export type InlineOptionalType = { optional_field: { a: string, } | null, }; Rename: export type Rename = "OneWord" | "Two words"; TransparentType: export type TransparentType = TransparentTypeInner; TransparentType2: export type TransparentType2 = null; TransparentTypeWithOverride: export type TransparentTypeWithOverride = string; HashMap: HashMap: Vec: EnumReferenceRecordKey: export type EnumReferenceRecordKey = { a: Partial<{ [key in BasicEnum]: number }>, }; FlattenOnNestedEnum: export type FlattenOnNestedEnum = { id: string, } & NestedEnum; MyEmptyInput: export type MyEmptyInput = Record; (String): ExtraBracketsInTupleVariant: export type ExtraBracketsInTupleVariant = { A: string }; ExtraBracketsInUnnamedStruct: export type ExtraBracketsInUnnamedStruct = string; Vec: InlineTuple: export type InlineTuple = { demo: [string, boolean], }; InlineTuple2: export type InlineTuple2 = { demo: [{ demo: [string, boolean], }, boolean], }; Box: Box: SkippedFieldWithinVariant: export type SkippedFieldWithinVariant = { type: "A" } | { type: "B"; data: string }; KebabCase: export type KebabCase = { "test-ing": string, }; Issue281<'_>: export type Issue281 = { default_unity_arguments: string[], }; LifetimeGenericStruct<'_, i32>: export type LifetimeGenericStruct = { borrowed: T[], owned: T[], }; LifetimeGenericEnum<'_, i32>: export type LifetimeGenericEnum = ({ Borrowed: T }) & { Owned?: never } | ({ Owned: T }) & { Borrowed?: never }; RenameWithWeirdCharsField: export type RenameWithWeirdCharsField = { "@odata.context": string, }; RenameWithWeirdCharsVariant: export type RenameWithWeirdCharsVariant = { "@odata.context": string }; RenamedFieldKeys: export type RenamedFieldKeys = { "": string, "a\"b": string, "a\\b": string, "line\nbreak": string, "line\u2028break": string, "line\u2029break": string, }; RenamedVariantWithSkippedPayload: export type RenamedVariantWithSkippedPayload = "a-b"; type_type::Type: export type Type = never; ActualType: export type ActualType = { a: GenericType, }; SpectaTypeOverride: export type SpectaTypeOverride = { string_ident: string, u32_ident: number, path: string, tuple: [string, number], }; ContainerTypeOverrideStruct: export type ContainerTypeOverrideStruct = string; ContainerTypeOverrideEnum: export type ContainerTypeOverrideEnum = string; ContainerTypeOverrideGeneric>: export type ContainerTypeOverrideGeneric = string; ContainerTypeOverrideToGeneric: export type ContainerTypeOverrideToGeneric = T; ContainerTypeOverrideTuple: export type ContainerTypeOverrideTuple = [string, number]; ContainerTypeOverrideTupleGeneric: export type ContainerTypeOverrideTupleGeneric = [T, string]; InvalidToValidType: export type InvalidToValidType = { cause: null, }; TupleStruct: export type TupleStruct = string; TupleStructWithRep: export type TupleStructWithRep = string; GenericTupleStruct: export type GenericTupleStruct = T; BracedStruct: export type BracedStruct = string; Struct: export type StructNew = { t: "StructNew", a: string, }; Struct2: export type Struct2 = { b: string, }; Enum: export type Enum = { t: "A" } | { t: "B" }; Enum2: export type Enum2 = { t: "C" } | { t: "B" } | { t: "D"; enumField: null }; Enum3: export type Enum3 = { t: "A"; b: string }; StructRenameAllUppercase: export type StructRenameAllUppercase = { A: number, B: number, }; RenameSerdeSpecialChar: export type RenameSerdeSpecialChar = { "a/b": number, }; EnumRenameAllUppercase: export type EnumRenameAllUppercase = "HELLOWORLD" | "VARIANTB" | "TESTINGWORDS"; Recursive: export type Recursive = { demo: Recursive, }; RecursiveMapValue: export type RecursiveMapValue = { demo: { [key in string]: RecursiveMapValue }, }; RecursiveTransparent: export type RecursiveTransparent = RecursiveInline; RecursiveInEnum: export type RecursiveInEnum = { A: { demo: RecursiveInEnum, } }; NonOptional: export type NonOptional = string | null; OptionalOnNamedField: export type OptionalOnNamedField = string | null; OptionalOnTransparentNamedField: export type OptionalOnTransparentNamedField = { b: string | null, }; OptionalInEnum: export type OptionalInEnum = ({ A?: string | null }) & { B?: never; C?: never } | ({ B: { a: string | null, } }) & { A?: never; C?: never } | ({ C: { a?: string | null, } }) & { A?: never; B?: never }; UntaggedVariants: export type UntaggedVariants = string | number | { id: string } | [string, boolean]; UntaggedVariantsWithoutValue: export type UntaggedVariantsWithoutValue = string | [number, string] | number; UntaggedVariantsWithDuplicateBranches: export type UntaggedVariantsWithDuplicateBranches = null | number; HashMap: Regular: export type Regular = { [key in string]: null }; HashMap: HashMap: HashMap: HashMap: ValidMaybeValidKey: export type ValidMaybeValidKey = { [key in MaybeValidKey]: null }; ValidMaybeValidKeyNested: export type ValidMaybeValidKeyNested = { [key in MaybeValidKey>]: null }; MacroStruct: export type MacroStruct = string; MacroStruct2: export type MacroStruct2 = { demo: string, }; MacroEnum: export type MacroEnum = ({ Demo: string }) & { Demo2?: never } | ({ Demo2: { demo2: string, } }) & { Demo?: never }; DeprecatedType: /** * @deprecated */ export type DeprecatedType = { a: number, }; DeprecatedTypeWithMsg: /** * @deprecated Look at you big man using a deprecation message */ export type DeprecatedTypeWithMsg = { a: number, }; DeprecatedTypeWithMsg2: /** * @deprecated Look at you big man using a deprecation message */ export type DeprecatedTypeWithMsg2 = { a: number, }; DeprecatedFields: export type DeprecatedFields = { a: number, /** * @deprecated */ b: string, /** * @deprecated This field is cringe! */ c: string, /** * @deprecated This field is cringe! */ d: string, }; DeprecatedTupleVariant: export type DeprecatedTupleVariant = [ /** * @deprecated */ string, /** * @deprecated Nope */ string, /** * @deprecated Nope */ number]; DeprecatedEnumVariants: export type DeprecatedEnumVariants = /** * @deprecated */ "A" | /** * @deprecated Nope */ "B" | /** * @deprecated Nope */ "C"; CommentedStruct: /** * Some triple-slash comment * Some more triple-slash comment */ export type CommentedStruct = { /** * Some triple-slash comment * Some more triple-slash comment */ a: number, }; CommentedEnum: /** * Some triple-slash comment * Some more triple-slash comment */ export type CommentedEnum = /** * Some triple-slash comment * Some more triple-slash comment */ ({ A: number }) & { B?: never } | /** * Some triple-slash comment * Some more triple-slash comment */ ({ B: { /** * Some triple-slash comment * Some more triple-slash comment */ a: number, } }) & { A?: never }; SingleLineComment: /** Some single-line comment */ export type SingleLineComment = /** Some single-line comment */ ({ A: number }) & { B?: never } | /** Some single-line comment */ ({ B: { /** Some single-line comment */ a: number, } }) & { A?: never }; NonGeneric: export type Demo = { a: A, b: B, }; HalfGenericA: export type Demo = { a: A, b: B, }; HalfGenericB: export type Demo = { a: A, b: B, }; FullGeneric: export type Demo = { a: A, b: B, }; Another: export type Demo = { a: A, b: B, }; MapA: MapB: MapC: AGenericStruct: export type AGenericStruct = { field: Demo, }; A: export type A = { a: B, b: { b: number, }, c: B, d: { flattened: number, }, e: { generic_flattened: number, }, }; DoubleFlattened: export type DoubleFlattened = { a: ToBeFlattened, b: ToBeFlattened, }; FlattenedInner: export type FlattenedInner = Inner; BoxFlattened: export type BoxFlattened = BoxedInner; BoxInline: export type BoxInline = { c: { a: number, }, }; First: export type First = { a: string, }; Second: export type Second = { a: number, }; Third: export type Third = { b: { [key in string]: string }, c: First, } & First; Fourth: export type Fourth = { a: First, b: { a: string, }, }; TagOnStructWithInline: export type TagOnStructWithInline = { type: "TagOnStructWithInline", a: First, b: { a: string, }, }; Sixth: export type Sixth = { a: First, b: First, }; Seventh: export type Seventh = { a: First, b: Second, }; Eight: export type Eight = { A: string } | "B"; Ninth: export type Ninth = { t: "A"; c: string } | { t: "B" } | { t: "C"; c: { a: string, } } | { t: "D"; c: First }; Tenth: export type Tenth = string | "B" | { a: string, } | First; MyEnumTagged: export type MyEnumTagged = { type: "Variant"; inner: First }; MyEnumExternal: export type MyEnumExternal = { Variant: { inner: First, } }; MyEnumAdjacent: export type MyEnumAdjacent = { t: "Variant"; c: { inner: First, } }; MyEnumUntagged: export type MyEnumUntagged = { inner: First }; EmptyStruct: export type EmptyStruct = Record; EmptyStructWithTag: export type EmptyStructWithTag = { a: "EmptyStructWithTag", }; AdjacentlyTagged: export type AdjacentlyTagged = { t: "A" } | { t: "B"; c: { id: string, method: string, } } | { t: "C"; c: string }; LoadProjectEvent: export type LoadProjectEvent = { event: "started"; data: { projectName: string, } } | { event: "progressTest"; data: { projectName: string, status: string, progress: number, } } | { event: "finished"; data: { projectName: string, } }; ExternallyTagged: export type ExternallyTagged = "A" | ({ B: { id: string, method: string, } }) & { C?: never } | ({ C: string }) & { B?: never }; Issue221External: export type Issue221External = ({ A: { a: string, } }) & { B?: never } | ({ B: { b: string, } }) & { A?: never }; InternallyTaggedD: export type InternallyTaggedD = { type: "A", } & { [key in string]: string }; InternallyTaggedE: export type InternallyTaggedE = { type: "A" }; InternallyTaggedF: export type InternallyTaggedF = { type: "A" }; InternallyTaggedH: export type InternallyTaggedH = { type: "A" }; InternallyTaggedL: export type InternallyTaggedL = { type: "A", } & { type: "A" } | { type: "B" }; InternallyTaggedM: export type InternallyTaggedM = { type: "A" }; StructWithAlias: export type StructWithAlias = { field: string, }; StructWithMultipleAliases: export type StructWithMultipleAliases = { field: string, }; StructWithAliasAndRename: export type StructWithAliasAndRename = { renamed_field: string, }; EnumWithVariantAlias: export type EnumWithVariantAlias = "Variant" | "Other"; EnumWithMultipleVariantAliases: export type EnumWithMultipleVariantAliases = "Variant" | "Other"; EnumWithVariantAliasAndRename: export type EnumWithVariantAliasAndRename = "renamed_variant" | "Other"; InternallyTaggedWithAlias: export type InternallyTaggedWithAlias = { type: "A"; field: string } | { type: "B"; other: number }; AdjacentlyTaggedWithAlias: export type AdjacentlyTaggedWithAlias = { type: "A"; data: { field: string, } } | { type: "B"; data: { other: number, } }; UntaggedWithAlias: export type UntaggedWithAlias = ({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }; Issue221UntaggedSafe: export type Issue221UntaggedSafe = ({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }; Issue221UntaggedMixed: export type Issue221UntaggedMixed = ({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never }; EmptyEnum: export type EmptyEnum = never; EmptyEnumTagged: export type EmptyEnumTagged = never; EmptyEnumTaggedWContent: export type EmptyEnumTaggedWContent = never; EmptyEnumUntagged: export type EmptyEnumUntagged = never; SkipOnlyField: export type SkipOnlyField = Record; SkipField: export type SkipField = { b: number, }; SkipVariant: export type SkipVariant = { A: string }; SkipUnnamedFieldInVariant: export type SkipUnnamedFieldInVariant = "A" | { B: [number] }; SkipNamedFieldInVariant: export type SkipNamedFieldInVariant = ({ A: Record }) & { B?: never } | ({ B: { b: number, } }) & { A?: never }; TransparentWithSkip: export type TransparentWithSkip = null; TransparentWithSkip2: export type TransparentWithSkip2 = string; TransparentWithSkip3: export type TransparentWithSkip3 = string; SkipVariant2: export type SkipVariant2 = { tag: "A"; data: string }; SkipVariant3: export type SkipVariant3 = { A: { a: string, } }; SkipStructFields: export type SkipStructFields = { a: number, }; SpectaSkipNonTypeField: export type SpectaSkipNonTypeField = { a: number, }; FlattenA: export type FlattenA = { a: number, b: number, }; FlattenB: export type FlattenB = { c: number, } & FlattenA; FlattenC: export type FlattenC = { c: number, } & FlattenA; FlattenD: export type FlattenD = { a: FlattenA, c: number, }; FlattenE: export type FlattenE = { b: ({ c: number, }) & (FlattenA), d: number, }; FlattenF: export type FlattenF = { b: ({ c: number, }) & (FlattenA), d: number, }; FlattenG: export type FlattenG = { b: FlattenB, d: number, }; TupleNested: export type TupleNested = [number[], [number[], number[]], [number[], number[], number[]]]; Generic1<()>: export type Generic1 = { value: T, values: T[], }; GenericAutoBound<()>: export type GenericAutoBound = { value: T, values: T[], }; GenericAutoBound2<()>: export type GenericAutoBound2 = { value: T, values: T[], }; Container1: export type Container1 = { foo: Generic1, bar: Generic1[], baz: { [key in string]: Generic1 }, }; Generic2<(), String, i32>: export type Generic2 = ({ A: A }) & { B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ B: [B, B, B] }) & { A?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ C: C[] }) & { A?: never; B?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ D: A[][][] }) & { A?: never; B?: never; C?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ E: { a: A, b: B, c: C, } }) & { A?: never; B?: never; C?: never; D?: never; X?: never; Y?: never; Z?: never } | ({ X: number[] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; Y?: never; Z?: never } | ({ Y: number }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Z?: never } | ({ Z: number[][] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never }; GenericNewType1<()>: export type GenericNewType1 = T[][]; GenericTuple<()>: export type GenericTuple = [T, T[], T[][]]; GenericStruct2<()>: export type GenericStruct2 = { a: T, b: [T, T], c: [T, [T, T]], d: [T, T, T], e: [([T, T]), ([T, T]), ([T, T])], f: T[], g: T[][], h: ([([T, T]), ([T, T]), ([T, T])])[], }; InlineGenericNewtype: InlineGenericNested: InlineFlattenGenericsG<()>: export type InlineFlattenGenericsG = { t: T, }; InlineFlattenGenerics: export type InlineFlattenGenerics = { g: InlineFlattenGenericsG, gi: { t: string, }, } & InlineFlattenGenericsG; GenericDefault: export type GenericDefault = { value: T, }; ChainedGenericDefault: export type ChainedGenericDefault = { first: T, second: U, }; ChainedGenericDefault: export type ChainedGenericDefault = { first: T, second: U, }; ChainedGenericDefault: export type ChainedGenericDefault = { first: T, second: U, }; ChainedGenericDefault: export type ChainedGenericDefault = { first: T, second: U, }; GenericDefaultSkipped: export type GenericDefaultSkipped = { value: T, }; GenericDefaultSkippedNonType: export type GenericDefaultSkippedNonType = { value: number, }; GenericParameterOrderPreserved: export type GenericParameterOrderPreserved = { pair: Pair, }; ConstGenericInNonConstContainer: export type ConstGenericInNonConstContainer = { data: [number], a: [number, number], d: [number, number], }; ConstGenericInConstContainer: export type ConstGenericInConstContainer = { data: number[], a: number[], d: [number, number], }; NamedConstGenericContainer: export type NamedConstGenericContainer = { a: NamedConstGeneric, b: NamedConstGeneric, d: [number, number], }; InlineConstGenericContainer: export type InlineConstGenericContainer = { b: { data: [number, number], a: [number, number], d: [number, number, number], }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], }, d: [number, number], }; InlineRecursiveConstGenericContainer: export type InlineRecursiveConstGenericContainer = { b: { data: [number, number], a: [number, number], d: [number, number, number], e: InlineRecursiveConstGeneric, }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], e: InlineRecursiveConstGeneric, }, d: [number, number], }; TestCollectionRegister: export type TestCollectionRegister = never; TestCollectionRegister: export type TestCollectionRegister = never; ================================================ FILE: tests/tests/snapshots/test__typescript__export-serde_phases.snap ================================================ --- source: tests/tests/typescript.rs expression: output --- Issue374: /** https://github.com/specta-rs/specta/issues/374 */ export type Issue374 = Issue374_Serialize | Issue374_Deserialize; Optional: export type Optional = Optional_Serialize | Optional_Deserialize; StructPhaseSpecificRename: export type StructPhaseSpecificRename = StructPhaseSpecificRenameSerialize | StructPhaseSpecificRenameDeserialize; Range: export type Range = { start: T, end: T, }; RangeInclusive: export type RangeInclusive = { start: T, end: T, }; String: PathBuf: IpAddr: Ipv4Addr: Ipv6Addr: SocketAddr: SocketAddrV4: SocketAddrV6: Cow<'static, str>: Cow<'static, i32>: Vec: Vec: Result: export type Result = { ok: T, err: E, }; Vec>>: PhantomData<()>: PhantomData: Infallible: Unit1: export type Unit1 = null; Unit2: export type Unit2 = Record; Unit3: export type Unit3 = []; Unit4: export type Unit4 = null; Unit5: export type Unit5 = "A"; Unit6: export type Unit6 = { A: null }; Unit7: export type Unit7 = { A: Record }; SimpleStruct: export type SimpleStruct = { a: number, b: string, c: [number, string, number], d: string[], e: string | null, }; TupleStruct1: export type TupleStruct1 = number; TupleStruct3: export type TupleStruct3 = [number, boolean, string]; TestEnum: export type TestEnum = "Unit" | ({ Single: number }) & { Multiple?: never; Struct?: never } | ({ Multiple: [number, number] }) & { Single?: never; Struct?: never } | ({ Struct: { a: number, } }) & { Multiple?: never; Single?: never }; RefStruct: export type RefStruct = TestEnum; InlinerStruct: export type InlinerStruct = { inline_this: { ref_struct: SimpleStruct, val: number, }, dont_inline_this: RefStruct, }; GenericStruct: export type GenericStruct = { arg: T, }; GenericStruct: export type GenericStruct = { arg: T, }; FlattenEnumStruct: export type FlattenEnumStruct = { outer: string, } & FlattenEnum; OverridenStruct: export type OverridenStruct = { overriden_field: string, }; HasGenericAlias: export type HasGenericAlias = { [key in number]: string }; EnumMacroAttributes: export type EnumMacroAttributes = ({ A: string }) & { D?: never; bbb?: never; cccc?: never } | ({ bbb: number }) & { A?: never; D?: never; cccc?: never } | ({ cccc: number }) & { A?: never; D?: never; bbb?: never } | ({ D: { a: string, bbbbbb: number, } }) & { A?: never; bbb?: never; cccc?: never }; InlineEnumField: export type InlineEnumField = { A: { a: string, } }; InlineOptionalType: export type InlineOptionalType = { optional_field: { a: string, } | null, }; Rename: export type Rename = "OneWord" | "Two words"; TransparentType: export type TransparentType = TransparentTypeInner; TransparentType2: export type TransparentType2 = null; TransparentTypeWithOverride: export type TransparentTypeWithOverride = string; HashMap: HashMap: Vec: EnumReferenceRecordKey: export type EnumReferenceRecordKey = { a: Partial<{ [key in BasicEnum]: number }>, }; FlattenOnNestedEnum: export type FlattenOnNestedEnum = { id: string, } & NestedEnum; MyEmptyInput: export type MyEmptyInput = Record; (String): ExtraBracketsInTupleVariant: export type ExtraBracketsInTupleVariant = { A: string }; ExtraBracketsInUnnamedStruct: export type ExtraBracketsInUnnamedStruct = string; Vec: InlineTuple: export type InlineTuple = { demo: [string, boolean], }; InlineTuple2: export type InlineTuple2 = { demo: [{ demo: [string, boolean], }, boolean], }; Box: Box: SkippedFieldWithinVariant: export type SkippedFieldWithinVariant = { type: "A" } | { type: "B"; data: string }; KebabCase: export type KebabCase = { "test-ing": string, }; Issue281<'_>: export type Issue281 = { default_unity_arguments: string[], }; LifetimeGenericStruct<'_, i32>: export type LifetimeGenericStruct = { borrowed: T[], owned: T[], }; LifetimeGenericEnum<'_, i32>: export type LifetimeGenericEnum = ({ Borrowed: T }) & { Owned?: never } | ({ Owned: T }) & { Borrowed?: never }; RenameWithWeirdCharsField: export type RenameWithWeirdCharsField = { "@odata.context": string, }; RenameWithWeirdCharsVariant: export type RenameWithWeirdCharsVariant = { "@odata.context": string }; RenamedFieldKeys: export type RenamedFieldKeys = { "": string, "a\"b": string, "a\\b": string, "line\nbreak": string, "line\u2028break": string, "line\u2029break": string, }; RenamedVariantWithSkippedPayload: export type RenamedVariantWithSkippedPayload = "a-b"; type_type::Type: export type Type = never; ActualType: export type ActualType = { a: GenericType, }; SpectaTypeOverride: export type SpectaTypeOverride = { string_ident: string, u32_ident: number, path: string, tuple: [string, number], }; ContainerTypeOverrideStruct: export type ContainerTypeOverrideStruct = string; ContainerTypeOverrideEnum: export type ContainerTypeOverrideEnum = string; ContainerTypeOverrideGeneric>: export type ContainerTypeOverrideGeneric = string; ContainerTypeOverrideToGeneric: export type ContainerTypeOverrideToGeneric = T; ContainerTypeOverrideTuple: export type ContainerTypeOverrideTuple = [string, number]; ContainerTypeOverrideTupleGeneric: export type ContainerTypeOverrideTupleGeneric = [T, string]; InvalidToValidType: export type InvalidToValidType = { cause: null, }; TupleStruct: export type TupleStruct = string; TupleStructWithRep: export type TupleStructWithRep = string; GenericTupleStruct: export type GenericTupleStruct = T; BracedStruct: export type BracedStruct = string; Struct: export type StructNew = { t: "StructNew", a: string, }; Struct2: export type Struct2 = { b: string, }; Enum: export type Enum = { t: "A" } | { t: "B" }; Enum2: export type Enum2 = { t: "C" } | { t: "B" } | { t: "D"; enumField: null }; Enum3: export type Enum3 = { t: "A"; b: string }; StructRenameAllUppercase: export type StructRenameAllUppercase = { A: number, B: number, }; RenameSerdeSpecialChar: export type RenameSerdeSpecialChar = { "a/b": number, }; EnumRenameAllUppercase: export type EnumRenameAllUppercase = "HELLOWORLD" | "VARIANTB" | "TESTINGWORDS"; Recursive: export type Recursive = { demo: Recursive, }; RecursiveMapValue: export type RecursiveMapValue = { demo: { [key in string]: RecursiveMapValue }, }; RecursiveTransparent: export type RecursiveTransparent = RecursiveInline; RecursiveInEnum: export type RecursiveInEnum = { A: { demo: RecursiveInEnum, } }; NonOptional: export type NonOptional = string | null; OptionalOnNamedField: export type OptionalOnNamedField = string | null; OptionalOnTransparentNamedField: export type OptionalOnTransparentNamedField = { b: string | null, }; OptionalInEnum: export type OptionalInEnum = ({ A?: string | null }) & { B?: never; C?: never } | ({ B: { a: string | null, } }) & { A?: never; C?: never } | ({ C: { a?: string | null, } }) & { A?: never; B?: never }; UntaggedVariants: export type UntaggedVariants = string | number | { id: string } | [string, boolean]; UntaggedVariantsWithoutValue: export type UntaggedVariantsWithoutValue = string | [number, string] | number; UntaggedVariantsWithDuplicateBranches: export type UntaggedVariantsWithDuplicateBranches = null | number; HashMap: Regular: export type Regular = { [key in string]: null }; HashMap: HashMap: HashMap: HashMap: ValidMaybeValidKey: export type ValidMaybeValidKey = { [key in MaybeValidKey]: null }; ValidMaybeValidKeyNested: export type ValidMaybeValidKeyNested = { [key in MaybeValidKey>]: null }; MacroStruct: export type MacroStruct = string; MacroStruct2: export type MacroStruct2 = { demo: string, }; MacroEnum: export type MacroEnum = ({ Demo: string }) & { Demo2?: never } | ({ Demo2: { demo2: string, } }) & { Demo?: never }; DeprecatedType: /** * @deprecated */ export type DeprecatedType = { a: number, }; DeprecatedTypeWithMsg: /** * @deprecated Look at you big man using a deprecation message */ export type DeprecatedTypeWithMsg = { a: number, }; DeprecatedTypeWithMsg2: /** * @deprecated Look at you big man using a deprecation message */ export type DeprecatedTypeWithMsg2 = { a: number, }; DeprecatedFields: export type DeprecatedFields = { a: number, /** * @deprecated */ b: string, /** * @deprecated This field is cringe! */ c: string, /** * @deprecated This field is cringe! */ d: string, }; DeprecatedTupleVariant: export type DeprecatedTupleVariant = [ /** * @deprecated */ string, /** * @deprecated Nope */ string, /** * @deprecated Nope */ number]; DeprecatedEnumVariants: export type DeprecatedEnumVariants = /** * @deprecated */ "A" | /** * @deprecated Nope */ "B" | /** * @deprecated Nope */ "C"; CommentedStruct: /** * Some triple-slash comment * Some more triple-slash comment */ export type CommentedStruct = { /** * Some triple-slash comment * Some more triple-slash comment */ a: number, }; CommentedEnum: /** * Some triple-slash comment * Some more triple-slash comment */ export type CommentedEnum = /** * Some triple-slash comment * Some more triple-slash comment */ ({ A: number }) & { B?: never } | /** * Some triple-slash comment * Some more triple-slash comment */ ({ B: { /** * Some triple-slash comment * Some more triple-slash comment */ a: number, } }) & { A?: never }; SingleLineComment: /** Some single-line comment */ export type SingleLineComment = /** Some single-line comment */ ({ A: number }) & { B?: never } | /** Some single-line comment */ ({ B: { /** Some single-line comment */ a: number, } }) & { A?: never }; NonGeneric: export type Demo = { a: A, b: B, }; HalfGenericA: export type Demo = { a: A, b: B, }; HalfGenericB: export type Demo = { a: A, b: B, }; FullGeneric: export type Demo = { a: A, b: B, }; Another: export type Demo = { a: A, b: B, }; MapA: MapB: MapC: AGenericStruct: export type AGenericStruct = { field: Demo, }; A: export type A = { a: B, b: { b: number, }, c: B, d: { flattened: number, }, e: { generic_flattened: number, }, }; DoubleFlattened: export type DoubleFlattened = { a: ToBeFlattened, b: ToBeFlattened, }; FlattenedInner: export type FlattenedInner = Inner; BoxFlattened: export type BoxFlattened = BoxedInner; BoxInline: export type BoxInline = { c: { a: number, }, }; First: export type First = { a: string, }; Second: export type Second = { a: number, }; Third: export type Third = { b: { [key in string]: string }, c: First, } & First; Fourth: export type Fourth = { a: First, b: { a: string, }, }; TagOnStructWithInline: export type TagOnStructWithInline = { type: "TagOnStructWithInline", a: First, b: { a: string, }, }; Sixth: export type Sixth = { a: First, b: First, }; Seventh: export type Seventh = { a: First, b: Second, }; Eight: export type Eight = { A: string } | "B"; Ninth: export type Ninth = { t: "A"; c: string } | { t: "B" } | { t: "C"; c: { a: string, } } | { t: "D"; c: First }; Tenth: export type Tenth = string | "B" | { a: string, } | First; MyEnumTagged: export type MyEnumTagged = { type: "Variant"; inner: First }; MyEnumExternal: export type MyEnumExternal = { Variant: { inner: First, } }; MyEnumAdjacent: export type MyEnumAdjacent = { t: "Variant"; c: { inner: First, } }; MyEnumUntagged: export type MyEnumUntagged = { inner: First }; EmptyStruct: export type EmptyStruct = Record; EmptyStructWithTag: export type EmptyStructWithTag = { a: "EmptyStructWithTag", }; AdjacentlyTagged: export type AdjacentlyTagged = { t: "A" } | { t: "B"; c: { id: string, method: string, } } | { t: "C"; c: string }; LoadProjectEvent: export type LoadProjectEvent = { event: "started"; data: { projectName: string, } } | { event: "progressTest"; data: { projectName: string, status: string, progress: number, } } | { event: "finished"; data: { projectName: string, } }; ExternallyTagged: export type ExternallyTagged = "A" | ({ B: { id: string, method: string, } }) & { C?: never } | ({ C: string }) & { B?: never }; Issue221External: export type Issue221External = ({ A: { a: string, } }) & { B?: never } | ({ B: { b: string, } }) & { A?: never }; InternallyTaggedD: export type InternallyTaggedD = { type: "A", } & { [key in string]: string }; InternallyTaggedE: export type InternallyTaggedE = { type: "A" }; InternallyTaggedF: export type InternallyTaggedF = { type: "A" }; InternallyTaggedH: export type InternallyTaggedH = { type: "A" }; InternallyTaggedL: export type InternallyTaggedL = { type: "A", } & { type: "A" } | { type: "B" }; InternallyTaggedM: export type InternallyTaggedM = { type: "A" }; StructWithAlias: export type StructWithAlias = { field: string, }; StructWithMultipleAliases: export type StructWithMultipleAliases = { field: string, }; StructWithAliasAndRename: export type StructWithAliasAndRename = { renamed_field: string, }; EnumWithVariantAlias: export type EnumWithVariantAlias = "Variant" | "Other"; EnumWithMultipleVariantAliases: export type EnumWithMultipleVariantAliases = "Variant" | "Other"; EnumWithVariantAliasAndRename: export type EnumWithVariantAliasAndRename = "renamed_variant" | "Other"; InternallyTaggedWithAlias: export type InternallyTaggedWithAlias = { type: "A"; field: string } | { type: "B"; other: number }; AdjacentlyTaggedWithAlias: export type AdjacentlyTaggedWithAlias = { type: "A"; data: { field: string, } } | { type: "B"; data: { other: number, } }; UntaggedWithAlias: export type UntaggedWithAlias = ({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }; Issue221UntaggedSafe: export type Issue221UntaggedSafe = ({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }; Issue221UntaggedMixed: export type Issue221UntaggedMixed = ({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never }; EmptyEnum: export type EmptyEnum = never; EmptyEnumTagged: export type EmptyEnumTagged = never; EmptyEnumTaggedWContent: export type EmptyEnumTaggedWContent = never; EmptyEnumUntagged: export type EmptyEnumUntagged = never; SkipOnlyField: export type SkipOnlyField = Record; SkipField: export type SkipField = { b: number, }; SkipVariant: export type SkipVariant = { A: string }; SkipUnnamedFieldInVariant: export type SkipUnnamedFieldInVariant = "A" | { B: [number] }; SkipNamedFieldInVariant: export type SkipNamedFieldInVariant = ({ A: Record }) & { B?: never } | ({ B: { b: number, } }) & { A?: never }; TransparentWithSkip: export type TransparentWithSkip = null; TransparentWithSkip2: export type TransparentWithSkip2 = string; TransparentWithSkip3: export type TransparentWithSkip3 = string; SkipVariant2: export type SkipVariant2 = { tag: "A"; data: string }; SkipVariant3: export type SkipVariant3 = { A: { a: string, } }; SkipStructFields: export type SkipStructFields = { a: number, }; SpectaSkipNonTypeField: export type SpectaSkipNonTypeField = { a: number, }; FlattenA: export type FlattenA = { a: number, b: number, }; FlattenB: export type FlattenB = { c: number, } & FlattenA; FlattenC: export type FlattenC = { c: number, } & FlattenA; FlattenD: export type FlattenD = { a: FlattenA, c: number, }; FlattenE: export type FlattenE = { b: ({ c: number, }) & (FlattenA), d: number, }; FlattenF: export type FlattenF = { b: ({ c: number, }) & (FlattenA), d: number, }; FlattenG: export type FlattenG = { b: FlattenB, d: number, }; TupleNested: export type TupleNested = [number[], [number[], number[]], [number[], number[], number[]]]; Generic1<()>: export type Generic1 = { value: T, values: T[], }; GenericAutoBound<()>: export type GenericAutoBound = { value: T, values: T[], }; GenericAutoBound2<()>: export type GenericAutoBound2 = { value: T, values: T[], }; Container1: export type Container1 = { foo: Generic1, bar: Generic1[], baz: { [key in string]: Generic1 }, }; Generic2<(), String, i32>: export type Generic2 = ({ A: A }) & { B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ B: [B, B, B] }) & { A?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ C: C[] }) & { A?: never; B?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ D: A[][][] }) & { A?: never; B?: never; C?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ E: { a: A, b: B, c: C, } }) & { A?: never; B?: never; C?: never; D?: never; X?: never; Y?: never; Z?: never } | ({ X: number[] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; Y?: never; Z?: never } | ({ Y: number }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Z?: never } | ({ Z: number[][] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never }; GenericNewType1<()>: export type GenericNewType1 = T[][]; GenericTuple<()>: export type GenericTuple = [T, T[], T[][]]; GenericStruct2<()>: export type GenericStruct2 = { a: T, b: [T, T], c: [T, [T, T]], d: [T, T, T], e: [([T, T]), ([T, T]), ([T, T])], f: T[], g: T[][], h: ([([T, T]), ([T, T]), ([T, T])])[], }; InlineGenericNewtype: InlineGenericNested: InlineFlattenGenericsG<()>: export type InlineFlattenGenericsG = { t: T, }; InlineFlattenGenerics: export type InlineFlattenGenerics = { g: InlineFlattenGenericsG, gi: { t: string, }, } & InlineFlattenGenericsG; GenericDefault: export type GenericDefault = { value: T, }; ChainedGenericDefault: export type ChainedGenericDefault = { first: T, second: U, }; ChainedGenericDefault: export type ChainedGenericDefault = { first: T, second: U, }; ChainedGenericDefault: export type ChainedGenericDefault = { first: T, second: U, }; ChainedGenericDefault: export type ChainedGenericDefault = { first: T, second: U, }; GenericDefaultSkipped: export type GenericDefaultSkipped = { value: T, }; GenericDefaultSkippedNonType: export type GenericDefaultSkippedNonType = { value: number, }; GenericParameterOrderPreserved: export type GenericParameterOrderPreserved = { pair: Pair, }; ConstGenericInNonConstContainer: export type ConstGenericInNonConstContainer = { data: [number], a: [number, number], d: [number, number], }; ConstGenericInConstContainer: export type ConstGenericInConstContainer = { data: number[], a: number[], d: [number, number], }; NamedConstGenericContainer: export type NamedConstGenericContainer = { a: NamedConstGeneric, b: NamedConstGeneric, d: [number, number], }; InlineConstGenericContainer: export type InlineConstGenericContainer = { b: { data: [number, number], a: [number, number], d: [number, number, number], }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], }, d: [number, number], }; InlineRecursiveConstGenericContainer: export type InlineRecursiveConstGenericContainer = { b: { data: [number, number], a: [number, number], d: [number, number, number], e: InlineRecursiveConstGeneric, }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], e: InlineRecursiveConstGeneric, }, d: [number, number], }; TestCollectionRegister: export type TestCollectionRegister = never; TestCollectionRegister: export type TestCollectionRegister = never; ================================================ FILE: tests/tests/snapshots/test__typescript__inline-raw.snap ================================================ --- source: tests/tests/typescript.rs expression: output --- i8: number i16: number i32: number u8: number u16: number u32: number f32: number f64: number bool: boolean char: string Range: { start: T, end: T, } RangeInclusive: { start: T, end: T, } (): null (String, i32): [string, number] (String, i32, bool): [string, number, boolean] ((String, i32), (bool, char, bool), ()): [[string, number], [boolean, string, boolean], null] (bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool): [boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean] (Vec, Vec): [number[], boolean[]] String: string PathBuf: string IpAddr: string Ipv4Addr: string Ipv6Addr: string SocketAddr: string SocketAddrV4: string SocketAddrV6: string Cow<'static, str>: string Cow<'static, i32>: number &'static str: string &'static bool: boolean &'static i32: number Vec: number[] &'static [i32]: number[] &'static [i32; 3]: [number, number, number] [i32; 3]: [number, number, number] Vec: MyEnum[] &'static [MyEnum]: MyEnum[] &'static [MyEnum; 6]: [MyEnum, MyEnum, MyEnum, MyEnum, MyEnum, MyEnum] [MyEnum; 2]: [MyEnum, MyEnum] &'static [i32; 1]: [number] &'static [i32; 0]: [] Option: number | null Option<()>: null Option>: number[] | null Result: { ok: T, err: E, } Vec>>: (number | null)[] Option>>: number[] | null [Vec; 3]: [string[], string[], string[]] Option>: string | null Option>>: string | null PhantomData<()>: null PhantomData: null Infallible: never Unit1: null Unit2: Record Unit3: [] Unit4: null Unit5: "A" Unit6: [] Unit7: Record SimpleStruct: { a: number, b: string, c: [number, string, number], d: string[], e: string | null, } TupleStruct1: number TupleStruct3: [number, boolean, string] TestEnum: "Unit" | number | [number, number] | { a: number } RefStruct: TestEnum InlinerStruct: { inline_this: { ref_struct: SimpleStruct, val: number, }, dont_inline_this: RefStruct, } GenericStruct: { arg: T, } GenericStruct: { arg: T, } FlattenEnumStruct: { outer: string, inner: FlattenEnum, } OverridenStruct: { overriden_field: string, } HasGenericAlias: { [key in number]: string } EnumMacroAttributes: string | number | { a: string; b: number } InlineEnumField: { a: string, } InlineOptionalType: { optional_field: { a: string, } | null, } Rename: "OneWord" | "TwoWords" TransparentType: TransparentTypeInner TransparentType2: null TransparentTypeWithOverride: string [Option; 3]: [(number | null), (number | null), (number | null)] HashMap: Partial<{ [key in BasicEnum]: null }> HashMap: Partial<{ [key in BasicEnum]: number }> Option>>>: number | null Vec: PlaceholderInnerField[] EnumReferenceRecordKey: { a: Partial<{ [key in BasicEnum]: number }>, } FlattenOnNestedEnum: { id: string, result: NestedEnum, } MyEmptyInput: Record (String): string (String,): [string] ExtraBracketsInTupleVariant: string ExtraBracketsInUnnamedStruct: string Vec: MyEnum[] InlineTuple: { demo: [string, boolean], } InlineTuple2: { demo: [{ demo: [string, boolean], }, boolean], } Box: string Box: string SkippedFieldWithinVariant: never | string KebabCase: { test_ing: string, } &[&str]: string[] Issue281<'_>: { default_unity_arguments: string[], } LifetimeGenericStruct<'_, i32>: { borrowed: T[], owned: T[], } LifetimeGenericEnum<'_, i32>: T RenameWithWeirdCharsField: { odata_context: string, } RenameWithWeirdCharsVariant: string RenamedFieldKeys: { empty: string, quote: string, backslash: string, newline: string, line_separator: string, paragraph_separator: string, } RenamedVariantWithSkippedPayload: never type_type::Type: never ActualType: { a: GenericType, } SpectaTypeOverride: { string_ident: string, u32_ident: number, path: string, tuple: [string, number], } ContainerTypeOverrideStruct: string ContainerTypeOverrideEnum: string ContainerTypeOverrideGeneric>: string ContainerTypeOverrideToGeneric: T ContainerTypeOverrideTuple: [string, number] ContainerTypeOverrideTupleGeneric: [T, string] InvalidToValidType: { cause: null, } TupleStruct: string TupleStructWithRep: string GenericTupleStruct: T BracedStruct: string Struct: { a: string, } Struct2: { a: string, } Enum: "A" | "B" Enum2: "A" | "B" | { enum_field: null } Enum3: { a: string } StructRenameAllUppercase: { a: number, b: number, } RenameSerdeSpecialChar: { b: number, } EnumRenameAllUppercase: "HelloWorld" | "VariantB" | "TestingWords" Recursive: { demo: Recursive, } RecursiveMapValue: { demo: { [key in string]: RecursiveMapValue }, } RecursiveTransparent: RecursiveInline RecursiveInEnum: { demo: RecursiveInEnum } NonOptional: string | null OptionalOnNamedField: string | null OptionalOnTransparentNamedField: { b: string | null, } OptionalInEnum: string | null | { a: string | null } | { a?: string | null } UntaggedVariants: string | number | { id: string } | [string, boolean] UntaggedVariantsWithoutValue: string | [number, string] | number UntaggedVariantsWithDuplicateBranches: null | number HashMap: { [key in string]: null } Regular: { [key in string]: null } HashMap: { [key in never]: null } HashMap: { [key in TransparentStruct]: null } HashMap: Partial<{ [key in UnitVariants]: null }> HashMap: Partial<{ [key in UntaggedVariantsKey]: null }> ValidMaybeValidKey: { [key in MaybeValidKey]: null } ValidMaybeValidKeyNested: { [key in MaybeValidKey>]: null } MacroStruct: string MacroStruct2: { demo: string, } MacroEnum: string | { demo2: string } DeprecatedType: { a: number, } DeprecatedTypeWithMsg: { a: number, } DeprecatedTypeWithMsg2: { a: number, } DeprecatedFields: { a: number, /** * @deprecated */ b: string, /** * @deprecated This field is cringe! */ c: string, /** * @deprecated This field is cringe! */ d: string, } DeprecatedTupleVariant: [ /** * @deprecated */ string, /** * @deprecated Nope */ string, /** * @deprecated Nope */ number] DeprecatedEnumVariants: /** * @deprecated */ "A" | /** * @deprecated Nope */ "B" | /** * @deprecated Nope */ "C" CommentedStruct: { /** * Some triple-slash comment * Some more triple-slash comment */ a: number, } CommentedEnum: /** * Some triple-slash comment * Some more triple-slash comment */ number | /** * Some triple-slash comment * Some more triple-slash comment */ { /** * Some triple-slash comment * Some more triple-slash comment */ a: number } SingleLineComment: /** Some single-line comment */ number | /** Some single-line comment */ { /** Some single-line comment */ a: number } NonGeneric: { a: A, b: B, } HalfGenericA: { a: A, b: B, } HalfGenericB: { a: A, b: B, } FullGeneric: { a: A, b: B, } Another: { a: A, b: B, } MapA: { [key in string]: number } MapB: { [key in number]: string } MapC: { [key in string]: AGenericStruct } AGenericStruct: { field: { a: A, b: B, }, } A: { a: B, b: { b: number, }, c: B, d: { flattened: number, }, e: { generic_flattened: number, }, } DoubleFlattened: { a: ToBeFlattened, b: ToBeFlattened, } FlattenedInner: { c: Inner, } BoxFlattened: { b: BoxedInner, } BoxInline: { c: { a: number, }, } First: { a: string, } Second: { a: number, } Third: { a: First, b: { [key in string]: string }, c: First, } Fourth: { a: First, b: { a: string, }, } TagOnStructWithInline: { a: First, b: { a: string, }, } Sixth: { a: First, b: First, } Seventh: { a: First, b: Second, } Eight: string | "B" Ninth: string | "B" | { a: string, } | First Tenth: string | "B" | { a: string, } | First MyEnumTagged: { inner: First } MyEnumExternal: { inner: First } MyEnumAdjacent: { inner: First } MyEnumUntagged: { inner: First } EmptyStruct: Record EmptyStructWithTag: Record AdjacentlyTagged: "A" | { id: string; method: string } | string LoadProjectEvent: ({ project_name: string }) & { progress?: never; status?: never } | { project_name: string; status: string; progress: number } ExternallyTagged: "A" | { id: string; method: string } | string Issue221External: ({ a: string }) & { b?: never } | ({ b: string }) & { a?: never } InternallyTaggedD: { [key in string]: string } InternallyTaggedE: null InternallyTaggedF: InternallyTaggedFInner InternallyTaggedH: InternallyTaggedHInner InternallyTaggedL: "A" | "B" InternallyTaggedM: "A" | "B" StructWithAlias: { field: string, } StructWithMultipleAliases: { field: string, } StructWithAliasAndRename: { field: string, } EnumWithVariantAlias: "Variant" | "Other" EnumWithMultipleVariantAliases: "Variant" | "Other" EnumWithVariantAliasAndRename: "Variant" | "Other" InternallyTaggedWithAlias: ({ field: string }) & { other?: never } | ({ other: number }) & { field?: never } AdjacentlyTaggedWithAlias: ({ field: string }) & { other?: never } | ({ other: number }) & { field?: never } UntaggedWithAlias: ({ field: string }) & { other?: never } | ({ other: number }) & { field?: never } Issue221UntaggedSafe: ({ a: string }) & { b?: never } | ({ b: string }) & { a?: never } Issue221UntaggedMixed: ({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never } EmptyEnum: never EmptyEnumTagged: never EmptyEnumTaggedWContent: never EmptyEnumUntagged: never SkipOnlyField: Record SkipField: { b: number, } SkipVariant: string SkipUnnamedFieldInVariant: never | [number] SkipNamedFieldInVariant: Record | { b: number } TransparentWithSkip: null TransparentWithSkip2: string TransparentWithSkip3: string SkipVariant2: string SkipVariant3: { a: string } SkipStructFields: { a: number, } SpectaSkipNonTypeField: { a: number, } FlattenA: { a: number, b: number, } FlattenB: { a: FlattenA, c: number, } FlattenC: { a: FlattenA, c: number, } FlattenD: { a: FlattenA, c: number, } FlattenE: { b: { a: FlattenA, c: number, }, d: number, } FlattenF: { b: { a: FlattenA, c: number, }, d: number, } FlattenG: { b: FlattenB, d: number, } TupleNested: [number[], [number[], number[]], [number[], number[], number[]]] Generic1<()>: { value: T, values: T[], } GenericAutoBound<()>: { value: T, values: T[], } GenericAutoBound2<()>: { value: T, values: T[], } Container1: { foo: Generic1, bar: Generic1[], baz: { [key in string]: Generic1 }, } Generic2<(), String, i32>: A | [B, B, B] | C[] | A[][][] | { a: A; b: B; c: C } | number[] | number | number[][] GenericNewType1<()>: T[][] GenericTuple<()>: [T, T[], T[][]] GenericStruct2<()>: { a: T, b: [T, T], c: [T, [T, T]], d: [T, T, T], e: [([T, T]), ([T, T]), ([T, T])], f: T[], g: T[][], h: ([([T, T]), ([T, T]), ([T, T])])[], } InlineGenericNewtype: string InlineGenericNested: [string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | string | { value: string }] InlineFlattenGenericsG<()>: { t: T, } InlineFlattenGenerics: { g: InlineFlattenGenericsG, gi: { t: string, }, t: InlineFlattenGenericsG, } GenericDefault: { value: T, } ChainedGenericDefault: { first: T, second: U, } ChainedGenericDefault: { first: T, second: U, } ChainedGenericDefault: { first: T, second: U, } ChainedGenericDefault: { first: T, second: U, } GenericDefaultSkipped: { value: T, } GenericDefaultSkippedNonType: { value: number, } GenericParameterOrderPreserved: { pair: Pair, } ConstGenericInNonConstContainer: { data: [number], a: [number, number], d: [number, number], } ConstGenericInConstContainer: { data: number[], a: number[], d: [number, number], } NamedConstGenericContainer: { a: NamedConstGeneric, b: NamedConstGeneric, d: [number, number], } InlineConstGenericContainer: { b: { data: [number, number], a: [number, number], d: [number, number, number], }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], }, d: [number, number], } InlineRecursiveConstGenericContainer: { b: { data: [number, number], a: [number, number], d: [number, number, number], e: InlineRecursiveConstGeneric, }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], e: InlineRecursiveConstGeneric, }, d: [number, number], } TestCollectionRegister: never TestCollectionRegister: never specta_typescript::Any: any specta_typescript::Any: any specta_typescript::Unknown: unknown specta_typescript::Unknown: unknown specta_typescript::Never: never specta_typescript::Never: never ================================================ FILE: tests/tests/snapshots/test__typescript__inline-serde.snap ================================================ --- source: tests/tests/typescript.rs expression: output --- i8: number i16: number i32: number u8: number u16: number u32: number f32: number f64: number bool: boolean char: string Range: { start: T, end: T, } RangeInclusive: { start: T, end: T, } (): null (String, i32): [string, number] (String, i32, bool): [string, number, boolean] ((String, i32), (bool, char, bool), ()): [[string, number], [boolean, string, boolean], null] (bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool): [boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean] (Vec, Vec): [number[], boolean[]] String: string PathBuf: string IpAddr: string Ipv4Addr: string Ipv6Addr: string SocketAddr: string SocketAddrV4: string SocketAddrV6: string Cow<'static, str>: string Cow<'static, i32>: number &'static str: string &'static bool: boolean &'static i32: number Vec: number[] &'static [i32]: number[] &'static [i32; 3]: [number, number, number] [i32; 3]: [number, number, number] Vec: MyEnum[] &'static [MyEnum]: MyEnum[] &'static [MyEnum; 6]: [MyEnum, MyEnum, MyEnum, MyEnum, MyEnum, MyEnum] [MyEnum; 2]: [MyEnum, MyEnum] &'static [i32; 1]: [number] &'static [i32; 0]: [] Option: number | null Option<()>: null Option>: number[] | null Result: { ok: T, err: E, } Vec>>: (number | null)[] Option>>: number[] | null [Vec; 3]: [string[], string[], string[]] Option>: string | null Option>>: string | null PhantomData<()>: null PhantomData: null Infallible: never Unit1: null Unit2: Record Unit3: [] Unit4: null Unit5: "A" Unit6: { A: null } Unit7: { A: Record } SimpleStruct: { a: number, b: string, c: [number, string, number], d: string[], e: string | null, } TupleStruct1: number TupleStruct3: [number, boolean, string] TestEnum: "Unit" | ({ Single: number }) & { Multiple?: never; Struct?: never } | ({ Multiple: [number, number] }) & { Single?: never; Struct?: never } | ({ Struct: { a: number, } }) & { Multiple?: never; Single?: never } RefStruct: TestEnum InlinerStruct: { inline_this: { ref_struct: SimpleStruct, val: number, }, dont_inline_this: RefStruct, } GenericStruct: { arg: T, } GenericStruct: { arg: T, } FlattenEnumStruct: ({ outer: string, }) & (FlattenEnum) OverridenStruct: { overriden_field: string, } HasGenericAlias: { [key in number]: string } EnumMacroAttributes: ({ A: string }) & { D?: never; bbb?: never; cccc?: never } | ({ bbb: number }) & { A?: never; D?: never; cccc?: never } | ({ cccc: number }) & { A?: never; D?: never; bbb?: never } | ({ D: { a: string, bbbbbb: number, } }) & { A?: never; bbb?: never; cccc?: never } InlineEnumField: { A: { a: string, } } InlineOptionalType: { optional_field: { a: string, } | null, } Rename: "OneWord" | "Two words" TransparentType: TransparentTypeInner TransparentType2: null TransparentTypeWithOverride: string [Option; 3]: [(number | null), (number | null), (number | null)] HashMap: Partial<{ [key in BasicEnum]: null }> HashMap: Partial<{ [key in BasicEnum]: number }> Option>>>: number | null Vec: PlaceholderInnerField[] EnumReferenceRecordKey: { a: Partial<{ [key in BasicEnum]: number }>, } FlattenOnNestedEnum: ({ id: string, }) & (NestedEnum) MyEmptyInput: Record (String): string (String,): [string] ExtraBracketsInTupleVariant: { A: string } ExtraBracketsInUnnamedStruct: string Vec: MyEnum[] InlineTuple: { demo: [string, boolean], } InlineTuple2: { demo: [{ demo: [string, boolean], }, boolean], } Box: string Box: string SkippedFieldWithinVariant: { type: "A" } | { type: "B"; data: string } KebabCase: { "test-ing": string, } &[&str]: string[] Issue281<'_>: { default_unity_arguments: string[], } LifetimeGenericStruct<'_, i32>: { borrowed: T[], owned: T[], } LifetimeGenericEnum<'_, i32>: ({ Borrowed: T }) & { Owned?: never } | ({ Owned: T }) & { Borrowed?: never } RenameWithWeirdCharsField: { "@odata.context": string, } RenameWithWeirdCharsVariant: { "@odata.context": string } RenamedFieldKeys: { "": string, "a\"b": string, "a\\b": string, "line\nbreak": string, "line\u2028break": string, "line\u2029break": string, } RenamedVariantWithSkippedPayload: "a-b" type_type::Type: never ActualType: { a: GenericType, } SpectaTypeOverride: { string_ident: string, u32_ident: number, path: string, tuple: [string, number], } ContainerTypeOverrideStruct: string ContainerTypeOverrideEnum: string ContainerTypeOverrideGeneric>: string ContainerTypeOverrideToGeneric: T ContainerTypeOverrideTuple: [string, number] ContainerTypeOverrideTupleGeneric: [T, string] InvalidToValidType: { cause: null, } TupleStruct: string TupleStructWithRep: string GenericTupleStruct: T BracedStruct: string Struct: { t: "StructNew", a: string, } Struct2: { b: string, } Enum: { t: "A" } | { t: "B" } Enum2: { t: "C" } | { t: "B" } | { t: "D"; enumField: null } Enum3: { t: "A"; b: string } StructRenameAllUppercase: { A: number, B: number, } RenameSerdeSpecialChar: { "a/b": number, } EnumRenameAllUppercase: "HELLOWORLD" | "VARIANTB" | "TESTINGWORDS" Recursive: { demo: Recursive, } RecursiveMapValue: { demo: { [key in string]: RecursiveMapValue }, } RecursiveTransparent: RecursiveInline RecursiveInEnum: { A: { demo: RecursiveInEnum, } } NonOptional: string | null OptionalOnNamedField: string | null OptionalOnTransparentNamedField: { b: string | null, } OptionalInEnum: ({ A?: string | null }) & { B?: never; C?: never } | ({ B: { a: string | null, } }) & { A?: never; C?: never } | ({ C: { a?: string | null, } }) & { A?: never; B?: never } UntaggedVariants: string | number | { id: string } | [string, boolean] UntaggedVariantsWithoutValue: string | [number, string] | number UntaggedVariantsWithDuplicateBranches: null | number HashMap: { [key in string]: null } Regular: { [key in string]: null } HashMap: { [key in never]: null } HashMap: { [key in TransparentStruct]: null } HashMap: Partial<{ [key in UnitVariants]: null }> HashMap: Partial<{ [key in UntaggedVariantsKey]: null }> ValidMaybeValidKey: { [key in MaybeValidKey]: null } ValidMaybeValidKeyNested: { [key in MaybeValidKey>]: null } MacroStruct: string MacroStruct2: { demo: string, } MacroEnum: ({ Demo: string }) & { Demo2?: never } | ({ Demo2: { demo2: string, } }) & { Demo?: never } DeprecatedType: { a: number, } DeprecatedTypeWithMsg: { a: number, } DeprecatedTypeWithMsg2: { a: number, } DeprecatedFields: { a: number, /** * @deprecated */ b: string, /** * @deprecated This field is cringe! */ c: string, /** * @deprecated This field is cringe! */ d: string, } DeprecatedTupleVariant: [ /** * @deprecated */ string, /** * @deprecated Nope */ string, /** * @deprecated Nope */ number] DeprecatedEnumVariants: /** * @deprecated */ "A" | /** * @deprecated Nope */ "B" | /** * @deprecated Nope */ "C" CommentedStruct: { /** * Some triple-slash comment * Some more triple-slash comment */ a: number, } CommentedEnum: /** * Some triple-slash comment * Some more triple-slash comment */ ({ A: number }) & { B?: never } | /** * Some triple-slash comment * Some more triple-slash comment */ ({ B: { /** * Some triple-slash comment * Some more triple-slash comment */ a: number, } }) & { A?: never } SingleLineComment: /** Some single-line comment */ ({ A: number }) & { B?: never } | /** Some single-line comment */ ({ B: { /** Some single-line comment */ a: number, } }) & { A?: never } NonGeneric: { a: A, b: B, } HalfGenericA: { a: A, b: B, } HalfGenericB: { a: A, b: B, } FullGeneric: { a: A, b: B, } Another: { a: A, b: B, } MapA: { [key in string]: number } MapB: { [key in number]: string } MapC: { [key in string]: AGenericStruct } AGenericStruct: { field: { a: A, b: B, }, } A: { a: B, b: { b: number, }, c: B, d: { flattened: number, }, e: { generic_flattened: number, }, } DoubleFlattened: { a: ToBeFlattened, b: ToBeFlattened, } FlattenedInner: (Inner) BoxFlattened: (BoxedInner) BoxInline: { c: { a: number, }, } First: { a: string, } Second: { a: number, } Third: ({ b: { [key in string]: string }, c: First, }) & (First) Fourth: { a: First, b: { a: string, }, } TagOnStructWithInline: { type: "TagOnStructWithInline", a: First, b: { a: string, }, } Sixth: { a: First, b: First, } Seventh: { a: First, b: Second, } Eight: { A: string } | "B" Ninth: { t: "A"; c: string } | { t: "B" } | { t: "C"; c: { a: string, } } | { t: "D"; c: First } Tenth: string | "B" | { a: string, } | First MyEnumTagged: { type: "Variant"; inner: First } MyEnumExternal: { Variant: { inner: First, } } MyEnumAdjacent: { t: "Variant"; c: { inner: First, } } MyEnumUntagged: { inner: First } EmptyStruct: Record EmptyStructWithTag: { a: "EmptyStructWithTag", } AdjacentlyTagged: { t: "A" } | { t: "B"; c: { id: string, method: string, } } | { t: "C"; c: string } LoadProjectEvent: { event: "started"; data: { projectName: string, } } | { event: "progressTest"; data: { projectName: string, status: string, progress: number, } } | { event: "finished"; data: { projectName: string, } } ExternallyTagged: "A" | ({ B: { id: string, method: string, } }) & { C?: never } | ({ C: string }) & { B?: never } Issue221External: ({ A: { a: string, } }) & { B?: never } | ({ B: { b: string, } }) & { A?: never } InternallyTaggedD: { type: "A", } & { [key in string]: string } InternallyTaggedE: { type: "A" } InternallyTaggedF: { type: "A" } InternallyTaggedH: { type: "A" } InternallyTaggedL: { type: "A", } & { type: "A" } | { type: "B" } InternallyTaggedM: { type: "A" } StructWithAlias: { field: string, } StructWithMultipleAliases: { field: string, } StructWithAliasAndRename: { renamed_field: string, } EnumWithVariantAlias: "Variant" | "Other" EnumWithMultipleVariantAliases: "Variant" | "Other" EnumWithVariantAliasAndRename: "renamed_variant" | "Other" InternallyTaggedWithAlias: { type: "A"; field: string } | { type: "B"; other: number } AdjacentlyTaggedWithAlias: { type: "A"; data: { field: string, } } | { type: "B"; data: { other: number, } } UntaggedWithAlias: ({ field: string }) & { other?: never } | ({ other: number }) & { field?: never } Issue221UntaggedSafe: ({ a: string }) & { b?: never } | ({ b: string }) & { a?: never } Issue221UntaggedMixed: ({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never } EmptyEnum: never EmptyEnumTagged: never EmptyEnumTaggedWContent: never EmptyEnumUntagged: never SkipOnlyField: Record SkipField: { b: number, } SkipVariant: { A: string } SkipUnnamedFieldInVariant: "A" | { B: [number] } SkipNamedFieldInVariant: ({ A: Record }) & { B?: never } | ({ B: { b: number, } }) & { A?: never } TransparentWithSkip: null TransparentWithSkip2: string TransparentWithSkip3: string SkipVariant2: { tag: "A"; data: string } SkipVariant3: { A: { a: string, } } SkipStructFields: { a: number, } SpectaSkipNonTypeField: { a: number, } FlattenA: { a: number, b: number, } FlattenB: ({ c: number, }) & (FlattenA) FlattenC: ({ c: number, }) & (FlattenA) FlattenD: { a: FlattenA, c: number, } FlattenE: { b: ({ c: number, }) & (FlattenA), d: number, } FlattenF: { b: ({ c: number, }) & (FlattenA), d: number, } FlattenG: { b: FlattenB, d: number, } TupleNested: [number[], [number[], number[]], [number[], number[], number[]]] Generic1<()>: { value: T, values: T[], } GenericAutoBound<()>: { value: T, values: T[], } GenericAutoBound2<()>: { value: T, values: T[], } Container1: { foo: Generic1, bar: Generic1[], baz: { [key in string]: Generic1 }, } Generic2<(), String, i32>: ({ A: A }) & { B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ B: [B, B, B] }) & { A?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ C: C[] }) & { A?: never; B?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ D: A[][][] }) & { A?: never; B?: never; C?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ E: { a: A, b: B, c: C, } }) & { A?: never; B?: never; C?: never; D?: never; X?: never; Y?: never; Z?: never } | ({ X: number[] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; Y?: never; Z?: never } | ({ Y: number }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Z?: never } | ({ Z: number[][] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never } GenericNewType1<()>: T[][] GenericTuple<()>: [T, T[], T[][]] GenericStruct2<()>: { a: T, b: [T, T], c: [T, [T, T]], d: [T, T, T], e: [([T, T]), ([T, T]), ([T, T])], f: T[], g: T[][], h: ([([T, T]), ([T, T]), ([T, T])])[], } InlineGenericNewtype: string InlineGenericNested: [string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | ({ Unnamed: string }) & { Named?: never } | ({ Named: { value: string, } }) & { Unnamed?: never }] InlineFlattenGenericsG<()>: { t: T, } InlineFlattenGenerics: ({ g: InlineFlattenGenericsG, gi: { t: string, }, }) & (InlineFlattenGenericsG) GenericDefault: { value: T, } ChainedGenericDefault: { first: T, second: U, } ChainedGenericDefault: { first: T, second: U, } ChainedGenericDefault: { first: T, second: U, } ChainedGenericDefault: { first: T, second: U, } GenericDefaultSkipped: { value: T, } GenericDefaultSkippedNonType: { value: number, } GenericParameterOrderPreserved: { pair: Pair, } ConstGenericInNonConstContainer: { data: [number], a: [number, number], d: [number, number], } ConstGenericInConstContainer: { data: number[], a: number[], d: [number, number], } NamedConstGenericContainer: { a: NamedConstGeneric, b: NamedConstGeneric, d: [number, number], } InlineConstGenericContainer: { b: { data: [number, number], a: [number, number], d: [number, number, number], }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], }, d: [number, number], } InlineRecursiveConstGenericContainer: { b: { data: [number, number], a: [number, number], d: [number, number, number], e: InlineRecursiveConstGeneric, }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], e: InlineRecursiveConstGeneric, }, d: [number, number], } TestCollectionRegister: never TestCollectionRegister: never specta_typescript::Any: any specta_typescript::Any: any specta_typescript::Unknown: unknown specta_typescript::Unknown: unknown specta_typescript::Never: never specta_typescript::Never: never ================================================ FILE: tests/tests/snapshots/test__typescript__inline-serde_phases.snap ================================================ --- source: tests/tests/typescript.rs expression: output --- Issue374: { foo?: boolean, bar?: boolean, } Optional: { a: number | null, b?: number | null, c?: string | null, d: boolean, } StructPhaseSpecificRename: { kind: "StructPhaseSpecificRenameSerialize", ser: string, } i8: number i16: number i32: number u8: number u16: number u32: number f32: number f64: number bool: boolean char: string Range: { start: T, end: T, } RangeInclusive: { start: T, end: T, } (): null (String, i32): [string, number] (String, i32, bool): [string, number, boolean] ((String, i32), (bool, char, bool), ()): [[string, number], [boolean, string, boolean], null] (bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool): [boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean] (Vec, Vec): [number[], boolean[]] String: string PathBuf: string IpAddr: string Ipv4Addr: string Ipv6Addr: string SocketAddr: string SocketAddrV4: string SocketAddrV6: string Cow<'static, str>: string Cow<'static, i32>: number &'static str: string &'static bool: boolean &'static i32: number Vec: number[] &'static [i32]: number[] &'static [i32; 3]: [number, number, number] [i32; 3]: [number, number, number] Vec: MyEnum[] &'static [MyEnum]: MyEnum[] &'static [MyEnum; 6]: [MyEnum, MyEnum, MyEnum, MyEnum, MyEnum, MyEnum] [MyEnum; 2]: [MyEnum, MyEnum] &'static [i32; 1]: [number] &'static [i32; 0]: [] Option: number | null Option<()>: null Option>: number[] | null Result: { ok: T, err: E, } Vec>>: (number | null)[] Option>>: number[] | null [Vec; 3]: [string[], string[], string[]] Option>: string | null Option>>: string | null PhantomData<()>: null PhantomData: null Infallible: never Unit1: null Unit2: Record Unit3: [] Unit4: null Unit5: "A" Unit6: { A: null } Unit7: { A: Record } SimpleStruct: { a: number, b: string, c: [number, string, number], d: string[], e: string | null, } TupleStruct1: number TupleStruct3: [number, boolean, string] TestEnum: "Unit" | ({ Single: number }) & { Multiple?: never; Struct?: never } | ({ Multiple: [number, number] }) & { Single?: never; Struct?: never } | ({ Struct: { a: number, } }) & { Multiple?: never; Single?: never } RefStruct: TestEnum InlinerStruct: { inline_this: { ref_struct: SimpleStruct, val: number, }, dont_inline_this: RefStruct, } GenericStruct: { arg: T, } GenericStruct: { arg: T, } FlattenEnumStruct: ({ outer: string, }) & (FlattenEnum) OverridenStruct: { overriden_field: string, } HasGenericAlias: { [key in number]: string } EnumMacroAttributes: ({ A: string }) & { D?: never; bbb?: never; cccc?: never } | ({ bbb: number }) & { A?: never; D?: never; cccc?: never } | ({ cccc: number }) & { A?: never; D?: never; bbb?: never } | ({ D: { a: string, bbbbbb: number, } }) & { A?: never; bbb?: never; cccc?: never } InlineEnumField: { A: { a: string, } } InlineOptionalType: { optional_field: { a: string, } | null, } Rename: "OneWord" | "Two words" TransparentType: TransparentTypeInner TransparentType2: null TransparentTypeWithOverride: string [Option; 3]: [(number | null), (number | null), (number | null)] HashMap: Partial<{ [key in BasicEnum]: null }> HashMap: Partial<{ [key in BasicEnum]: number }> Option>>>: number | null Vec: PlaceholderInnerField[] EnumReferenceRecordKey: { a: Partial<{ [key in BasicEnum]: number }>, } FlattenOnNestedEnum: ({ id: string, }) & (NestedEnum) MyEmptyInput: Record (String): string (String,): [string] ExtraBracketsInTupleVariant: { A: string } ExtraBracketsInUnnamedStruct: string Vec: MyEnum[] InlineTuple: { demo: [string, boolean], } InlineTuple2: { demo: [{ demo: [string, boolean], }, boolean], } Box: string Box: string SkippedFieldWithinVariant: { type: "A" } | { type: "B"; data: string } KebabCase: { "test-ing": string, } &[&str]: string[] Issue281<'_>: { default_unity_arguments: string[], } LifetimeGenericStruct<'_, i32>: { borrowed: T[], owned: T[], } LifetimeGenericEnum<'_, i32>: ({ Borrowed: T }) & { Owned?: never } | ({ Owned: T }) & { Borrowed?: never } RenameWithWeirdCharsField: { "@odata.context": string, } RenameWithWeirdCharsVariant: { "@odata.context": string } RenamedFieldKeys: { "": string, "a\"b": string, "a\\b": string, "line\nbreak": string, "line\u2028break": string, "line\u2029break": string, } RenamedVariantWithSkippedPayload: "a-b" type_type::Type: never ActualType: { a: GenericType, } SpectaTypeOverride: { string_ident: string, u32_ident: number, path: string, tuple: [string, number], } ContainerTypeOverrideStruct: string ContainerTypeOverrideEnum: string ContainerTypeOverrideGeneric>: string ContainerTypeOverrideToGeneric: T ContainerTypeOverrideTuple: [string, number] ContainerTypeOverrideTupleGeneric: [T, string] InvalidToValidType: { cause: null, } TupleStruct: string TupleStructWithRep: string GenericTupleStruct: T BracedStruct: string Struct: { t: "StructNew", a: string, } Struct2: { b: string, } Enum: { t: "A" } | { t: "B" } Enum2: { t: "C" } | { t: "B" } | { t: "D"; enumField: null } Enum3: { t: "A"; b: string } StructRenameAllUppercase: { A: number, B: number, } RenameSerdeSpecialChar: { "a/b": number, } EnumRenameAllUppercase: "HELLOWORLD" | "VARIANTB" | "TESTINGWORDS" Recursive: { demo: Recursive, } RecursiveMapValue: { demo: { [key in string]: RecursiveMapValue }, } RecursiveTransparent: RecursiveInline RecursiveInEnum: { A: { demo: RecursiveInEnum, } } NonOptional: string | null OptionalOnNamedField: string | null OptionalOnTransparentNamedField: { b: string | null, } OptionalInEnum: ({ A?: string | null }) & { B?: never; C?: never } | ({ B: { a: string | null, } }) & { A?: never; C?: never } | ({ C: { a?: string | null, } }) & { A?: never; B?: never } UntaggedVariants: string | number | { id: string } | [string, boolean] UntaggedVariantsWithoutValue: string | [number, string] | number UntaggedVariantsWithDuplicateBranches: null | number HashMap: { [key in string]: null } Regular: { [key in string]: null } HashMap: { [key in never]: null } HashMap: { [key in TransparentStruct]: null } HashMap: Partial<{ [key in UnitVariants]: null }> HashMap: Partial<{ [key in UntaggedVariantsKey]: null }> ValidMaybeValidKey: { [key in MaybeValidKey]: null } ValidMaybeValidKeyNested: { [key in MaybeValidKey>]: null } MacroStruct: string MacroStruct2: { demo: string, } MacroEnum: ({ Demo: string }) & { Demo2?: never } | ({ Demo2: { demo2: string, } }) & { Demo?: never } DeprecatedType: { a: number, } DeprecatedTypeWithMsg: { a: number, } DeprecatedTypeWithMsg2: { a: number, } DeprecatedFields: { a: number, /** * @deprecated */ b: string, /** * @deprecated This field is cringe! */ c: string, /** * @deprecated This field is cringe! */ d: string, } DeprecatedTupleVariant: [ /** * @deprecated */ string, /** * @deprecated Nope */ string, /** * @deprecated Nope */ number] DeprecatedEnumVariants: /** * @deprecated */ "A" | /** * @deprecated Nope */ "B" | /** * @deprecated Nope */ "C" CommentedStruct: { /** * Some triple-slash comment * Some more triple-slash comment */ a: number, } CommentedEnum: /** * Some triple-slash comment * Some more triple-slash comment */ ({ A: number }) & { B?: never } | /** * Some triple-slash comment * Some more triple-slash comment */ ({ B: { /** * Some triple-slash comment * Some more triple-slash comment */ a: number, } }) & { A?: never } SingleLineComment: /** Some single-line comment */ ({ A: number }) & { B?: never } | /** Some single-line comment */ ({ B: { /** Some single-line comment */ a: number, } }) & { A?: never } NonGeneric: { a: A, b: B, } HalfGenericA: { a: A, b: B, } HalfGenericB: { a: A, b: B, } FullGeneric: { a: A, b: B, } Another: { a: A, b: B, } MapA: { [key in string]: number } MapB: { [key in number]: string } MapC: { [key in string]: AGenericStruct } AGenericStruct: { field: { a: A, b: B, }, } A: { a: B, b: { b: number, }, c: B, d: { flattened: number, }, e: { generic_flattened: number, }, } DoubleFlattened: { a: ToBeFlattened, b: ToBeFlattened, } FlattenedInner: (Inner) BoxFlattened: (BoxedInner) BoxInline: { c: { a: number, }, } First: { a: string, } Second: { a: number, } Third: ({ b: { [key in string]: string }, c: First, }) & (First) Fourth: { a: First, b: { a: string, }, } TagOnStructWithInline: { type: "TagOnStructWithInline", a: First, b: { a: string, }, } Sixth: { a: First, b: First, } Seventh: { a: First, b: Second, } Eight: { A: string } | "B" Ninth: { t: "A"; c: string } | { t: "B" } | { t: "C"; c: { a: string, } } | { t: "D"; c: First } Tenth: string | "B" | { a: string, } | First MyEnumTagged: { type: "Variant"; inner: First } MyEnumExternal: { Variant: { inner: First, } } MyEnumAdjacent: { t: "Variant"; c: { inner: First, } } MyEnumUntagged: { inner: First } EmptyStruct: Record EmptyStructWithTag: { a: "EmptyStructWithTag", } AdjacentlyTagged: { t: "A" } | { t: "B"; c: { id: string, method: string, } } | { t: "C"; c: string } LoadProjectEvent: { event: "started"; data: { projectName: string, } } | { event: "progressTest"; data: { projectName: string, status: string, progress: number, } } | { event: "finished"; data: { projectName: string, } } ExternallyTagged: "A" | ({ B: { id: string, method: string, } }) & { C?: never } | ({ C: string }) & { B?: never } Issue221External: ({ A: { a: string, } }) & { B?: never } | ({ B: { b: string, } }) & { A?: never } InternallyTaggedD: { type: "A", } & { [key in string]: string } InternallyTaggedE: { type: "A" } InternallyTaggedF: { type: "A" } InternallyTaggedH: { type: "A" } InternallyTaggedL: { type: "A", } & { type: "A" } | { type: "B" } InternallyTaggedM: { type: "A" } StructWithAlias: { field: string, } StructWithMultipleAliases: { field: string, } StructWithAliasAndRename: { renamed_field: string, } EnumWithVariantAlias: "Variant" | "Other" EnumWithMultipleVariantAliases: "Variant" | "Other" EnumWithVariantAliasAndRename: "renamed_variant" | "Other" InternallyTaggedWithAlias: { type: "A"; field: string } | { type: "B"; other: number } AdjacentlyTaggedWithAlias: { type: "A"; data: { field: string, } } | { type: "B"; data: { other: number, } } UntaggedWithAlias: ({ field: string }) & { other?: never } | ({ other: number }) & { field?: never } Issue221UntaggedSafe: ({ a: string }) & { b?: never } | ({ b: string }) & { a?: never } Issue221UntaggedMixed: ({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never } EmptyEnum: never EmptyEnumTagged: never EmptyEnumTaggedWContent: never EmptyEnumUntagged: never SkipOnlyField: Record SkipField: { b: number, } SkipVariant: { A: string } SkipUnnamedFieldInVariant: "A" | { B: [number] } SkipNamedFieldInVariant: ({ A: Record }) & { B?: never } | ({ B: { b: number, } }) & { A?: never } TransparentWithSkip: null TransparentWithSkip2: string TransparentWithSkip3: string SkipVariant2: { tag: "A"; data: string } SkipVariant3: { A: { a: string, } } SkipStructFields: { a: number, } SpectaSkipNonTypeField: { a: number, } FlattenA: { a: number, b: number, } FlattenB: ({ c: number, }) & (FlattenA) FlattenC: ({ c: number, }) & (FlattenA) FlattenD: { a: FlattenA, c: number, } FlattenE: { b: ({ c: number, }) & (FlattenA), d: number, } FlattenF: { b: ({ c: number, }) & (FlattenA), d: number, } FlattenG: { b: FlattenB, d: number, } TupleNested: [number[], [number[], number[]], [number[], number[], number[]]] Generic1<()>: { value: T, values: T[], } GenericAutoBound<()>: { value: T, values: T[], } GenericAutoBound2<()>: { value: T, values: T[], } Container1: { foo: Generic1, bar: Generic1[], baz: { [key in string]: Generic1 }, } Generic2<(), String, i32>: ({ A: A }) & { B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ B: [B, B, B] }) & { A?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ C: C[] }) & { A?: never; B?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ D: A[][][] }) & { A?: never; B?: never; C?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ E: { a: A, b: B, c: C, } }) & { A?: never; B?: never; C?: never; D?: never; X?: never; Y?: never; Z?: never } | ({ X: number[] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; Y?: never; Z?: never } | ({ Y: number }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Z?: never } | ({ Z: number[][] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never } GenericNewType1<()>: T[][] GenericTuple<()>: [T, T[], T[][]] GenericStruct2<()>: { a: T, b: [T, T], c: [T, [T, T]], d: [T, T, T], e: [([T, T]), ([T, T]), ([T, T])], f: T[], g: T[][], h: ([([T, T]), ([T, T]), ([T, T])])[], } InlineGenericNewtype: string InlineGenericNested: [string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | ({ Unnamed: string }) & { Named?: never } | ({ Named: { value: string, } }) & { Unnamed?: never }] InlineFlattenGenericsG<()>: { t: T, } InlineFlattenGenerics: ({ g: InlineFlattenGenericsG, gi: { t: string, }, }) & (InlineFlattenGenericsG) GenericDefault: { value: T, } ChainedGenericDefault: { first: T, second: U, } ChainedGenericDefault: { first: T, second: U, } ChainedGenericDefault: { first: T, second: U, } ChainedGenericDefault: { first: T, second: U, } GenericDefaultSkipped: { value: T, } GenericDefaultSkippedNonType: { value: number, } GenericParameterOrderPreserved: { pair: Pair, } ConstGenericInNonConstContainer: { data: [number], a: [number, number], d: [number, number], } ConstGenericInConstContainer: { data: number[], a: number[], d: [number, number], } NamedConstGenericContainer: { a: NamedConstGeneric, b: NamedConstGeneric, d: [number, number], } InlineConstGenericContainer: { b: { data: [number, number], a: [number, number], d: [number, number, number], }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], }, d: [number, number], } InlineRecursiveConstGenericContainer: { b: { data: [number, number], a: [number, number], d: [number, number, number], e: InlineRecursiveConstGeneric, }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], e: InlineRecursiveConstGeneric, }, d: [number, number], } TestCollectionRegister: never TestCollectionRegister: never specta_typescript::Any: any specta_typescript::Any: any specta_typescript::Unknown: unknown specta_typescript::Unknown: unknown specta_typescript::Never: never specta_typescript::Never: never ================================================ FILE: tests/tests/snapshots/test__typescript__reference-raw.snap ================================================ --- source: tests/tests/typescript.rs expression: output --- Range: Range RangeInclusive: RangeInclusive String: string PathBuf: string IpAddr: string Ipv4Addr: string Ipv6Addr: string SocketAddr: string SocketAddrV4: string SocketAddrV6: string Cow<'static, str>: string Cow<'static, i32>: number Vec: number[] Vec: MyEnum[] Result: Result Vec>>: (number | null)[] PhantomData<()>: null PhantomData: null Infallible: never Unit1: Unit1 Unit2: Unit2 Unit3: Unit3 Unit4: Unit4 Unit5: Unit5 Unit6: Unit6 Unit7: Unit7 SimpleStruct: SimpleStruct TupleStruct1: TupleStruct1 TupleStruct3: TupleStruct3 TestEnum: TestEnum RefStruct: RefStruct InlinerStruct: InlinerStruct GenericStruct: GenericStruct GenericStruct: GenericStruct FlattenEnumStruct: FlattenEnumStruct OverridenStruct: OverridenStruct HasGenericAlias: HasGenericAlias EnumMacroAttributes: EnumMacroAttributes InlineEnumField: InlineEnumField InlineOptionalType: InlineOptionalType Rename: Rename TransparentType: TransparentType TransparentType2: TransparentType2 TransparentTypeWithOverride: TransparentTypeWithOverride HashMap: Partial<{ [key in BasicEnum]: null }> HashMap: Partial<{ [key in BasicEnum]: number }> Vec: PlaceholderInnerField[] EnumReferenceRecordKey: EnumReferenceRecordKey FlattenOnNestedEnum: FlattenOnNestedEnum MyEmptyInput: MyEmptyInput (String): string ExtraBracketsInTupleVariant: ExtraBracketsInTupleVariant ExtraBracketsInUnnamedStruct: ExtraBracketsInUnnamedStruct Vec: MyEnum[] InlineTuple: InlineTuple InlineTuple2: InlineTuple2 Box: string Box: string SkippedFieldWithinVariant: SkippedFieldWithinVariant KebabCase: KebabCase Issue281<'_>: Issue281 LifetimeGenericStruct<'_, i32>: LifetimeGenericStruct LifetimeGenericEnum<'_, i32>: LifetimeGenericEnum RenameWithWeirdCharsField: RenameWithWeirdCharsField RenameWithWeirdCharsVariant: RenameWithWeirdCharsVariant RenamedFieldKeys: RenamedFieldKeys RenamedVariantWithSkippedPayload: RenamedVariantWithSkippedPayload type_type::Type: Type ActualType: ActualType SpectaTypeOverride: SpectaTypeOverride ContainerTypeOverrideStruct: ContainerTypeOverrideStruct ContainerTypeOverrideEnum: ContainerTypeOverrideEnum ContainerTypeOverrideGeneric>: ContainerTypeOverrideGeneric ContainerTypeOverrideToGeneric: ContainerTypeOverrideToGeneric ContainerTypeOverrideTuple: ContainerTypeOverrideTuple ContainerTypeOverrideTupleGeneric: ContainerTypeOverrideTupleGeneric InvalidToValidType: InvalidToValidType TupleStruct: TupleStruct TupleStructWithRep: TupleStructWithRep GenericTupleStruct: GenericTupleStruct BracedStruct: BracedStruct Struct: Struct Struct2: Struct2 Enum: Enum Enum2: Enum2 Enum3: Enum3 StructRenameAllUppercase: StructRenameAllUppercase RenameSerdeSpecialChar: RenameSerdeSpecialChar EnumRenameAllUppercase: EnumRenameAllUppercase Recursive: Recursive RecursiveMapValue: RecursiveMapValue RecursiveTransparent: RecursiveTransparent RecursiveInEnum: RecursiveInEnum NonOptional: NonOptional OptionalOnNamedField: OptionalOnNamedField OptionalOnTransparentNamedField: OptionalOnTransparentNamedField OptionalInEnum: OptionalInEnum UntaggedVariants: UntaggedVariants UntaggedVariantsWithoutValue: UntaggedVariantsWithoutValue UntaggedVariantsWithDuplicateBranches: UntaggedVariantsWithDuplicateBranches HashMap: { [key in string]: null } Regular: Regular HashMap: { [key in never]: null } HashMap: { [key in TransparentStruct]: null } HashMap: Partial<{ [key in UnitVariants]: null }> HashMap: Partial<{ [key in UntaggedVariantsKey]: null }> ValidMaybeValidKey: ValidMaybeValidKey ValidMaybeValidKeyNested: ValidMaybeValidKeyNested MacroStruct: MacroStruct MacroStruct2: MacroStruct2 MacroEnum: MacroEnum DeprecatedType: DeprecatedType DeprecatedTypeWithMsg: DeprecatedTypeWithMsg DeprecatedTypeWithMsg2: DeprecatedTypeWithMsg2 DeprecatedFields: DeprecatedFields DeprecatedTupleVariant: DeprecatedTupleVariant DeprecatedEnumVariants: DeprecatedEnumVariants CommentedStruct: CommentedStruct CommentedEnum: CommentedEnum SingleLineComment: SingleLineComment NonGeneric: Demo HalfGenericA: Demo HalfGenericB: Demo FullGeneric: Demo Another: Demo MapA: { [key in string]: number } MapB: { [key in number]: string } MapC: { [key in string]: AGenericStruct } AGenericStruct: AGenericStruct A: A DoubleFlattened: DoubleFlattened FlattenedInner: FlattenedInner BoxFlattened: BoxFlattened BoxInline: BoxInline First: First Second: Second Third: Third Fourth: Fourth TagOnStructWithInline: TagOnStructWithInline Sixth: Sixth Seventh: Seventh Eight: Eight Ninth: Ninth Tenth: Tenth MyEnumTagged: MyEnumTagged MyEnumExternal: MyEnumExternal MyEnumAdjacent: MyEnumAdjacent MyEnumUntagged: MyEnumUntagged EmptyStruct: EmptyStruct EmptyStructWithTag: EmptyStructWithTag AdjacentlyTagged: AdjacentlyTagged LoadProjectEvent: LoadProjectEvent ExternallyTagged: ExternallyTagged Issue221External: Issue221External InternallyTaggedD: InternallyTaggedD InternallyTaggedE: InternallyTaggedE InternallyTaggedF: InternallyTaggedF InternallyTaggedH: InternallyTaggedH InternallyTaggedL: InternallyTaggedL InternallyTaggedM: InternallyTaggedM StructWithAlias: StructWithAlias StructWithMultipleAliases: StructWithMultipleAliases StructWithAliasAndRename: StructWithAliasAndRename EnumWithVariantAlias: EnumWithVariantAlias EnumWithMultipleVariantAliases: EnumWithMultipleVariantAliases EnumWithVariantAliasAndRename: EnumWithVariantAliasAndRename InternallyTaggedWithAlias: InternallyTaggedWithAlias AdjacentlyTaggedWithAlias: AdjacentlyTaggedWithAlias UntaggedWithAlias: UntaggedWithAlias Issue221UntaggedSafe: Issue221UntaggedSafe Issue221UntaggedMixed: Issue221UntaggedMixed EmptyEnum: EmptyEnum EmptyEnumTagged: EmptyEnumTagged EmptyEnumTaggedWContent: EmptyEnumTaggedWContent EmptyEnumUntagged: EmptyEnumUntagged SkipOnlyField: SkipOnlyField SkipField: SkipField SkipVariant: SkipVariant SkipUnnamedFieldInVariant: SkipUnnamedFieldInVariant SkipNamedFieldInVariant: SkipNamedFieldInVariant TransparentWithSkip: TransparentWithSkip TransparentWithSkip2: TransparentWithSkip2 TransparentWithSkip3: TransparentWithSkip3 SkipVariant2: SkipVariant2 SkipVariant3: SkipVariant3 SkipStructFields: SkipStructFields SpectaSkipNonTypeField: SpectaSkipNonTypeField FlattenA: FlattenA FlattenB: FlattenB FlattenC: FlattenC FlattenD: FlattenD FlattenE: FlattenE FlattenF: FlattenF FlattenG: FlattenG TupleNested: TupleNested Generic1<()>: Generic1 GenericAutoBound<()>: GenericAutoBound GenericAutoBound2<()>: GenericAutoBound2 Container1: Container1 Generic2<(), String, i32>: Generic2 GenericNewType1<()>: GenericNewType1 GenericTuple<()>: GenericTuple GenericStruct2<()>: GenericStruct2 InlineGenericNewtype: string InlineGenericNested: [string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | string | { value: string }] InlineFlattenGenericsG<()>: InlineFlattenGenericsG InlineFlattenGenerics: InlineFlattenGenerics GenericDefault: GenericDefault ChainedGenericDefault: ChainedGenericDefault ChainedGenericDefault: ChainedGenericDefault ChainedGenericDefault: ChainedGenericDefault ChainedGenericDefault: ChainedGenericDefault GenericDefaultSkipped: GenericDefaultSkipped GenericDefaultSkippedNonType: GenericDefaultSkippedNonType GenericParameterOrderPreserved: GenericParameterOrderPreserved ConstGenericInNonConstContainer: ConstGenericInNonConstContainer ConstGenericInConstContainer: ConstGenericInConstContainer NamedConstGenericContainer: NamedConstGenericContainer InlineConstGenericContainer: InlineConstGenericContainer InlineRecursiveConstGenericContainer: InlineRecursiveConstGenericContainer TestCollectionRegister: TestCollectionRegister TestCollectionRegister: TestCollectionRegister specta_typescript::Any: any specta_typescript::Any: any specta_typescript::Unknown: unknown specta_typescript::Unknown: unknown specta_typescript::Never: never specta_typescript::Never: never ================================================ FILE: tests/tests/snapshots/test__typescript__reference-serde.snap ================================================ --- source: tests/tests/typescript.rs expression: output --- Range: Range RangeInclusive: RangeInclusive String: string PathBuf: string IpAddr: string Ipv4Addr: string Ipv6Addr: string SocketAddr: string SocketAddrV4: string SocketAddrV6: string Cow<'static, str>: string Cow<'static, i32>: number Vec: number[] Vec: MyEnum[] Result: Result Vec>>: (number | null)[] PhantomData<()>: null PhantomData: null Infallible: never Unit1: Unit1 Unit2: Unit2 Unit3: Unit3 Unit4: Unit4 Unit5: Unit5 Unit6: Unit6 Unit7: Unit7 SimpleStruct: SimpleStruct TupleStruct1: TupleStruct1 TupleStruct3: TupleStruct3 TestEnum: TestEnum RefStruct: RefStruct InlinerStruct: InlinerStruct GenericStruct: GenericStruct GenericStruct: GenericStruct FlattenEnumStruct: FlattenEnumStruct OverridenStruct: OverridenStruct HasGenericAlias: HasGenericAlias EnumMacroAttributes: EnumMacroAttributes InlineEnumField: InlineEnumField InlineOptionalType: InlineOptionalType Rename: Rename TransparentType: TransparentType TransparentType2: TransparentType2 TransparentTypeWithOverride: TransparentTypeWithOverride HashMap: Partial<{ [key in BasicEnum]: null }> HashMap: Partial<{ [key in BasicEnum]: number }> Vec: PlaceholderInnerField[] EnumReferenceRecordKey: EnumReferenceRecordKey FlattenOnNestedEnum: FlattenOnNestedEnum MyEmptyInput: MyEmptyInput (String): string ExtraBracketsInTupleVariant: ExtraBracketsInTupleVariant ExtraBracketsInUnnamedStruct: ExtraBracketsInUnnamedStruct Vec: MyEnum[] InlineTuple: InlineTuple InlineTuple2: InlineTuple2 Box: string Box: string SkippedFieldWithinVariant: SkippedFieldWithinVariant KebabCase: KebabCase Issue281<'_>: Issue281 LifetimeGenericStruct<'_, i32>: LifetimeGenericStruct LifetimeGenericEnum<'_, i32>: LifetimeGenericEnum RenameWithWeirdCharsField: RenameWithWeirdCharsField RenameWithWeirdCharsVariant: RenameWithWeirdCharsVariant RenamedFieldKeys: RenamedFieldKeys RenamedVariantWithSkippedPayload: RenamedVariantWithSkippedPayload type_type::Type: Type ActualType: ActualType SpectaTypeOverride: SpectaTypeOverride ContainerTypeOverrideStruct: ContainerTypeOverrideStruct ContainerTypeOverrideEnum: ContainerTypeOverrideEnum ContainerTypeOverrideGeneric>: ContainerTypeOverrideGeneric ContainerTypeOverrideToGeneric: ContainerTypeOverrideToGeneric ContainerTypeOverrideTuple: ContainerTypeOverrideTuple ContainerTypeOverrideTupleGeneric: ContainerTypeOverrideTupleGeneric InvalidToValidType: InvalidToValidType TupleStruct: TupleStruct TupleStructWithRep: TupleStructWithRep GenericTupleStruct: GenericTupleStruct BracedStruct: BracedStruct Struct: StructNew Struct2: Struct2 Enum: Enum Enum2: Enum2 Enum3: Enum3 StructRenameAllUppercase: StructRenameAllUppercase RenameSerdeSpecialChar: RenameSerdeSpecialChar EnumRenameAllUppercase: EnumRenameAllUppercase Recursive: Recursive RecursiveMapValue: RecursiveMapValue RecursiveTransparent: RecursiveTransparent RecursiveInEnum: RecursiveInEnum NonOptional: NonOptional OptionalOnNamedField: OptionalOnNamedField OptionalOnTransparentNamedField: OptionalOnTransparentNamedField OptionalInEnum: OptionalInEnum UntaggedVariants: UntaggedVariants UntaggedVariantsWithoutValue: UntaggedVariantsWithoutValue UntaggedVariantsWithDuplicateBranches: UntaggedVariantsWithDuplicateBranches HashMap: { [key in string]: null } Regular: Regular HashMap: { [key in never]: null } HashMap: { [key in TransparentStruct]: null } HashMap: Partial<{ [key in UnitVariants]: null }> HashMap: Partial<{ [key in UntaggedVariantsKey]: null }> ValidMaybeValidKey: ValidMaybeValidKey ValidMaybeValidKeyNested: ValidMaybeValidKeyNested MacroStruct: MacroStruct MacroStruct2: MacroStruct2 MacroEnum: MacroEnum DeprecatedType: DeprecatedType DeprecatedTypeWithMsg: DeprecatedTypeWithMsg DeprecatedTypeWithMsg2: DeprecatedTypeWithMsg2 DeprecatedFields: DeprecatedFields DeprecatedTupleVariant: DeprecatedTupleVariant DeprecatedEnumVariants: DeprecatedEnumVariants CommentedStruct: CommentedStruct CommentedEnum: CommentedEnum SingleLineComment: SingleLineComment NonGeneric: Demo HalfGenericA: Demo HalfGenericB: Demo FullGeneric: Demo Another: Demo MapA: { [key in string]: number } MapB: { [key in number]: string } MapC: { [key in string]: AGenericStruct } AGenericStruct: AGenericStruct A: A DoubleFlattened: DoubleFlattened FlattenedInner: FlattenedInner BoxFlattened: BoxFlattened BoxInline: BoxInline First: First Second: Second Third: Third Fourth: Fourth TagOnStructWithInline: TagOnStructWithInline Sixth: Sixth Seventh: Seventh Eight: Eight Ninth: Ninth Tenth: Tenth MyEnumTagged: MyEnumTagged MyEnumExternal: MyEnumExternal MyEnumAdjacent: MyEnumAdjacent MyEnumUntagged: MyEnumUntagged EmptyStruct: EmptyStruct EmptyStructWithTag: EmptyStructWithTag AdjacentlyTagged: AdjacentlyTagged LoadProjectEvent: LoadProjectEvent ExternallyTagged: ExternallyTagged Issue221External: Issue221External InternallyTaggedD: InternallyTaggedD InternallyTaggedE: InternallyTaggedE InternallyTaggedF: InternallyTaggedF InternallyTaggedH: InternallyTaggedH InternallyTaggedL: InternallyTaggedL InternallyTaggedM: InternallyTaggedM StructWithAlias: StructWithAlias StructWithMultipleAliases: StructWithMultipleAliases StructWithAliasAndRename: StructWithAliasAndRename EnumWithVariantAlias: EnumWithVariantAlias EnumWithMultipleVariantAliases: EnumWithMultipleVariantAliases EnumWithVariantAliasAndRename: EnumWithVariantAliasAndRename InternallyTaggedWithAlias: InternallyTaggedWithAlias AdjacentlyTaggedWithAlias: AdjacentlyTaggedWithAlias UntaggedWithAlias: UntaggedWithAlias Issue221UntaggedSafe: Issue221UntaggedSafe Issue221UntaggedMixed: Issue221UntaggedMixed EmptyEnum: EmptyEnum EmptyEnumTagged: EmptyEnumTagged EmptyEnumTaggedWContent: EmptyEnumTaggedWContent EmptyEnumUntagged: EmptyEnumUntagged SkipOnlyField: SkipOnlyField SkipField: SkipField SkipVariant: SkipVariant SkipUnnamedFieldInVariant: SkipUnnamedFieldInVariant SkipNamedFieldInVariant: SkipNamedFieldInVariant TransparentWithSkip: TransparentWithSkip TransparentWithSkip2: TransparentWithSkip2 TransparentWithSkip3: TransparentWithSkip3 SkipVariant2: SkipVariant2 SkipVariant3: SkipVariant3 SkipStructFields: SkipStructFields SpectaSkipNonTypeField: SpectaSkipNonTypeField FlattenA: FlattenA FlattenB: FlattenB FlattenC: FlattenC FlattenD: FlattenD FlattenE: FlattenE FlattenF: FlattenF FlattenG: FlattenG TupleNested: TupleNested Generic1<()>: Generic1 GenericAutoBound<()>: GenericAutoBound GenericAutoBound2<()>: GenericAutoBound2 Container1: Container1 Generic2<(), String, i32>: Generic2 GenericNewType1<()>: GenericNewType1 GenericTuple<()>: GenericTuple GenericStruct2<()>: GenericStruct2 InlineGenericNewtype: string InlineGenericNested: [string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | ({ Unnamed: string }) & { Named?: never } | ({ Named: { value: string, } }) & { Unnamed?: never }] InlineFlattenGenericsG<()>: InlineFlattenGenericsG InlineFlattenGenerics: InlineFlattenGenerics GenericDefault: GenericDefault ChainedGenericDefault: ChainedGenericDefault ChainedGenericDefault: ChainedGenericDefault ChainedGenericDefault: ChainedGenericDefault ChainedGenericDefault: ChainedGenericDefault GenericDefaultSkipped: GenericDefaultSkipped GenericDefaultSkippedNonType: GenericDefaultSkippedNonType GenericParameterOrderPreserved: GenericParameterOrderPreserved ConstGenericInNonConstContainer: ConstGenericInNonConstContainer ConstGenericInConstContainer: ConstGenericInConstContainer NamedConstGenericContainer: NamedConstGenericContainer InlineConstGenericContainer: InlineConstGenericContainer InlineRecursiveConstGenericContainer: InlineRecursiveConstGenericContainer TestCollectionRegister: TestCollectionRegister TestCollectionRegister: TestCollectionRegister specta_typescript::Any: any specta_typescript::Any: any specta_typescript::Unknown: unknown specta_typescript::Unknown: unknown specta_typescript::Never: never specta_typescript::Never: never ================================================ FILE: tests/tests/snapshots/test__typescript__reference-serde_phases.snap ================================================ --- source: tests/tests/typescript.rs expression: output --- Issue374: Issue374_Serialize Optional: Optional_Serialize StructPhaseSpecificRename: StructPhaseSpecificRenameSerialize Range: Range RangeInclusive: RangeInclusive String: string PathBuf: string IpAddr: string Ipv4Addr: string Ipv6Addr: string SocketAddr: string SocketAddrV4: string SocketAddrV6: string Cow<'static, str>: string Cow<'static, i32>: number Vec: number[] Vec: MyEnum[] Result: Result Vec>>: (number | null)[] PhantomData<()>: null PhantomData: null Infallible: never Unit1: Unit1 Unit2: Unit2 Unit3: Unit3 Unit4: Unit4 Unit5: Unit5 Unit6: Unit6 Unit7: Unit7 SimpleStruct: SimpleStruct TupleStruct1: TupleStruct1 TupleStruct3: TupleStruct3 TestEnum: TestEnum RefStruct: RefStruct InlinerStruct: InlinerStruct GenericStruct: GenericStruct GenericStruct: GenericStruct FlattenEnumStruct: FlattenEnumStruct OverridenStruct: OverridenStruct HasGenericAlias: HasGenericAlias EnumMacroAttributes: EnumMacroAttributes InlineEnumField: InlineEnumField InlineOptionalType: InlineOptionalType Rename: Rename TransparentType: TransparentType TransparentType2: TransparentType2 TransparentTypeWithOverride: TransparentTypeWithOverride HashMap: Partial<{ [key in BasicEnum]: null }> HashMap: Partial<{ [key in BasicEnum]: number }> Vec: PlaceholderInnerField[] EnumReferenceRecordKey: EnumReferenceRecordKey FlattenOnNestedEnum: FlattenOnNestedEnum MyEmptyInput: MyEmptyInput (String): string ExtraBracketsInTupleVariant: ExtraBracketsInTupleVariant ExtraBracketsInUnnamedStruct: ExtraBracketsInUnnamedStruct Vec: MyEnum[] InlineTuple: InlineTuple InlineTuple2: InlineTuple2 Box: string Box: string SkippedFieldWithinVariant: SkippedFieldWithinVariant KebabCase: KebabCase Issue281<'_>: Issue281 LifetimeGenericStruct<'_, i32>: LifetimeGenericStruct LifetimeGenericEnum<'_, i32>: LifetimeGenericEnum RenameWithWeirdCharsField: RenameWithWeirdCharsField RenameWithWeirdCharsVariant: RenameWithWeirdCharsVariant RenamedFieldKeys: RenamedFieldKeys RenamedVariantWithSkippedPayload: RenamedVariantWithSkippedPayload type_type::Type: Type ActualType: ActualType SpectaTypeOverride: SpectaTypeOverride ContainerTypeOverrideStruct: ContainerTypeOverrideStruct ContainerTypeOverrideEnum: ContainerTypeOverrideEnum ContainerTypeOverrideGeneric>: ContainerTypeOverrideGeneric ContainerTypeOverrideToGeneric: ContainerTypeOverrideToGeneric ContainerTypeOverrideTuple: ContainerTypeOverrideTuple ContainerTypeOverrideTupleGeneric: ContainerTypeOverrideTupleGeneric InvalidToValidType: InvalidToValidType TupleStruct: TupleStruct TupleStructWithRep: TupleStructWithRep GenericTupleStruct: GenericTupleStruct BracedStruct: BracedStruct Struct: StructNew Struct2: Struct2 Enum: Enum Enum2: Enum2 Enum3: Enum3 StructRenameAllUppercase: StructRenameAllUppercase RenameSerdeSpecialChar: RenameSerdeSpecialChar EnumRenameAllUppercase: EnumRenameAllUppercase Recursive: Recursive RecursiveMapValue: RecursiveMapValue RecursiveTransparent: RecursiveTransparent RecursiveInEnum: RecursiveInEnum NonOptional: NonOptional OptionalOnNamedField: OptionalOnNamedField OptionalOnTransparentNamedField: OptionalOnTransparentNamedField OptionalInEnum: OptionalInEnum UntaggedVariants: UntaggedVariants UntaggedVariantsWithoutValue: UntaggedVariantsWithoutValue UntaggedVariantsWithDuplicateBranches: UntaggedVariantsWithDuplicateBranches HashMap: { [key in string]: null } Regular: Regular HashMap: { [key in never]: null } HashMap: { [key in TransparentStruct]: null } HashMap: Partial<{ [key in UnitVariants]: null }> HashMap: Partial<{ [key in UntaggedVariantsKey]: null }> ValidMaybeValidKey: ValidMaybeValidKey ValidMaybeValidKeyNested: ValidMaybeValidKeyNested MacroStruct: MacroStruct MacroStruct2: MacroStruct2 MacroEnum: MacroEnum DeprecatedType: DeprecatedType DeprecatedTypeWithMsg: DeprecatedTypeWithMsg DeprecatedTypeWithMsg2: DeprecatedTypeWithMsg2 DeprecatedFields: DeprecatedFields DeprecatedTupleVariant: DeprecatedTupleVariant DeprecatedEnumVariants: DeprecatedEnumVariants CommentedStruct: CommentedStruct CommentedEnum: CommentedEnum SingleLineComment: SingleLineComment NonGeneric: Demo HalfGenericA: Demo HalfGenericB: Demo FullGeneric: Demo Another: Demo MapA: { [key in string]: number } MapB: { [key in number]: string } MapC: { [key in string]: AGenericStruct } AGenericStruct: AGenericStruct A: A DoubleFlattened: DoubleFlattened FlattenedInner: FlattenedInner BoxFlattened: BoxFlattened BoxInline: BoxInline First: First Second: Second Third: Third Fourth: Fourth TagOnStructWithInline: TagOnStructWithInline Sixth: Sixth Seventh: Seventh Eight: Eight Ninth: Ninth Tenth: Tenth MyEnumTagged: MyEnumTagged MyEnumExternal: MyEnumExternal MyEnumAdjacent: MyEnumAdjacent MyEnumUntagged: MyEnumUntagged EmptyStruct: EmptyStruct EmptyStructWithTag: EmptyStructWithTag AdjacentlyTagged: AdjacentlyTagged LoadProjectEvent: LoadProjectEvent ExternallyTagged: ExternallyTagged Issue221External: Issue221External InternallyTaggedD: InternallyTaggedD InternallyTaggedE: InternallyTaggedE InternallyTaggedF: InternallyTaggedF InternallyTaggedH: InternallyTaggedH InternallyTaggedL: InternallyTaggedL InternallyTaggedM: InternallyTaggedM StructWithAlias: StructWithAlias StructWithMultipleAliases: StructWithMultipleAliases StructWithAliasAndRename: StructWithAliasAndRename EnumWithVariantAlias: EnumWithVariantAlias EnumWithMultipleVariantAliases: EnumWithMultipleVariantAliases EnumWithVariantAliasAndRename: EnumWithVariantAliasAndRename InternallyTaggedWithAlias: InternallyTaggedWithAlias AdjacentlyTaggedWithAlias: AdjacentlyTaggedWithAlias UntaggedWithAlias: UntaggedWithAlias Issue221UntaggedSafe: Issue221UntaggedSafe Issue221UntaggedMixed: Issue221UntaggedMixed EmptyEnum: EmptyEnum EmptyEnumTagged: EmptyEnumTagged EmptyEnumTaggedWContent: EmptyEnumTaggedWContent EmptyEnumUntagged: EmptyEnumUntagged SkipOnlyField: SkipOnlyField SkipField: SkipField SkipVariant: SkipVariant SkipUnnamedFieldInVariant: SkipUnnamedFieldInVariant SkipNamedFieldInVariant: SkipNamedFieldInVariant TransparentWithSkip: TransparentWithSkip TransparentWithSkip2: TransparentWithSkip2 TransparentWithSkip3: TransparentWithSkip3 SkipVariant2: SkipVariant2 SkipVariant3: SkipVariant3 SkipStructFields: SkipStructFields SpectaSkipNonTypeField: SpectaSkipNonTypeField FlattenA: FlattenA FlattenB: FlattenB FlattenC: FlattenC FlattenD: FlattenD FlattenE: FlattenE FlattenF: FlattenF FlattenG: FlattenG TupleNested: TupleNested Generic1<()>: Generic1 GenericAutoBound<()>: GenericAutoBound GenericAutoBound2<()>: GenericAutoBound2 Container1: Container1 Generic2<(), String, i32>: Generic2 GenericNewType1<()>: GenericNewType1 GenericTuple<()>: GenericTuple GenericStruct2<()>: GenericStruct2 InlineGenericNewtype: string InlineGenericNested: [string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | ({ Unnamed: string }) & { Named?: never } | ({ Named: { value: string, } }) & { Unnamed?: never }] InlineFlattenGenericsG<()>: InlineFlattenGenericsG InlineFlattenGenerics: InlineFlattenGenerics GenericDefault: GenericDefault ChainedGenericDefault: ChainedGenericDefault ChainedGenericDefault: ChainedGenericDefault ChainedGenericDefault: ChainedGenericDefault ChainedGenericDefault: ChainedGenericDefault GenericDefaultSkipped: GenericDefaultSkipped GenericDefaultSkippedNonType: GenericDefaultSkippedNonType GenericParameterOrderPreserved: GenericParameterOrderPreserved ConstGenericInNonConstContainer: ConstGenericInNonConstContainer ConstGenericInConstContainer: ConstGenericInConstContainer NamedConstGenericContainer: NamedConstGenericContainer InlineConstGenericContainer: InlineConstGenericContainer InlineRecursiveConstGenericContainer: InlineRecursiveConstGenericContainer TestCollectionRegister: TestCollectionRegister TestCollectionRegister: TestCollectionRegister specta_typescript::Any: any specta_typescript::Any: any specta_typescript::Unknown: unknown specta_typescript::Unknown: unknown specta_typescript::Never: never specta_typescript::Never: never ================================================ FILE: tests/tests/snapshots/test__typescript__ts-export-raw.snap ================================================ --- source: tests/tests/typescript.rs expression: "Typescript::default().export(&types, format).unwrap()" --- // This file has been generated by Specta. Do not edit this file manually. export type A = { a: B, b: { b: number, }, c: B, d: { flattened: number, }, e: { generic_flattened: number, }, }; export type AGenericStruct = { field: Demo, }; export type ActualType = { a: GenericType, }; export type AdjacentlyTagged = "A" | { id: string; method: string } | string; export type AdjacentlyTaggedWithAlias = ({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }; export type B = { b: number, }; export type BasicEnum = "A" | "B"; export type BoxFlattened = { b: BoxedInner, }; export type BoxInline = { c: { a: number, }, }; export type BoxedInner = { a: number, }; export type BracedStruct = string; export type ChainedGenericDefault = { first: T, second: U, }; /** * Some triple-slash comment * Some more triple-slash comment */ export type CommentedEnum = /** * Some triple-slash comment * Some more triple-slash comment */ number | /** * Some triple-slash comment * Some more triple-slash comment */ { /** * Some triple-slash comment * Some more triple-slash comment */ a: number }; /** * Some triple-slash comment * Some more triple-slash comment */ export type CommentedStruct = { /** * Some triple-slash comment * Some more triple-slash comment */ a: number, }; export type ConstGenericInConstContainer = { data: number[], a: number[], d: [number, number], }; export type ConstGenericInNonConstContainer = { data: [number], a: [number, number], d: [number, number], }; export type Container1 = { foo: Generic1, bar: Generic1[], baz: { [key in string]: Generic1 }, }; export type ContainerTypeOverrideEnum = string; export type ContainerTypeOverrideGeneric = string; export type ContainerTypeOverrideStruct = string; export type ContainerTypeOverrideToGeneric = T; export type ContainerTypeOverrideTuple = [string, number]; export type ContainerTypeOverrideTupleGeneric = [T, string]; export type D = { flattened: number, }; export type Demo = { a: A, b: B, }; export type DeprecatedEnumVariants = /** * @deprecated */ "A" | /** * @deprecated Nope */ "B" | /** * @deprecated Nope */ "C"; export type DeprecatedFields = { a: number, /** * @deprecated */ b: string, /** * @deprecated This field is cringe! */ c: string, /** * @deprecated This field is cringe! */ d: string, }; export type DeprecatedTupleVariant = [ /** * @deprecated */ string, /** * @deprecated Nope */ string, /** * @deprecated Nope */ number]; /** * @deprecated */ export type DeprecatedType = { a: number, }; /** * @deprecated Look at you big man using a deprecation message */ export type DeprecatedTypeWithMsg = { a: number, }; /** * @deprecated Look at you big man using a deprecation message */ export type DeprecatedTypeWithMsg2 = { a: number, }; export type DoubleFlattened = { a: ToBeFlattened, b: ToBeFlattened, }; export type Eight = string | "B"; export type EmptyEnum = never; export type EmptyEnumTagged = never; export type EmptyEnumTaggedWContent = never; export type EmptyEnumUntagged = never; export type EmptyStruct = Record; export type EmptyStructWithTag = Record; export type Enum = "A" | "B"; export type Enum2 = "A" | "B" | { enum_field: null }; export type Enum3 = { a: string }; export type EnumMacroAttributes = string | number | { a: string; b: number }; export type EnumReferenceRecordKey = { a: Partial<{ [key in BasicEnum]: number }>, }; export type EnumRenameAllUppercase = "HelloWorld" | "VariantB" | "TestingWords"; export type EnumWithMultipleVariantAliases = "Variant" | "Other"; export type EnumWithVariantAlias = "Variant" | "Other"; export type EnumWithVariantAliasAndRename = "Variant" | "Other"; export type ExternallyTagged = "A" | { id: string; method: string } | string; export type ExtraBracketsInTupleVariant = string; export type ExtraBracketsInUnnamedStruct = string; export type First = { a: string, }; export type FlattenA = { a: number, b: number, }; export type FlattenB = { a: FlattenA, c: number, }; export type FlattenC = { a: FlattenA, c: number, }; export type FlattenD = { a: FlattenA, c: number, }; export type FlattenE = { b: { a: FlattenA, c: number, }, d: number, }; export type FlattenEnum = "One" | "Two" | "Three"; export type FlattenEnumStruct = { outer: string, inner: FlattenEnum, }; export type FlattenF = { b: { a: FlattenA, c: number, }, d: number, }; export type FlattenG = { b: FlattenB, d: number, }; export type FlattenOnNestedEnum = { id: string, result: NestedEnum, }; export type FlattenedInner = { c: Inner, }; export type Fourth = { a: First, b: { a: string, }, }; export type Generic1 = { value: T, values: T[], }; export type Generic2 = A | [B, B, B] | C[] | A[][][] | { a: A; b: B; c: C } | number[] | number | number[][]; export type GenericAutoBound = { value: T, values: T[], }; export type GenericAutoBound2 = { value: T, values: T[], }; export type GenericDefault = { value: T, }; export type GenericDefaultSkipped = { value: T, }; export type GenericDefaultSkippedNonType = { value: number, }; export type GenericFlattened = { generic_flattened: T, }; export type GenericNewType1 = T[][]; export type GenericParameterOrderPreserved = { pair: Pair, }; export type GenericStruct = { arg: T, }; export type GenericStruct2 = { a: T, b: [T, T], c: [T, [T, T]], d: [T, T, T], e: [([T, T]), ([T, T]), ([T, T])], f: T[], g: T[][], h: ([([T, T]), ([T, T]), ([T, T])])[], }; export type GenericTuple = [T, T[], T[][]]; export type GenericTupleStruct = T; export type GenericType = "Undefined" | T; export type HasGenericAlias = { [key in number]: string }; export type InlineConstGenericContainer = { b: { data: [number, number], a: [number, number], d: [number, number, number], }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], }, d: [number, number], }; export type InlineEnumField = { a: string, }; export type InlineFlattenGenerics = { g: InlineFlattenGenericsG, gi: { t: string, }, t: InlineFlattenGenericsG, }; export type InlineFlattenGenericsG = { t: T, }; export type InlineOptionalType = { optional_field: { a: string, } | null, }; export type InlineRecursiveConstGeneric = { data: number[], a: number[], d: [number, number, number], e: InlineRecursiveConstGeneric, }; export type InlineRecursiveConstGenericContainer = { b: { data: [number, number], a: [number, number], d: [number, number, number], e: InlineRecursiveConstGeneric, }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], e: InlineRecursiveConstGeneric, }, d: [number, number], }; export type InlineStruct = { ref_struct: SimpleStruct, val: number, }; export type InlineTuple = { demo: [string, boolean], }; export type InlineTuple2 = { demo: [{ demo: [string, boolean], }, boolean], }; export type InlinerStruct = { inline_this: { ref_struct: SimpleStruct, val: number, }, dont_inline_this: RefStruct, }; export type Inner = { a: number, b: FlattenedInner, }; export type InternallyTaggedD = { [key in string]: string }; export type InternallyTaggedE = null; export type InternallyTaggedF = InternallyTaggedFInner; export type InternallyTaggedFInner = null; export type InternallyTaggedH = InternallyTaggedHInner; export type InternallyTaggedHInner = null; export type InternallyTaggedL = "A" | "B"; export type InternallyTaggedLInner = "A" | "B"; export type InternallyTaggedM = "A" | "B"; export type InternallyTaggedMInner = "A" | "B"; export type InternallyTaggedWithAlias = ({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }; export type InvalidToValidType = { cause: null, }; export type Issue221External = ({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }; export type Issue221UntaggedMixed = ({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never }; export type Issue221UntaggedSafe = ({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }; export type Issue281 = { default_unity_arguments: string[], }; export type KebabCase = { test_ing: string, }; export type LifetimeGenericEnum = T; export type LifetimeGenericStruct = { borrowed: T[], owned: T[], }; export type LoadProjectEvent = ({ project_name: string }) & { progress?: never; status?: never } | { project_name: string; status: string; progress: number }; export type MacroEnum = string | { demo2: string }; export type MacroStruct = string; export type MacroStruct2 = { demo: string, }; export type MaybeValidKey = T; export type MyEmptyInput = Record; export type MyEnum = string | number; export type MyEnumAdjacent = { inner: First }; export type MyEnumExternal = { inner: First }; export type MyEnumTagged = { inner: First }; export type MyEnumUntagged = { inner: First }; export type NamedConstGeneric = { data: number[], a: number[], d: [number, number], }; export type NamedConstGenericContainer = { a: NamedConstGeneric, b: NamedConstGeneric, d: [number, number], }; export type NestedEnum = string | number; export type Ninth = string | "B" | { a: string, } | First; export type NonOptional = string | null; export type OptionalInEnum = string | null | { a: string | null } | { a?: string | null }; export type OptionalOnNamedField = string | null; export type OptionalOnTransparentNamedField = { b: string | null, }; export type OverridenStruct = { overriden_field: string, }; export type Pair = { first: Z, second: A, }; export type PlaceholderInnerField = { a: string, }; export type Primitives = { i8: number, i16: number, i32: number, u8: number, u16: number, u32: number, f32: number, f64: number, bool: boolean, char: string, "Range": Range, "RangeInclusive": RangeInclusive, "()": null, "(String, i32)": [string, number], "(String, i32, bool)": [string, number, boolean], "((String, i32), (bool, char, bool), ())": [[string, number], [boolean, string, boolean], null], "(bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool)": [boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean], "(Vec, Vec)": [number[], boolean[]], String: string, PathBuf: string, IpAddr: string, Ipv4Addr: string, Ipv6Addr: string, SocketAddr: string, SocketAddrV4: string, SocketAddrV6: string, "Cow<'static, str>": string, "Cow<'static, i32>": number, "&'static str": string, "&'static bool": boolean, "&'static i32": number, "Vec": number[], "&'static [i32]": number[], "&'static [i32; 3]": [number, number, number], "[i32; 3]": [number, number, number], "Vec": MyEnum[], "&'static [MyEnum]": MyEnum[], "&'static [MyEnum; 6]": [MyEnum, MyEnum, MyEnum, MyEnum, MyEnum, MyEnum], "[MyEnum; 2]": [MyEnum, MyEnum], "&'static [i32; 1]": [number], "&'static [i32; 0]": [], "Option": number | null, "Option<()>": null, "Option>": number[] | null, "Result": Result, "Vec>>": (number | null)[], "Option>>": number[] | null, "[Vec; 3]": [string[], string[], string[]], "Option>": string | null, "Option>>": string | null, "PhantomData<()>": null, "PhantomData": null, Infallible: never, Unit1: Unit1, Unit2: Unit2, Unit3: Unit3, Unit4: Unit4, Unit5: Unit5, Unit6: Unit6, Unit7: Unit7, SimpleStruct: SimpleStruct, TupleStruct1: TupleStruct1, TupleStruct3: TupleStruct3, TestEnum: TestEnum, RefStruct: RefStruct, InlinerStruct: InlinerStruct, "GenericStruct": GenericStruct, "GenericStruct": GenericStruct, FlattenEnumStruct: FlattenEnumStruct, OverridenStruct: OverridenStruct, HasGenericAlias: HasGenericAlias, EnumMacroAttributes: EnumMacroAttributes, InlineEnumField: InlineEnumField, InlineOptionalType: InlineOptionalType, Rename: Rename, TransparentType: TransparentType, TransparentType2: TransparentType2, TransparentTypeWithOverride: TransparentTypeWithOverride, "[Option; 3]": [(number | null), (number | null), (number | null)], "HashMap": Partial<{ [key in BasicEnum]: null }>, "HashMap": Partial<{ [key in BasicEnum]: number }>, "Option>>>": number | null, "Vec": PlaceholderInnerField[], EnumReferenceRecordKey: EnumReferenceRecordKey, FlattenOnNestedEnum: FlattenOnNestedEnum, MyEmptyInput: MyEmptyInput, "(String)": string, "(String,)": [string], ExtraBracketsInTupleVariant: ExtraBracketsInTupleVariant, ExtraBracketsInUnnamedStruct: ExtraBracketsInUnnamedStruct, "Vec": MyEnum[], InlineTuple: InlineTuple, InlineTuple2: InlineTuple2, "Box": string, "Box": string, SkippedFieldWithinVariant: SkippedFieldWithinVariant, KebabCase: KebabCase, "&[&str]": string[], "Issue281<'_>": Issue281, "LifetimeGenericStruct<'_, i32>": LifetimeGenericStruct, "LifetimeGenericEnum<'_, i32>": LifetimeGenericEnum, RenameWithWeirdCharsField: RenameWithWeirdCharsField, RenameWithWeirdCharsVariant: RenameWithWeirdCharsVariant, RenamedFieldKeys: RenamedFieldKeys, RenamedVariantWithSkippedPayload: RenamedVariantWithSkippedPayload, "type_type::Type": Type, ActualType: ActualType, SpectaTypeOverride: SpectaTypeOverride, ContainerTypeOverrideStruct: ContainerTypeOverrideStruct, ContainerTypeOverrideEnum: ContainerTypeOverrideEnum, "ContainerTypeOverrideGeneric>": ContainerTypeOverrideGeneric, "ContainerTypeOverrideToGeneric": ContainerTypeOverrideToGeneric, ContainerTypeOverrideTuple: ContainerTypeOverrideTuple, "ContainerTypeOverrideTupleGeneric": ContainerTypeOverrideTupleGeneric, InvalidToValidType: InvalidToValidType, TupleStruct: TupleStruct, TupleStructWithRep: TupleStructWithRep, "GenericTupleStruct": GenericTupleStruct, BracedStruct: BracedStruct, Struct: Struct, Struct2: Struct2, Enum: Enum, Enum2: Enum2, Enum3: Enum3, StructRenameAllUppercase: StructRenameAllUppercase, RenameSerdeSpecialChar: RenameSerdeSpecialChar, EnumRenameAllUppercase: EnumRenameAllUppercase, Recursive: Recursive, RecursiveMapValue: RecursiveMapValue, RecursiveTransparent: RecursiveTransparent, RecursiveInEnum: RecursiveInEnum, NonOptional: NonOptional, OptionalOnNamedField: OptionalOnNamedField, OptionalOnTransparentNamedField: OptionalOnTransparentNamedField, OptionalInEnum: OptionalInEnum, UntaggedVariants: UntaggedVariants, UntaggedVariantsWithoutValue: UntaggedVariantsWithoutValue, UntaggedVariantsWithDuplicateBranches: UntaggedVariantsWithDuplicateBranches, "HashMap": { [key in string]: null }, Regular: Regular, "HashMap": { [key in never]: null }, "HashMap": { [key in TransparentStruct]: null }, "HashMap": Partial<{ [key in UnitVariants]: null }>, "HashMap": Partial<{ [key in UntaggedVariantsKey]: null }>, ValidMaybeValidKey: ValidMaybeValidKey, ValidMaybeValidKeyNested: ValidMaybeValidKeyNested, MacroStruct: MacroStruct, MacroStruct2: MacroStruct2, MacroEnum: MacroEnum, DeprecatedType: DeprecatedType, DeprecatedTypeWithMsg: DeprecatedTypeWithMsg, DeprecatedTypeWithMsg2: DeprecatedTypeWithMsg2, DeprecatedFields: DeprecatedFields, DeprecatedTupleVariant: DeprecatedTupleVariant, DeprecatedEnumVariants: DeprecatedEnumVariants, CommentedStruct: CommentedStruct, CommentedEnum: CommentedEnum, SingleLineComment: SingleLineComment, NonGeneric: Demo, "HalfGenericA": Demo, "HalfGenericB": Demo, "FullGeneric": Demo, "Another": Demo, "MapA": { [key in string]: number }, "MapB": { [key in number]: string }, "MapC": { [key in string]: AGenericStruct }, "AGenericStruct": AGenericStruct, A: A, DoubleFlattened: DoubleFlattened, FlattenedInner: FlattenedInner, BoxFlattened: BoxFlattened, BoxInline: BoxInline, First: First, Second: Second, Third: Third, Fourth: Fourth, TagOnStructWithInline: TagOnStructWithInline, Sixth: Sixth, Seventh: Seventh, Eight: Eight, Ninth: Ninth, Tenth: Tenth, MyEnumTagged: MyEnumTagged, MyEnumExternal: MyEnumExternal, MyEnumAdjacent: MyEnumAdjacent, MyEnumUntagged: MyEnumUntagged, EmptyStruct: EmptyStruct, EmptyStructWithTag: EmptyStructWithTag, AdjacentlyTagged: AdjacentlyTagged, LoadProjectEvent: LoadProjectEvent, ExternallyTagged: ExternallyTagged, Issue221External: Issue221External, InternallyTaggedD: InternallyTaggedD, InternallyTaggedE: InternallyTaggedE, InternallyTaggedF: InternallyTaggedF, InternallyTaggedH: InternallyTaggedH, InternallyTaggedL: InternallyTaggedL, InternallyTaggedM: InternallyTaggedM, StructWithAlias: StructWithAlias, StructWithMultipleAliases: StructWithMultipleAliases, StructWithAliasAndRename: StructWithAliasAndRename, EnumWithVariantAlias: EnumWithVariantAlias, EnumWithMultipleVariantAliases: EnumWithMultipleVariantAliases, EnumWithVariantAliasAndRename: EnumWithVariantAliasAndRename, InternallyTaggedWithAlias: InternallyTaggedWithAlias, AdjacentlyTaggedWithAlias: AdjacentlyTaggedWithAlias, UntaggedWithAlias: UntaggedWithAlias, Issue221UntaggedSafe: Issue221UntaggedSafe, Issue221UntaggedMixed: Issue221UntaggedMixed, EmptyEnum: EmptyEnum, EmptyEnumTagged: EmptyEnumTagged, EmptyEnumTaggedWContent: EmptyEnumTaggedWContent, EmptyEnumUntagged: EmptyEnumUntagged, SkipOnlyField: SkipOnlyField, SkipField: SkipField, SkipVariant: SkipVariant, SkipUnnamedFieldInVariant: SkipUnnamedFieldInVariant, SkipNamedFieldInVariant: SkipNamedFieldInVariant, TransparentWithSkip: TransparentWithSkip, TransparentWithSkip2: TransparentWithSkip2, TransparentWithSkip3: TransparentWithSkip3, SkipVariant2: SkipVariant2, SkipVariant3: SkipVariant3, SkipStructFields: SkipStructFields, SpectaSkipNonTypeField: SpectaSkipNonTypeField, FlattenA: FlattenA, FlattenB: FlattenB, FlattenC: FlattenC, FlattenD: FlattenD, FlattenE: FlattenE, FlattenF: FlattenF, FlattenG: FlattenG, TupleNested: TupleNested, "Generic1<()>": Generic1, "GenericAutoBound<()>": GenericAutoBound, "GenericAutoBound2<()>": GenericAutoBound2, Container1: Container1, "Generic2<(), String, i32>": Generic2, "GenericNewType1<()>": GenericNewType1, "GenericTuple<()>": GenericTuple, "GenericStruct2<()>": GenericStruct2, "InlineGenericNewtype": string, "InlineGenericNested": [string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | string | { value: string }], "InlineFlattenGenericsG<()>": InlineFlattenGenericsG, InlineFlattenGenerics: InlineFlattenGenerics, GenericDefault: GenericDefault, ChainedGenericDefault: ChainedGenericDefault, "ChainedGenericDefault": ChainedGenericDefault, "ChainedGenericDefault": ChainedGenericDefault, "ChainedGenericDefault": ChainedGenericDefault, GenericDefaultSkipped: GenericDefaultSkipped, GenericDefaultSkippedNonType: GenericDefaultSkippedNonType, GenericParameterOrderPreserved: GenericParameterOrderPreserved, ConstGenericInNonConstContainer: ConstGenericInNonConstContainer, ConstGenericInConstContainer: ConstGenericInConstContainer, NamedConstGenericContainer: NamedConstGenericContainer, InlineConstGenericContainer: InlineConstGenericContainer, InlineRecursiveConstGenericContainer: InlineRecursiveConstGenericContainer, TestCollectionRegister: TestCollectionRegister, TestCollectionRegister: TestCollectionRegister, }; export type Range = { start: T, end: T, }; export type RangeInclusive = { start: T, end: T, }; export type Recursive = { demo: Recursive, }; export type RecursiveInEnum = { demo: RecursiveInEnum }; export type RecursiveInline = { demo: RecursiveInline, }; export type RecursiveMapValue = { demo: { [key in string]: RecursiveMapValue }, }; export type RecursiveTransparent = RecursiveInline; export type RefStruct = TestEnum; export type Regular = { [key in string]: null }; export type Rename = "OneWord" | "TwoWords"; export type RenameSerdeSpecialChar = { b: number, }; export type RenameWithWeirdCharsField = { odata_context: string, }; export type RenameWithWeirdCharsVariant = string; export type RenamedFieldKeys = { empty: string, quote: string, backslash: string, newline: string, line_separator: string, paragraph_separator: string, }; export type RenamedVariantWithSkippedPayload = never; export type Result = { ok: T, err: E, }; export type Second = { a: number, }; export type Seventh = { a: First, b: Second, }; export type SimpleStruct = { a: number, b: string, c: [number, string, number], d: string[], e: string | null, }; /** Some single-line comment */ export type SingleLineComment = /** Some single-line comment */ number | /** Some single-line comment */ { /** Some single-line comment */ a: number }; export type Sixth = { a: First, b: First, }; export type SkipField = { b: number, }; export type SkipNamedFieldInVariant = Record | { b: number }; export type SkipOnlyField = Record; export type SkipStructFields = { a: number, }; export type SkipUnnamedFieldInVariant = never | [number]; export type SkipVariant = string; export type SkipVariant2 = string; export type SkipVariant3 = { a: string }; export type SkippedFieldWithinVariant = never | string; export type SpectaSkipNonTypeField = { a: number, }; export type SpectaTypeOverride = { string_ident: string, u32_ident: number, path: string, tuple: [string, number], }; export type Struct = { a: string, }; export type Struct2 = { a: string, }; export type StructRenameAllUppercase = { a: number, b: number, }; export type StructWithAlias = { field: string, }; export type StructWithAliasAndRename = { field: string, }; export type StructWithMultipleAliases = { field: string, }; export type TagOnStructWithInline = { a: First, b: { a: string, }, }; export type Tenth = string | "B" | { a: string, } | First; export type TestCollectionRegister = never; export type TestEnum = "Unit" | number | [number, number] | { a: number }; export type Third = { a: First, b: { [key in string]: string }, c: First, }; export type ToBeFlattened = { a: string, }; export type TransparentStruct = string; export type TransparentType = TransparentTypeInner; export type TransparentType2 = null; export type TransparentTypeInner = { inner: string, }; export type TransparentTypeWithOverride = string; export type TransparentWithSkip = null; export type TransparentWithSkip2 = string; export type TransparentWithSkip3 = string; export type TupleNested = [number[], [number[], number[]], [number[], number[], number[]]]; export type TupleStruct = string; export type TupleStruct1 = number; export type TupleStruct3 = [number, boolean, string]; export type TupleStructWithRep = string; export type Type = never; export type Unit1 = null; export type Unit2 = Record; export type Unit3 = []; export type Unit4 = null; export type Unit5 = "A"; export type Unit6 = []; export type Unit7 = Record; export type UnitVariants = "A" | "B" | "C"; export type UntaggedVariants = string | number | { id: string } | [string, boolean]; export type UntaggedVariantsKey = string | number; export type UntaggedVariantsWithDuplicateBranches = null | number; export type UntaggedVariantsWithoutValue = string | [number, string] | number; export type UntaggedWithAlias = ({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }; export type ValidMaybeValidKey = { [key in MaybeValidKey]: null }; export type ValidMaybeValidKeyNested = { [key in MaybeValidKey>]: null }; ================================================ FILE: tests/tests/snapshots/test__typescript__ts-export-serde.snap ================================================ --- source: tests/tests/typescript.rs expression: "Typescript::default().export(&types, format).unwrap()" --- // This file has been generated by Specta. Do not edit this file manually. export type A = { a: B, b: { b: number, }, c: B, d: { flattened: number, }, e: { generic_flattened: number, }, }; export type AGenericStruct = { field: Demo, }; export type ActualType = { a: GenericType, }; export type AdjacentlyTagged = { t: "A" } | { t: "B"; c: { id: string, method: string, } } | { t: "C"; c: string }; export type AdjacentlyTaggedWithAlias = { type: "A"; data: { field: string, } } | { type: "B"; data: { other: number, } }; export type B = { b: number, }; export type BasicEnum = "A" | "B"; export type BoxFlattened = BoxedInner; export type BoxInline = { c: { a: number, }, }; export type BoxedInner = { a: number, }; export type BracedStruct = string; export type ChainedGenericDefault = { first: T, second: U, }; /** * Some triple-slash comment * Some more triple-slash comment */ export type CommentedEnum = /** * Some triple-slash comment * Some more triple-slash comment */ ({ A: number }) & { B?: never } | /** * Some triple-slash comment * Some more triple-slash comment */ ({ B: { /** * Some triple-slash comment * Some more triple-slash comment */ a: number, } }) & { A?: never }; /** * Some triple-slash comment * Some more triple-slash comment */ export type CommentedStruct = { /** * Some triple-slash comment * Some more triple-slash comment */ a: number, }; export type ConstGenericInConstContainer = { data: number[], a: number[], d: [number, number], }; export type ConstGenericInNonConstContainer = { data: [number], a: [number, number], d: [number, number], }; export type Container1 = { foo: Generic1, bar: Generic1[], baz: { [key in string]: Generic1 }, }; export type ContainerTypeOverrideEnum = string; export type ContainerTypeOverrideGeneric = string; export type ContainerTypeOverrideStruct = string; export type ContainerTypeOverrideToGeneric = T; export type ContainerTypeOverrideTuple = [string, number]; export type ContainerTypeOverrideTupleGeneric = [T, string]; export type D = { flattened: number, }; export type Demo = { a: A, b: B, }; export type DeprecatedEnumVariants = /** * @deprecated */ "A" | /** * @deprecated Nope */ "B" | /** * @deprecated Nope */ "C"; export type DeprecatedFields = { a: number, /** * @deprecated */ b: string, /** * @deprecated This field is cringe! */ c: string, /** * @deprecated This field is cringe! */ d: string, }; export type DeprecatedTupleVariant = [ /** * @deprecated */ string, /** * @deprecated Nope */ string, /** * @deprecated Nope */ number]; /** * @deprecated */ export type DeprecatedType = { a: number, }; /** * @deprecated Look at you big man using a deprecation message */ export type DeprecatedTypeWithMsg = { a: number, }; /** * @deprecated Look at you big man using a deprecation message */ export type DeprecatedTypeWithMsg2 = { a: number, }; export type DoubleFlattened = { a: ToBeFlattened, b: ToBeFlattened, }; export type Eight = { A: string } | "B"; export type EmptyEnum = never; export type EmptyEnumTagged = never; export type EmptyEnumTaggedWContent = never; export type EmptyEnumUntagged = never; export type EmptyStruct = Record; export type EmptyStructWithTag = { a: "EmptyStructWithTag", }; export type Enum = { t: "A" } | { t: "B" }; export type Enum2 = { t: "C" } | { t: "B" } | { t: "D"; enumField: null }; export type Enum3 = { t: "A"; b: string }; export type EnumMacroAttributes = ({ A: string }) & { D?: never; bbb?: never; cccc?: never } | ({ bbb: number }) & { A?: never; D?: never; cccc?: never } | ({ cccc: number }) & { A?: never; D?: never; bbb?: never } | ({ D: { a: string, bbbbbb: number, } }) & { A?: never; bbb?: never; cccc?: never }; export type EnumReferenceRecordKey = { a: Partial<{ [key in BasicEnum]: number }>, }; export type EnumRenameAllUppercase = "HELLOWORLD" | "VARIANTB" | "TESTINGWORDS"; export type EnumWithMultipleVariantAliases = "Variant" | "Other"; export type EnumWithVariantAlias = "Variant" | "Other"; export type EnumWithVariantAliasAndRename = "renamed_variant" | "Other"; export type ExternallyTagged = "A" | ({ B: { id: string, method: string, } }) & { C?: never } | ({ C: string }) & { B?: never }; export type ExtraBracketsInTupleVariant = { A: string }; export type ExtraBracketsInUnnamedStruct = string; export type First = { a: string, }; export type FlattenA = { a: number, b: number, }; export type FlattenB = { c: number, } & FlattenA; export type FlattenC = { c: number, } & FlattenA; export type FlattenD = { a: FlattenA, c: number, }; export type FlattenE = { b: ({ c: number, }) & (FlattenA), d: number, }; export type FlattenEnum = { tag: "One" } | { tag: "Two" } | { tag: "Three" }; export type FlattenEnumStruct = { outer: string, } & FlattenEnum; export type FlattenF = { b: ({ c: number, }) & (FlattenA), d: number, }; export type FlattenG = { b: FlattenB, d: number, }; export type FlattenOnNestedEnum = { id: string, } & NestedEnum; export type FlattenedInner = Inner; export type Fourth = { a: First, b: { a: string, }, }; export type Generic1 = { value: T, values: T[], }; export type Generic2 = ({ A: A }) & { B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ B: [B, B, B] }) & { A?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ C: C[] }) & { A?: never; B?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ D: A[][][] }) & { A?: never; B?: never; C?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ E: { a: A, b: B, c: C, } }) & { A?: never; B?: never; C?: never; D?: never; X?: never; Y?: never; Z?: never } | ({ X: number[] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; Y?: never; Z?: never } | ({ Y: number }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Z?: never } | ({ Z: number[][] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never }; export type GenericAutoBound = { value: T, values: T[], }; export type GenericAutoBound2 = { value: T, values: T[], }; export type GenericDefault = { value: T, }; export type GenericDefaultSkipped = { value: T, }; export type GenericDefaultSkippedNonType = { value: number, }; export type GenericFlattened = { generic_flattened: T, }; export type GenericNewType1 = T[][]; export type GenericParameterOrderPreserved = { pair: Pair, }; export type GenericStruct = { arg: T, }; export type GenericStruct2 = { a: T, b: [T, T], c: [T, [T, T]], d: [T, T, T], e: [([T, T]), ([T, T]), ([T, T])], f: T[], g: T[][], h: ([([T, T]), ([T, T]), ([T, T])])[], }; export type GenericTuple = [T, T[], T[][]]; export type GenericTupleStruct = T; export type GenericType = "Undefined" | T; export type HasGenericAlias = { [key in number]: string }; export type InlineConstGenericContainer = { b: { data: [number, number], a: [number, number], d: [number, number, number], }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], }, d: [number, number], }; export type InlineEnumField = { A: { a: string, } }; export type InlineFlattenGenerics = { g: InlineFlattenGenericsG, gi: { t: string, }, } & InlineFlattenGenericsG; export type InlineFlattenGenericsG = { t: T, }; export type InlineOptionalType = { optional_field: { a: string, } | null, }; export type InlineRecursiveConstGeneric = { data: number[], a: number[], d: [number, number, number], e: InlineRecursiveConstGeneric, }; export type InlineRecursiveConstGenericContainer = { b: { data: [number, number], a: [number, number], d: [number, number, number], e: InlineRecursiveConstGeneric, }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], e: InlineRecursiveConstGeneric, }, d: [number, number], }; export type InlineStruct = { ref_struct: SimpleStruct, val: number, }; export type InlineTuple = { demo: [string, boolean], }; export type InlineTuple2 = { demo: [{ demo: [string, boolean], }, boolean], }; export type InlinerStruct = { inline_this: { ref_struct: SimpleStruct, val: number, }, dont_inline_this: RefStruct, }; export type Inner = { a: number, } & FlattenedInner; export type InternallyTaggedD = { type: "A", } & { [key in string]: string }; export type InternallyTaggedE = { type: "A" }; export type InternallyTaggedF = { type: "A" }; export type InternallyTaggedFInner = null; export type InternallyTaggedH = { type: "A" }; export type InternallyTaggedHInner = null; export type InternallyTaggedL = { type: "A", } & { type: "A" } | { type: "B" }; export type InternallyTaggedLInner = { type: "A" } | { type: "B" }; export type InternallyTaggedM = { type: "A" }; export type InternallyTaggedMInner = "A" | "B"; export type InternallyTaggedWithAlias = { type: "A"; field: string } | { type: "B"; other: number }; export type InvalidToValidType = { cause: null, }; export type Issue221External = ({ A: { a: string, } }) & { B?: never } | ({ B: { b: string, } }) & { A?: never }; export type Issue221UntaggedMixed = ({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never }; export type Issue221UntaggedSafe = ({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }; export type Issue281 = { default_unity_arguments: string[], }; export type KebabCase = { "test-ing": string, }; export type LifetimeGenericEnum = ({ Borrowed: T }) & { Owned?: never } | ({ Owned: T }) & { Borrowed?: never }; export type LifetimeGenericStruct = { borrowed: T[], owned: T[], }; export type LoadProjectEvent = { event: "started"; data: { projectName: string, } } | { event: "progressTest"; data: { projectName: string, status: string, progress: number, } } | { event: "finished"; data: { projectName: string, } }; export type MacroEnum = ({ Demo: string }) & { Demo2?: never } | ({ Demo2: { demo2: string, } }) & { Demo?: never }; export type MacroStruct = string; export type MacroStruct2 = { demo: string, }; export type MaybeValidKey = T; export type MyEmptyInput = Record; export type MyEnum = ({ A: string }) & { B?: never } | ({ B: number }) & { A?: never }; export type MyEnumAdjacent = { t: "Variant"; c: { inner: First, } }; export type MyEnumExternal = { Variant: { inner: First, } }; export type MyEnumTagged = { type: "Variant"; inner: First }; export type MyEnumUntagged = { inner: First }; export type NamedConstGeneric = { data: number[], a: number[], d: [number, number], }; export type NamedConstGenericContainer = { a: NamedConstGeneric, b: NamedConstGeneric, d: [number, number], }; export type NestedEnum = { type: "a"; value: string } | { type: "b"; value: number }; export type Ninth = { t: "A"; c: string } | { t: "B" } | { t: "C"; c: { a: string, } } | { t: "D"; c: First }; export type NonOptional = string | null; export type OptionalInEnum = ({ A?: string | null }) & { B?: never; C?: never } | ({ B: { a: string | null, } }) & { A?: never; C?: never } | ({ C: { a?: string | null, } }) & { A?: never; B?: never }; export type OptionalOnNamedField = string | null; export type OptionalOnTransparentNamedField = { b: string | null, }; export type OverridenStruct = { overriden_field: string, }; export type Pair = { first: Z, second: A, }; export type PlaceholderInnerField = { a: string, }; export type Primitives = { i8: number, i16: number, i32: number, u8: number, u16: number, u32: number, f32: number, f64: number, bool: boolean, char: string, "Range": Range, "RangeInclusive": RangeInclusive, "()": null, "(String, i32)": [string, number], "(String, i32, bool)": [string, number, boolean], "((String, i32), (bool, char, bool), ())": [[string, number], [boolean, string, boolean], null], "(bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool)": [boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean], "(Vec, Vec)": [number[], boolean[]], String: string, PathBuf: string, IpAddr: string, Ipv4Addr: string, Ipv6Addr: string, SocketAddr: string, SocketAddrV4: string, SocketAddrV6: string, "Cow<'static, str>": string, "Cow<'static, i32>": number, "&'static str": string, "&'static bool": boolean, "&'static i32": number, "Vec": number[], "&'static [i32]": number[], "&'static [i32; 3]": [number, number, number], "[i32; 3]": [number, number, number], "Vec": MyEnum[], "&'static [MyEnum]": MyEnum[], "&'static [MyEnum; 6]": [MyEnum, MyEnum, MyEnum, MyEnum, MyEnum, MyEnum], "[MyEnum; 2]": [MyEnum, MyEnum], "&'static [i32; 1]": [number], "&'static [i32; 0]": [], "Option": number | null, "Option<()>": null, "Option>": number[] | null, "Result": Result, "Vec>>": (number | null)[], "Option>>": number[] | null, "[Vec; 3]": [string[], string[], string[]], "Option>": string | null, "Option>>": string | null, "PhantomData<()>": null, "PhantomData": null, Infallible: never, Unit1: Unit1, Unit2: Unit2, Unit3: Unit3, Unit4: Unit4, Unit5: Unit5, Unit6: Unit6, Unit7: Unit7, SimpleStruct: SimpleStruct, TupleStruct1: TupleStruct1, TupleStruct3: TupleStruct3, TestEnum: TestEnum, RefStruct: RefStruct, InlinerStruct: InlinerStruct, "GenericStruct": GenericStruct, "GenericStruct": GenericStruct, FlattenEnumStruct: FlattenEnumStruct, OverridenStruct: OverridenStruct, HasGenericAlias: HasGenericAlias, EnumMacroAttributes: EnumMacroAttributes, InlineEnumField: InlineEnumField, InlineOptionalType: InlineOptionalType, Rename: Rename, TransparentType: TransparentType, TransparentType2: TransparentType2, TransparentTypeWithOverride: TransparentTypeWithOverride, "[Option; 3]": [(number | null), (number | null), (number | null)], "HashMap": Partial<{ [key in BasicEnum]: null }>, "HashMap": Partial<{ [key in BasicEnum]: number }>, "Option>>>": number | null, "Vec": PlaceholderInnerField[], EnumReferenceRecordKey: EnumReferenceRecordKey, FlattenOnNestedEnum: FlattenOnNestedEnum, MyEmptyInput: MyEmptyInput, "(String)": string, "(String,)": [string], ExtraBracketsInTupleVariant: ExtraBracketsInTupleVariant, ExtraBracketsInUnnamedStruct: ExtraBracketsInUnnamedStruct, "Vec": MyEnum[], InlineTuple: InlineTuple, InlineTuple2: InlineTuple2, "Box": string, "Box": string, SkippedFieldWithinVariant: SkippedFieldWithinVariant, KebabCase: KebabCase, "&[&str]": string[], "Issue281<'_>": Issue281, "LifetimeGenericStruct<'_, i32>": LifetimeGenericStruct, "LifetimeGenericEnum<'_, i32>": LifetimeGenericEnum, RenameWithWeirdCharsField: RenameWithWeirdCharsField, RenameWithWeirdCharsVariant: RenameWithWeirdCharsVariant, RenamedFieldKeys: RenamedFieldKeys, RenamedVariantWithSkippedPayload: RenamedVariantWithSkippedPayload, "type_type::Type": Type, ActualType: ActualType, SpectaTypeOverride: SpectaTypeOverride, ContainerTypeOverrideStruct: ContainerTypeOverrideStruct, ContainerTypeOverrideEnum: ContainerTypeOverrideEnum, "ContainerTypeOverrideGeneric>": ContainerTypeOverrideGeneric, "ContainerTypeOverrideToGeneric": ContainerTypeOverrideToGeneric, ContainerTypeOverrideTuple: ContainerTypeOverrideTuple, "ContainerTypeOverrideTupleGeneric": ContainerTypeOverrideTupleGeneric, InvalidToValidType: InvalidToValidType, TupleStruct: TupleStruct, TupleStructWithRep: TupleStructWithRep, "GenericTupleStruct": GenericTupleStruct, BracedStruct: BracedStruct, Struct: StructNew, Struct2: Struct2, Enum: Enum, Enum2: Enum2, Enum3: Enum3, StructRenameAllUppercase: StructRenameAllUppercase, RenameSerdeSpecialChar: RenameSerdeSpecialChar, EnumRenameAllUppercase: EnumRenameAllUppercase, Recursive: Recursive, RecursiveMapValue: RecursiveMapValue, RecursiveTransparent: RecursiveTransparent, RecursiveInEnum: RecursiveInEnum, NonOptional: NonOptional, OptionalOnNamedField: OptionalOnNamedField, OptionalOnTransparentNamedField: OptionalOnTransparentNamedField, OptionalInEnum: OptionalInEnum, UntaggedVariants: UntaggedVariants, UntaggedVariantsWithoutValue: UntaggedVariantsWithoutValue, UntaggedVariantsWithDuplicateBranches: UntaggedVariantsWithDuplicateBranches, "HashMap": { [key in string]: null }, Regular: Regular, "HashMap": { [key in never]: null }, "HashMap": { [key in TransparentStruct]: null }, "HashMap": Partial<{ [key in UnitVariants]: null }>, "HashMap": Partial<{ [key in UntaggedVariantsKey]: null }>, ValidMaybeValidKey: ValidMaybeValidKey, ValidMaybeValidKeyNested: ValidMaybeValidKeyNested, MacroStruct: MacroStruct, MacroStruct2: MacroStruct2, MacroEnum: MacroEnum, DeprecatedType: DeprecatedType, DeprecatedTypeWithMsg: DeprecatedTypeWithMsg, DeprecatedTypeWithMsg2: DeprecatedTypeWithMsg2, DeprecatedFields: DeprecatedFields, DeprecatedTupleVariant: DeprecatedTupleVariant, DeprecatedEnumVariants: DeprecatedEnumVariants, CommentedStruct: CommentedStruct, CommentedEnum: CommentedEnum, SingleLineComment: SingleLineComment, NonGeneric: Demo, "HalfGenericA": Demo, "HalfGenericB": Demo, "FullGeneric": Demo, "Another": Demo, "MapA": { [key in string]: number }, "MapB": { [key in number]: string }, "MapC": { [key in string]: AGenericStruct }, "AGenericStruct": AGenericStruct, A: A, DoubleFlattened: DoubleFlattened, FlattenedInner: FlattenedInner, BoxFlattened: BoxFlattened, BoxInline: BoxInline, First: First, Second: Second, Third: Third, Fourth: Fourth, TagOnStructWithInline: TagOnStructWithInline, Sixth: Sixth, Seventh: Seventh, Eight: Eight, Ninth: Ninth, Tenth: Tenth, MyEnumTagged: MyEnumTagged, MyEnumExternal: MyEnumExternal, MyEnumAdjacent: MyEnumAdjacent, MyEnumUntagged: MyEnumUntagged, EmptyStruct: EmptyStruct, EmptyStructWithTag: EmptyStructWithTag, AdjacentlyTagged: AdjacentlyTagged, LoadProjectEvent: LoadProjectEvent, ExternallyTagged: ExternallyTagged, Issue221External: Issue221External, InternallyTaggedD: InternallyTaggedD, InternallyTaggedE: InternallyTaggedE, InternallyTaggedF: InternallyTaggedF, InternallyTaggedH: InternallyTaggedH, InternallyTaggedL: InternallyTaggedL, InternallyTaggedM: InternallyTaggedM, StructWithAlias: StructWithAlias, StructWithMultipleAliases: StructWithMultipleAliases, StructWithAliasAndRename: StructWithAliasAndRename, EnumWithVariantAlias: EnumWithVariantAlias, EnumWithMultipleVariantAliases: EnumWithMultipleVariantAliases, EnumWithVariantAliasAndRename: EnumWithVariantAliasAndRename, InternallyTaggedWithAlias: InternallyTaggedWithAlias, AdjacentlyTaggedWithAlias: AdjacentlyTaggedWithAlias, UntaggedWithAlias: UntaggedWithAlias, Issue221UntaggedSafe: Issue221UntaggedSafe, Issue221UntaggedMixed: Issue221UntaggedMixed, EmptyEnum: EmptyEnum, EmptyEnumTagged: EmptyEnumTagged, EmptyEnumTaggedWContent: EmptyEnumTaggedWContent, EmptyEnumUntagged: EmptyEnumUntagged, SkipOnlyField: SkipOnlyField, SkipField: SkipField, SkipVariant: SkipVariant, SkipUnnamedFieldInVariant: SkipUnnamedFieldInVariant, SkipNamedFieldInVariant: SkipNamedFieldInVariant, TransparentWithSkip: TransparentWithSkip, TransparentWithSkip2: TransparentWithSkip2, TransparentWithSkip3: TransparentWithSkip3, SkipVariant2: SkipVariant2, SkipVariant3: SkipVariant3, SkipStructFields: SkipStructFields, SpectaSkipNonTypeField: SpectaSkipNonTypeField, FlattenA: FlattenA, FlattenB: FlattenB, FlattenC: FlattenC, FlattenD: FlattenD, FlattenE: FlattenE, FlattenF: FlattenF, FlattenG: FlattenG, TupleNested: TupleNested, "Generic1<()>": Generic1, "GenericAutoBound<()>": GenericAutoBound, "GenericAutoBound2<()>": GenericAutoBound2, Container1: Container1, "Generic2<(), String, i32>": Generic2, "GenericNewType1<()>": GenericNewType1, "GenericTuple<()>": GenericTuple, "GenericStruct2<()>": GenericStruct2, "InlineGenericNewtype": string, "InlineGenericNested": [string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | ({ Unnamed: string }) & { Named?: never } | ({ Named: { value: string, } }) & { Unnamed?: never }], "InlineFlattenGenericsG<()>": InlineFlattenGenericsG, InlineFlattenGenerics: InlineFlattenGenerics, GenericDefault: GenericDefault, ChainedGenericDefault: ChainedGenericDefault, "ChainedGenericDefault": ChainedGenericDefault, "ChainedGenericDefault": ChainedGenericDefault, "ChainedGenericDefault": ChainedGenericDefault, GenericDefaultSkipped: GenericDefaultSkipped, GenericDefaultSkippedNonType: GenericDefaultSkippedNonType, GenericParameterOrderPreserved: GenericParameterOrderPreserved, ConstGenericInNonConstContainer: ConstGenericInNonConstContainer, ConstGenericInConstContainer: ConstGenericInConstContainer, NamedConstGenericContainer: NamedConstGenericContainer, InlineConstGenericContainer: InlineConstGenericContainer, InlineRecursiveConstGenericContainer: InlineRecursiveConstGenericContainer, TestCollectionRegister: TestCollectionRegister, TestCollectionRegister: TestCollectionRegister, }; export type Range = { start: T, end: T, }; export type RangeInclusive = { start: T, end: T, }; export type Recursive = { demo: Recursive, }; export type RecursiveInEnum = { A: { demo: RecursiveInEnum, } }; export type RecursiveInline = RecursiveInline; export type RecursiveMapValue = { demo: { [key in string]: RecursiveMapValue }, }; export type RecursiveTransparent = RecursiveInline; export type RefStruct = TestEnum; export type Regular = { [key in string]: null }; export type Rename = "OneWord" | "Two words"; export type RenameSerdeSpecialChar = { "a/b": number, }; export type RenameWithWeirdCharsField = { "@odata.context": string, }; export type RenameWithWeirdCharsVariant = { "@odata.context": string }; export type RenamedFieldKeys = { "": string, "a\"b": string, "a\\b": string, "line\nbreak": string, "line\u2028break": string, "line\u2029break": string, }; export type RenamedVariantWithSkippedPayload = "a-b"; export type Result = { ok: T, err: E, }; export type Second = { a: number, }; export type Seventh = { a: First, b: Second, }; export type SimpleStruct = { a: number, b: string, c: [number, string, number], d: string[], e: string | null, }; /** Some single-line comment */ export type SingleLineComment = /** Some single-line comment */ ({ A: number }) & { B?: never } | /** Some single-line comment */ ({ B: { /** Some single-line comment */ a: number, } }) & { A?: never }; export type Sixth = { a: First, b: First, }; export type SkipField = { b: number, }; export type SkipNamedFieldInVariant = ({ A: Record }) & { B?: never } | ({ B: { b: number, } }) & { A?: never }; export type SkipOnlyField = Record; export type SkipStructFields = { a: number, }; export type SkipUnnamedFieldInVariant = "A" | { B: [number] }; export type SkipVariant = { A: string }; export type SkipVariant2 = { tag: "A"; data: string }; export type SkipVariant3 = { A: { a: string, } }; export type SkippedFieldWithinVariant = { type: "A" } | { type: "B"; data: string }; export type SpectaSkipNonTypeField = { a: number, }; export type SpectaTypeOverride = { string_ident: string, u32_ident: number, path: string, tuple: [string, number], }; export type Struct2 = { b: string, }; export type StructNew = { t: "StructNew", a: string, }; export type StructRenameAllUppercase = { A: number, B: number, }; export type StructWithAlias = { field: string, }; export type StructWithAliasAndRename = { renamed_field: string, }; export type StructWithMultipleAliases = { field: string, }; export type TagOnStructWithInline = { type: "TagOnStructWithInline", a: First, b: { a: string, }, }; export type Tenth = string | "B" | { a: string, } | First; export type TestCollectionRegister = never; export type TestEnum = "Unit" | ({ Single: number }) & { Multiple?: never; Struct?: never } | ({ Multiple: [number, number] }) & { Single?: never; Struct?: never } | ({ Struct: { a: number, } }) & { Multiple?: never; Single?: never }; export type Third = { b: { [key in string]: string }, c: First, } & First; export type ToBeFlattened = { a: string, }; export type TransparentStruct = string; export type TransparentType = TransparentTypeInner; export type TransparentType2 = null; export type TransparentTypeInner = { inner: string, }; export type TransparentTypeWithOverride = string; export type TransparentWithSkip = null; export type TransparentWithSkip2 = string; export type TransparentWithSkip3 = string; export type TupleNested = [number[], [number[], number[]], [number[], number[], number[]]]; export type TupleStruct = string; export type TupleStruct1 = number; export type TupleStruct3 = [number, boolean, string]; export type TupleStructWithRep = string; export type Type = never; export type Unit1 = null; export type Unit2 = Record; export type Unit3 = []; export type Unit4 = null; export type Unit5 = "A"; export type Unit6 = { A: null }; export type Unit7 = { A: Record }; export type UnitVariants = "A" | "B" | "C"; export type UntaggedVariants = string | number | { id: string } | [string, boolean]; export type UntaggedVariantsKey = string | number; export type UntaggedVariantsWithDuplicateBranches = null | number; export type UntaggedVariantsWithoutValue = string | [number, string] | number; export type UntaggedWithAlias = ({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }; export type ValidMaybeValidKey = { [key in MaybeValidKey]: null }; export type ValidMaybeValidKeyNested = { [key in MaybeValidKey>]: null }; ================================================ FILE: tests/tests/snapshots/test__typescript__ts-export-serde_phases.snap ================================================ --- source: tests/tests/typescript.rs expression: "Typescript::default().export(&types, format).unwrap()" --- // This file has been generated by Specta. Do not edit this file manually. export type A = { a: B, b: { b: number, }, c: B, d: { flattened: number, }, e: { generic_flattened: number, }, }; export type AGenericStruct = { field: Demo, }; export type ActualType = { a: GenericType, }; export type AdjacentlyTagged = { t: "A" } | { t: "B"; c: { id: string, method: string, } } | { t: "C"; c: string }; export type AdjacentlyTaggedWithAlias = { type: "A"; data: { field: string, } } | { type: "B"; data: { other: number, } }; export type B = { b: number, }; export type BasicEnum = "A" | "B"; export type BoxFlattened = BoxedInner; export type BoxInline = { c: { a: number, }, }; export type BoxedInner = { a: number, }; export type BracedStruct = string; export type ChainedGenericDefault = { first: T, second: U, }; /** * Some triple-slash comment * Some more triple-slash comment */ export type CommentedEnum = /** * Some triple-slash comment * Some more triple-slash comment */ ({ A: number }) & { B?: never } | /** * Some triple-slash comment * Some more triple-slash comment */ ({ B: { /** * Some triple-slash comment * Some more triple-slash comment */ a: number, } }) & { A?: never }; /** * Some triple-slash comment * Some more triple-slash comment */ export type CommentedStruct = { /** * Some triple-slash comment * Some more triple-slash comment */ a: number, }; export type ConstGenericInConstContainer = { data: number[], a: number[], d: [number, number], }; export type ConstGenericInNonConstContainer = { data: [number], a: [number, number], d: [number, number], }; export type Container1 = { foo: Generic1, bar: Generic1[], baz: { [key in string]: Generic1 }, }; export type ContainerTypeOverrideEnum = string; export type ContainerTypeOverrideGeneric = string; export type ContainerTypeOverrideStruct = string; export type ContainerTypeOverrideToGeneric = T; export type ContainerTypeOverrideTuple = [string, number]; export type ContainerTypeOverrideTupleGeneric = [T, string]; export type D = { flattened: number, }; export type Demo = { a: A, b: B, }; export type DeprecatedEnumVariants = /** * @deprecated */ "A" | /** * @deprecated Nope */ "B" | /** * @deprecated Nope */ "C"; export type DeprecatedFields = { a: number, /** * @deprecated */ b: string, /** * @deprecated This field is cringe! */ c: string, /** * @deprecated This field is cringe! */ d: string, }; export type DeprecatedTupleVariant = [ /** * @deprecated */ string, /** * @deprecated Nope */ string, /** * @deprecated Nope */ number]; /** * @deprecated */ export type DeprecatedType = { a: number, }; /** * @deprecated Look at you big man using a deprecation message */ export type DeprecatedTypeWithMsg = { a: number, }; /** * @deprecated Look at you big man using a deprecation message */ export type DeprecatedTypeWithMsg2 = { a: number, }; export type DoubleFlattened = { a: ToBeFlattened, b: ToBeFlattened, }; export type Eight = { A: string } | "B"; export type EmptyEnum = never; export type EmptyEnumTagged = never; export type EmptyEnumTaggedWContent = never; export type EmptyEnumUntagged = never; export type EmptyStruct = Record; export type EmptyStructWithTag = { a: "EmptyStructWithTag", }; export type Enum = { t: "A" } | { t: "B" }; export type Enum2 = { t: "C" } | { t: "B" } | { t: "D"; enumField: null }; export type Enum3 = { t: "A"; b: string }; export type EnumMacroAttributes = ({ A: string }) & { D?: never; bbb?: never; cccc?: never } | ({ bbb: number }) & { A?: never; D?: never; cccc?: never } | ({ cccc: number }) & { A?: never; D?: never; bbb?: never } | ({ D: { a: string, bbbbbb: number, } }) & { A?: never; bbb?: never; cccc?: never }; export type EnumReferenceRecordKey = { a: Partial<{ [key in BasicEnum]: number }>, }; export type EnumRenameAllUppercase = "HELLOWORLD" | "VARIANTB" | "TESTINGWORDS"; export type EnumWithMultipleVariantAliases = "Variant" | "Other"; export type EnumWithVariantAlias = "Variant" | "Other"; export type EnumWithVariantAliasAndRename = "renamed_variant" | "Other"; export type ExternallyTagged = "A" | ({ B: { id: string, method: string, } }) & { C?: never } | ({ C: string }) & { B?: never }; export type ExtraBracketsInTupleVariant = { A: string }; export type ExtraBracketsInUnnamedStruct = string; export type First = { a: string, }; export type FlattenA = { a: number, b: number, }; export type FlattenB = { c: number, } & FlattenA; export type FlattenC = { c: number, } & FlattenA; export type FlattenD = { a: FlattenA, c: number, }; export type FlattenE = { b: ({ c: number, }) & (FlattenA), d: number, }; export type FlattenEnum = { tag: "One" } | { tag: "Two" } | { tag: "Three" }; export type FlattenEnumStruct = { outer: string, } & FlattenEnum; export type FlattenF = { b: ({ c: number, }) & (FlattenA), d: number, }; export type FlattenG = { b: FlattenB, d: number, }; export type FlattenOnNestedEnum = { id: string, } & NestedEnum; export type FlattenedInner = Inner; export type Fourth = { a: First, b: { a: string, }, }; export type Generic1 = { value: T, values: T[], }; export type Generic2 = ({ A: A }) & { B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ B: [B, B, B] }) & { A?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ C: C[] }) & { A?: never; B?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ D: A[][][] }) & { A?: never; B?: never; C?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ E: { a: A, b: B, c: C, } }) & { A?: never; B?: never; C?: never; D?: never; X?: never; Y?: never; Z?: never } | ({ X: number[] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; Y?: never; Z?: never } | ({ Y: number }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Z?: never } | ({ Z: number[][] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never }; export type GenericAutoBound = { value: T, values: T[], }; export type GenericAutoBound2 = { value: T, values: T[], }; export type GenericDefault = { value: T, }; export type GenericDefaultSkipped = { value: T, }; export type GenericDefaultSkippedNonType = { value: number, }; export type GenericFlattened = { generic_flattened: T, }; export type GenericNewType1 = T[][]; export type GenericParameterOrderPreserved = { pair: Pair, }; export type GenericStruct = { arg: T, }; export type GenericStruct2 = { a: T, b: [T, T], c: [T, [T, T]], d: [T, T, T], e: [([T, T]), ([T, T]), ([T, T])], f: T[], g: T[][], h: ([([T, T]), ([T, T]), ([T, T])])[], }; export type GenericTuple = [T, T[], T[][]]; export type GenericTupleStruct = T; export type GenericType = "Undefined" | T; export type HasGenericAlias = { [key in number]: string }; export type InlineConstGenericContainer = { b: { data: [number, number], a: [number, number], d: [number, number, number], }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], }, d: [number, number], }; export type InlineEnumField = { A: { a: string, } }; export type InlineFlattenGenerics = { g: InlineFlattenGenericsG, gi: { t: string, }, } & InlineFlattenGenericsG; export type InlineFlattenGenericsG = { t: T, }; export type InlineOptionalType = { optional_field: { a: string, } | null, }; export type InlineRecursiveConstGeneric = { data: number[], a: number[], d: [number, number, number], e: InlineRecursiveConstGeneric, }; export type InlineRecursiveConstGenericContainer = { b: { data: [number, number], a: [number, number], d: [number, number, number], e: InlineRecursiveConstGeneric, }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], e: InlineRecursiveConstGeneric, }, d: [number, number], }; export type InlineStruct = { ref_struct: SimpleStruct, val: number, }; export type InlineTuple = { demo: [string, boolean], }; export type InlineTuple2 = { demo: [{ demo: [string, boolean], }, boolean], }; export type InlinerStruct = { inline_this: { ref_struct: SimpleStruct, val: number, }, dont_inline_this: RefStruct, }; export type Inner = { a: number, } & FlattenedInner; export type InternallyTaggedD = { type: "A", } & { [key in string]: string }; export type InternallyTaggedE = { type: "A" }; export type InternallyTaggedF = { type: "A" }; export type InternallyTaggedFInner = null; export type InternallyTaggedH = { type: "A" }; export type InternallyTaggedHInner = null; export type InternallyTaggedL = { type: "A", } & { type: "A" } | { type: "B" }; export type InternallyTaggedLInner = { type: "A" } | { type: "B" }; export type InternallyTaggedM = { type: "A" }; export type InternallyTaggedMInner = "A" | "B"; export type InternallyTaggedWithAlias = { type: "A"; field: string } | { type: "B"; other: number }; export type InvalidToValidType = { cause: null, }; export type Issue221External = ({ A: { a: string, } }) & { B?: never } | ({ B: { b: string, } }) & { A?: never }; export type Issue221UntaggedMixed = ({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never }; export type Issue221UntaggedSafe = ({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }; export type Issue281 = { default_unity_arguments: string[], }; /** https://github.com/specta-rs/specta/issues/374 */ export type Issue374 = Issue374_Serialize | Issue374_Deserialize; /** https://github.com/specta-rs/specta/issues/374 */ export type Issue374_Deserialize = { foo?: boolean, bar?: boolean, }; /** https://github.com/specta-rs/specta/issues/374 */ export type Issue374_Serialize = { foo?: boolean, bar?: boolean, }; export type KebabCase = { "test-ing": string, }; export type LifetimeGenericEnum = ({ Borrowed: T }) & { Owned?: never } | ({ Owned: T }) & { Borrowed?: never }; export type LifetimeGenericStruct = { borrowed: T[], owned: T[], }; export type LoadProjectEvent = { event: "started"; data: { projectName: string, } } | { event: "progressTest"; data: { projectName: string, status: string, progress: number, } } | { event: "finished"; data: { projectName: string, } }; export type MacroEnum = ({ Demo: string }) & { Demo2?: never } | ({ Demo2: { demo2: string, } }) & { Demo?: never }; export type MacroStruct = string; export type MacroStruct2 = { demo: string, }; export type MaybeValidKey = T; export type MyEmptyInput = Record; export type MyEnum = ({ A: string }) & { B?: never } | ({ B: number }) & { A?: never }; export type MyEnumAdjacent = { t: "Variant"; c: { inner: First, } }; export type MyEnumExternal = { Variant: { inner: First, } }; export type MyEnumTagged = { type: "Variant"; inner: First }; export type MyEnumUntagged = { inner: First }; export type NamedConstGeneric = { data: number[], a: number[], d: [number, number], }; export type NamedConstGenericContainer = { a: NamedConstGeneric, b: NamedConstGeneric, d: [number, number], }; export type NestedEnum = { type: "a"; value: string } | { type: "b"; value: number }; export type Ninth = { t: "A"; c: string } | { t: "B" } | { t: "C"; c: { a: string, } } | { t: "D"; c: First }; export type NonOptional = string | null; export type Optional = Optional_Serialize | Optional_Deserialize; export type OptionalInEnum = ({ A?: string | null }) & { B?: never; C?: never } | ({ B: { a: string | null, } }) & { A?: never; C?: never } | ({ C: { a?: string | null, } }) & { A?: never; B?: never }; export type OptionalOnNamedField = string | null; export type OptionalOnTransparentNamedField = { b: string | null, }; export type Optional_Deserialize = { a: number | null, b?: number | null, c: string | null, d?: boolean, }; export type Optional_Serialize = { a: number | null, b?: number | null, c?: string | null, d: boolean, }; export type OverridenStruct = { overriden_field: string, }; export type Pair = { first: Z, second: A, }; export type PlaceholderInnerField = { a: string, }; export type Primitives = { i8: number, i16: number, i32: number, u8: number, u16: number, u32: number, f32: number, f64: number, bool: boolean, char: string, "Range": Range, "RangeInclusive": RangeInclusive, "()": null, "(String, i32)": [string, number], "(String, i32, bool)": [string, number, boolean], "((String, i32), (bool, char, bool), ())": [[string, number], [boolean, string, boolean], null], "(bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool)": [boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean], "(Vec, Vec)": [number[], boolean[]], String: string, PathBuf: string, IpAddr: string, Ipv4Addr: string, Ipv6Addr: string, SocketAddr: string, SocketAddrV4: string, SocketAddrV6: string, "Cow<'static, str>": string, "Cow<'static, i32>": number, "&'static str": string, "&'static bool": boolean, "&'static i32": number, "Vec": number[], "&'static [i32]": number[], "&'static [i32; 3]": [number, number, number], "[i32; 3]": [number, number, number], "Vec": MyEnum[], "&'static [MyEnum]": MyEnum[], "&'static [MyEnum; 6]": [MyEnum, MyEnum, MyEnum, MyEnum, MyEnum, MyEnum], "[MyEnum; 2]": [MyEnum, MyEnum], "&'static [i32; 1]": [number], "&'static [i32; 0]": [], "Option": number | null, "Option<()>": null, "Option>": number[] | null, "Result": Result, "Vec>>": (number | null)[], "Option>>": number[] | null, "[Vec; 3]": [string[], string[], string[]], "Option>": string | null, "Option>>": string | null, "PhantomData<()>": null, "PhantomData": null, Infallible: never, Unit1: Unit1, Unit2: Unit2, Unit3: Unit3, Unit4: Unit4, Unit5: Unit5, Unit6: Unit6, Unit7: Unit7, SimpleStruct: SimpleStruct, TupleStruct1: TupleStruct1, TupleStruct3: TupleStruct3, TestEnum: TestEnum, RefStruct: RefStruct, InlinerStruct: InlinerStruct, "GenericStruct": GenericStruct, "GenericStruct": GenericStruct, FlattenEnumStruct: FlattenEnumStruct, OverridenStruct: OverridenStruct, HasGenericAlias: HasGenericAlias, EnumMacroAttributes: EnumMacroAttributes, InlineEnumField: InlineEnumField, InlineOptionalType: InlineOptionalType, Rename: Rename, TransparentType: TransparentType, TransparentType2: TransparentType2, TransparentTypeWithOverride: TransparentTypeWithOverride, "[Option; 3]": [(number | null), (number | null), (number | null)], "HashMap": Partial<{ [key in BasicEnum]: null }>, "HashMap": Partial<{ [key in BasicEnum]: number }>, "Option>>>": number | null, "Vec": PlaceholderInnerField[], EnumReferenceRecordKey: EnumReferenceRecordKey, FlattenOnNestedEnum: FlattenOnNestedEnum, MyEmptyInput: MyEmptyInput, "(String)": string, "(String,)": [string], ExtraBracketsInTupleVariant: ExtraBracketsInTupleVariant, ExtraBracketsInUnnamedStruct: ExtraBracketsInUnnamedStruct, "Vec": MyEnum[], InlineTuple: InlineTuple, InlineTuple2: InlineTuple2, "Box": string, "Box": string, SkippedFieldWithinVariant: SkippedFieldWithinVariant, KebabCase: KebabCase, "&[&str]": string[], "Issue281<'_>": Issue281, "LifetimeGenericStruct<'_, i32>": LifetimeGenericStruct, "LifetimeGenericEnum<'_, i32>": LifetimeGenericEnum, RenameWithWeirdCharsField: RenameWithWeirdCharsField, RenameWithWeirdCharsVariant: RenameWithWeirdCharsVariant, RenamedFieldKeys: RenamedFieldKeys, RenamedVariantWithSkippedPayload: RenamedVariantWithSkippedPayload, "type_type::Type": Type, ActualType: ActualType, SpectaTypeOverride: SpectaTypeOverride, ContainerTypeOverrideStruct: ContainerTypeOverrideStruct, ContainerTypeOverrideEnum: ContainerTypeOverrideEnum, "ContainerTypeOverrideGeneric>": ContainerTypeOverrideGeneric, "ContainerTypeOverrideToGeneric": ContainerTypeOverrideToGeneric, ContainerTypeOverrideTuple: ContainerTypeOverrideTuple, "ContainerTypeOverrideTupleGeneric": ContainerTypeOverrideTupleGeneric, InvalidToValidType: InvalidToValidType, TupleStruct: TupleStruct, TupleStructWithRep: TupleStructWithRep, "GenericTupleStruct": GenericTupleStruct, BracedStruct: BracedStruct, Struct: StructNew, Struct2: Struct2, Enum: Enum, Enum2: Enum2, Enum3: Enum3, StructRenameAllUppercase: StructRenameAllUppercase, RenameSerdeSpecialChar: RenameSerdeSpecialChar, EnumRenameAllUppercase: EnumRenameAllUppercase, Recursive: Recursive, RecursiveMapValue: RecursiveMapValue, RecursiveTransparent: RecursiveTransparent, RecursiveInEnum: RecursiveInEnum, NonOptional: NonOptional, OptionalOnNamedField: OptionalOnNamedField, OptionalOnTransparentNamedField: OptionalOnTransparentNamedField, OptionalInEnum: OptionalInEnum, UntaggedVariants: UntaggedVariants, UntaggedVariantsWithoutValue: UntaggedVariantsWithoutValue, UntaggedVariantsWithDuplicateBranches: UntaggedVariantsWithDuplicateBranches, "HashMap": { [key in string]: null }, Regular: Regular, "HashMap": { [key in never]: null }, "HashMap": { [key in TransparentStruct]: null }, "HashMap": Partial<{ [key in UnitVariants]: null }>, "HashMap": Partial<{ [key in UntaggedVariantsKey]: null }>, ValidMaybeValidKey: ValidMaybeValidKey, ValidMaybeValidKeyNested: ValidMaybeValidKeyNested, MacroStruct: MacroStruct, MacroStruct2: MacroStruct2, MacroEnum: MacroEnum, DeprecatedType: DeprecatedType, DeprecatedTypeWithMsg: DeprecatedTypeWithMsg, DeprecatedTypeWithMsg2: DeprecatedTypeWithMsg2, DeprecatedFields: DeprecatedFields, DeprecatedTupleVariant: DeprecatedTupleVariant, DeprecatedEnumVariants: DeprecatedEnumVariants, CommentedStruct: CommentedStruct, CommentedEnum: CommentedEnum, SingleLineComment: SingleLineComment, NonGeneric: Demo, "HalfGenericA": Demo, "HalfGenericB": Demo, "FullGeneric": Demo, "Another": Demo, "MapA": { [key in string]: number }, "MapB": { [key in number]: string }, "MapC": { [key in string]: AGenericStruct }, "AGenericStruct": AGenericStruct, A: A, DoubleFlattened: DoubleFlattened, FlattenedInner: FlattenedInner, BoxFlattened: BoxFlattened, BoxInline: BoxInline, First: First, Second: Second, Third: Third, Fourth: Fourth, TagOnStructWithInline: TagOnStructWithInline, Sixth: Sixth, Seventh: Seventh, Eight: Eight, Ninth: Ninth, Tenth: Tenth, MyEnumTagged: MyEnumTagged, MyEnumExternal: MyEnumExternal, MyEnumAdjacent: MyEnumAdjacent, MyEnumUntagged: MyEnumUntagged, EmptyStruct: EmptyStruct, EmptyStructWithTag: EmptyStructWithTag, AdjacentlyTagged: AdjacentlyTagged, LoadProjectEvent: LoadProjectEvent, ExternallyTagged: ExternallyTagged, Issue221External: Issue221External, InternallyTaggedD: InternallyTaggedD, InternallyTaggedE: InternallyTaggedE, InternallyTaggedF: InternallyTaggedF, InternallyTaggedH: InternallyTaggedH, InternallyTaggedL: InternallyTaggedL, InternallyTaggedM: InternallyTaggedM, StructWithAlias: StructWithAlias, StructWithMultipleAliases: StructWithMultipleAliases, StructWithAliasAndRename: StructWithAliasAndRename, EnumWithVariantAlias: EnumWithVariantAlias, EnumWithMultipleVariantAliases: EnumWithMultipleVariantAliases, EnumWithVariantAliasAndRename: EnumWithVariantAliasAndRename, InternallyTaggedWithAlias: InternallyTaggedWithAlias, AdjacentlyTaggedWithAlias: AdjacentlyTaggedWithAlias, UntaggedWithAlias: UntaggedWithAlias, Issue221UntaggedSafe: Issue221UntaggedSafe, Issue221UntaggedMixed: Issue221UntaggedMixed, EmptyEnum: EmptyEnum, EmptyEnumTagged: EmptyEnumTagged, EmptyEnumTaggedWContent: EmptyEnumTaggedWContent, EmptyEnumUntagged: EmptyEnumUntagged, SkipOnlyField: SkipOnlyField, SkipField: SkipField, SkipVariant: SkipVariant, SkipUnnamedFieldInVariant: SkipUnnamedFieldInVariant, SkipNamedFieldInVariant: SkipNamedFieldInVariant, TransparentWithSkip: TransparentWithSkip, TransparentWithSkip2: TransparentWithSkip2, TransparentWithSkip3: TransparentWithSkip3, SkipVariant2: SkipVariant2, SkipVariant3: SkipVariant3, SkipStructFields: SkipStructFields, SpectaSkipNonTypeField: SpectaSkipNonTypeField, FlattenA: FlattenA, FlattenB: FlattenB, FlattenC: FlattenC, FlattenD: FlattenD, FlattenE: FlattenE, FlattenF: FlattenF, FlattenG: FlattenG, TupleNested: TupleNested, "Generic1<()>": Generic1, "GenericAutoBound<()>": GenericAutoBound, "GenericAutoBound2<()>": GenericAutoBound2, Container1: Container1, "Generic2<(), String, i32>": Generic2, "GenericNewType1<()>": GenericNewType1, "GenericTuple<()>": GenericTuple, "GenericStruct2<()>": GenericStruct2, "InlineGenericNewtype": string, "InlineGenericNested": [string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | ({ Unnamed: string }) & { Named?: never } | ({ Named: { value: string, } }) & { Unnamed?: never }], "InlineFlattenGenericsG<()>": InlineFlattenGenericsG, InlineFlattenGenerics: InlineFlattenGenerics, GenericDefault: GenericDefault, ChainedGenericDefault: ChainedGenericDefault, "ChainedGenericDefault": ChainedGenericDefault, "ChainedGenericDefault": ChainedGenericDefault, "ChainedGenericDefault": ChainedGenericDefault, GenericDefaultSkipped: GenericDefaultSkipped, GenericDefaultSkippedNonType: GenericDefaultSkippedNonType, GenericParameterOrderPreserved: GenericParameterOrderPreserved, ConstGenericInNonConstContainer: ConstGenericInNonConstContainer, ConstGenericInConstContainer: ConstGenericInConstContainer, NamedConstGenericContainer: NamedConstGenericContainer, InlineConstGenericContainer: InlineConstGenericContainer, InlineRecursiveConstGenericContainer: InlineRecursiveConstGenericContainer, TestCollectionRegister: TestCollectionRegister, TestCollectionRegister: TestCollectionRegister, }; export type Range = { start: T, end: T, }; export type RangeInclusive = { start: T, end: T, }; export type Recursive = { demo: Recursive, }; export type RecursiveInEnum = { A: { demo: RecursiveInEnum, } }; export type RecursiveInline = RecursiveInline; export type RecursiveMapValue = { demo: { [key in string]: RecursiveMapValue }, }; export type RecursiveTransparent = RecursiveInline; export type RefStruct = TestEnum; export type Regular = { [key in string]: null }; export type Rename = "OneWord" | "Two words"; export type RenameSerdeSpecialChar = { "a/b": number, }; export type RenameWithWeirdCharsField = { "@odata.context": string, }; export type RenameWithWeirdCharsVariant = { "@odata.context": string }; export type RenamedFieldKeys = { "": string, "a\"b": string, "a\\b": string, "line\nbreak": string, "line\u2028break": string, "line\u2029break": string, }; export type RenamedVariantWithSkippedPayload = "a-b"; export type Result = { ok: T, err: E, }; export type Second = { a: number, }; export type Seventh = { a: First, b: Second, }; export type SimpleStruct = { a: number, b: string, c: [number, string, number], d: string[], e: string | null, }; /** Some single-line comment */ export type SingleLineComment = /** Some single-line comment */ ({ A: number }) & { B?: never } | /** Some single-line comment */ ({ B: { /** Some single-line comment */ a: number, } }) & { A?: never }; export type Sixth = { a: First, b: First, }; export type SkipField = { b: number, }; export type SkipNamedFieldInVariant = ({ A: Record }) & { B?: never } | ({ B: { b: number, } }) & { A?: never }; export type SkipOnlyField = Record; export type SkipStructFields = { a: number, }; export type SkipUnnamedFieldInVariant = "A" | { B: [number] }; export type SkipVariant = { A: string }; export type SkipVariant2 = { tag: "A"; data: string }; export type SkipVariant3 = { A: { a: string, } }; export type SkippedFieldWithinVariant = { type: "A" } | { type: "B"; data: string }; export type SpectaSkipNonTypeField = { a: number, }; export type SpectaTypeOverride = { string_ident: string, u32_ident: number, path: string, tuple: [string, number], }; export type Struct2 = { b: string, }; export type StructNew = { t: "StructNew", a: string, }; export type StructPhaseSpecificRename = StructPhaseSpecificRenameSerialize | StructPhaseSpecificRenameDeserialize; export type StructPhaseSpecificRenameDeserialize = { kind: "StructPhaseSpecificRenameDeserialize", der: string, }; export type StructPhaseSpecificRenameSerialize = { kind: "StructPhaseSpecificRenameSerialize", ser: string, }; export type StructRenameAllUppercase = { A: number, B: number, }; export type StructWithAlias = { field: string, }; export type StructWithAliasAndRename = { renamed_field: string, }; export type StructWithMultipleAliases = { field: string, }; export type TagOnStructWithInline = { type: "TagOnStructWithInline", a: First, b: { a: string, }, }; export type Tenth = string | "B" | { a: string, } | First; export type TestCollectionRegister = never; export type TestEnum = "Unit" | ({ Single: number }) & { Multiple?: never; Struct?: never } | ({ Multiple: [number, number] }) & { Single?: never; Struct?: never } | ({ Struct: { a: number, } }) & { Multiple?: never; Single?: never }; export type Third = { b: { [key in string]: string }, c: First, } & First; export type ToBeFlattened = { a: string, }; export type TransparentStruct = string; export type TransparentType = TransparentTypeInner; export type TransparentType2 = null; export type TransparentTypeInner = { inner: string, }; export type TransparentTypeWithOverride = string; export type TransparentWithSkip = null; export type TransparentWithSkip2 = string; export type TransparentWithSkip3 = string; export type TupleNested = [number[], [number[], number[]], [number[], number[], number[]]]; export type TupleStruct = string; export type TupleStruct1 = number; export type TupleStruct3 = [number, boolean, string]; export type TupleStructWithRep = string; export type Type = never; export type Unit1 = null; export type Unit2 = Record; export type Unit3 = []; export type Unit4 = null; export type Unit5 = "A"; export type Unit6 = { A: null }; export type Unit7 = { A: Record }; export type UnitVariants = "A" | "B" | "C"; export type UntaggedVariants = string | number | { id: string } | [string, boolean]; export type UntaggedVariantsKey = string | number; export type UntaggedVariantsWithDuplicateBranches = null | number; export type UntaggedVariantsWithoutValue = string | [number, string] | number; export type UntaggedWithAlias = ({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }; export type ValidMaybeValidKey = { [key in MaybeValidKey]: null }; export type ValidMaybeValidKeyNested = { [key in MaybeValidKey>]: null }; ================================================ FILE: tests/tests/snapshots/test__typescript__ts-export-to-files-raw.snap ================================================ --- source: tests/tests/typescript.rs expression: output --- std/ ops.ts (181 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. export type Range = { start: T, end: T, }; export type RangeInclusive = { start: T, end: T, }; ════════════════════════════════════════ result.ts (124 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. export type Result = { ok: T, err: E, }; ════════════════════════════════════════ test/ types/ type_type.ts (101 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. export type Type = never; ════════════════════════════════════════ types.ts (14154 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. export type A = { a: B, b: { b: number, }, c: B, d: { flattened: number, }, e: { generic_flattened: number, }, }; export type AGenericStruct = { field: Demo, }; export type ActualType = { a: GenericType, }; export type AdjacentlyTagged = "A" | { id: string; method: string } | string; export type AdjacentlyTaggedWithAlias = ({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }; export type B = { b: number, }; export type BasicEnum = "A" | "B"; export type BoxFlattened = { b: BoxedInner, }; export type BoxInline = { c: { a: number, }, }; export type BoxedInner = { a: number, }; export type BracedStruct = string; export type ChainedGenericDefault = { first: T, second: U, }; /** * Some triple-slash comment * Some more triple-slash comment */ export type CommentedEnum = /** * Some triple-slash comment * Some more triple-slash comment */ number | /** * Some triple-slash comment * Some more triple-slash comment */ { /** * Some triple-slash comment * Some more triple-slash comment */ a: number }; /** * Some triple-slash comment * Some more triple-slash comment */ export type CommentedStruct = { /** * Some triple-slash comment * Some more triple-slash comment */ a: number, }; export type ConstGenericInConstContainer = { data: number[], a: number[], d: [number, number], }; export type ConstGenericInNonConstContainer = { data: [number], a: [number, number], d: [number, number], }; export type Container1 = { foo: Generic1, bar: Generic1[], baz: { [key in string]: Generic1 }, }; export type ContainerTypeOverrideEnum = string; export type ContainerTypeOverrideGeneric = string; export type ContainerTypeOverrideStruct = string; export type ContainerTypeOverrideToGeneric = T; export type ContainerTypeOverrideTuple = [string, number]; export type ContainerTypeOverrideTupleGeneric = [T, string]; export type D = { flattened: number, }; export type Demo = { a: A, b: B, }; export type DeprecatedEnumVariants = /** * @deprecated */ "A" | /** * @deprecated Nope */ "B" | /** * @deprecated Nope */ "C"; export type DeprecatedFields = { a: number, /** * @deprecated */ b: string, /** * @deprecated This field is cringe! */ c: string, /** * @deprecated This field is cringe! */ d: string, }; export type DeprecatedTupleVariant = [ /** * @deprecated */ string, /** * @deprecated Nope */ string, /** * @deprecated Nope */ number]; /** * @deprecated */ export type DeprecatedType = { a: number, }; /** * @deprecated Look at you big man using a deprecation message */ export type DeprecatedTypeWithMsg = { a: number, }; /** * @deprecated Look at you big man using a deprecation message */ export type DeprecatedTypeWithMsg2 = { a: number, }; export type DoubleFlattened = { a: ToBeFlattened, b: ToBeFlattened, }; export type Eight = string | "B"; export type EmptyEnum = never; export type EmptyEnumTagged = never; export type EmptyEnumTaggedWContent = never; export type EmptyEnumUntagged = never; export type EmptyStruct = Record; export type EmptyStructWithTag = Record; export type Enum = "A" | "B"; export type Enum2 = "A" | "B" | { enum_field: null }; export type Enum3 = { a: string }; export type EnumMacroAttributes = string | number | { a: string; b: number }; export type EnumReferenceRecordKey = { a: Partial<{ [key in BasicEnum]: number }>, }; export type EnumRenameAllUppercase = "HelloWorld" | "VariantB" | "TestingWords"; export type EnumWithMultipleVariantAliases = "Variant" | "Other"; export type EnumWithVariantAlias = "Variant" | "Other"; export type EnumWithVariantAliasAndRename = "Variant" | "Other"; export type ExternallyTagged = "A" | { id: string; method: string } | string; export type ExtraBracketsInTupleVariant = string; export type ExtraBracketsInUnnamedStruct = string; export type First = { a: string, }; export type FlattenA = { a: number, b: number, }; export type FlattenB = { a: FlattenA, c: number, }; export type FlattenC = { a: FlattenA, c: number, }; export type FlattenD = { a: FlattenA, c: number, }; export type FlattenE = { b: { a: FlattenA, c: number, }, d: number, }; export type FlattenEnum = "One" | "Two" | "Three"; export type FlattenEnumStruct = { outer: string, inner: FlattenEnum, }; export type FlattenF = { b: { a: FlattenA, c: number, }, d: number, }; export type FlattenG = { b: FlattenB, d: number, }; export type FlattenOnNestedEnum = { id: string, result: NestedEnum, }; export type FlattenedInner = { c: Inner, }; export type Fourth = { a: First, b: { a: string, }, }; export type Generic1 = { value: T, values: T[], }; export type Generic2 = A | [B, B, B] | C[] | A[][][] | { a: A; b: B; c: C } | number[] | number | number[][]; export type GenericAutoBound = { value: T, values: T[], }; export type GenericAutoBound2 = { value: T, values: T[], }; export type GenericDefault = { value: T, }; export type GenericDefaultSkipped = { value: T, }; export type GenericDefaultSkippedNonType = { value: number, }; export type GenericFlattened = { generic_flattened: T, }; export type GenericNewType1 = T[][]; export type GenericParameterOrderPreserved = { pair: Pair, }; export type GenericStruct = { arg: T, }; export type GenericStruct2 = { a: T, b: [T, T], c: [T, [T, T]], d: [T, T, T], e: [([T, T]), ([T, T]), ([T, T])], f: T[], g: T[][], h: ([([T, T]), ([T, T]), ([T, T])])[], }; export type GenericTuple = [T, T[], T[][]]; export type GenericTupleStruct = T; export type GenericType = "Undefined" | T; export type HasGenericAlias = { [key in number]: string }; export type InlineConstGenericContainer = { b: { data: [number, number], a: [number, number], d: [number, number, number], }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], }, d: [number, number], }; export type InlineEnumField = { a: string, }; export type InlineFlattenGenerics = { g: InlineFlattenGenericsG, gi: { t: string, }, t: InlineFlattenGenericsG, }; export type InlineFlattenGenericsG = { t: T, }; export type InlineOptionalType = { optional_field: { a: string, } | null, }; export type InlineRecursiveConstGeneric = { data: number[], a: number[], d: [number, number, number], e: InlineRecursiveConstGeneric, }; export type InlineRecursiveConstGenericContainer = { b: { data: [number, number], a: [number, number], d: [number, number, number], e: InlineRecursiveConstGeneric, }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], e: InlineRecursiveConstGeneric, }, d: [number, number], }; export type InlineStruct = { ref_struct: SimpleStruct, val: number, }; export type InlineTuple = { demo: [string, boolean], }; export type InlineTuple2 = { demo: [{ demo: [string, boolean], }, boolean], }; export type InlinerStruct = { inline_this: { ref_struct: SimpleStruct, val: number, }, dont_inline_this: RefStruct, }; export type Inner = { a: number, b: FlattenedInner, }; export type InternallyTaggedD = { [key in string]: string }; export type InternallyTaggedE = null; export type InternallyTaggedF = InternallyTaggedFInner; export type InternallyTaggedFInner = null; export type InternallyTaggedH = InternallyTaggedHInner; export type InternallyTaggedHInner = null; export type InternallyTaggedL = "A" | "B"; export type InternallyTaggedLInner = "A" | "B"; export type InternallyTaggedM = "A" | "B"; export type InternallyTaggedMInner = "A" | "B"; export type InternallyTaggedWithAlias = ({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }; export type InvalidToValidType = { cause: null, }; export type Issue221External = ({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }; export type Issue221UntaggedMixed = ({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never }; export type Issue221UntaggedSafe = ({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }; export type Issue281 = { default_unity_arguments: string[], }; export type KebabCase = { test_ing: string, }; export type LifetimeGenericEnum = T; export type LifetimeGenericStruct = { borrowed: T[], owned: T[], }; export type LoadProjectEvent = ({ project_name: string }) & { progress?: never; status?: never } | { project_name: string; status: string; progress: number }; export type MacroEnum = string | { demo2: string }; export type MacroStruct = string; export type MacroStruct2 = { demo: string, }; export type MaybeValidKey = T; export type MyEmptyInput = Record; export type MyEnum = string | number; export type MyEnumAdjacent = { inner: First }; export type MyEnumExternal = { inner: First }; export type MyEnumTagged = { inner: First }; export type MyEnumUntagged = { inner: First }; export type NamedConstGeneric = { data: number[], a: number[], d: [number, number], }; export type NamedConstGenericContainer = { a: NamedConstGeneric, b: NamedConstGeneric, d: [number, number], }; export type NestedEnum = string | number; export type Ninth = string | "B" | { a: string, } | First; export type NonOptional = string | null; export type OptionalInEnum = string | null | { a: string | null } | { a?: string | null }; export type OptionalOnNamedField = string | null; export type OptionalOnTransparentNamedField = { b: string | null, }; export type OverridenStruct = { overriden_field: string, }; export type Pair = { first: Z, second: A, }; export type PlaceholderInnerField = { a: string, }; export type Recursive = { demo: Recursive, }; export type RecursiveInEnum = { demo: RecursiveInEnum }; export type RecursiveInline = { demo: RecursiveInline, }; export type RecursiveMapValue = { demo: { [key in string]: RecursiveMapValue }, }; export type RecursiveTransparent = RecursiveInline; export type RefStruct = TestEnum; export type Regular = { [key in string]: null }; export type Rename = "OneWord" | "TwoWords"; export type RenameSerdeSpecialChar = { b: number, }; export type RenameWithWeirdCharsField = { odata_context: string, }; export type RenameWithWeirdCharsVariant = string; export type RenamedFieldKeys = { empty: string, quote: string, backslash: string, newline: string, line_separator: string, paragraph_separator: string, }; export type RenamedVariantWithSkippedPayload = never; export type Second = { a: number, }; export type Seventh = { a: First, b: Second, }; export type SimpleStruct = { a: number, b: string, c: [number, string, number], d: string[], e: string | null, }; /** Some single-line comment */ export type SingleLineComment = /** Some single-line comment */ number | /** Some single-line comment */ { /** Some single-line comment */ a: number }; export type Sixth = { a: First, b: First, }; export type SkipField = { b: number, }; export type SkipNamedFieldInVariant = Record | { b: number }; export type SkipOnlyField = Record; export type SkipStructFields = { a: number, }; export type SkipUnnamedFieldInVariant = never | [number]; export type SkipVariant = string; export type SkipVariant2 = string; export type SkipVariant3 = { a: string }; export type SkippedFieldWithinVariant = never | string; export type SpectaSkipNonTypeField = { a: number, }; export type SpectaTypeOverride = { string_ident: string, u32_ident: number, path: string, tuple: [string, number], }; export type Struct = { a: string, }; export type Struct2 = { a: string, }; export type StructRenameAllUppercase = { a: number, b: number, }; export type StructWithAlias = { field: string, }; export type StructWithAliasAndRename = { field: string, }; export type StructWithMultipleAliases = { field: string, }; export type TagOnStructWithInline = { a: First, b: { a: string, }, }; export type Tenth = string | "B" | { a: string, } | First; export type TestCollectionRegister = never; export type TestEnum = "Unit" | number | [number, number] | { a: number }; export type Third = { a: First, b: { [key in string]: string }, c: First, }; export type ToBeFlattened = { a: string, }; export type TransparentStruct = string; export type TransparentType = TransparentTypeInner; export type TransparentType2 = null; export type TransparentTypeInner = { inner: string, }; export type TransparentTypeWithOverride = string; export type TransparentWithSkip = null; export type TransparentWithSkip2 = string; export type TransparentWithSkip3 = string; export type TupleNested = [number[], [number[], number[]], [number[], number[], number[]]]; export type TupleStruct = string; export type TupleStruct1 = number; export type TupleStruct3 = [number, boolean, string]; export type TupleStructWithRep = string; export type Unit1 = null; export type Unit2 = Record; export type Unit3 = []; export type Unit4 = null; export type Unit5 = "A"; export type Unit6 = []; export type Unit7 = Record; export type UnitVariants = "A" | "B" | "C"; export type UntaggedVariants = string | number | { id: string } | [string, boolean]; export type UntaggedVariantsKey = string | number; export type UntaggedVariantsWithDuplicateBranches = null | number; export type UntaggedVariantsWithoutValue = string | [number, string] | number; export type UntaggedWithAlias = ({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }; export type ValidMaybeValidKey = { [key in MaybeValidKey]: null }; export type ValidMaybeValidKeyNested = { [key in MaybeValidKey>]: null }; ════════════════════════════════════════ tests/ tests/ types.ts (12857 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. import type * as std$ops from "../../std/ops"; import type * as std$result from "../../std/result"; import type * as test$types from "../../test/types"; import type * as test$types$type_type from "../../test/types/type_type"; export type Primitives = { i8: number, i16: number, i32: number, u8: number, u16: number, u32: number, f32: number, f64: number, bool: boolean, char: string, "Range": std$ops.Range, "RangeInclusive": std$ops.RangeInclusive, "()": null, "(String, i32)": [string, number], "(String, i32, bool)": [string, number, boolean], "((String, i32), (bool, char, bool), ())": [[string, number], [boolean, string, boolean], null], "(bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool)": [boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean], "(Vec, Vec)": [number[], boolean[]], String: string, PathBuf: string, IpAddr: string, Ipv4Addr: string, Ipv6Addr: string, SocketAddr: string, SocketAddrV4: string, SocketAddrV6: string, "Cow<'static, str>": string, "Cow<'static, i32>": number, "&'static str": string, "&'static bool": boolean, "&'static i32": number, "Vec": number[], "&'static [i32]": number[], "&'static [i32; 3]": [number, number, number], "[i32; 3]": [number, number, number], "Vec": test$types.MyEnum[], "&'static [MyEnum]": test$types.MyEnum[], "&'static [MyEnum; 6]": [test$types.MyEnum, test$types.MyEnum, test$types.MyEnum, test$types.MyEnum, test$types.MyEnum, test$types.MyEnum], "[MyEnum; 2]": [test$types.MyEnum, test$types.MyEnum], "&'static [i32; 1]": [number], "&'static [i32; 0]": [], "Option": number | null, "Option<()>": null, "Option>": number[] | null, "Result": std$result.Result, "Vec>>": (number | null)[], "Option>>": number[] | null, "[Vec; 3]": [string[], string[], string[]], "Option>": string | null, "Option>>": string | null, "PhantomData<()>": null, "PhantomData": null, Infallible: never, Unit1: test$types.Unit1, Unit2: test$types.Unit2, Unit3: test$types.Unit3, Unit4: test$types.Unit4, Unit5: test$types.Unit5, Unit6: test$types.Unit6, Unit7: test$types.Unit7, SimpleStruct: test$types.SimpleStruct, TupleStruct1: test$types.TupleStruct1, TupleStruct3: test$types.TupleStruct3, TestEnum: test$types.TestEnum, RefStruct: test$types.RefStruct, InlinerStruct: test$types.InlinerStruct, "GenericStruct": test$types.GenericStruct, "GenericStruct": test$types.GenericStruct, FlattenEnumStruct: test$types.FlattenEnumStruct, OverridenStruct: test$types.OverridenStruct, HasGenericAlias: test$types.HasGenericAlias, EnumMacroAttributes: test$types.EnumMacroAttributes, InlineEnumField: test$types.InlineEnumField, InlineOptionalType: test$types.InlineOptionalType, Rename: test$types.Rename, TransparentType: test$types.TransparentType, TransparentType2: test$types.TransparentType2, TransparentTypeWithOverride: test$types.TransparentTypeWithOverride, "[Option; 3]": [(number | null), (number | null), (number | null)], "HashMap": Partial<{ [key in test$types.BasicEnum]: null }>, "HashMap": Partial<{ [key in test$types.BasicEnum]: number }>, "Option>>>": number | null, "Vec": test$types.PlaceholderInnerField[], EnumReferenceRecordKey: test$types.EnumReferenceRecordKey, FlattenOnNestedEnum: test$types.FlattenOnNestedEnum, MyEmptyInput: test$types.MyEmptyInput, "(String)": string, "(String,)": [string], ExtraBracketsInTupleVariant: test$types.ExtraBracketsInTupleVariant, ExtraBracketsInUnnamedStruct: test$types.ExtraBracketsInUnnamedStruct, "Vec": test$types.MyEnum[], InlineTuple: test$types.InlineTuple, InlineTuple2: test$types.InlineTuple2, "Box": string, "Box": string, SkippedFieldWithinVariant: test$types.SkippedFieldWithinVariant, KebabCase: test$types.KebabCase, "&[&str]": string[], "Issue281<'_>": test$types.Issue281, "LifetimeGenericStruct<'_, i32>": test$types.LifetimeGenericStruct, "LifetimeGenericEnum<'_, i32>": test$types.LifetimeGenericEnum, RenameWithWeirdCharsField: test$types.RenameWithWeirdCharsField, RenameWithWeirdCharsVariant: test$types.RenameWithWeirdCharsVariant, RenamedFieldKeys: test$types.RenamedFieldKeys, RenamedVariantWithSkippedPayload: test$types.RenamedVariantWithSkippedPayload, "type_type::Type": test$types$type_type.Type, ActualType: test$types.ActualType, SpectaTypeOverride: test$types.SpectaTypeOverride, ContainerTypeOverrideStruct: test$types.ContainerTypeOverrideStruct, ContainerTypeOverrideEnum: test$types.ContainerTypeOverrideEnum, "ContainerTypeOverrideGeneric>": test$types.ContainerTypeOverrideGeneric, "ContainerTypeOverrideToGeneric": test$types.ContainerTypeOverrideToGeneric, ContainerTypeOverrideTuple: test$types.ContainerTypeOverrideTuple, "ContainerTypeOverrideTupleGeneric": test$types.ContainerTypeOverrideTupleGeneric, InvalidToValidType: test$types.InvalidToValidType, TupleStruct: test$types.TupleStruct, TupleStructWithRep: test$types.TupleStructWithRep, "GenericTupleStruct": test$types.GenericTupleStruct, BracedStruct: test$types.BracedStruct, Struct: test$types.Struct, Struct2: test$types.Struct2, Enum: test$types.Enum, Enum2: test$types.Enum2, Enum3: test$types.Enum3, StructRenameAllUppercase: test$types.StructRenameAllUppercase, RenameSerdeSpecialChar: test$types.RenameSerdeSpecialChar, EnumRenameAllUppercase: test$types.EnumRenameAllUppercase, Recursive: test$types.Recursive, RecursiveMapValue: test$types.RecursiveMapValue, RecursiveTransparent: test$types.RecursiveTransparent, RecursiveInEnum: test$types.RecursiveInEnum, NonOptional: test$types.NonOptional, OptionalOnNamedField: test$types.OptionalOnNamedField, OptionalOnTransparentNamedField: test$types.OptionalOnTransparentNamedField, OptionalInEnum: test$types.OptionalInEnum, UntaggedVariants: test$types.UntaggedVariants, UntaggedVariantsWithoutValue: test$types.UntaggedVariantsWithoutValue, UntaggedVariantsWithDuplicateBranches: test$types.UntaggedVariantsWithDuplicateBranches, "HashMap": { [key in string]: null }, Regular: test$types.Regular, "HashMap": { [key in never]: null }, "HashMap": { [key in test$types.TransparentStruct]: null }, "HashMap": Partial<{ [key in test$types.UnitVariants]: null }>, "HashMap": Partial<{ [key in test$types.UntaggedVariantsKey]: null }>, ValidMaybeValidKey: test$types.ValidMaybeValidKey, ValidMaybeValidKeyNested: test$types.ValidMaybeValidKeyNested, MacroStruct: test$types.MacroStruct, MacroStruct2: test$types.MacroStruct2, MacroEnum: test$types.MacroEnum, DeprecatedType: test$types.DeprecatedType, DeprecatedTypeWithMsg: test$types.DeprecatedTypeWithMsg, DeprecatedTypeWithMsg2: test$types.DeprecatedTypeWithMsg2, DeprecatedFields: test$types.DeprecatedFields, DeprecatedTupleVariant: test$types.DeprecatedTupleVariant, DeprecatedEnumVariants: test$types.DeprecatedEnumVariants, CommentedStruct: test$types.CommentedStruct, CommentedEnum: test$types.CommentedEnum, SingleLineComment: test$types.SingleLineComment, NonGeneric: test$types.Demo, "HalfGenericA": test$types.Demo, "HalfGenericB": test$types.Demo, "FullGeneric": test$types.Demo, "Another": test$types.Demo, "MapA": { [key in string]: number }, "MapB": { [key in number]: string }, "MapC": { [key in string]: test$types.AGenericStruct }, "AGenericStruct": test$types.AGenericStruct, A: test$types.A, DoubleFlattened: test$types.DoubleFlattened, FlattenedInner: test$types.FlattenedInner, BoxFlattened: test$types.BoxFlattened, BoxInline: test$types.BoxInline, First: test$types.First, Second: test$types.Second, Third: test$types.Third, Fourth: test$types.Fourth, TagOnStructWithInline: test$types.TagOnStructWithInline, Sixth: test$types.Sixth, Seventh: test$types.Seventh, Eight: test$types.Eight, Ninth: test$types.Ninth, Tenth: test$types.Tenth, MyEnumTagged: test$types.MyEnumTagged, MyEnumExternal: test$types.MyEnumExternal, MyEnumAdjacent: test$types.MyEnumAdjacent, MyEnumUntagged: test$types.MyEnumUntagged, EmptyStruct: test$types.EmptyStruct, EmptyStructWithTag: test$types.EmptyStructWithTag, AdjacentlyTagged: test$types.AdjacentlyTagged, LoadProjectEvent: test$types.LoadProjectEvent, ExternallyTagged: test$types.ExternallyTagged, Issue221External: test$types.Issue221External, InternallyTaggedD: test$types.InternallyTaggedD, InternallyTaggedE: test$types.InternallyTaggedE, InternallyTaggedF: test$types.InternallyTaggedF, InternallyTaggedH: test$types.InternallyTaggedH, InternallyTaggedL: test$types.InternallyTaggedL, InternallyTaggedM: test$types.InternallyTaggedM, StructWithAlias: test$types.StructWithAlias, StructWithMultipleAliases: test$types.StructWithMultipleAliases, StructWithAliasAndRename: test$types.StructWithAliasAndRename, EnumWithVariantAlias: test$types.EnumWithVariantAlias, EnumWithMultipleVariantAliases: test$types.EnumWithMultipleVariantAliases, EnumWithVariantAliasAndRename: test$types.EnumWithVariantAliasAndRename, InternallyTaggedWithAlias: test$types.InternallyTaggedWithAlias, AdjacentlyTaggedWithAlias: test$types.AdjacentlyTaggedWithAlias, UntaggedWithAlias: test$types.UntaggedWithAlias, Issue221UntaggedSafe: test$types.Issue221UntaggedSafe, Issue221UntaggedMixed: test$types.Issue221UntaggedMixed, EmptyEnum: test$types.EmptyEnum, EmptyEnumTagged: test$types.EmptyEnumTagged, EmptyEnumTaggedWContent: test$types.EmptyEnumTaggedWContent, EmptyEnumUntagged: test$types.EmptyEnumUntagged, SkipOnlyField: test$types.SkipOnlyField, SkipField: test$types.SkipField, SkipVariant: test$types.SkipVariant, SkipUnnamedFieldInVariant: test$types.SkipUnnamedFieldInVariant, SkipNamedFieldInVariant: test$types.SkipNamedFieldInVariant, TransparentWithSkip: test$types.TransparentWithSkip, TransparentWithSkip2: test$types.TransparentWithSkip2, TransparentWithSkip3: test$types.TransparentWithSkip3, SkipVariant2: test$types.SkipVariant2, SkipVariant3: test$types.SkipVariant3, SkipStructFields: test$types.SkipStructFields, SpectaSkipNonTypeField: test$types.SpectaSkipNonTypeField, FlattenA: test$types.FlattenA, FlattenB: test$types.FlattenB, FlattenC: test$types.FlattenC, FlattenD: test$types.FlattenD, FlattenE: test$types.FlattenE, FlattenF: test$types.FlattenF, FlattenG: test$types.FlattenG, TupleNested: test$types.TupleNested, "Generic1<()>": test$types.Generic1, "GenericAutoBound<()>": test$types.GenericAutoBound, "GenericAutoBound2<()>": test$types.GenericAutoBound2, Container1: test$types.Container1, "Generic2<(), String, i32>": test$types.Generic2, "GenericNewType1<()>": test$types.GenericNewType1, "GenericTuple<()>": test$types.GenericTuple, "GenericStruct2<()>": test$types.GenericStruct2, "InlineGenericNewtype": string, "InlineGenericNested": [string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | string | { value: string }], "InlineFlattenGenericsG<()>": test$types.InlineFlattenGenericsG, InlineFlattenGenerics: test$types.InlineFlattenGenerics, GenericDefault: test$types.GenericDefault, ChainedGenericDefault: test$types.ChainedGenericDefault, "ChainedGenericDefault": test$types.ChainedGenericDefault, "ChainedGenericDefault": test$types.ChainedGenericDefault, "ChainedGenericDefault": test$types.ChainedGenericDefault, GenericDefaultSkipped: test$types.GenericDefaultSkipped, GenericDefaultSkippedNonType: test$types.GenericDefaultSkippedNonType, GenericParameterOrderPreserved: test$types.GenericParameterOrderPreserved, ConstGenericInNonConstContainer: test$types.ConstGenericInNonConstContainer, ConstGenericInConstContainer: test$types.ConstGenericInConstContainer, NamedConstGenericContainer: test$types.NamedConstGenericContainer, InlineConstGenericContainer: test$types.InlineConstGenericContainer, InlineRecursiveConstGenericContainer: test$types.InlineRecursiveConstGenericContainer, TestCollectionRegister: test$types.TestCollectionRegister, TestCollectionRegister: test$types.TestCollectionRegister, }; ════════════════════════════════════════ ================================================ FILE: tests/tests/snapshots/test__typescript__ts-export-to-files-serde.snap ================================================ --- source: tests/tests/typescript.rs expression: output --- std/ ops.ts (181 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. export type Range = { start: T, end: T, }; export type RangeInclusive = { start: T, end: T, }; ════════════════════════════════════════ result.ts (124 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. export type Result = { ok: T, err: E, }; ════════════════════════════════════════ test/ types/ type_type.ts (101 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. export type Type = never; ════════════════════════════════════════ types.ts (16366 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. export type A = { a: B, b: { b: number, }, c: B, d: { flattened: number, }, e: { generic_flattened: number, }, }; export type AGenericStruct = { field: Demo, }; export type ActualType = { a: GenericType, }; export type AdjacentlyTagged = { t: "A" } | { t: "B"; c: { id: string, method: string, } } | { t: "C"; c: string }; export type AdjacentlyTaggedWithAlias = { type: "A"; data: { field: string, } } | { type: "B"; data: { other: number, } }; export type B = { b: number, }; export type BasicEnum = "A" | "B"; export type BoxFlattened = BoxedInner; export type BoxInline = { c: { a: number, }, }; export type BoxedInner = { a: number, }; export type BracedStruct = string; export type ChainedGenericDefault = { first: T, second: U, }; /** * Some triple-slash comment * Some more triple-slash comment */ export type CommentedEnum = /** * Some triple-slash comment * Some more triple-slash comment */ ({ A: number }) & { B?: never } | /** * Some triple-slash comment * Some more triple-slash comment */ ({ B: { /** * Some triple-slash comment * Some more triple-slash comment */ a: number, } }) & { A?: never }; /** * Some triple-slash comment * Some more triple-slash comment */ export type CommentedStruct = { /** * Some triple-slash comment * Some more triple-slash comment */ a: number, }; export type ConstGenericInConstContainer = { data: number[], a: number[], d: [number, number], }; export type ConstGenericInNonConstContainer = { data: [number], a: [number, number], d: [number, number], }; export type Container1 = { foo: Generic1, bar: Generic1[], baz: { [key in string]: Generic1 }, }; export type ContainerTypeOverrideEnum = string; export type ContainerTypeOverrideGeneric = string; export type ContainerTypeOverrideStruct = string; export type ContainerTypeOverrideToGeneric = T; export type ContainerTypeOverrideTuple = [string, number]; export type ContainerTypeOverrideTupleGeneric = [T, string]; export type D = { flattened: number, }; export type Demo = { a: A, b: B, }; export type DeprecatedEnumVariants = /** * @deprecated */ "A" | /** * @deprecated Nope */ "B" | /** * @deprecated Nope */ "C"; export type DeprecatedFields = { a: number, /** * @deprecated */ b: string, /** * @deprecated This field is cringe! */ c: string, /** * @deprecated This field is cringe! */ d: string, }; export type DeprecatedTupleVariant = [ /** * @deprecated */ string, /** * @deprecated Nope */ string, /** * @deprecated Nope */ number]; /** * @deprecated */ export type DeprecatedType = { a: number, }; /** * @deprecated Look at you big man using a deprecation message */ export type DeprecatedTypeWithMsg = { a: number, }; /** * @deprecated Look at you big man using a deprecation message */ export type DeprecatedTypeWithMsg2 = { a: number, }; export type DoubleFlattened = { a: ToBeFlattened, b: ToBeFlattened, }; export type Eight = { A: string } | "B"; export type EmptyEnum = never; export type EmptyEnumTagged = never; export type EmptyEnumTaggedWContent = never; export type EmptyEnumUntagged = never; export type EmptyStruct = Record; export type EmptyStructWithTag = { a: "EmptyStructWithTag", }; export type Enum = { t: "A" } | { t: "B" }; export type Enum2 = { t: "C" } | { t: "B" } | { t: "D"; enumField: null }; export type Enum3 = { t: "A"; b: string }; export type EnumMacroAttributes = ({ A: string }) & { D?: never; bbb?: never; cccc?: never } | ({ bbb: number }) & { A?: never; D?: never; cccc?: never } | ({ cccc: number }) & { A?: never; D?: never; bbb?: never } | ({ D: { a: string, bbbbbb: number, } }) & { A?: never; bbb?: never; cccc?: never }; export type EnumReferenceRecordKey = { a: Partial<{ [key in BasicEnum]: number }>, }; export type EnumRenameAllUppercase = "HELLOWORLD" | "VARIANTB" | "TESTINGWORDS"; export type EnumWithMultipleVariantAliases = "Variant" | "Other"; export type EnumWithVariantAlias = "Variant" | "Other"; export type EnumWithVariantAliasAndRename = "renamed_variant" | "Other"; export type ExternallyTagged = "A" | ({ B: { id: string, method: string, } }) & { C?: never } | ({ C: string }) & { B?: never }; export type ExtraBracketsInTupleVariant = { A: string }; export type ExtraBracketsInUnnamedStruct = string; export type First = { a: string, }; export type FlattenA = { a: number, b: number, }; export type FlattenB = { c: number, } & FlattenA; export type FlattenC = { c: number, } & FlattenA; export type FlattenD = { a: FlattenA, c: number, }; export type FlattenE = { b: ({ c: number, }) & (FlattenA), d: number, }; export type FlattenEnum = { tag: "One" } | { tag: "Two" } | { tag: "Three" }; export type FlattenEnumStruct = { outer: string, } & FlattenEnum; export type FlattenF = { b: ({ c: number, }) & (FlattenA), d: number, }; export type FlattenG = { b: FlattenB, d: number, }; export type FlattenOnNestedEnum = { id: string, } & NestedEnum; export type FlattenedInner = Inner; export type Fourth = { a: First, b: { a: string, }, }; export type Generic1 = { value: T, values: T[], }; export type Generic2 = ({ A: A }) & { B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ B: [B, B, B] }) & { A?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ C: C[] }) & { A?: never; B?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ D: A[][][] }) & { A?: never; B?: never; C?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ E: { a: A, b: B, c: C, } }) & { A?: never; B?: never; C?: never; D?: never; X?: never; Y?: never; Z?: never } | ({ X: number[] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; Y?: never; Z?: never } | ({ Y: number }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Z?: never } | ({ Z: number[][] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never }; export type GenericAutoBound = { value: T, values: T[], }; export type GenericAutoBound2 = { value: T, values: T[], }; export type GenericDefault = { value: T, }; export type GenericDefaultSkipped = { value: T, }; export type GenericDefaultSkippedNonType = { value: number, }; export type GenericFlattened = { generic_flattened: T, }; export type GenericNewType1 = T[][]; export type GenericParameterOrderPreserved = { pair: Pair, }; export type GenericStruct = { arg: T, }; export type GenericStruct2 = { a: T, b: [T, T], c: [T, [T, T]], d: [T, T, T], e: [([T, T]), ([T, T]), ([T, T])], f: T[], g: T[][], h: ([([T, T]), ([T, T]), ([T, T])])[], }; export type GenericTuple = [T, T[], T[][]]; export type GenericTupleStruct = T; export type GenericType = "Undefined" | T; export type HasGenericAlias = { [key in number]: string }; export type InlineConstGenericContainer = { b: { data: [number, number], a: [number, number], d: [number, number, number], }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], }, d: [number, number], }; export type InlineEnumField = { A: { a: string, } }; export type InlineFlattenGenerics = { g: InlineFlattenGenericsG, gi: { t: string, }, } & InlineFlattenGenericsG; export type InlineFlattenGenericsG = { t: T, }; export type InlineOptionalType = { optional_field: { a: string, } | null, }; export type InlineRecursiveConstGeneric = { data: number[], a: number[], d: [number, number, number], e: InlineRecursiveConstGeneric, }; export type InlineRecursiveConstGenericContainer = { b: { data: [number, number], a: [number, number], d: [number, number, number], e: InlineRecursiveConstGeneric, }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], e: InlineRecursiveConstGeneric, }, d: [number, number], }; export type InlineStruct = { ref_struct: SimpleStruct, val: number, }; export type InlineTuple = { demo: [string, boolean], }; export type InlineTuple2 = { demo: [{ demo: [string, boolean], }, boolean], }; export type InlinerStruct = { inline_this: { ref_struct: SimpleStruct, val: number, }, dont_inline_this: RefStruct, }; export type Inner = { a: number, } & FlattenedInner; export type InternallyTaggedD = { type: "A", } & { [key in string]: string }; export type InternallyTaggedE = { type: "A" }; export type InternallyTaggedF = { type: "A" }; export type InternallyTaggedFInner = null; export type InternallyTaggedH = { type: "A" }; export type InternallyTaggedHInner = null; export type InternallyTaggedL = { type: "A", } & { type: "A" } | { type: "B" }; export type InternallyTaggedLInner = { type: "A" } | { type: "B" }; export type InternallyTaggedM = { type: "A" }; export type InternallyTaggedMInner = "A" | "B"; export type InternallyTaggedWithAlias = { type: "A"; field: string } | { type: "B"; other: number }; export type InvalidToValidType = { cause: null, }; export type Issue221External = ({ A: { a: string, } }) & { B?: never } | ({ B: { b: string, } }) & { A?: never }; export type Issue221UntaggedMixed = ({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never }; export type Issue221UntaggedSafe = ({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }; export type Issue281 = { default_unity_arguments: string[], }; export type KebabCase = { "test-ing": string, }; export type LifetimeGenericEnum = ({ Borrowed: T }) & { Owned?: never } | ({ Owned: T }) & { Borrowed?: never }; export type LifetimeGenericStruct = { borrowed: T[], owned: T[], }; export type LoadProjectEvent = { event: "started"; data: { projectName: string, } } | { event: "progressTest"; data: { projectName: string, status: string, progress: number, } } | { event: "finished"; data: { projectName: string, } }; export type MacroEnum = ({ Demo: string }) & { Demo2?: never } | ({ Demo2: { demo2: string, } }) & { Demo?: never }; export type MacroStruct = string; export type MacroStruct2 = { demo: string, }; export type MaybeValidKey = T; export type MyEmptyInput = Record; export type MyEnum = ({ A: string }) & { B?: never } | ({ B: number }) & { A?: never }; export type MyEnumAdjacent = { t: "Variant"; c: { inner: First, } }; export type MyEnumExternal = { Variant: { inner: First, } }; export type MyEnumTagged = { type: "Variant"; inner: First }; export type MyEnumUntagged = { inner: First }; export type NamedConstGeneric = { data: number[], a: number[], d: [number, number], }; export type NamedConstGenericContainer = { a: NamedConstGeneric, b: NamedConstGeneric, d: [number, number], }; export type NestedEnum = { type: "a"; value: string } | { type: "b"; value: number }; export type Ninth = { t: "A"; c: string } | { t: "B" } | { t: "C"; c: { a: string, } } | { t: "D"; c: First }; export type NonOptional = string | null; export type OptionalInEnum = ({ A?: string | null }) & { B?: never; C?: never } | ({ B: { a: string | null, } }) & { A?: never; C?: never } | ({ C: { a?: string | null, } }) & { A?: never; B?: never }; export type OptionalOnNamedField = string | null; export type OptionalOnTransparentNamedField = { b: string | null, }; export type OverridenStruct = { overriden_field: string, }; export type Pair = { first: Z, second: A, }; export type PlaceholderInnerField = { a: string, }; export type Recursive = { demo: Recursive, }; export type RecursiveInEnum = { A: { demo: RecursiveInEnum, } }; export type RecursiveInline = RecursiveInline; export type RecursiveMapValue = { demo: { [key in string]: RecursiveMapValue }, }; export type RecursiveTransparent = RecursiveInline; export type RefStruct = TestEnum; export type Regular = { [key in string]: null }; export type Rename = "OneWord" | "Two words"; export type RenameSerdeSpecialChar = { "a/b": number, }; export type RenameWithWeirdCharsField = { "@odata.context": string, }; export type RenameWithWeirdCharsVariant = { "@odata.context": string }; export type RenamedFieldKeys = { "": string, "a\"b": string, "a\\b": string, "line\nbreak": string, "line\u2028break": string, "line\u2029break": string, }; export type RenamedVariantWithSkippedPayload = "a-b"; export type Second = { a: number, }; export type Seventh = { a: First, b: Second, }; export type SimpleStruct = { a: number, b: string, c: [number, string, number], d: string[], e: string | null, }; /** Some single-line comment */ export type SingleLineComment = /** Some single-line comment */ ({ A: number }) & { B?: never } | /** Some single-line comment */ ({ B: { /** Some single-line comment */ a: number, } }) & { A?: never }; export type Sixth = { a: First, b: First, }; export type SkipField = { b: number, }; export type SkipNamedFieldInVariant = ({ A: Record }) & { B?: never } | ({ B: { b: number, } }) & { A?: never }; export type SkipOnlyField = Record; export type SkipStructFields = { a: number, }; export type SkipUnnamedFieldInVariant = "A" | { B: [number] }; export type SkipVariant = { A: string }; export type SkipVariant2 = { tag: "A"; data: string }; export type SkipVariant3 = { A: { a: string, } }; export type SkippedFieldWithinVariant = { type: "A" } | { type: "B"; data: string }; export type SpectaSkipNonTypeField = { a: number, }; export type SpectaTypeOverride = { string_ident: string, u32_ident: number, path: string, tuple: [string, number], }; export type Struct2 = { b: string, }; export type StructNew = { t: "StructNew", a: string, }; export type StructRenameAllUppercase = { A: number, B: number, }; export type StructWithAlias = { field: string, }; export type StructWithAliasAndRename = { renamed_field: string, }; export type StructWithMultipleAliases = { field: string, }; export type TagOnStructWithInline = { type: "TagOnStructWithInline", a: First, b: { a: string, }, }; export type Tenth = string | "B" | { a: string, } | First; export type TestCollectionRegister = never; export type TestEnum = "Unit" | ({ Single: number }) & { Multiple?: never; Struct?: never } | ({ Multiple: [number, number] }) & { Single?: never; Struct?: never } | ({ Struct: { a: number, } }) & { Multiple?: never; Single?: never }; export type Third = { b: { [key in string]: string }, c: First, } & First; export type ToBeFlattened = { a: string, }; export type TransparentStruct = string; export type TransparentType = TransparentTypeInner; export type TransparentType2 = null; export type TransparentTypeInner = { inner: string, }; export type TransparentTypeWithOverride = string; export type TransparentWithSkip = null; export type TransparentWithSkip2 = string; export type TransparentWithSkip3 = string; export type TupleNested = [number[], [number[], number[]], [number[], number[], number[]]]; export type TupleStruct = string; export type TupleStruct1 = number; export type TupleStruct3 = [number, boolean, string]; export type TupleStructWithRep = string; export type Unit1 = null; export type Unit2 = Record; export type Unit3 = []; export type Unit4 = null; export type Unit5 = "A"; export type Unit6 = { A: null }; export type Unit7 = { A: Record }; export type UnitVariants = "A" | "B" | "C"; export type UntaggedVariants = string | number | { id: string } | [string, boolean]; export type UntaggedVariantsKey = string | number; export type UntaggedVariantsWithDuplicateBranches = null | number; export type UntaggedVariantsWithoutValue = string | [number, string] | number; export type UntaggedWithAlias = ({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }; export type ValidMaybeValidKey = { [key in MaybeValidKey]: null }; export type ValidMaybeValidKeyNested = { [key in MaybeValidKey>]: null }; ════════════════════════════════════════ tests/ tests/ types.ts (12932 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. import type * as std$ops from "../../std/ops"; import type * as std$result from "../../std/result"; import type * as test$types from "../../test/types"; import type * as test$types$type_type from "../../test/types/type_type"; export type Primitives = { i8: number, i16: number, i32: number, u8: number, u16: number, u32: number, f32: number, f64: number, bool: boolean, char: string, "Range": std$ops.Range, "RangeInclusive": std$ops.RangeInclusive, "()": null, "(String, i32)": [string, number], "(String, i32, bool)": [string, number, boolean], "((String, i32), (bool, char, bool), ())": [[string, number], [boolean, string, boolean], null], "(bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool)": [boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean], "(Vec, Vec)": [number[], boolean[]], String: string, PathBuf: string, IpAddr: string, Ipv4Addr: string, Ipv6Addr: string, SocketAddr: string, SocketAddrV4: string, SocketAddrV6: string, "Cow<'static, str>": string, "Cow<'static, i32>": number, "&'static str": string, "&'static bool": boolean, "&'static i32": number, "Vec": number[], "&'static [i32]": number[], "&'static [i32; 3]": [number, number, number], "[i32; 3]": [number, number, number], "Vec": test$types.MyEnum[], "&'static [MyEnum]": test$types.MyEnum[], "&'static [MyEnum; 6]": [test$types.MyEnum, test$types.MyEnum, test$types.MyEnum, test$types.MyEnum, test$types.MyEnum, test$types.MyEnum], "[MyEnum; 2]": [test$types.MyEnum, test$types.MyEnum], "&'static [i32; 1]": [number], "&'static [i32; 0]": [], "Option": number | null, "Option<()>": null, "Option>": number[] | null, "Result": std$result.Result, "Vec>>": (number | null)[], "Option>>": number[] | null, "[Vec; 3]": [string[], string[], string[]], "Option>": string | null, "Option>>": string | null, "PhantomData<()>": null, "PhantomData": null, Infallible: never, Unit1: test$types.Unit1, Unit2: test$types.Unit2, Unit3: test$types.Unit3, Unit4: test$types.Unit4, Unit5: test$types.Unit5, Unit6: test$types.Unit6, Unit7: test$types.Unit7, SimpleStruct: test$types.SimpleStruct, TupleStruct1: test$types.TupleStruct1, TupleStruct3: test$types.TupleStruct3, TestEnum: test$types.TestEnum, RefStruct: test$types.RefStruct, InlinerStruct: test$types.InlinerStruct, "GenericStruct": test$types.GenericStruct, "GenericStruct": test$types.GenericStruct, FlattenEnumStruct: test$types.FlattenEnumStruct, OverridenStruct: test$types.OverridenStruct, HasGenericAlias: test$types.HasGenericAlias, EnumMacroAttributes: test$types.EnumMacroAttributes, InlineEnumField: test$types.InlineEnumField, InlineOptionalType: test$types.InlineOptionalType, Rename: test$types.Rename, TransparentType: test$types.TransparentType, TransparentType2: test$types.TransparentType2, TransparentTypeWithOverride: test$types.TransparentTypeWithOverride, "[Option; 3]": [(number | null), (number | null), (number | null)], "HashMap": Partial<{ [key in test$types.BasicEnum]: null }>, "HashMap": Partial<{ [key in test$types.BasicEnum]: number }>, "Option>>>": number | null, "Vec": test$types.PlaceholderInnerField[], EnumReferenceRecordKey: test$types.EnumReferenceRecordKey, FlattenOnNestedEnum: test$types.FlattenOnNestedEnum, MyEmptyInput: test$types.MyEmptyInput, "(String)": string, "(String,)": [string], ExtraBracketsInTupleVariant: test$types.ExtraBracketsInTupleVariant, ExtraBracketsInUnnamedStruct: test$types.ExtraBracketsInUnnamedStruct, "Vec": test$types.MyEnum[], InlineTuple: test$types.InlineTuple, InlineTuple2: test$types.InlineTuple2, "Box": string, "Box": string, SkippedFieldWithinVariant: test$types.SkippedFieldWithinVariant, KebabCase: test$types.KebabCase, "&[&str]": string[], "Issue281<'_>": test$types.Issue281, "LifetimeGenericStruct<'_, i32>": test$types.LifetimeGenericStruct, "LifetimeGenericEnum<'_, i32>": test$types.LifetimeGenericEnum, RenameWithWeirdCharsField: test$types.RenameWithWeirdCharsField, RenameWithWeirdCharsVariant: test$types.RenameWithWeirdCharsVariant, RenamedFieldKeys: test$types.RenamedFieldKeys, RenamedVariantWithSkippedPayload: test$types.RenamedVariantWithSkippedPayload, "type_type::Type": test$types$type_type.Type, ActualType: test$types.ActualType, SpectaTypeOverride: test$types.SpectaTypeOverride, ContainerTypeOverrideStruct: test$types.ContainerTypeOverrideStruct, ContainerTypeOverrideEnum: test$types.ContainerTypeOverrideEnum, "ContainerTypeOverrideGeneric>": test$types.ContainerTypeOverrideGeneric, "ContainerTypeOverrideToGeneric": test$types.ContainerTypeOverrideToGeneric, ContainerTypeOverrideTuple: test$types.ContainerTypeOverrideTuple, "ContainerTypeOverrideTupleGeneric": test$types.ContainerTypeOverrideTupleGeneric, InvalidToValidType: test$types.InvalidToValidType, TupleStruct: test$types.TupleStruct, TupleStructWithRep: test$types.TupleStructWithRep, "GenericTupleStruct": test$types.GenericTupleStruct, BracedStruct: test$types.BracedStruct, Struct: test$types.StructNew, Struct2: test$types.Struct2, Enum: test$types.Enum, Enum2: test$types.Enum2, Enum3: test$types.Enum3, StructRenameAllUppercase: test$types.StructRenameAllUppercase, RenameSerdeSpecialChar: test$types.RenameSerdeSpecialChar, EnumRenameAllUppercase: test$types.EnumRenameAllUppercase, Recursive: test$types.Recursive, RecursiveMapValue: test$types.RecursiveMapValue, RecursiveTransparent: test$types.RecursiveTransparent, RecursiveInEnum: test$types.RecursiveInEnum, NonOptional: test$types.NonOptional, OptionalOnNamedField: test$types.OptionalOnNamedField, OptionalOnTransparentNamedField: test$types.OptionalOnTransparentNamedField, OptionalInEnum: test$types.OptionalInEnum, UntaggedVariants: test$types.UntaggedVariants, UntaggedVariantsWithoutValue: test$types.UntaggedVariantsWithoutValue, UntaggedVariantsWithDuplicateBranches: test$types.UntaggedVariantsWithDuplicateBranches, "HashMap": { [key in string]: null }, Regular: test$types.Regular, "HashMap": { [key in never]: null }, "HashMap": { [key in test$types.TransparentStruct]: null }, "HashMap": Partial<{ [key in test$types.UnitVariants]: null }>, "HashMap": Partial<{ [key in test$types.UntaggedVariantsKey]: null }>, ValidMaybeValidKey: test$types.ValidMaybeValidKey, ValidMaybeValidKeyNested: test$types.ValidMaybeValidKeyNested, MacroStruct: test$types.MacroStruct, MacroStruct2: test$types.MacroStruct2, MacroEnum: test$types.MacroEnum, DeprecatedType: test$types.DeprecatedType, DeprecatedTypeWithMsg: test$types.DeprecatedTypeWithMsg, DeprecatedTypeWithMsg2: test$types.DeprecatedTypeWithMsg2, DeprecatedFields: test$types.DeprecatedFields, DeprecatedTupleVariant: test$types.DeprecatedTupleVariant, DeprecatedEnumVariants: test$types.DeprecatedEnumVariants, CommentedStruct: test$types.CommentedStruct, CommentedEnum: test$types.CommentedEnum, SingleLineComment: test$types.SingleLineComment, NonGeneric: test$types.Demo, "HalfGenericA": test$types.Demo, "HalfGenericB": test$types.Demo, "FullGeneric": test$types.Demo, "Another": test$types.Demo, "MapA": { [key in string]: number }, "MapB": { [key in number]: string }, "MapC": { [key in string]: test$types.AGenericStruct }, "AGenericStruct": test$types.AGenericStruct, A: test$types.A, DoubleFlattened: test$types.DoubleFlattened, FlattenedInner: test$types.FlattenedInner, BoxFlattened: test$types.BoxFlattened, BoxInline: test$types.BoxInline, First: test$types.First, Second: test$types.Second, Third: test$types.Third, Fourth: test$types.Fourth, TagOnStructWithInline: test$types.TagOnStructWithInline, Sixth: test$types.Sixth, Seventh: test$types.Seventh, Eight: test$types.Eight, Ninth: test$types.Ninth, Tenth: test$types.Tenth, MyEnumTagged: test$types.MyEnumTagged, MyEnumExternal: test$types.MyEnumExternal, MyEnumAdjacent: test$types.MyEnumAdjacent, MyEnumUntagged: test$types.MyEnumUntagged, EmptyStruct: test$types.EmptyStruct, EmptyStructWithTag: test$types.EmptyStructWithTag, AdjacentlyTagged: test$types.AdjacentlyTagged, LoadProjectEvent: test$types.LoadProjectEvent, ExternallyTagged: test$types.ExternallyTagged, Issue221External: test$types.Issue221External, InternallyTaggedD: test$types.InternallyTaggedD, InternallyTaggedE: test$types.InternallyTaggedE, InternallyTaggedF: test$types.InternallyTaggedF, InternallyTaggedH: test$types.InternallyTaggedH, InternallyTaggedL: test$types.InternallyTaggedL, InternallyTaggedM: test$types.InternallyTaggedM, StructWithAlias: test$types.StructWithAlias, StructWithMultipleAliases: test$types.StructWithMultipleAliases, StructWithAliasAndRename: test$types.StructWithAliasAndRename, EnumWithVariantAlias: test$types.EnumWithVariantAlias, EnumWithMultipleVariantAliases: test$types.EnumWithMultipleVariantAliases, EnumWithVariantAliasAndRename: test$types.EnumWithVariantAliasAndRename, InternallyTaggedWithAlias: test$types.InternallyTaggedWithAlias, AdjacentlyTaggedWithAlias: test$types.AdjacentlyTaggedWithAlias, UntaggedWithAlias: test$types.UntaggedWithAlias, Issue221UntaggedSafe: test$types.Issue221UntaggedSafe, Issue221UntaggedMixed: test$types.Issue221UntaggedMixed, EmptyEnum: test$types.EmptyEnum, EmptyEnumTagged: test$types.EmptyEnumTagged, EmptyEnumTaggedWContent: test$types.EmptyEnumTaggedWContent, EmptyEnumUntagged: test$types.EmptyEnumUntagged, SkipOnlyField: test$types.SkipOnlyField, SkipField: test$types.SkipField, SkipVariant: test$types.SkipVariant, SkipUnnamedFieldInVariant: test$types.SkipUnnamedFieldInVariant, SkipNamedFieldInVariant: test$types.SkipNamedFieldInVariant, TransparentWithSkip: test$types.TransparentWithSkip, TransparentWithSkip2: test$types.TransparentWithSkip2, TransparentWithSkip3: test$types.TransparentWithSkip3, SkipVariant2: test$types.SkipVariant2, SkipVariant3: test$types.SkipVariant3, SkipStructFields: test$types.SkipStructFields, SpectaSkipNonTypeField: test$types.SpectaSkipNonTypeField, FlattenA: test$types.FlattenA, FlattenB: test$types.FlattenB, FlattenC: test$types.FlattenC, FlattenD: test$types.FlattenD, FlattenE: test$types.FlattenE, FlattenF: test$types.FlattenF, FlattenG: test$types.FlattenG, TupleNested: test$types.TupleNested, "Generic1<()>": test$types.Generic1, "GenericAutoBound<()>": test$types.GenericAutoBound, "GenericAutoBound2<()>": test$types.GenericAutoBound2, Container1: test$types.Container1, "Generic2<(), String, i32>": test$types.Generic2, "GenericNewType1<()>": test$types.GenericNewType1, "GenericTuple<()>": test$types.GenericTuple, "GenericStruct2<()>": test$types.GenericStruct2, "InlineGenericNewtype": string, "InlineGenericNested": [string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | ({ Unnamed: string }) & { Named?: never } | ({ Named: { value: string, } }) & { Unnamed?: never }], "InlineFlattenGenericsG<()>": test$types.InlineFlattenGenericsG, InlineFlattenGenerics: test$types.InlineFlattenGenerics, GenericDefault: test$types.GenericDefault, ChainedGenericDefault: test$types.ChainedGenericDefault, "ChainedGenericDefault": test$types.ChainedGenericDefault, "ChainedGenericDefault": test$types.ChainedGenericDefault, "ChainedGenericDefault": test$types.ChainedGenericDefault, GenericDefaultSkipped: test$types.GenericDefaultSkipped, GenericDefaultSkippedNonType: test$types.GenericDefaultSkippedNonType, GenericParameterOrderPreserved: test$types.GenericParameterOrderPreserved, ConstGenericInNonConstContainer: test$types.ConstGenericInNonConstContainer, ConstGenericInConstContainer: test$types.ConstGenericInConstContainer, NamedConstGenericContainer: test$types.NamedConstGenericContainer, InlineConstGenericContainer: test$types.InlineConstGenericContainer, InlineRecursiveConstGenericContainer: test$types.InlineRecursiveConstGenericContainer, TestCollectionRegister: test$types.TestCollectionRegister, TestCollectionRegister: test$types.TestCollectionRegister, }; ════════════════════════════════════════ ================================================ FILE: tests/tests/snapshots/test__typescript__ts-export-to-files-serde_phases.snap ================================================ --- source: tests/tests/typescript.rs expression: output --- std/ ops.ts (181 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. export type Range = { start: T, end: T, }; export type RangeInclusive = { start: T, end: T, }; ════════════════════════════════════════ result.ts (124 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. export type Result = { ok: T, err: E, }; ════════════════════════════════════════ test/ types/ type_type.ts (101 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. export type Type = never; ════════════════════════════════════════ types.ts (17381 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. export type A = { a: B, b: { b: number, }, c: B, d: { flattened: number, }, e: { generic_flattened: number, }, }; export type AGenericStruct = { field: Demo, }; export type ActualType = { a: GenericType, }; export type AdjacentlyTagged = { t: "A" } | { t: "B"; c: { id: string, method: string, } } | { t: "C"; c: string }; export type AdjacentlyTaggedWithAlias = { type: "A"; data: { field: string, } } | { type: "B"; data: { other: number, } }; export type B = { b: number, }; export type BasicEnum = "A" | "B"; export type BoxFlattened = BoxedInner; export type BoxInline = { c: { a: number, }, }; export type BoxedInner = { a: number, }; export type BracedStruct = string; export type ChainedGenericDefault = { first: T, second: U, }; /** * Some triple-slash comment * Some more triple-slash comment */ export type CommentedEnum = /** * Some triple-slash comment * Some more triple-slash comment */ ({ A: number }) & { B?: never } | /** * Some triple-slash comment * Some more triple-slash comment */ ({ B: { /** * Some triple-slash comment * Some more triple-slash comment */ a: number, } }) & { A?: never }; /** * Some triple-slash comment * Some more triple-slash comment */ export type CommentedStruct = { /** * Some triple-slash comment * Some more triple-slash comment */ a: number, }; export type ConstGenericInConstContainer = { data: number[], a: number[], d: [number, number], }; export type ConstGenericInNonConstContainer = { data: [number], a: [number, number], d: [number, number], }; export type Container1 = { foo: Generic1, bar: Generic1[], baz: { [key in string]: Generic1 }, }; export type ContainerTypeOverrideEnum = string; export type ContainerTypeOverrideGeneric = string; export type ContainerTypeOverrideStruct = string; export type ContainerTypeOverrideToGeneric = T; export type ContainerTypeOverrideTuple = [string, number]; export type ContainerTypeOverrideTupleGeneric = [T, string]; export type D = { flattened: number, }; export type Demo = { a: A, b: B, }; export type DeprecatedEnumVariants = /** * @deprecated */ "A" | /** * @deprecated Nope */ "B" | /** * @deprecated Nope */ "C"; export type DeprecatedFields = { a: number, /** * @deprecated */ b: string, /** * @deprecated This field is cringe! */ c: string, /** * @deprecated This field is cringe! */ d: string, }; export type DeprecatedTupleVariant = [ /** * @deprecated */ string, /** * @deprecated Nope */ string, /** * @deprecated Nope */ number]; /** * @deprecated */ export type DeprecatedType = { a: number, }; /** * @deprecated Look at you big man using a deprecation message */ export type DeprecatedTypeWithMsg = { a: number, }; /** * @deprecated Look at you big man using a deprecation message */ export type DeprecatedTypeWithMsg2 = { a: number, }; export type DoubleFlattened = { a: ToBeFlattened, b: ToBeFlattened, }; export type Eight = { A: string } | "B"; export type EmptyEnum = never; export type EmptyEnumTagged = never; export type EmptyEnumTaggedWContent = never; export type EmptyEnumUntagged = never; export type EmptyStruct = Record; export type EmptyStructWithTag = { a: "EmptyStructWithTag", }; export type Enum = { t: "A" } | { t: "B" }; export type Enum2 = { t: "C" } | { t: "B" } | { t: "D"; enumField: null }; export type Enum3 = { t: "A"; b: string }; export type EnumMacroAttributes = ({ A: string }) & { D?: never; bbb?: never; cccc?: never } | ({ bbb: number }) & { A?: never; D?: never; cccc?: never } | ({ cccc: number }) & { A?: never; D?: never; bbb?: never } | ({ D: { a: string, bbbbbb: number, } }) & { A?: never; bbb?: never; cccc?: never }; export type EnumReferenceRecordKey = { a: Partial<{ [key in BasicEnum]: number }>, }; export type EnumRenameAllUppercase = "HELLOWORLD" | "VARIANTB" | "TESTINGWORDS"; export type EnumWithMultipleVariantAliases = "Variant" | "Other"; export type EnumWithVariantAlias = "Variant" | "Other"; export type EnumWithVariantAliasAndRename = "renamed_variant" | "Other"; export type ExternallyTagged = "A" | ({ B: { id: string, method: string, } }) & { C?: never } | ({ C: string }) & { B?: never }; export type ExtraBracketsInTupleVariant = { A: string }; export type ExtraBracketsInUnnamedStruct = string; export type First = { a: string, }; export type FlattenA = { a: number, b: number, }; export type FlattenB = { c: number, } & FlattenA; export type FlattenC = { c: number, } & FlattenA; export type FlattenD = { a: FlattenA, c: number, }; export type FlattenE = { b: ({ c: number, }) & (FlattenA), d: number, }; export type FlattenEnum = { tag: "One" } | { tag: "Two" } | { tag: "Three" }; export type FlattenEnumStruct = { outer: string, } & FlattenEnum; export type FlattenF = { b: ({ c: number, }) & (FlattenA), d: number, }; export type FlattenG = { b: FlattenB, d: number, }; export type FlattenOnNestedEnum = { id: string, } & NestedEnum; export type FlattenedInner = Inner; export type Fourth = { a: First, b: { a: string, }, }; export type Generic1 = { value: T, values: T[], }; export type Generic2 = ({ A: A }) & { B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ B: [B, B, B] }) & { A?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ C: C[] }) & { A?: never; B?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ D: A[][][] }) & { A?: never; B?: never; C?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ E: { a: A, b: B, c: C, } }) & { A?: never; B?: never; C?: never; D?: never; X?: never; Y?: never; Z?: never } | ({ X: number[] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; Y?: never; Z?: never } | ({ Y: number }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Z?: never } | ({ Z: number[][] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never }; export type GenericAutoBound = { value: T, values: T[], }; export type GenericAutoBound2 = { value: T, values: T[], }; export type GenericDefault = { value: T, }; export type GenericDefaultSkipped = { value: T, }; export type GenericDefaultSkippedNonType = { value: number, }; export type GenericFlattened = { generic_flattened: T, }; export type GenericNewType1 = T[][]; export type GenericParameterOrderPreserved = { pair: Pair, }; export type GenericStruct = { arg: T, }; export type GenericStruct2 = { a: T, b: [T, T], c: [T, [T, T]], d: [T, T, T], e: [([T, T]), ([T, T]), ([T, T])], f: T[], g: T[][], h: ([([T, T]), ([T, T]), ([T, T])])[], }; export type GenericTuple = [T, T[], T[][]]; export type GenericTupleStruct = T; export type GenericType = "Undefined" | T; export type HasGenericAlias = { [key in number]: string }; export type InlineConstGenericContainer = { b: { data: [number, number], a: [number, number], d: [number, number, number], }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], }, d: [number, number], }; export type InlineEnumField = { A: { a: string, } }; export type InlineFlattenGenerics = { g: InlineFlattenGenericsG, gi: { t: string, }, } & InlineFlattenGenericsG; export type InlineFlattenGenericsG = { t: T, }; export type InlineOptionalType = { optional_field: { a: string, } | null, }; export type InlineRecursiveConstGeneric = { data: number[], a: number[], d: [number, number, number], e: InlineRecursiveConstGeneric, }; export type InlineRecursiveConstGenericContainer = { b: { data: [number, number], a: [number, number], d: [number, number, number], e: InlineRecursiveConstGeneric, }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], e: InlineRecursiveConstGeneric, }, d: [number, number], }; export type InlineStruct = { ref_struct: SimpleStruct, val: number, }; export type InlineTuple = { demo: [string, boolean], }; export type InlineTuple2 = { demo: [{ demo: [string, boolean], }, boolean], }; export type InlinerStruct = { inline_this: { ref_struct: SimpleStruct, val: number, }, dont_inline_this: RefStruct, }; export type Inner = { a: number, } & FlattenedInner; export type InternallyTaggedD = { type: "A", } & { [key in string]: string }; export type InternallyTaggedE = { type: "A" }; export type InternallyTaggedF = { type: "A" }; export type InternallyTaggedFInner = null; export type InternallyTaggedH = { type: "A" }; export type InternallyTaggedHInner = null; export type InternallyTaggedL = { type: "A", } & { type: "A" } | { type: "B" }; export type InternallyTaggedLInner = { type: "A" } | { type: "B" }; export type InternallyTaggedM = { type: "A" }; export type InternallyTaggedMInner = "A" | "B"; export type InternallyTaggedWithAlias = { type: "A"; field: string } | { type: "B"; other: number }; export type InvalidToValidType = { cause: null, }; export type Issue221External = ({ A: { a: string, } }) & { B?: never } | ({ B: { b: string, } }) & { A?: never }; export type Issue221UntaggedMixed = ({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never }; export type Issue221UntaggedSafe = ({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }; export type Issue281 = { default_unity_arguments: string[], }; /** https://github.com/specta-rs/specta/issues/374 */ export type Issue374 = Issue374_Serialize | Issue374_Deserialize; /** https://github.com/specta-rs/specta/issues/374 */ export type Issue374_Deserialize = { foo?: boolean, bar?: boolean, }; /** https://github.com/specta-rs/specta/issues/374 */ export type Issue374_Serialize = { foo?: boolean, bar?: boolean, }; export type KebabCase = { "test-ing": string, }; export type LifetimeGenericEnum = ({ Borrowed: T }) & { Owned?: never } | ({ Owned: T }) & { Borrowed?: never }; export type LifetimeGenericStruct = { borrowed: T[], owned: T[], }; export type LoadProjectEvent = { event: "started"; data: { projectName: string, } } | { event: "progressTest"; data: { projectName: string, status: string, progress: number, } } | { event: "finished"; data: { projectName: string, } }; export type MacroEnum = ({ Demo: string }) & { Demo2?: never } | ({ Demo2: { demo2: string, } }) & { Demo?: never }; export type MacroStruct = string; export type MacroStruct2 = { demo: string, }; export type MaybeValidKey = T; export type MyEmptyInput = Record; export type MyEnum = ({ A: string }) & { B?: never } | ({ B: number }) & { A?: never }; export type MyEnumAdjacent = { t: "Variant"; c: { inner: First, } }; export type MyEnumExternal = { Variant: { inner: First, } }; export type MyEnumTagged = { type: "Variant"; inner: First }; export type MyEnumUntagged = { inner: First }; export type NamedConstGeneric = { data: number[], a: number[], d: [number, number], }; export type NamedConstGenericContainer = { a: NamedConstGeneric, b: NamedConstGeneric, d: [number, number], }; export type NestedEnum = { type: "a"; value: string } | { type: "b"; value: number }; export type Ninth = { t: "A"; c: string } | { t: "B" } | { t: "C"; c: { a: string, } } | { t: "D"; c: First }; export type NonOptional = string | null; export type Optional = Optional_Serialize | Optional_Deserialize; export type OptionalInEnum = ({ A?: string | null }) & { B?: never; C?: never } | ({ B: { a: string | null, } }) & { A?: never; C?: never } | ({ C: { a?: string | null, } }) & { A?: never; B?: never }; export type OptionalOnNamedField = string | null; export type OptionalOnTransparentNamedField = { b: string | null, }; export type Optional_Deserialize = { a: number | null, b?: number | null, c: string | null, d?: boolean, }; export type Optional_Serialize = { a: number | null, b?: number | null, c?: string | null, d: boolean, }; export type OverridenStruct = { overriden_field: string, }; export type Pair = { first: Z, second: A, }; export type PlaceholderInnerField = { a: string, }; export type Recursive = { demo: Recursive, }; export type RecursiveInEnum = { A: { demo: RecursiveInEnum, } }; export type RecursiveInline = RecursiveInline; export type RecursiveMapValue = { demo: { [key in string]: RecursiveMapValue }, }; export type RecursiveTransparent = RecursiveInline; export type RefStruct = TestEnum; export type Regular = { [key in string]: null }; export type Rename = "OneWord" | "Two words"; export type RenameSerdeSpecialChar = { "a/b": number, }; export type RenameWithWeirdCharsField = { "@odata.context": string, }; export type RenameWithWeirdCharsVariant = { "@odata.context": string }; export type RenamedFieldKeys = { "": string, "a\"b": string, "a\\b": string, "line\nbreak": string, "line\u2028break": string, "line\u2029break": string, }; export type RenamedVariantWithSkippedPayload = "a-b"; export type Second = { a: number, }; export type Seventh = { a: First, b: Second, }; export type SimpleStruct = { a: number, b: string, c: [number, string, number], d: string[], e: string | null, }; /** Some single-line comment */ export type SingleLineComment = /** Some single-line comment */ ({ A: number }) & { B?: never } | /** Some single-line comment */ ({ B: { /** Some single-line comment */ a: number, } }) & { A?: never }; export type Sixth = { a: First, b: First, }; export type SkipField = { b: number, }; export type SkipNamedFieldInVariant = ({ A: Record }) & { B?: never } | ({ B: { b: number, } }) & { A?: never }; export type SkipOnlyField = Record; export type SkipStructFields = { a: number, }; export type SkipUnnamedFieldInVariant = "A" | { B: [number] }; export type SkipVariant = { A: string }; export type SkipVariant2 = { tag: "A"; data: string }; export type SkipVariant3 = { A: { a: string, } }; export type SkippedFieldWithinVariant = { type: "A" } | { type: "B"; data: string }; export type SpectaSkipNonTypeField = { a: number, }; export type SpectaTypeOverride = { string_ident: string, u32_ident: number, path: string, tuple: [string, number], }; export type Struct2 = { b: string, }; export type StructNew = { t: "StructNew", a: string, }; export type StructPhaseSpecificRename = StructPhaseSpecificRenameSerialize | StructPhaseSpecificRenameDeserialize; export type StructPhaseSpecificRenameDeserialize = { kind: "StructPhaseSpecificRenameDeserialize", der: string, }; export type StructPhaseSpecificRenameSerialize = { kind: "StructPhaseSpecificRenameSerialize", ser: string, }; export type StructRenameAllUppercase = { A: number, B: number, }; export type StructWithAlias = { field: string, }; export type StructWithAliasAndRename = { renamed_field: string, }; export type StructWithMultipleAliases = { field: string, }; export type TagOnStructWithInline = { type: "TagOnStructWithInline", a: First, b: { a: string, }, }; export type Tenth = string | "B" | { a: string, } | First; export type TestCollectionRegister = never; export type TestEnum = "Unit" | ({ Single: number }) & { Multiple?: never; Struct?: never } | ({ Multiple: [number, number] }) & { Single?: never; Struct?: never } | ({ Struct: { a: number, } }) & { Multiple?: never; Single?: never }; export type Third = { b: { [key in string]: string }, c: First, } & First; export type ToBeFlattened = { a: string, }; export type TransparentStruct = string; export type TransparentType = TransparentTypeInner; export type TransparentType2 = null; export type TransparentTypeInner = { inner: string, }; export type TransparentTypeWithOverride = string; export type TransparentWithSkip = null; export type TransparentWithSkip2 = string; export type TransparentWithSkip3 = string; export type TupleNested = [number[], [number[], number[]], [number[], number[], number[]]]; export type TupleStruct = string; export type TupleStruct1 = number; export type TupleStruct3 = [number, boolean, string]; export type TupleStructWithRep = string; export type Unit1 = null; export type Unit2 = Record; export type Unit3 = []; export type Unit4 = null; export type Unit5 = "A"; export type Unit6 = { A: null }; export type Unit7 = { A: Record }; export type UnitVariants = "A" | "B" | "C"; export type UntaggedVariants = string | number | { id: string } | [string, boolean]; export type UntaggedVariantsKey = string | number; export type UntaggedVariantsWithDuplicateBranches = null | number; export type UntaggedVariantsWithoutValue = string | [number, string] | number; export type UntaggedWithAlias = ({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }; export type ValidMaybeValidKey = { [key in MaybeValidKey]: null }; export type ValidMaybeValidKeyNested = { [key in MaybeValidKey>]: null }; ════════════════════════════════════════ tests/ tests/ types.ts (12932 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. import type * as std$ops from "../../std/ops"; import type * as std$result from "../../std/result"; import type * as test$types from "../../test/types"; import type * as test$types$type_type from "../../test/types/type_type"; export type Primitives = { i8: number, i16: number, i32: number, u8: number, u16: number, u32: number, f32: number, f64: number, bool: boolean, char: string, "Range": std$ops.Range, "RangeInclusive": std$ops.RangeInclusive, "()": null, "(String, i32)": [string, number], "(String, i32, bool)": [string, number, boolean], "((String, i32), (bool, char, bool), ())": [[string, number], [boolean, string, boolean], null], "(bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool)": [boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean], "(Vec, Vec)": [number[], boolean[]], String: string, PathBuf: string, IpAddr: string, Ipv4Addr: string, Ipv6Addr: string, SocketAddr: string, SocketAddrV4: string, SocketAddrV6: string, "Cow<'static, str>": string, "Cow<'static, i32>": number, "&'static str": string, "&'static bool": boolean, "&'static i32": number, "Vec": number[], "&'static [i32]": number[], "&'static [i32; 3]": [number, number, number], "[i32; 3]": [number, number, number], "Vec": test$types.MyEnum[], "&'static [MyEnum]": test$types.MyEnum[], "&'static [MyEnum; 6]": [test$types.MyEnum, test$types.MyEnum, test$types.MyEnum, test$types.MyEnum, test$types.MyEnum, test$types.MyEnum], "[MyEnum; 2]": [test$types.MyEnum, test$types.MyEnum], "&'static [i32; 1]": [number], "&'static [i32; 0]": [], "Option": number | null, "Option<()>": null, "Option>": number[] | null, "Result": std$result.Result, "Vec>>": (number | null)[], "Option>>": number[] | null, "[Vec; 3]": [string[], string[], string[]], "Option>": string | null, "Option>>": string | null, "PhantomData<()>": null, "PhantomData": null, Infallible: never, Unit1: test$types.Unit1, Unit2: test$types.Unit2, Unit3: test$types.Unit3, Unit4: test$types.Unit4, Unit5: test$types.Unit5, Unit6: test$types.Unit6, Unit7: test$types.Unit7, SimpleStruct: test$types.SimpleStruct, TupleStruct1: test$types.TupleStruct1, TupleStruct3: test$types.TupleStruct3, TestEnum: test$types.TestEnum, RefStruct: test$types.RefStruct, InlinerStruct: test$types.InlinerStruct, "GenericStruct": test$types.GenericStruct, "GenericStruct": test$types.GenericStruct, FlattenEnumStruct: test$types.FlattenEnumStruct, OverridenStruct: test$types.OverridenStruct, HasGenericAlias: test$types.HasGenericAlias, EnumMacroAttributes: test$types.EnumMacroAttributes, InlineEnumField: test$types.InlineEnumField, InlineOptionalType: test$types.InlineOptionalType, Rename: test$types.Rename, TransparentType: test$types.TransparentType, TransparentType2: test$types.TransparentType2, TransparentTypeWithOverride: test$types.TransparentTypeWithOverride, "[Option; 3]": [(number | null), (number | null), (number | null)], "HashMap": Partial<{ [key in test$types.BasicEnum]: null }>, "HashMap": Partial<{ [key in test$types.BasicEnum]: number }>, "Option>>>": number | null, "Vec": test$types.PlaceholderInnerField[], EnumReferenceRecordKey: test$types.EnumReferenceRecordKey, FlattenOnNestedEnum: test$types.FlattenOnNestedEnum, MyEmptyInput: test$types.MyEmptyInput, "(String)": string, "(String,)": [string], ExtraBracketsInTupleVariant: test$types.ExtraBracketsInTupleVariant, ExtraBracketsInUnnamedStruct: test$types.ExtraBracketsInUnnamedStruct, "Vec": test$types.MyEnum[], InlineTuple: test$types.InlineTuple, InlineTuple2: test$types.InlineTuple2, "Box": string, "Box": string, SkippedFieldWithinVariant: test$types.SkippedFieldWithinVariant, KebabCase: test$types.KebabCase, "&[&str]": string[], "Issue281<'_>": test$types.Issue281, "LifetimeGenericStruct<'_, i32>": test$types.LifetimeGenericStruct, "LifetimeGenericEnum<'_, i32>": test$types.LifetimeGenericEnum, RenameWithWeirdCharsField: test$types.RenameWithWeirdCharsField, RenameWithWeirdCharsVariant: test$types.RenameWithWeirdCharsVariant, RenamedFieldKeys: test$types.RenamedFieldKeys, RenamedVariantWithSkippedPayload: test$types.RenamedVariantWithSkippedPayload, "type_type::Type": test$types$type_type.Type, ActualType: test$types.ActualType, SpectaTypeOverride: test$types.SpectaTypeOverride, ContainerTypeOverrideStruct: test$types.ContainerTypeOverrideStruct, ContainerTypeOverrideEnum: test$types.ContainerTypeOverrideEnum, "ContainerTypeOverrideGeneric>": test$types.ContainerTypeOverrideGeneric, "ContainerTypeOverrideToGeneric": test$types.ContainerTypeOverrideToGeneric, ContainerTypeOverrideTuple: test$types.ContainerTypeOverrideTuple, "ContainerTypeOverrideTupleGeneric": test$types.ContainerTypeOverrideTupleGeneric, InvalidToValidType: test$types.InvalidToValidType, TupleStruct: test$types.TupleStruct, TupleStructWithRep: test$types.TupleStructWithRep, "GenericTupleStruct": test$types.GenericTupleStruct, BracedStruct: test$types.BracedStruct, Struct: test$types.StructNew, Struct2: test$types.Struct2, Enum: test$types.Enum, Enum2: test$types.Enum2, Enum3: test$types.Enum3, StructRenameAllUppercase: test$types.StructRenameAllUppercase, RenameSerdeSpecialChar: test$types.RenameSerdeSpecialChar, EnumRenameAllUppercase: test$types.EnumRenameAllUppercase, Recursive: test$types.Recursive, RecursiveMapValue: test$types.RecursiveMapValue, RecursiveTransparent: test$types.RecursiveTransparent, RecursiveInEnum: test$types.RecursiveInEnum, NonOptional: test$types.NonOptional, OptionalOnNamedField: test$types.OptionalOnNamedField, OptionalOnTransparentNamedField: test$types.OptionalOnTransparentNamedField, OptionalInEnum: test$types.OptionalInEnum, UntaggedVariants: test$types.UntaggedVariants, UntaggedVariantsWithoutValue: test$types.UntaggedVariantsWithoutValue, UntaggedVariantsWithDuplicateBranches: test$types.UntaggedVariantsWithDuplicateBranches, "HashMap": { [key in string]: null }, Regular: test$types.Regular, "HashMap": { [key in never]: null }, "HashMap": { [key in test$types.TransparentStruct]: null }, "HashMap": Partial<{ [key in test$types.UnitVariants]: null }>, "HashMap": Partial<{ [key in test$types.UntaggedVariantsKey]: null }>, ValidMaybeValidKey: test$types.ValidMaybeValidKey, ValidMaybeValidKeyNested: test$types.ValidMaybeValidKeyNested, MacroStruct: test$types.MacroStruct, MacroStruct2: test$types.MacroStruct2, MacroEnum: test$types.MacroEnum, DeprecatedType: test$types.DeprecatedType, DeprecatedTypeWithMsg: test$types.DeprecatedTypeWithMsg, DeprecatedTypeWithMsg2: test$types.DeprecatedTypeWithMsg2, DeprecatedFields: test$types.DeprecatedFields, DeprecatedTupleVariant: test$types.DeprecatedTupleVariant, DeprecatedEnumVariants: test$types.DeprecatedEnumVariants, CommentedStruct: test$types.CommentedStruct, CommentedEnum: test$types.CommentedEnum, SingleLineComment: test$types.SingleLineComment, NonGeneric: test$types.Demo, "HalfGenericA": test$types.Demo, "HalfGenericB": test$types.Demo, "FullGeneric": test$types.Demo, "Another": test$types.Demo, "MapA": { [key in string]: number }, "MapB": { [key in number]: string }, "MapC": { [key in string]: test$types.AGenericStruct }, "AGenericStruct": test$types.AGenericStruct, A: test$types.A, DoubleFlattened: test$types.DoubleFlattened, FlattenedInner: test$types.FlattenedInner, BoxFlattened: test$types.BoxFlattened, BoxInline: test$types.BoxInline, First: test$types.First, Second: test$types.Second, Third: test$types.Third, Fourth: test$types.Fourth, TagOnStructWithInline: test$types.TagOnStructWithInline, Sixth: test$types.Sixth, Seventh: test$types.Seventh, Eight: test$types.Eight, Ninth: test$types.Ninth, Tenth: test$types.Tenth, MyEnumTagged: test$types.MyEnumTagged, MyEnumExternal: test$types.MyEnumExternal, MyEnumAdjacent: test$types.MyEnumAdjacent, MyEnumUntagged: test$types.MyEnumUntagged, EmptyStruct: test$types.EmptyStruct, EmptyStructWithTag: test$types.EmptyStructWithTag, AdjacentlyTagged: test$types.AdjacentlyTagged, LoadProjectEvent: test$types.LoadProjectEvent, ExternallyTagged: test$types.ExternallyTagged, Issue221External: test$types.Issue221External, InternallyTaggedD: test$types.InternallyTaggedD, InternallyTaggedE: test$types.InternallyTaggedE, InternallyTaggedF: test$types.InternallyTaggedF, InternallyTaggedH: test$types.InternallyTaggedH, InternallyTaggedL: test$types.InternallyTaggedL, InternallyTaggedM: test$types.InternallyTaggedM, StructWithAlias: test$types.StructWithAlias, StructWithMultipleAliases: test$types.StructWithMultipleAliases, StructWithAliasAndRename: test$types.StructWithAliasAndRename, EnumWithVariantAlias: test$types.EnumWithVariantAlias, EnumWithMultipleVariantAliases: test$types.EnumWithMultipleVariantAliases, EnumWithVariantAliasAndRename: test$types.EnumWithVariantAliasAndRename, InternallyTaggedWithAlias: test$types.InternallyTaggedWithAlias, AdjacentlyTaggedWithAlias: test$types.AdjacentlyTaggedWithAlias, UntaggedWithAlias: test$types.UntaggedWithAlias, Issue221UntaggedSafe: test$types.Issue221UntaggedSafe, Issue221UntaggedMixed: test$types.Issue221UntaggedMixed, EmptyEnum: test$types.EmptyEnum, EmptyEnumTagged: test$types.EmptyEnumTagged, EmptyEnumTaggedWContent: test$types.EmptyEnumTaggedWContent, EmptyEnumUntagged: test$types.EmptyEnumUntagged, SkipOnlyField: test$types.SkipOnlyField, SkipField: test$types.SkipField, SkipVariant: test$types.SkipVariant, SkipUnnamedFieldInVariant: test$types.SkipUnnamedFieldInVariant, SkipNamedFieldInVariant: test$types.SkipNamedFieldInVariant, TransparentWithSkip: test$types.TransparentWithSkip, TransparentWithSkip2: test$types.TransparentWithSkip2, TransparentWithSkip3: test$types.TransparentWithSkip3, SkipVariant2: test$types.SkipVariant2, SkipVariant3: test$types.SkipVariant3, SkipStructFields: test$types.SkipStructFields, SpectaSkipNonTypeField: test$types.SpectaSkipNonTypeField, FlattenA: test$types.FlattenA, FlattenB: test$types.FlattenB, FlattenC: test$types.FlattenC, FlattenD: test$types.FlattenD, FlattenE: test$types.FlattenE, FlattenF: test$types.FlattenF, FlattenG: test$types.FlattenG, TupleNested: test$types.TupleNested, "Generic1<()>": test$types.Generic1, "GenericAutoBound<()>": test$types.GenericAutoBound, "GenericAutoBound2<()>": test$types.GenericAutoBound2, Container1: test$types.Container1, "Generic2<(), String, i32>": test$types.Generic2, "GenericNewType1<()>": test$types.GenericNewType1, "GenericTuple<()>": test$types.GenericTuple, "GenericStruct2<()>": test$types.GenericStruct2, "InlineGenericNewtype": string, "InlineGenericNested": [string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | ({ Unnamed: string }) & { Named?: never } | ({ Named: { value: string, } }) & { Unnamed?: never }], "InlineFlattenGenericsG<()>": test$types.InlineFlattenGenericsG, InlineFlattenGenerics: test$types.InlineFlattenGenerics, GenericDefault: test$types.GenericDefault, ChainedGenericDefault: test$types.ChainedGenericDefault, "ChainedGenericDefault": test$types.ChainedGenericDefault, "ChainedGenericDefault": test$types.ChainedGenericDefault, "ChainedGenericDefault": test$types.ChainedGenericDefault, GenericDefaultSkipped: test$types.GenericDefaultSkipped, GenericDefaultSkippedNonType: test$types.GenericDefaultSkippedNonType, GenericParameterOrderPreserved: test$types.GenericParameterOrderPreserved, ConstGenericInNonConstContainer: test$types.ConstGenericInNonConstContainer, ConstGenericInConstContainer: test$types.ConstGenericInConstContainer, NamedConstGenericContainer: test$types.NamedConstGenericContainer, InlineConstGenericContainer: test$types.InlineConstGenericContainer, InlineRecursiveConstGenericContainer: test$types.InlineRecursiveConstGenericContainer, TestCollectionRegister: test$types.TestCollectionRegister, TestCollectionRegister: test$types.TestCollectionRegister, }; ════════════════════════════════════════ ================================================ FILE: tests/tests/snapshots/test__typescript__ts-export-to-flatfile-raw.snap ================================================ --- source: tests/tests/typescript.rs expression: output --- ts-export-to-flatfile-raw (24613 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. export type A = { a: B, b: { b: number, }, c: B, d: { flattened: number, }, e: { generic_flattened: number, }, }; export type AGenericStruct = { field: Demo, }; export type ActualType = { a: GenericType, }; export type AdjacentlyTagged = "A" | { id: string; method: string } | string; export type AdjacentlyTaggedWithAlias = ({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }; export type B = { b: number, }; export type BasicEnum = "A" | "B"; export type BoxFlattened = { b: BoxedInner, }; export type BoxInline = { c: { a: number, }, }; export type BoxedInner = { a: number, }; export type BracedStruct = string; export type ChainedGenericDefault = { first: T, second: U, }; /** * Some triple-slash comment * Some more triple-slash comment */ export type CommentedEnum = /** * Some triple-slash comment * Some more triple-slash comment */ number | /** * Some triple-slash comment * Some more triple-slash comment */ { /** * Some triple-slash comment * Some more triple-slash comment */ a: number }; /** * Some triple-slash comment * Some more triple-slash comment */ export type CommentedStruct = { /** * Some triple-slash comment * Some more triple-slash comment */ a: number, }; export type ConstGenericInConstContainer = { data: number[], a: number[], d: [number, number], }; export type ConstGenericInNonConstContainer = { data: [number], a: [number, number], d: [number, number], }; export type Container1 = { foo: Generic1, bar: Generic1[], baz: { [key in string]: Generic1 }, }; export type ContainerTypeOverrideEnum = string; export type ContainerTypeOverrideGeneric = string; export type ContainerTypeOverrideStruct = string; export type ContainerTypeOverrideToGeneric = T; export type ContainerTypeOverrideTuple = [string, number]; export type ContainerTypeOverrideTupleGeneric = [T, string]; export type D = { flattened: number, }; export type Demo = { a: A, b: B, }; export type DeprecatedEnumVariants = /** * @deprecated */ "A" | /** * @deprecated Nope */ "B" | /** * @deprecated Nope */ "C"; export type DeprecatedFields = { a: number, /** * @deprecated */ b: string, /** * @deprecated This field is cringe! */ c: string, /** * @deprecated This field is cringe! */ d: string, }; export type DeprecatedTupleVariant = [ /** * @deprecated */ string, /** * @deprecated Nope */ string, /** * @deprecated Nope */ number]; /** * @deprecated */ export type DeprecatedType = { a: number, }; /** * @deprecated Look at you big man using a deprecation message */ export type DeprecatedTypeWithMsg = { a: number, }; /** * @deprecated Look at you big man using a deprecation message */ export type DeprecatedTypeWithMsg2 = { a: number, }; export type DoubleFlattened = { a: ToBeFlattened, b: ToBeFlattened, }; export type Eight = string | "B"; export type EmptyEnum = never; export type EmptyEnumTagged = never; export type EmptyEnumTaggedWContent = never; export type EmptyEnumUntagged = never; export type EmptyStruct = Record; export type EmptyStructWithTag = Record; export type Enum = "A" | "B"; export type Enum2 = "A" | "B" | { enum_field: null }; export type Enum3 = { a: string }; export type EnumMacroAttributes = string | number | { a: string; b: number }; export type EnumReferenceRecordKey = { a: Partial<{ [key in BasicEnum]: number }>, }; export type EnumRenameAllUppercase = "HelloWorld" | "VariantB" | "TestingWords"; export type EnumWithMultipleVariantAliases = "Variant" | "Other"; export type EnumWithVariantAlias = "Variant" | "Other"; export type EnumWithVariantAliasAndRename = "Variant" | "Other"; export type ExternallyTagged = "A" | { id: string; method: string } | string; export type ExtraBracketsInTupleVariant = string; export type ExtraBracketsInUnnamedStruct = string; export type First = { a: string, }; export type FlattenA = { a: number, b: number, }; export type FlattenB = { a: FlattenA, c: number, }; export type FlattenC = { a: FlattenA, c: number, }; export type FlattenD = { a: FlattenA, c: number, }; export type FlattenE = { b: { a: FlattenA, c: number, }, d: number, }; export type FlattenEnum = "One" | "Two" | "Three"; export type FlattenEnumStruct = { outer: string, inner: FlattenEnum, }; export type FlattenF = { b: { a: FlattenA, c: number, }, d: number, }; export type FlattenG = { b: FlattenB, d: number, }; export type FlattenOnNestedEnum = { id: string, result: NestedEnum, }; export type FlattenedInner = { c: Inner, }; export type Fourth = { a: First, b: { a: string, }, }; export type Generic1 = { value: T, values: T[], }; export type Generic2 = A | [B, B, B] | C[] | A[][][] | { a: A; b: B; c: C } | number[] | number | number[][]; export type GenericAutoBound = { value: T, values: T[], }; export type GenericAutoBound2 = { value: T, values: T[], }; export type GenericDefault = { value: T, }; export type GenericDefaultSkipped = { value: T, }; export type GenericDefaultSkippedNonType = { value: number, }; export type GenericFlattened = { generic_flattened: T, }; export type GenericNewType1 = T[][]; export type GenericParameterOrderPreserved = { pair: Pair, }; export type GenericStruct = { arg: T, }; export type GenericStruct2 = { a: T, b: [T, T], c: [T, [T, T]], d: [T, T, T], e: [([T, T]), ([T, T]), ([T, T])], f: T[], g: T[][], h: ([([T, T]), ([T, T]), ([T, T])])[], }; export type GenericTuple = [T, T[], T[][]]; export type GenericTupleStruct = T; export type GenericType = "Undefined" | T; export type HasGenericAlias = { [key in number]: string }; export type InlineConstGenericContainer = { b: { data: [number, number], a: [number, number], d: [number, number, number], }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], }, d: [number, number], }; export type InlineEnumField = { a: string, }; export type InlineFlattenGenerics = { g: InlineFlattenGenericsG, gi: { t: string, }, t: InlineFlattenGenericsG, }; export type InlineFlattenGenericsG = { t: T, }; export type InlineOptionalType = { optional_field: { a: string, } | null, }; export type InlineRecursiveConstGeneric = { data: number[], a: number[], d: [number, number, number], e: InlineRecursiveConstGeneric, }; export type InlineRecursiveConstGenericContainer = { b: { data: [number, number], a: [number, number], d: [number, number, number], e: InlineRecursiveConstGeneric, }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], e: InlineRecursiveConstGeneric, }, d: [number, number], }; export type InlineStruct = { ref_struct: SimpleStruct, val: number, }; export type InlineTuple = { demo: [string, boolean], }; export type InlineTuple2 = { demo: [{ demo: [string, boolean], }, boolean], }; export type InlinerStruct = { inline_this: { ref_struct: SimpleStruct, val: number, }, dont_inline_this: RefStruct, }; export type Inner = { a: number, b: FlattenedInner, }; export type InternallyTaggedD = { [key in string]: string }; export type InternallyTaggedE = null; export type InternallyTaggedF = InternallyTaggedFInner; export type InternallyTaggedFInner = null; export type InternallyTaggedH = InternallyTaggedHInner; export type InternallyTaggedHInner = null; export type InternallyTaggedL = "A" | "B"; export type InternallyTaggedLInner = "A" | "B"; export type InternallyTaggedM = "A" | "B"; export type InternallyTaggedMInner = "A" | "B"; export type InternallyTaggedWithAlias = ({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }; export type InvalidToValidType = { cause: null, }; export type Issue221External = ({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }; export type Issue221UntaggedMixed = ({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never }; export type Issue221UntaggedSafe = ({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }; export type Issue281 = { default_unity_arguments: string[], }; export type KebabCase = { test_ing: string, }; export type LifetimeGenericEnum = T; export type LifetimeGenericStruct = { borrowed: T[], owned: T[], }; export type LoadProjectEvent = ({ project_name: string }) & { progress?: never; status?: never } | { project_name: string; status: string; progress: number }; export type MacroEnum = string | { demo2: string }; export type MacroStruct = string; export type MacroStruct2 = { demo: string, }; export type MaybeValidKey = T; export type MyEmptyInput = Record; export type MyEnum = string | number; export type MyEnumAdjacent = { inner: First }; export type MyEnumExternal = { inner: First }; export type MyEnumTagged = { inner: First }; export type MyEnumUntagged = { inner: First }; export type NamedConstGeneric = { data: number[], a: number[], d: [number, number], }; export type NamedConstGenericContainer = { a: NamedConstGeneric, b: NamedConstGeneric, d: [number, number], }; export type NestedEnum = string | number; export type Ninth = string | "B" | { a: string, } | First; export type NonOptional = string | null; export type OptionalInEnum = string | null | { a: string | null } | { a?: string | null }; export type OptionalOnNamedField = string | null; export type OptionalOnTransparentNamedField = { b: string | null, }; export type OverridenStruct = { overriden_field: string, }; export type Pair = { first: Z, second: A, }; export type PlaceholderInnerField = { a: string, }; export type Primitives = { i8: number, i16: number, i32: number, u8: number, u16: number, u32: number, f32: number, f64: number, bool: boolean, char: string, "Range": Range, "RangeInclusive": RangeInclusive, "()": null, "(String, i32)": [string, number], "(String, i32, bool)": [string, number, boolean], "((String, i32), (bool, char, bool), ())": [[string, number], [boolean, string, boolean], null], "(bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool)": [boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean], "(Vec, Vec)": [number[], boolean[]], String: string, PathBuf: string, IpAddr: string, Ipv4Addr: string, Ipv6Addr: string, SocketAddr: string, SocketAddrV4: string, SocketAddrV6: string, "Cow<'static, str>": string, "Cow<'static, i32>": number, "&'static str": string, "&'static bool": boolean, "&'static i32": number, "Vec": number[], "&'static [i32]": number[], "&'static [i32; 3]": [number, number, number], "[i32; 3]": [number, number, number], "Vec": MyEnum[], "&'static [MyEnum]": MyEnum[], "&'static [MyEnum; 6]": [MyEnum, MyEnum, MyEnum, MyEnum, MyEnum, MyEnum], "[MyEnum; 2]": [MyEnum, MyEnum], "&'static [i32; 1]": [number], "&'static [i32; 0]": [], "Option": number | null, "Option<()>": null, "Option>": number[] | null, "Result": Result, "Vec>>": (number | null)[], "Option>>": number[] | null, "[Vec; 3]": [string[], string[], string[]], "Option>": string | null, "Option>>": string | null, "PhantomData<()>": null, "PhantomData": null, Infallible: never, Unit1: Unit1, Unit2: Unit2, Unit3: Unit3, Unit4: Unit4, Unit5: Unit5, Unit6: Unit6, Unit7: Unit7, SimpleStruct: SimpleStruct, TupleStruct1: TupleStruct1, TupleStruct3: TupleStruct3, TestEnum: TestEnum, RefStruct: RefStruct, InlinerStruct: InlinerStruct, "GenericStruct": GenericStruct, "GenericStruct": GenericStruct, FlattenEnumStruct: FlattenEnumStruct, OverridenStruct: OverridenStruct, HasGenericAlias: HasGenericAlias, EnumMacroAttributes: EnumMacroAttributes, InlineEnumField: InlineEnumField, InlineOptionalType: InlineOptionalType, Rename: Rename, TransparentType: TransparentType, TransparentType2: TransparentType2, TransparentTypeWithOverride: TransparentTypeWithOverride, "[Option; 3]": [(number | null), (number | null), (number | null)], "HashMap": Partial<{ [key in BasicEnum]: null }>, "HashMap": Partial<{ [key in BasicEnum]: number }>, "Option>>>": number | null, "Vec": PlaceholderInnerField[], EnumReferenceRecordKey: EnumReferenceRecordKey, FlattenOnNestedEnum: FlattenOnNestedEnum, MyEmptyInput: MyEmptyInput, "(String)": string, "(String,)": [string], ExtraBracketsInTupleVariant: ExtraBracketsInTupleVariant, ExtraBracketsInUnnamedStruct: ExtraBracketsInUnnamedStruct, "Vec": MyEnum[], InlineTuple: InlineTuple, InlineTuple2: InlineTuple2, "Box": string, "Box": string, SkippedFieldWithinVariant: SkippedFieldWithinVariant, KebabCase: KebabCase, "&[&str]": string[], "Issue281<'_>": Issue281, "LifetimeGenericStruct<'_, i32>": LifetimeGenericStruct, "LifetimeGenericEnum<'_, i32>": LifetimeGenericEnum, RenameWithWeirdCharsField: RenameWithWeirdCharsField, RenameWithWeirdCharsVariant: RenameWithWeirdCharsVariant, RenamedFieldKeys: RenamedFieldKeys, RenamedVariantWithSkippedPayload: RenamedVariantWithSkippedPayload, "type_type::Type": Type, ActualType: ActualType, SpectaTypeOverride: SpectaTypeOverride, ContainerTypeOverrideStruct: ContainerTypeOverrideStruct, ContainerTypeOverrideEnum: ContainerTypeOverrideEnum, "ContainerTypeOverrideGeneric>": ContainerTypeOverrideGeneric, "ContainerTypeOverrideToGeneric": ContainerTypeOverrideToGeneric, ContainerTypeOverrideTuple: ContainerTypeOverrideTuple, "ContainerTypeOverrideTupleGeneric": ContainerTypeOverrideTupleGeneric, InvalidToValidType: InvalidToValidType, TupleStruct: TupleStruct, TupleStructWithRep: TupleStructWithRep, "GenericTupleStruct": GenericTupleStruct, BracedStruct: BracedStruct, Struct: Struct, Struct2: Struct2, Enum: Enum, Enum2: Enum2, Enum3: Enum3, StructRenameAllUppercase: StructRenameAllUppercase, RenameSerdeSpecialChar: RenameSerdeSpecialChar, EnumRenameAllUppercase: EnumRenameAllUppercase, Recursive: Recursive, RecursiveMapValue: RecursiveMapValue, RecursiveTransparent: RecursiveTransparent, RecursiveInEnum: RecursiveInEnum, NonOptional: NonOptional, OptionalOnNamedField: OptionalOnNamedField, OptionalOnTransparentNamedField: OptionalOnTransparentNamedField, OptionalInEnum: OptionalInEnum, UntaggedVariants: UntaggedVariants, UntaggedVariantsWithoutValue: UntaggedVariantsWithoutValue, UntaggedVariantsWithDuplicateBranches: UntaggedVariantsWithDuplicateBranches, "HashMap": { [key in string]: null }, Regular: Regular, "HashMap": { [key in never]: null }, "HashMap": { [key in TransparentStruct]: null }, "HashMap": Partial<{ [key in UnitVariants]: null }>, "HashMap": Partial<{ [key in UntaggedVariantsKey]: null }>, ValidMaybeValidKey: ValidMaybeValidKey, ValidMaybeValidKeyNested: ValidMaybeValidKeyNested, MacroStruct: MacroStruct, MacroStruct2: MacroStruct2, MacroEnum: MacroEnum, DeprecatedType: DeprecatedType, DeprecatedTypeWithMsg: DeprecatedTypeWithMsg, DeprecatedTypeWithMsg2: DeprecatedTypeWithMsg2, DeprecatedFields: DeprecatedFields, DeprecatedTupleVariant: DeprecatedTupleVariant, DeprecatedEnumVariants: DeprecatedEnumVariants, CommentedStruct: CommentedStruct, CommentedEnum: CommentedEnum, SingleLineComment: SingleLineComment, NonGeneric: Demo, "HalfGenericA": Demo, "HalfGenericB": Demo, "FullGeneric": Demo, "Another": Demo, "MapA": { [key in string]: number }, "MapB": { [key in number]: string }, "MapC": { [key in string]: AGenericStruct }, "AGenericStruct": AGenericStruct, A: A, DoubleFlattened: DoubleFlattened, FlattenedInner: FlattenedInner, BoxFlattened: BoxFlattened, BoxInline: BoxInline, First: First, Second: Second, Third: Third, Fourth: Fourth, TagOnStructWithInline: TagOnStructWithInline, Sixth: Sixth, Seventh: Seventh, Eight: Eight, Ninth: Ninth, Tenth: Tenth, MyEnumTagged: MyEnumTagged, MyEnumExternal: MyEnumExternal, MyEnumAdjacent: MyEnumAdjacent, MyEnumUntagged: MyEnumUntagged, EmptyStruct: EmptyStruct, EmptyStructWithTag: EmptyStructWithTag, AdjacentlyTagged: AdjacentlyTagged, LoadProjectEvent: LoadProjectEvent, ExternallyTagged: ExternallyTagged, Issue221External: Issue221External, InternallyTaggedD: InternallyTaggedD, InternallyTaggedE: InternallyTaggedE, InternallyTaggedF: InternallyTaggedF, InternallyTaggedH: InternallyTaggedH, InternallyTaggedL: InternallyTaggedL, InternallyTaggedM: InternallyTaggedM, StructWithAlias: StructWithAlias, StructWithMultipleAliases: StructWithMultipleAliases, StructWithAliasAndRename: StructWithAliasAndRename, EnumWithVariantAlias: EnumWithVariantAlias, EnumWithMultipleVariantAliases: EnumWithMultipleVariantAliases, EnumWithVariantAliasAndRename: EnumWithVariantAliasAndRename, InternallyTaggedWithAlias: InternallyTaggedWithAlias, AdjacentlyTaggedWithAlias: AdjacentlyTaggedWithAlias, UntaggedWithAlias: UntaggedWithAlias, Issue221UntaggedSafe: Issue221UntaggedSafe, Issue221UntaggedMixed: Issue221UntaggedMixed, EmptyEnum: EmptyEnum, EmptyEnumTagged: EmptyEnumTagged, EmptyEnumTaggedWContent: EmptyEnumTaggedWContent, EmptyEnumUntagged: EmptyEnumUntagged, SkipOnlyField: SkipOnlyField, SkipField: SkipField, SkipVariant: SkipVariant, SkipUnnamedFieldInVariant: SkipUnnamedFieldInVariant, SkipNamedFieldInVariant: SkipNamedFieldInVariant, TransparentWithSkip: TransparentWithSkip, TransparentWithSkip2: TransparentWithSkip2, TransparentWithSkip3: TransparentWithSkip3, SkipVariant2: SkipVariant2, SkipVariant3: SkipVariant3, SkipStructFields: SkipStructFields, SpectaSkipNonTypeField: SpectaSkipNonTypeField, FlattenA: FlattenA, FlattenB: FlattenB, FlattenC: FlattenC, FlattenD: FlattenD, FlattenE: FlattenE, FlattenF: FlattenF, FlattenG: FlattenG, TupleNested: TupleNested, "Generic1<()>": Generic1, "GenericAutoBound<()>": GenericAutoBound, "GenericAutoBound2<()>": GenericAutoBound2, Container1: Container1, "Generic2<(), String, i32>": Generic2, "GenericNewType1<()>": GenericNewType1, "GenericTuple<()>": GenericTuple, "GenericStruct2<()>": GenericStruct2, "InlineGenericNewtype": string, "InlineGenericNested": [string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | string | { value: string }], "InlineFlattenGenericsG<()>": InlineFlattenGenericsG, InlineFlattenGenerics: InlineFlattenGenerics, GenericDefault: GenericDefault, ChainedGenericDefault: ChainedGenericDefault, "ChainedGenericDefault": ChainedGenericDefault, "ChainedGenericDefault": ChainedGenericDefault, "ChainedGenericDefault": ChainedGenericDefault, GenericDefaultSkipped: GenericDefaultSkipped, GenericDefaultSkippedNonType: GenericDefaultSkippedNonType, GenericParameterOrderPreserved: GenericParameterOrderPreserved, ConstGenericInNonConstContainer: ConstGenericInNonConstContainer, ConstGenericInConstContainer: ConstGenericInConstContainer, NamedConstGenericContainer: NamedConstGenericContainer, InlineConstGenericContainer: InlineConstGenericContainer, InlineRecursiveConstGenericContainer: InlineRecursiveConstGenericContainer, TestCollectionRegister: TestCollectionRegister, TestCollectionRegister: TestCollectionRegister, }; export type Range = { start: T, end: T, }; export type RangeInclusive = { start: T, end: T, }; export type Recursive = { demo: Recursive, }; export type RecursiveInEnum = { demo: RecursiveInEnum }; export type RecursiveInline = { demo: RecursiveInline, }; export type RecursiveMapValue = { demo: { [key in string]: RecursiveMapValue }, }; export type RecursiveTransparent = RecursiveInline; export type RefStruct = TestEnum; export type Regular = { [key in string]: null }; export type Rename = "OneWord" | "TwoWords"; export type RenameSerdeSpecialChar = { b: number, }; export type RenameWithWeirdCharsField = { odata_context: string, }; export type RenameWithWeirdCharsVariant = string; export type RenamedFieldKeys = { empty: string, quote: string, backslash: string, newline: string, line_separator: string, paragraph_separator: string, }; export type RenamedVariantWithSkippedPayload = never; export type Result = { ok: T, err: E, }; export type Second = { a: number, }; export type Seventh = { a: First, b: Second, }; export type SimpleStruct = { a: number, b: string, c: [number, string, number], d: string[], e: string | null, }; /** Some single-line comment */ export type SingleLineComment = /** Some single-line comment */ number | /** Some single-line comment */ { /** Some single-line comment */ a: number }; export type Sixth = { a: First, b: First, }; export type SkipField = { b: number, }; export type SkipNamedFieldInVariant = Record | { b: number }; export type SkipOnlyField = Record; export type SkipStructFields = { a: number, }; export type SkipUnnamedFieldInVariant = never | [number]; export type SkipVariant = string; export type SkipVariant2 = string; export type SkipVariant3 = { a: string }; export type SkippedFieldWithinVariant = never | string; export type SpectaSkipNonTypeField = { a: number, }; export type SpectaTypeOverride = { string_ident: string, u32_ident: number, path: string, tuple: [string, number], }; export type Struct = { a: string, }; export type Struct2 = { a: string, }; export type StructRenameAllUppercase = { a: number, b: number, }; export type StructWithAlias = { field: string, }; export type StructWithAliasAndRename = { field: string, }; export type StructWithMultipleAliases = { field: string, }; export type TagOnStructWithInline = { a: First, b: { a: string, }, }; export type Tenth = string | "B" | { a: string, } | First; export type TestCollectionRegister = never; export type TestEnum = "Unit" | number | [number, number] | { a: number }; export type Third = { a: First, b: { [key in string]: string }, c: First, }; export type ToBeFlattened = { a: string, }; export type TransparentStruct = string; export type TransparentType = TransparentTypeInner; export type TransparentType2 = null; export type TransparentTypeInner = { inner: string, }; export type TransparentTypeWithOverride = string; export type TransparentWithSkip = null; export type TransparentWithSkip2 = string; export type TransparentWithSkip3 = string; export type TupleNested = [number[], [number[], number[]], [number[], number[], number[]]]; export type TupleStruct = string; export type TupleStruct1 = number; export type TupleStruct3 = [number, boolean, string]; export type TupleStructWithRep = string; export type Type = never; export type Unit1 = null; export type Unit2 = Record; export type Unit3 = []; export type Unit4 = null; export type Unit5 = "A"; export type Unit6 = []; export type Unit7 = Record; export type UnitVariants = "A" | "B" | "C"; export type UntaggedVariants = string | number | { id: string } | [string, boolean]; export type UntaggedVariantsKey = string | number; export type UntaggedVariantsWithDuplicateBranches = null | number; export type UntaggedVariantsWithoutValue = string | [number, string] | number; export type UntaggedWithAlias = ({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }; export type ValidMaybeValidKey = { [key in MaybeValidKey]: null }; export type ValidMaybeValidKeyNested = { [key in MaybeValidKey>]: null }; ════════════════════════════════════════ ================================================ FILE: tests/tests/snapshots/test__typescript__ts-export-to-flatfile-serde.snap ================================================ --- source: tests/tests/typescript.rs expression: output --- ts-export-to-flatfile-serde (26900 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. export type A = { a: B, b: { b: number, }, c: B, d: { flattened: number, }, e: { generic_flattened: number, }, }; export type AGenericStruct = { field: Demo, }; export type ActualType = { a: GenericType, }; export type AdjacentlyTagged = { t: "A" } | { t: "B"; c: { id: string, method: string, } } | { t: "C"; c: string }; export type AdjacentlyTaggedWithAlias = { type: "A"; data: { field: string, } } | { type: "B"; data: { other: number, } }; export type B = { b: number, }; export type BasicEnum = "A" | "B"; export type BoxFlattened = BoxedInner; export type BoxInline = { c: { a: number, }, }; export type BoxedInner = { a: number, }; export type BracedStruct = string; export type ChainedGenericDefault = { first: T, second: U, }; /** * Some triple-slash comment * Some more triple-slash comment */ export type CommentedEnum = /** * Some triple-slash comment * Some more triple-slash comment */ ({ A: number }) & { B?: never } | /** * Some triple-slash comment * Some more triple-slash comment */ ({ B: { /** * Some triple-slash comment * Some more triple-slash comment */ a: number, } }) & { A?: never }; /** * Some triple-slash comment * Some more triple-slash comment */ export type CommentedStruct = { /** * Some triple-slash comment * Some more triple-slash comment */ a: number, }; export type ConstGenericInConstContainer = { data: number[], a: number[], d: [number, number], }; export type ConstGenericInNonConstContainer = { data: [number], a: [number, number], d: [number, number], }; export type Container1 = { foo: Generic1, bar: Generic1[], baz: { [key in string]: Generic1 }, }; export type ContainerTypeOverrideEnum = string; export type ContainerTypeOverrideGeneric = string; export type ContainerTypeOverrideStruct = string; export type ContainerTypeOverrideToGeneric = T; export type ContainerTypeOverrideTuple = [string, number]; export type ContainerTypeOverrideTupleGeneric = [T, string]; export type D = { flattened: number, }; export type Demo = { a: A, b: B, }; export type DeprecatedEnumVariants = /** * @deprecated */ "A" | /** * @deprecated Nope */ "B" | /** * @deprecated Nope */ "C"; export type DeprecatedFields = { a: number, /** * @deprecated */ b: string, /** * @deprecated This field is cringe! */ c: string, /** * @deprecated This field is cringe! */ d: string, }; export type DeprecatedTupleVariant = [ /** * @deprecated */ string, /** * @deprecated Nope */ string, /** * @deprecated Nope */ number]; /** * @deprecated */ export type DeprecatedType = { a: number, }; /** * @deprecated Look at you big man using a deprecation message */ export type DeprecatedTypeWithMsg = { a: number, }; /** * @deprecated Look at you big man using a deprecation message */ export type DeprecatedTypeWithMsg2 = { a: number, }; export type DoubleFlattened = { a: ToBeFlattened, b: ToBeFlattened, }; export type Eight = { A: string } | "B"; export type EmptyEnum = never; export type EmptyEnumTagged = never; export type EmptyEnumTaggedWContent = never; export type EmptyEnumUntagged = never; export type EmptyStruct = Record; export type EmptyStructWithTag = { a: "EmptyStructWithTag", }; export type Enum = { t: "A" } | { t: "B" }; export type Enum2 = { t: "C" } | { t: "B" } | { t: "D"; enumField: null }; export type Enum3 = { t: "A"; b: string }; export type EnumMacroAttributes = ({ A: string }) & { D?: never; bbb?: never; cccc?: never } | ({ bbb: number }) & { A?: never; D?: never; cccc?: never } | ({ cccc: number }) & { A?: never; D?: never; bbb?: never } | ({ D: { a: string, bbbbbb: number, } }) & { A?: never; bbb?: never; cccc?: never }; export type EnumReferenceRecordKey = { a: Partial<{ [key in BasicEnum]: number }>, }; export type EnumRenameAllUppercase = "HELLOWORLD" | "VARIANTB" | "TESTINGWORDS"; export type EnumWithMultipleVariantAliases = "Variant" | "Other"; export type EnumWithVariantAlias = "Variant" | "Other"; export type EnumWithVariantAliasAndRename = "renamed_variant" | "Other"; export type ExternallyTagged = "A" | ({ B: { id: string, method: string, } }) & { C?: never } | ({ C: string }) & { B?: never }; export type ExtraBracketsInTupleVariant = { A: string }; export type ExtraBracketsInUnnamedStruct = string; export type First = { a: string, }; export type FlattenA = { a: number, b: number, }; export type FlattenB = { c: number, } & FlattenA; export type FlattenC = { c: number, } & FlattenA; export type FlattenD = { a: FlattenA, c: number, }; export type FlattenE = { b: ({ c: number, }) & (FlattenA), d: number, }; export type FlattenEnum = { tag: "One" } | { tag: "Two" } | { tag: "Three" }; export type FlattenEnumStruct = { outer: string, } & FlattenEnum; export type FlattenF = { b: ({ c: number, }) & (FlattenA), d: number, }; export type FlattenG = { b: FlattenB, d: number, }; export type FlattenOnNestedEnum = { id: string, } & NestedEnum; export type FlattenedInner = Inner; export type Fourth = { a: First, b: { a: string, }, }; export type Generic1 = { value: T, values: T[], }; export type Generic2 = ({ A: A }) & { B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ B: [B, B, B] }) & { A?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ C: C[] }) & { A?: never; B?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ D: A[][][] }) & { A?: never; B?: never; C?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ E: { a: A, b: B, c: C, } }) & { A?: never; B?: never; C?: never; D?: never; X?: never; Y?: never; Z?: never } | ({ X: number[] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; Y?: never; Z?: never } | ({ Y: number }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Z?: never } | ({ Z: number[][] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never }; export type GenericAutoBound = { value: T, values: T[], }; export type GenericAutoBound2 = { value: T, values: T[], }; export type GenericDefault = { value: T, }; export type GenericDefaultSkipped = { value: T, }; export type GenericDefaultSkippedNonType = { value: number, }; export type GenericFlattened = { generic_flattened: T, }; export type GenericNewType1 = T[][]; export type GenericParameterOrderPreserved = { pair: Pair, }; export type GenericStruct = { arg: T, }; export type GenericStruct2 = { a: T, b: [T, T], c: [T, [T, T]], d: [T, T, T], e: [([T, T]), ([T, T]), ([T, T])], f: T[], g: T[][], h: ([([T, T]), ([T, T]), ([T, T])])[], }; export type GenericTuple = [T, T[], T[][]]; export type GenericTupleStruct = T; export type GenericType = "Undefined" | T; export type HasGenericAlias = { [key in number]: string }; export type InlineConstGenericContainer = { b: { data: [number, number], a: [number, number], d: [number, number, number], }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], }, d: [number, number], }; export type InlineEnumField = { A: { a: string, } }; export type InlineFlattenGenerics = { g: InlineFlattenGenericsG, gi: { t: string, }, } & InlineFlattenGenericsG; export type InlineFlattenGenericsG = { t: T, }; export type InlineOptionalType = { optional_field: { a: string, } | null, }; export type InlineRecursiveConstGeneric = { data: number[], a: number[], d: [number, number, number], e: InlineRecursiveConstGeneric, }; export type InlineRecursiveConstGenericContainer = { b: { data: [number, number], a: [number, number], d: [number, number, number], e: InlineRecursiveConstGeneric, }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], e: InlineRecursiveConstGeneric, }, d: [number, number], }; export type InlineStruct = { ref_struct: SimpleStruct, val: number, }; export type InlineTuple = { demo: [string, boolean], }; export type InlineTuple2 = { demo: [{ demo: [string, boolean], }, boolean], }; export type InlinerStruct = { inline_this: { ref_struct: SimpleStruct, val: number, }, dont_inline_this: RefStruct, }; export type Inner = { a: number, } & FlattenedInner; export type InternallyTaggedD = { type: "A", } & { [key in string]: string }; export type InternallyTaggedE = { type: "A" }; export type InternallyTaggedF = { type: "A" }; export type InternallyTaggedFInner = null; export type InternallyTaggedH = { type: "A" }; export type InternallyTaggedHInner = null; export type InternallyTaggedL = { type: "A", } & { type: "A" } | { type: "B" }; export type InternallyTaggedLInner = { type: "A" } | { type: "B" }; export type InternallyTaggedM = { type: "A" }; export type InternallyTaggedMInner = "A" | "B"; export type InternallyTaggedWithAlias = { type: "A"; field: string } | { type: "B"; other: number }; export type InvalidToValidType = { cause: null, }; export type Issue221External = ({ A: { a: string, } }) & { B?: never } | ({ B: { b: string, } }) & { A?: never }; export type Issue221UntaggedMixed = ({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never }; export type Issue221UntaggedSafe = ({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }; export type Issue281 = { default_unity_arguments: string[], }; export type KebabCase = { "test-ing": string, }; export type LifetimeGenericEnum = ({ Borrowed: T }) & { Owned?: never } | ({ Owned: T }) & { Borrowed?: never }; export type LifetimeGenericStruct = { borrowed: T[], owned: T[], }; export type LoadProjectEvent = { event: "started"; data: { projectName: string, } } | { event: "progressTest"; data: { projectName: string, status: string, progress: number, } } | { event: "finished"; data: { projectName: string, } }; export type MacroEnum = ({ Demo: string }) & { Demo2?: never } | ({ Demo2: { demo2: string, } }) & { Demo?: never }; export type MacroStruct = string; export type MacroStruct2 = { demo: string, }; export type MaybeValidKey = T; export type MyEmptyInput = Record; export type MyEnum = ({ A: string }) & { B?: never } | ({ B: number }) & { A?: never }; export type MyEnumAdjacent = { t: "Variant"; c: { inner: First, } }; export type MyEnumExternal = { Variant: { inner: First, } }; export type MyEnumTagged = { type: "Variant"; inner: First }; export type MyEnumUntagged = { inner: First }; export type NamedConstGeneric = { data: number[], a: number[], d: [number, number], }; export type NamedConstGenericContainer = { a: NamedConstGeneric, b: NamedConstGeneric, d: [number, number], }; export type NestedEnum = { type: "a"; value: string } | { type: "b"; value: number }; export type Ninth = { t: "A"; c: string } | { t: "B" } | { t: "C"; c: { a: string, } } | { t: "D"; c: First }; export type NonOptional = string | null; export type OptionalInEnum = ({ A?: string | null }) & { B?: never; C?: never } | ({ B: { a: string | null, } }) & { A?: never; C?: never } | ({ C: { a?: string | null, } }) & { A?: never; B?: never }; export type OptionalOnNamedField = string | null; export type OptionalOnTransparentNamedField = { b: string | null, }; export type OverridenStruct = { overriden_field: string, }; export type Pair = { first: Z, second: A, }; export type PlaceholderInnerField = { a: string, }; export type Primitives = { i8: number, i16: number, i32: number, u8: number, u16: number, u32: number, f32: number, f64: number, bool: boolean, char: string, "Range": Range, "RangeInclusive": RangeInclusive, "()": null, "(String, i32)": [string, number], "(String, i32, bool)": [string, number, boolean], "((String, i32), (bool, char, bool), ())": [[string, number], [boolean, string, boolean], null], "(bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool)": [boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean], "(Vec, Vec)": [number[], boolean[]], String: string, PathBuf: string, IpAddr: string, Ipv4Addr: string, Ipv6Addr: string, SocketAddr: string, SocketAddrV4: string, SocketAddrV6: string, "Cow<'static, str>": string, "Cow<'static, i32>": number, "&'static str": string, "&'static bool": boolean, "&'static i32": number, "Vec": number[], "&'static [i32]": number[], "&'static [i32; 3]": [number, number, number], "[i32; 3]": [number, number, number], "Vec": MyEnum[], "&'static [MyEnum]": MyEnum[], "&'static [MyEnum; 6]": [MyEnum, MyEnum, MyEnum, MyEnum, MyEnum, MyEnum], "[MyEnum; 2]": [MyEnum, MyEnum], "&'static [i32; 1]": [number], "&'static [i32; 0]": [], "Option": number | null, "Option<()>": null, "Option>": number[] | null, "Result": Result, "Vec>>": (number | null)[], "Option>>": number[] | null, "[Vec; 3]": [string[], string[], string[]], "Option>": string | null, "Option>>": string | null, "PhantomData<()>": null, "PhantomData": null, Infallible: never, Unit1: Unit1, Unit2: Unit2, Unit3: Unit3, Unit4: Unit4, Unit5: Unit5, Unit6: Unit6, Unit7: Unit7, SimpleStruct: SimpleStruct, TupleStruct1: TupleStruct1, TupleStruct3: TupleStruct3, TestEnum: TestEnum, RefStruct: RefStruct, InlinerStruct: InlinerStruct, "GenericStruct": GenericStruct, "GenericStruct": GenericStruct, FlattenEnumStruct: FlattenEnumStruct, OverridenStruct: OverridenStruct, HasGenericAlias: HasGenericAlias, EnumMacroAttributes: EnumMacroAttributes, InlineEnumField: InlineEnumField, InlineOptionalType: InlineOptionalType, Rename: Rename, TransparentType: TransparentType, TransparentType2: TransparentType2, TransparentTypeWithOverride: TransparentTypeWithOverride, "[Option; 3]": [(number | null), (number | null), (number | null)], "HashMap": Partial<{ [key in BasicEnum]: null }>, "HashMap": Partial<{ [key in BasicEnum]: number }>, "Option>>>": number | null, "Vec": PlaceholderInnerField[], EnumReferenceRecordKey: EnumReferenceRecordKey, FlattenOnNestedEnum: FlattenOnNestedEnum, MyEmptyInput: MyEmptyInput, "(String)": string, "(String,)": [string], ExtraBracketsInTupleVariant: ExtraBracketsInTupleVariant, ExtraBracketsInUnnamedStruct: ExtraBracketsInUnnamedStruct, "Vec": MyEnum[], InlineTuple: InlineTuple, InlineTuple2: InlineTuple2, "Box": string, "Box": string, SkippedFieldWithinVariant: SkippedFieldWithinVariant, KebabCase: KebabCase, "&[&str]": string[], "Issue281<'_>": Issue281, "LifetimeGenericStruct<'_, i32>": LifetimeGenericStruct, "LifetimeGenericEnum<'_, i32>": LifetimeGenericEnum, RenameWithWeirdCharsField: RenameWithWeirdCharsField, RenameWithWeirdCharsVariant: RenameWithWeirdCharsVariant, RenamedFieldKeys: RenamedFieldKeys, RenamedVariantWithSkippedPayload: RenamedVariantWithSkippedPayload, "type_type::Type": Type, ActualType: ActualType, SpectaTypeOverride: SpectaTypeOverride, ContainerTypeOverrideStruct: ContainerTypeOverrideStruct, ContainerTypeOverrideEnum: ContainerTypeOverrideEnum, "ContainerTypeOverrideGeneric>": ContainerTypeOverrideGeneric, "ContainerTypeOverrideToGeneric": ContainerTypeOverrideToGeneric, ContainerTypeOverrideTuple: ContainerTypeOverrideTuple, "ContainerTypeOverrideTupleGeneric": ContainerTypeOverrideTupleGeneric, InvalidToValidType: InvalidToValidType, TupleStruct: TupleStruct, TupleStructWithRep: TupleStructWithRep, "GenericTupleStruct": GenericTupleStruct, BracedStruct: BracedStruct, Struct: StructNew, Struct2: Struct2, Enum: Enum, Enum2: Enum2, Enum3: Enum3, StructRenameAllUppercase: StructRenameAllUppercase, RenameSerdeSpecialChar: RenameSerdeSpecialChar, EnumRenameAllUppercase: EnumRenameAllUppercase, Recursive: Recursive, RecursiveMapValue: RecursiveMapValue, RecursiveTransparent: RecursiveTransparent, RecursiveInEnum: RecursiveInEnum, NonOptional: NonOptional, OptionalOnNamedField: OptionalOnNamedField, OptionalOnTransparentNamedField: OptionalOnTransparentNamedField, OptionalInEnum: OptionalInEnum, UntaggedVariants: UntaggedVariants, UntaggedVariantsWithoutValue: UntaggedVariantsWithoutValue, UntaggedVariantsWithDuplicateBranches: UntaggedVariantsWithDuplicateBranches, "HashMap": { [key in string]: null }, Regular: Regular, "HashMap": { [key in never]: null }, "HashMap": { [key in TransparentStruct]: null }, "HashMap": Partial<{ [key in UnitVariants]: null }>, "HashMap": Partial<{ [key in UntaggedVariantsKey]: null }>, ValidMaybeValidKey: ValidMaybeValidKey, ValidMaybeValidKeyNested: ValidMaybeValidKeyNested, MacroStruct: MacroStruct, MacroStruct2: MacroStruct2, MacroEnum: MacroEnum, DeprecatedType: DeprecatedType, DeprecatedTypeWithMsg: DeprecatedTypeWithMsg, DeprecatedTypeWithMsg2: DeprecatedTypeWithMsg2, DeprecatedFields: DeprecatedFields, DeprecatedTupleVariant: DeprecatedTupleVariant, DeprecatedEnumVariants: DeprecatedEnumVariants, CommentedStruct: CommentedStruct, CommentedEnum: CommentedEnum, SingleLineComment: SingleLineComment, NonGeneric: Demo, "HalfGenericA": Demo, "HalfGenericB": Demo, "FullGeneric": Demo, "Another": Demo, "MapA": { [key in string]: number }, "MapB": { [key in number]: string }, "MapC": { [key in string]: AGenericStruct }, "AGenericStruct": AGenericStruct, A: A, DoubleFlattened: DoubleFlattened, FlattenedInner: FlattenedInner, BoxFlattened: BoxFlattened, BoxInline: BoxInline, First: First, Second: Second, Third: Third, Fourth: Fourth, TagOnStructWithInline: TagOnStructWithInline, Sixth: Sixth, Seventh: Seventh, Eight: Eight, Ninth: Ninth, Tenth: Tenth, MyEnumTagged: MyEnumTagged, MyEnumExternal: MyEnumExternal, MyEnumAdjacent: MyEnumAdjacent, MyEnumUntagged: MyEnumUntagged, EmptyStruct: EmptyStruct, EmptyStructWithTag: EmptyStructWithTag, AdjacentlyTagged: AdjacentlyTagged, LoadProjectEvent: LoadProjectEvent, ExternallyTagged: ExternallyTagged, Issue221External: Issue221External, InternallyTaggedD: InternallyTaggedD, InternallyTaggedE: InternallyTaggedE, InternallyTaggedF: InternallyTaggedF, InternallyTaggedH: InternallyTaggedH, InternallyTaggedL: InternallyTaggedL, InternallyTaggedM: InternallyTaggedM, StructWithAlias: StructWithAlias, StructWithMultipleAliases: StructWithMultipleAliases, StructWithAliasAndRename: StructWithAliasAndRename, EnumWithVariantAlias: EnumWithVariantAlias, EnumWithMultipleVariantAliases: EnumWithMultipleVariantAliases, EnumWithVariantAliasAndRename: EnumWithVariantAliasAndRename, InternallyTaggedWithAlias: InternallyTaggedWithAlias, AdjacentlyTaggedWithAlias: AdjacentlyTaggedWithAlias, UntaggedWithAlias: UntaggedWithAlias, Issue221UntaggedSafe: Issue221UntaggedSafe, Issue221UntaggedMixed: Issue221UntaggedMixed, EmptyEnum: EmptyEnum, EmptyEnumTagged: EmptyEnumTagged, EmptyEnumTaggedWContent: EmptyEnumTaggedWContent, EmptyEnumUntagged: EmptyEnumUntagged, SkipOnlyField: SkipOnlyField, SkipField: SkipField, SkipVariant: SkipVariant, SkipUnnamedFieldInVariant: SkipUnnamedFieldInVariant, SkipNamedFieldInVariant: SkipNamedFieldInVariant, TransparentWithSkip: TransparentWithSkip, TransparentWithSkip2: TransparentWithSkip2, TransparentWithSkip3: TransparentWithSkip3, SkipVariant2: SkipVariant2, SkipVariant3: SkipVariant3, SkipStructFields: SkipStructFields, SpectaSkipNonTypeField: SpectaSkipNonTypeField, FlattenA: FlattenA, FlattenB: FlattenB, FlattenC: FlattenC, FlattenD: FlattenD, FlattenE: FlattenE, FlattenF: FlattenF, FlattenG: FlattenG, TupleNested: TupleNested, "Generic1<()>": Generic1, "GenericAutoBound<()>": GenericAutoBound, "GenericAutoBound2<()>": GenericAutoBound2, Container1: Container1, "Generic2<(), String, i32>": Generic2, "GenericNewType1<()>": GenericNewType1, "GenericTuple<()>": GenericTuple, "GenericStruct2<()>": GenericStruct2, "InlineGenericNewtype": string, "InlineGenericNested": [string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | ({ Unnamed: string }) & { Named?: never } | ({ Named: { value: string, } }) & { Unnamed?: never }], "InlineFlattenGenericsG<()>": InlineFlattenGenericsG, InlineFlattenGenerics: InlineFlattenGenerics, GenericDefault: GenericDefault, ChainedGenericDefault: ChainedGenericDefault, "ChainedGenericDefault": ChainedGenericDefault, "ChainedGenericDefault": ChainedGenericDefault, "ChainedGenericDefault": ChainedGenericDefault, GenericDefaultSkipped: GenericDefaultSkipped, GenericDefaultSkippedNonType: GenericDefaultSkippedNonType, GenericParameterOrderPreserved: GenericParameterOrderPreserved, ConstGenericInNonConstContainer: ConstGenericInNonConstContainer, ConstGenericInConstContainer: ConstGenericInConstContainer, NamedConstGenericContainer: NamedConstGenericContainer, InlineConstGenericContainer: InlineConstGenericContainer, InlineRecursiveConstGenericContainer: InlineRecursiveConstGenericContainer, TestCollectionRegister: TestCollectionRegister, TestCollectionRegister: TestCollectionRegister, }; export type Range = { start: T, end: T, }; export type RangeInclusive = { start: T, end: T, }; export type Recursive = { demo: Recursive, }; export type RecursiveInEnum = { A: { demo: RecursiveInEnum, } }; export type RecursiveInline = RecursiveInline; export type RecursiveMapValue = { demo: { [key in string]: RecursiveMapValue }, }; export type RecursiveTransparent = RecursiveInline; export type RefStruct = TestEnum; export type Regular = { [key in string]: null }; export type Rename = "OneWord" | "Two words"; export type RenameSerdeSpecialChar = { "a/b": number, }; export type RenameWithWeirdCharsField = { "@odata.context": string, }; export type RenameWithWeirdCharsVariant = { "@odata.context": string }; export type RenamedFieldKeys = { "": string, "a\"b": string, "a\\b": string, "line\nbreak": string, "line\u2028break": string, "line\u2029break": string, }; export type RenamedVariantWithSkippedPayload = "a-b"; export type Result = { ok: T, err: E, }; export type Second = { a: number, }; export type Seventh = { a: First, b: Second, }; export type SimpleStruct = { a: number, b: string, c: [number, string, number], d: string[], e: string | null, }; /** Some single-line comment */ export type SingleLineComment = /** Some single-line comment */ ({ A: number }) & { B?: never } | /** Some single-line comment */ ({ B: { /** Some single-line comment */ a: number, } }) & { A?: never }; export type Sixth = { a: First, b: First, }; export type SkipField = { b: number, }; export type SkipNamedFieldInVariant = ({ A: Record }) & { B?: never } | ({ B: { b: number, } }) & { A?: never }; export type SkipOnlyField = Record; export type SkipStructFields = { a: number, }; export type SkipUnnamedFieldInVariant = "A" | { B: [number] }; export type SkipVariant = { A: string }; export type SkipVariant2 = { tag: "A"; data: string }; export type SkipVariant3 = { A: { a: string, } }; export type SkippedFieldWithinVariant = { type: "A" } | { type: "B"; data: string }; export type SpectaSkipNonTypeField = { a: number, }; export type SpectaTypeOverride = { string_ident: string, u32_ident: number, path: string, tuple: [string, number], }; export type Struct2 = { b: string, }; export type StructNew = { t: "StructNew", a: string, }; export type StructRenameAllUppercase = { A: number, B: number, }; export type StructWithAlias = { field: string, }; export type StructWithAliasAndRename = { renamed_field: string, }; export type StructWithMultipleAliases = { field: string, }; export type TagOnStructWithInline = { type: "TagOnStructWithInline", a: First, b: { a: string, }, }; export type Tenth = string | "B" | { a: string, } | First; export type TestCollectionRegister = never; export type TestEnum = "Unit" | ({ Single: number }) & { Multiple?: never; Struct?: never } | ({ Multiple: [number, number] }) & { Single?: never; Struct?: never } | ({ Struct: { a: number, } }) & { Multiple?: never; Single?: never }; export type Third = { b: { [key in string]: string }, c: First, } & First; export type ToBeFlattened = { a: string, }; export type TransparentStruct = string; export type TransparentType = TransparentTypeInner; export type TransparentType2 = null; export type TransparentTypeInner = { inner: string, }; export type TransparentTypeWithOverride = string; export type TransparentWithSkip = null; export type TransparentWithSkip2 = string; export type TransparentWithSkip3 = string; export type TupleNested = [number[], [number[], number[]], [number[], number[], number[]]]; export type TupleStruct = string; export type TupleStruct1 = number; export type TupleStruct3 = [number, boolean, string]; export type TupleStructWithRep = string; export type Type = never; export type Unit1 = null; export type Unit2 = Record; export type Unit3 = []; export type Unit4 = null; export type Unit5 = "A"; export type Unit6 = { A: null }; export type Unit7 = { A: Record }; export type UnitVariants = "A" | "B" | "C"; export type UntaggedVariants = string | number | { id: string } | [string, boolean]; export type UntaggedVariantsKey = string | number; export type UntaggedVariantsWithDuplicateBranches = null | number; export type UntaggedVariantsWithoutValue = string | [number, string] | number; export type UntaggedWithAlias = ({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }; export type ValidMaybeValidKey = { [key in MaybeValidKey]: null }; export type ValidMaybeValidKeyNested = { [key in MaybeValidKey>]: null }; ════════════════════════════════════════ ================================================ FILE: tests/tests/snapshots/test__typescript__ts-export-to-flatfile-serde_phases.snap ================================================ --- source: tests/tests/typescript.rs expression: output --- ts-export-to-flatfile-serde_phases (27915 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. export type A = { a: B, b: { b: number, }, c: B, d: { flattened: number, }, e: { generic_flattened: number, }, }; export type AGenericStruct = { field: Demo, }; export type ActualType = { a: GenericType, }; export type AdjacentlyTagged = { t: "A" } | { t: "B"; c: { id: string, method: string, } } | { t: "C"; c: string }; export type AdjacentlyTaggedWithAlias = { type: "A"; data: { field: string, } } | { type: "B"; data: { other: number, } }; export type B = { b: number, }; export type BasicEnum = "A" | "B"; export type BoxFlattened = BoxedInner; export type BoxInline = { c: { a: number, }, }; export type BoxedInner = { a: number, }; export type BracedStruct = string; export type ChainedGenericDefault = { first: T, second: U, }; /** * Some triple-slash comment * Some more triple-slash comment */ export type CommentedEnum = /** * Some triple-slash comment * Some more triple-slash comment */ ({ A: number }) & { B?: never } | /** * Some triple-slash comment * Some more triple-slash comment */ ({ B: { /** * Some triple-slash comment * Some more triple-slash comment */ a: number, } }) & { A?: never }; /** * Some triple-slash comment * Some more triple-slash comment */ export type CommentedStruct = { /** * Some triple-slash comment * Some more triple-slash comment */ a: number, }; export type ConstGenericInConstContainer = { data: number[], a: number[], d: [number, number], }; export type ConstGenericInNonConstContainer = { data: [number], a: [number, number], d: [number, number], }; export type Container1 = { foo: Generic1, bar: Generic1[], baz: { [key in string]: Generic1 }, }; export type ContainerTypeOverrideEnum = string; export type ContainerTypeOverrideGeneric = string; export type ContainerTypeOverrideStruct = string; export type ContainerTypeOverrideToGeneric = T; export type ContainerTypeOverrideTuple = [string, number]; export type ContainerTypeOverrideTupleGeneric = [T, string]; export type D = { flattened: number, }; export type Demo = { a: A, b: B, }; export type DeprecatedEnumVariants = /** * @deprecated */ "A" | /** * @deprecated Nope */ "B" | /** * @deprecated Nope */ "C"; export type DeprecatedFields = { a: number, /** * @deprecated */ b: string, /** * @deprecated This field is cringe! */ c: string, /** * @deprecated This field is cringe! */ d: string, }; export type DeprecatedTupleVariant = [ /** * @deprecated */ string, /** * @deprecated Nope */ string, /** * @deprecated Nope */ number]; /** * @deprecated */ export type DeprecatedType = { a: number, }; /** * @deprecated Look at you big man using a deprecation message */ export type DeprecatedTypeWithMsg = { a: number, }; /** * @deprecated Look at you big man using a deprecation message */ export type DeprecatedTypeWithMsg2 = { a: number, }; export type DoubleFlattened = { a: ToBeFlattened, b: ToBeFlattened, }; export type Eight = { A: string } | "B"; export type EmptyEnum = never; export type EmptyEnumTagged = never; export type EmptyEnumTaggedWContent = never; export type EmptyEnumUntagged = never; export type EmptyStruct = Record; export type EmptyStructWithTag = { a: "EmptyStructWithTag", }; export type Enum = { t: "A" } | { t: "B" }; export type Enum2 = { t: "C" } | { t: "B" } | { t: "D"; enumField: null }; export type Enum3 = { t: "A"; b: string }; export type EnumMacroAttributes = ({ A: string }) & { D?: never; bbb?: never; cccc?: never } | ({ bbb: number }) & { A?: never; D?: never; cccc?: never } | ({ cccc: number }) & { A?: never; D?: never; bbb?: never } | ({ D: { a: string, bbbbbb: number, } }) & { A?: never; bbb?: never; cccc?: never }; export type EnumReferenceRecordKey = { a: Partial<{ [key in BasicEnum]: number }>, }; export type EnumRenameAllUppercase = "HELLOWORLD" | "VARIANTB" | "TESTINGWORDS"; export type EnumWithMultipleVariantAliases = "Variant" | "Other"; export type EnumWithVariantAlias = "Variant" | "Other"; export type EnumWithVariantAliasAndRename = "renamed_variant" | "Other"; export type ExternallyTagged = "A" | ({ B: { id: string, method: string, } }) & { C?: never } | ({ C: string }) & { B?: never }; export type ExtraBracketsInTupleVariant = { A: string }; export type ExtraBracketsInUnnamedStruct = string; export type First = { a: string, }; export type FlattenA = { a: number, b: number, }; export type FlattenB = { c: number, } & FlattenA; export type FlattenC = { c: number, } & FlattenA; export type FlattenD = { a: FlattenA, c: number, }; export type FlattenE = { b: ({ c: number, }) & (FlattenA), d: number, }; export type FlattenEnum = { tag: "One" } | { tag: "Two" } | { tag: "Three" }; export type FlattenEnumStruct = { outer: string, } & FlattenEnum; export type FlattenF = { b: ({ c: number, }) & (FlattenA), d: number, }; export type FlattenG = { b: FlattenB, d: number, }; export type FlattenOnNestedEnum = { id: string, } & NestedEnum; export type FlattenedInner = Inner; export type Fourth = { a: First, b: { a: string, }, }; export type Generic1 = { value: T, values: T[], }; export type Generic2 = ({ A: A }) & { B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ B: [B, B, B] }) & { A?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ C: C[] }) & { A?: never; B?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ D: A[][][] }) & { A?: never; B?: never; C?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ E: { a: A, b: B, c: C, } }) & { A?: never; B?: never; C?: never; D?: never; X?: never; Y?: never; Z?: never } | ({ X: number[] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; Y?: never; Z?: never } | ({ Y: number }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Z?: never } | ({ Z: number[][] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never }; export type GenericAutoBound = { value: T, values: T[], }; export type GenericAutoBound2 = { value: T, values: T[], }; export type GenericDefault = { value: T, }; export type GenericDefaultSkipped = { value: T, }; export type GenericDefaultSkippedNonType = { value: number, }; export type GenericFlattened = { generic_flattened: T, }; export type GenericNewType1 = T[][]; export type GenericParameterOrderPreserved = { pair: Pair, }; export type GenericStruct = { arg: T, }; export type GenericStruct2 = { a: T, b: [T, T], c: [T, [T, T]], d: [T, T, T], e: [([T, T]), ([T, T]), ([T, T])], f: T[], g: T[][], h: ([([T, T]), ([T, T]), ([T, T])])[], }; export type GenericTuple = [T, T[], T[][]]; export type GenericTupleStruct = T; export type GenericType = "Undefined" | T; export type HasGenericAlias = { [key in number]: string }; export type InlineConstGenericContainer = { b: { data: [number, number], a: [number, number], d: [number, number, number], }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], }, d: [number, number], }; export type InlineEnumField = { A: { a: string, } }; export type InlineFlattenGenerics = { g: InlineFlattenGenericsG, gi: { t: string, }, } & InlineFlattenGenericsG; export type InlineFlattenGenericsG = { t: T, }; export type InlineOptionalType = { optional_field: { a: string, } | null, }; export type InlineRecursiveConstGeneric = { data: number[], a: number[], d: [number, number, number], e: InlineRecursiveConstGeneric, }; export type InlineRecursiveConstGenericContainer = { b: { data: [number, number], a: [number, number], d: [number, number, number], e: InlineRecursiveConstGeneric, }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], e: InlineRecursiveConstGeneric, }, d: [number, number], }; export type InlineStruct = { ref_struct: SimpleStruct, val: number, }; export type InlineTuple = { demo: [string, boolean], }; export type InlineTuple2 = { demo: [{ demo: [string, boolean], }, boolean], }; export type InlinerStruct = { inline_this: { ref_struct: SimpleStruct, val: number, }, dont_inline_this: RefStruct, }; export type Inner = { a: number, } & FlattenedInner; export type InternallyTaggedD = { type: "A", } & { [key in string]: string }; export type InternallyTaggedE = { type: "A" }; export type InternallyTaggedF = { type: "A" }; export type InternallyTaggedFInner = null; export type InternallyTaggedH = { type: "A" }; export type InternallyTaggedHInner = null; export type InternallyTaggedL = { type: "A", } & { type: "A" } | { type: "B" }; export type InternallyTaggedLInner = { type: "A" } | { type: "B" }; export type InternallyTaggedM = { type: "A" }; export type InternallyTaggedMInner = "A" | "B"; export type InternallyTaggedWithAlias = { type: "A"; field: string } | { type: "B"; other: number }; export type InvalidToValidType = { cause: null, }; export type Issue221External = ({ A: { a: string, } }) & { B?: never } | ({ B: { b: string, } }) & { A?: never }; export type Issue221UntaggedMixed = ({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never }; export type Issue221UntaggedSafe = ({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }; export type Issue281 = { default_unity_arguments: string[], }; /** https://github.com/specta-rs/specta/issues/374 */ export type Issue374 = Issue374_Serialize | Issue374_Deserialize; /** https://github.com/specta-rs/specta/issues/374 */ export type Issue374_Deserialize = { foo?: boolean, bar?: boolean, }; /** https://github.com/specta-rs/specta/issues/374 */ export type Issue374_Serialize = { foo?: boolean, bar?: boolean, }; export type KebabCase = { "test-ing": string, }; export type LifetimeGenericEnum = ({ Borrowed: T }) & { Owned?: never } | ({ Owned: T }) & { Borrowed?: never }; export type LifetimeGenericStruct = { borrowed: T[], owned: T[], }; export type LoadProjectEvent = { event: "started"; data: { projectName: string, } } | { event: "progressTest"; data: { projectName: string, status: string, progress: number, } } | { event: "finished"; data: { projectName: string, } }; export type MacroEnum = ({ Demo: string }) & { Demo2?: never } | ({ Demo2: { demo2: string, } }) & { Demo?: never }; export type MacroStruct = string; export type MacroStruct2 = { demo: string, }; export type MaybeValidKey = T; export type MyEmptyInput = Record; export type MyEnum = ({ A: string }) & { B?: never } | ({ B: number }) & { A?: never }; export type MyEnumAdjacent = { t: "Variant"; c: { inner: First, } }; export type MyEnumExternal = { Variant: { inner: First, } }; export type MyEnumTagged = { type: "Variant"; inner: First }; export type MyEnumUntagged = { inner: First }; export type NamedConstGeneric = { data: number[], a: number[], d: [number, number], }; export type NamedConstGenericContainer = { a: NamedConstGeneric, b: NamedConstGeneric, d: [number, number], }; export type NestedEnum = { type: "a"; value: string } | { type: "b"; value: number }; export type Ninth = { t: "A"; c: string } | { t: "B" } | { t: "C"; c: { a: string, } } | { t: "D"; c: First }; export type NonOptional = string | null; export type Optional = Optional_Serialize | Optional_Deserialize; export type OptionalInEnum = ({ A?: string | null }) & { B?: never; C?: never } | ({ B: { a: string | null, } }) & { A?: never; C?: never } | ({ C: { a?: string | null, } }) & { A?: never; B?: never }; export type OptionalOnNamedField = string | null; export type OptionalOnTransparentNamedField = { b: string | null, }; export type Optional_Deserialize = { a: number | null, b?: number | null, c: string | null, d?: boolean, }; export type Optional_Serialize = { a: number | null, b?: number | null, c?: string | null, d: boolean, }; export type OverridenStruct = { overriden_field: string, }; export type Pair = { first: Z, second: A, }; export type PlaceholderInnerField = { a: string, }; export type Primitives = { i8: number, i16: number, i32: number, u8: number, u16: number, u32: number, f32: number, f64: number, bool: boolean, char: string, "Range": Range, "RangeInclusive": RangeInclusive, "()": null, "(String, i32)": [string, number], "(String, i32, bool)": [string, number, boolean], "((String, i32), (bool, char, bool), ())": [[string, number], [boolean, string, boolean], null], "(bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool)": [boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean], "(Vec, Vec)": [number[], boolean[]], String: string, PathBuf: string, IpAddr: string, Ipv4Addr: string, Ipv6Addr: string, SocketAddr: string, SocketAddrV4: string, SocketAddrV6: string, "Cow<'static, str>": string, "Cow<'static, i32>": number, "&'static str": string, "&'static bool": boolean, "&'static i32": number, "Vec": number[], "&'static [i32]": number[], "&'static [i32; 3]": [number, number, number], "[i32; 3]": [number, number, number], "Vec": MyEnum[], "&'static [MyEnum]": MyEnum[], "&'static [MyEnum; 6]": [MyEnum, MyEnum, MyEnum, MyEnum, MyEnum, MyEnum], "[MyEnum; 2]": [MyEnum, MyEnum], "&'static [i32; 1]": [number], "&'static [i32; 0]": [], "Option": number | null, "Option<()>": null, "Option>": number[] | null, "Result": Result, "Vec>>": (number | null)[], "Option>>": number[] | null, "[Vec; 3]": [string[], string[], string[]], "Option>": string | null, "Option>>": string | null, "PhantomData<()>": null, "PhantomData": null, Infallible: never, Unit1: Unit1, Unit2: Unit2, Unit3: Unit3, Unit4: Unit4, Unit5: Unit5, Unit6: Unit6, Unit7: Unit7, SimpleStruct: SimpleStruct, TupleStruct1: TupleStruct1, TupleStruct3: TupleStruct3, TestEnum: TestEnum, RefStruct: RefStruct, InlinerStruct: InlinerStruct, "GenericStruct": GenericStruct, "GenericStruct": GenericStruct, FlattenEnumStruct: FlattenEnumStruct, OverridenStruct: OverridenStruct, HasGenericAlias: HasGenericAlias, EnumMacroAttributes: EnumMacroAttributes, InlineEnumField: InlineEnumField, InlineOptionalType: InlineOptionalType, Rename: Rename, TransparentType: TransparentType, TransparentType2: TransparentType2, TransparentTypeWithOverride: TransparentTypeWithOverride, "[Option; 3]": [(number | null), (number | null), (number | null)], "HashMap": Partial<{ [key in BasicEnum]: null }>, "HashMap": Partial<{ [key in BasicEnum]: number }>, "Option>>>": number | null, "Vec": PlaceholderInnerField[], EnumReferenceRecordKey: EnumReferenceRecordKey, FlattenOnNestedEnum: FlattenOnNestedEnum, MyEmptyInput: MyEmptyInput, "(String)": string, "(String,)": [string], ExtraBracketsInTupleVariant: ExtraBracketsInTupleVariant, ExtraBracketsInUnnamedStruct: ExtraBracketsInUnnamedStruct, "Vec": MyEnum[], InlineTuple: InlineTuple, InlineTuple2: InlineTuple2, "Box": string, "Box": string, SkippedFieldWithinVariant: SkippedFieldWithinVariant, KebabCase: KebabCase, "&[&str]": string[], "Issue281<'_>": Issue281, "LifetimeGenericStruct<'_, i32>": LifetimeGenericStruct, "LifetimeGenericEnum<'_, i32>": LifetimeGenericEnum, RenameWithWeirdCharsField: RenameWithWeirdCharsField, RenameWithWeirdCharsVariant: RenameWithWeirdCharsVariant, RenamedFieldKeys: RenamedFieldKeys, RenamedVariantWithSkippedPayload: RenamedVariantWithSkippedPayload, "type_type::Type": Type, ActualType: ActualType, SpectaTypeOverride: SpectaTypeOverride, ContainerTypeOverrideStruct: ContainerTypeOverrideStruct, ContainerTypeOverrideEnum: ContainerTypeOverrideEnum, "ContainerTypeOverrideGeneric>": ContainerTypeOverrideGeneric, "ContainerTypeOverrideToGeneric": ContainerTypeOverrideToGeneric, ContainerTypeOverrideTuple: ContainerTypeOverrideTuple, "ContainerTypeOverrideTupleGeneric": ContainerTypeOverrideTupleGeneric, InvalidToValidType: InvalidToValidType, TupleStruct: TupleStruct, TupleStructWithRep: TupleStructWithRep, "GenericTupleStruct": GenericTupleStruct, BracedStruct: BracedStruct, Struct: StructNew, Struct2: Struct2, Enum: Enum, Enum2: Enum2, Enum3: Enum3, StructRenameAllUppercase: StructRenameAllUppercase, RenameSerdeSpecialChar: RenameSerdeSpecialChar, EnumRenameAllUppercase: EnumRenameAllUppercase, Recursive: Recursive, RecursiveMapValue: RecursiveMapValue, RecursiveTransparent: RecursiveTransparent, RecursiveInEnum: RecursiveInEnum, NonOptional: NonOptional, OptionalOnNamedField: OptionalOnNamedField, OptionalOnTransparentNamedField: OptionalOnTransparentNamedField, OptionalInEnum: OptionalInEnum, UntaggedVariants: UntaggedVariants, UntaggedVariantsWithoutValue: UntaggedVariantsWithoutValue, UntaggedVariantsWithDuplicateBranches: UntaggedVariantsWithDuplicateBranches, "HashMap": { [key in string]: null }, Regular: Regular, "HashMap": { [key in never]: null }, "HashMap": { [key in TransparentStruct]: null }, "HashMap": Partial<{ [key in UnitVariants]: null }>, "HashMap": Partial<{ [key in UntaggedVariantsKey]: null }>, ValidMaybeValidKey: ValidMaybeValidKey, ValidMaybeValidKeyNested: ValidMaybeValidKeyNested, MacroStruct: MacroStruct, MacroStruct2: MacroStruct2, MacroEnum: MacroEnum, DeprecatedType: DeprecatedType, DeprecatedTypeWithMsg: DeprecatedTypeWithMsg, DeprecatedTypeWithMsg2: DeprecatedTypeWithMsg2, DeprecatedFields: DeprecatedFields, DeprecatedTupleVariant: DeprecatedTupleVariant, DeprecatedEnumVariants: DeprecatedEnumVariants, CommentedStruct: CommentedStruct, CommentedEnum: CommentedEnum, SingleLineComment: SingleLineComment, NonGeneric: Demo, "HalfGenericA": Demo, "HalfGenericB": Demo, "FullGeneric": Demo, "Another": Demo, "MapA": { [key in string]: number }, "MapB": { [key in number]: string }, "MapC": { [key in string]: AGenericStruct }, "AGenericStruct": AGenericStruct, A: A, DoubleFlattened: DoubleFlattened, FlattenedInner: FlattenedInner, BoxFlattened: BoxFlattened, BoxInline: BoxInline, First: First, Second: Second, Third: Third, Fourth: Fourth, TagOnStructWithInline: TagOnStructWithInline, Sixth: Sixth, Seventh: Seventh, Eight: Eight, Ninth: Ninth, Tenth: Tenth, MyEnumTagged: MyEnumTagged, MyEnumExternal: MyEnumExternal, MyEnumAdjacent: MyEnumAdjacent, MyEnumUntagged: MyEnumUntagged, EmptyStruct: EmptyStruct, EmptyStructWithTag: EmptyStructWithTag, AdjacentlyTagged: AdjacentlyTagged, LoadProjectEvent: LoadProjectEvent, ExternallyTagged: ExternallyTagged, Issue221External: Issue221External, InternallyTaggedD: InternallyTaggedD, InternallyTaggedE: InternallyTaggedE, InternallyTaggedF: InternallyTaggedF, InternallyTaggedH: InternallyTaggedH, InternallyTaggedL: InternallyTaggedL, InternallyTaggedM: InternallyTaggedM, StructWithAlias: StructWithAlias, StructWithMultipleAliases: StructWithMultipleAliases, StructWithAliasAndRename: StructWithAliasAndRename, EnumWithVariantAlias: EnumWithVariantAlias, EnumWithMultipleVariantAliases: EnumWithMultipleVariantAliases, EnumWithVariantAliasAndRename: EnumWithVariantAliasAndRename, InternallyTaggedWithAlias: InternallyTaggedWithAlias, AdjacentlyTaggedWithAlias: AdjacentlyTaggedWithAlias, UntaggedWithAlias: UntaggedWithAlias, Issue221UntaggedSafe: Issue221UntaggedSafe, Issue221UntaggedMixed: Issue221UntaggedMixed, EmptyEnum: EmptyEnum, EmptyEnumTagged: EmptyEnumTagged, EmptyEnumTaggedWContent: EmptyEnumTaggedWContent, EmptyEnumUntagged: EmptyEnumUntagged, SkipOnlyField: SkipOnlyField, SkipField: SkipField, SkipVariant: SkipVariant, SkipUnnamedFieldInVariant: SkipUnnamedFieldInVariant, SkipNamedFieldInVariant: SkipNamedFieldInVariant, TransparentWithSkip: TransparentWithSkip, TransparentWithSkip2: TransparentWithSkip2, TransparentWithSkip3: TransparentWithSkip3, SkipVariant2: SkipVariant2, SkipVariant3: SkipVariant3, SkipStructFields: SkipStructFields, SpectaSkipNonTypeField: SpectaSkipNonTypeField, FlattenA: FlattenA, FlattenB: FlattenB, FlattenC: FlattenC, FlattenD: FlattenD, FlattenE: FlattenE, FlattenF: FlattenF, FlattenG: FlattenG, TupleNested: TupleNested, "Generic1<()>": Generic1, "GenericAutoBound<()>": GenericAutoBound, "GenericAutoBound2<()>": GenericAutoBound2, Container1: Container1, "Generic2<(), String, i32>": Generic2, "GenericNewType1<()>": GenericNewType1, "GenericTuple<()>": GenericTuple, "GenericStruct2<()>": GenericStruct2, "InlineGenericNewtype": string, "InlineGenericNested": [string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | ({ Unnamed: string }) & { Named?: never } | ({ Named: { value: string, } }) & { Unnamed?: never }], "InlineFlattenGenericsG<()>": InlineFlattenGenericsG, InlineFlattenGenerics: InlineFlattenGenerics, GenericDefault: GenericDefault, ChainedGenericDefault: ChainedGenericDefault, "ChainedGenericDefault": ChainedGenericDefault, "ChainedGenericDefault": ChainedGenericDefault, "ChainedGenericDefault": ChainedGenericDefault, GenericDefaultSkipped: GenericDefaultSkipped, GenericDefaultSkippedNonType: GenericDefaultSkippedNonType, GenericParameterOrderPreserved: GenericParameterOrderPreserved, ConstGenericInNonConstContainer: ConstGenericInNonConstContainer, ConstGenericInConstContainer: ConstGenericInConstContainer, NamedConstGenericContainer: NamedConstGenericContainer, InlineConstGenericContainer: InlineConstGenericContainer, InlineRecursiveConstGenericContainer: InlineRecursiveConstGenericContainer, TestCollectionRegister: TestCollectionRegister, TestCollectionRegister: TestCollectionRegister, }; export type Range = { start: T, end: T, }; export type RangeInclusive = { start: T, end: T, }; export type Recursive = { demo: Recursive, }; export type RecursiveInEnum = { A: { demo: RecursiveInEnum, } }; export type RecursiveInline = RecursiveInline; export type RecursiveMapValue = { demo: { [key in string]: RecursiveMapValue }, }; export type RecursiveTransparent = RecursiveInline; export type RefStruct = TestEnum; export type Regular = { [key in string]: null }; export type Rename = "OneWord" | "Two words"; export type RenameSerdeSpecialChar = { "a/b": number, }; export type RenameWithWeirdCharsField = { "@odata.context": string, }; export type RenameWithWeirdCharsVariant = { "@odata.context": string }; export type RenamedFieldKeys = { "": string, "a\"b": string, "a\\b": string, "line\nbreak": string, "line\u2028break": string, "line\u2029break": string, }; export type RenamedVariantWithSkippedPayload = "a-b"; export type Result = { ok: T, err: E, }; export type Second = { a: number, }; export type Seventh = { a: First, b: Second, }; export type SimpleStruct = { a: number, b: string, c: [number, string, number], d: string[], e: string | null, }; /** Some single-line comment */ export type SingleLineComment = /** Some single-line comment */ ({ A: number }) & { B?: never } | /** Some single-line comment */ ({ B: { /** Some single-line comment */ a: number, } }) & { A?: never }; export type Sixth = { a: First, b: First, }; export type SkipField = { b: number, }; export type SkipNamedFieldInVariant = ({ A: Record }) & { B?: never } | ({ B: { b: number, } }) & { A?: never }; export type SkipOnlyField = Record; export type SkipStructFields = { a: number, }; export type SkipUnnamedFieldInVariant = "A" | { B: [number] }; export type SkipVariant = { A: string }; export type SkipVariant2 = { tag: "A"; data: string }; export type SkipVariant3 = { A: { a: string, } }; export type SkippedFieldWithinVariant = { type: "A" } | { type: "B"; data: string }; export type SpectaSkipNonTypeField = { a: number, }; export type SpectaTypeOverride = { string_ident: string, u32_ident: number, path: string, tuple: [string, number], }; export type Struct2 = { b: string, }; export type StructNew = { t: "StructNew", a: string, }; export type StructPhaseSpecificRename = StructPhaseSpecificRenameSerialize | StructPhaseSpecificRenameDeserialize; export type StructPhaseSpecificRenameDeserialize = { kind: "StructPhaseSpecificRenameDeserialize", der: string, }; export type StructPhaseSpecificRenameSerialize = { kind: "StructPhaseSpecificRenameSerialize", ser: string, }; export type StructRenameAllUppercase = { A: number, B: number, }; export type StructWithAlias = { field: string, }; export type StructWithAliasAndRename = { renamed_field: string, }; export type StructWithMultipleAliases = { field: string, }; export type TagOnStructWithInline = { type: "TagOnStructWithInline", a: First, b: { a: string, }, }; export type Tenth = string | "B" | { a: string, } | First; export type TestCollectionRegister = never; export type TestEnum = "Unit" | ({ Single: number }) & { Multiple?: never; Struct?: never } | ({ Multiple: [number, number] }) & { Single?: never; Struct?: never } | ({ Struct: { a: number, } }) & { Multiple?: never; Single?: never }; export type Third = { b: { [key in string]: string }, c: First, } & First; export type ToBeFlattened = { a: string, }; export type TransparentStruct = string; export type TransparentType = TransparentTypeInner; export type TransparentType2 = null; export type TransparentTypeInner = { inner: string, }; export type TransparentTypeWithOverride = string; export type TransparentWithSkip = null; export type TransparentWithSkip2 = string; export type TransparentWithSkip3 = string; export type TupleNested = [number[], [number[], number[]], [number[], number[], number[]]]; export type TupleStruct = string; export type TupleStruct1 = number; export type TupleStruct3 = [number, boolean, string]; export type TupleStructWithRep = string; export type Type = never; export type Unit1 = null; export type Unit2 = Record; export type Unit3 = []; export type Unit4 = null; export type Unit5 = "A"; export type Unit6 = { A: null }; export type Unit7 = { A: Record }; export type UnitVariants = "A" | "B" | "C"; export type UntaggedVariants = string | number | { id: string } | [string, boolean]; export type UntaggedVariantsKey = string | number; export type UntaggedVariantsWithDuplicateBranches = null | number; export type UntaggedVariantsWithoutValue = string | [number, string] | number; export type UntaggedWithAlias = ({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }; export type ValidMaybeValidKey = { [key in MaybeValidKey]: null }; export type ValidMaybeValidKeyNested = { [key in MaybeValidKey>]: null }; ════════════════════════════════════════ ================================================ FILE: tests/tests/snapshots/test__typescript__ts-export-to-moduleprefixedname-raw.snap ================================================ --- source: tests/tests/typescript.rs expression: output --- ts-export-to-moduleprefixedname-raw (29820 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. export type test_types_A = { a: test_types_B, b: { b: number, }, c: test_types_B, d: { flattened: number, }, e: { generic_flattened: number, }, }; export type test_types_AGenericStruct = { field: test_types_Demo, }; export type test_types_ActualType = { a: test_types_GenericType, }; export type test_types_AdjacentlyTagged = "A" | { id: string; method: string } | string; export type test_types_AdjacentlyTaggedWithAlias = ({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }; export type test_types_B = { b: number, }; export type test_types_BasicEnum = "A" | "B"; export type test_types_BoxFlattened = { b: test_types_BoxedInner, }; export type test_types_BoxInline = { c: { a: number, }, }; export type test_types_BoxedInner = { a: number, }; export type test_types_BracedStruct = string; export type test_types_ChainedGenericDefault = { first: T, second: U, }; /** * Some triple-slash comment * Some more triple-slash comment */ export type test_types_CommentedEnum = /** * Some triple-slash comment * Some more triple-slash comment */ number | /** * Some triple-slash comment * Some more triple-slash comment */ { /** * Some triple-slash comment * Some more triple-slash comment */ a: number }; /** * Some triple-slash comment * Some more triple-slash comment */ export type test_types_CommentedStruct = { /** * Some triple-slash comment * Some more triple-slash comment */ a: number, }; export type test_types_ConstGenericInConstContainer = { data: number[], a: number[], d: [number, number], }; export type test_types_ConstGenericInNonConstContainer = { data: [number], a: [number, number], d: [number, number], }; export type test_types_Container1 = { foo: test_types_Generic1, bar: test_types_Generic1[], baz: { [key in string]: test_types_Generic1 }, }; export type test_types_ContainerTypeOverrideEnum = string; export type test_types_ContainerTypeOverrideGeneric = string; export type test_types_ContainerTypeOverrideStruct = string; export type test_types_ContainerTypeOverrideToGeneric = T; export type test_types_ContainerTypeOverrideTuple = [string, number]; export type test_types_ContainerTypeOverrideTupleGeneric = [T, string]; export type test_types_D = { flattened: number, }; export type test_types_Demo = { a: A, b: B, }; export type test_types_DeprecatedEnumVariants = /** * @deprecated */ "A" | /** * @deprecated Nope */ "B" | /** * @deprecated Nope */ "C"; export type test_types_DeprecatedFields = { a: number, /** * @deprecated */ b: string, /** * @deprecated This field is cringe! */ c: string, /** * @deprecated This field is cringe! */ d: string, }; export type test_types_DeprecatedTupleVariant = [ /** * @deprecated */ string, /** * @deprecated Nope */ string, /** * @deprecated Nope */ number]; /** * @deprecated */ export type test_types_DeprecatedType = { a: number, }; /** * @deprecated Look at you big man using a deprecation message */ export type test_types_DeprecatedTypeWithMsg = { a: number, }; /** * @deprecated Look at you big man using a deprecation message */ export type test_types_DeprecatedTypeWithMsg2 = { a: number, }; export type test_types_DoubleFlattened = { a: test_types_ToBeFlattened, b: test_types_ToBeFlattened, }; export type test_types_Eight = string | "B"; export type test_types_EmptyEnum = never; export type test_types_EmptyEnumTagged = never; export type test_types_EmptyEnumTaggedWContent = never; export type test_types_EmptyEnumUntagged = never; export type test_types_EmptyStruct = Record; export type test_types_EmptyStructWithTag = Record; export type test_types_Enum = "A" | "B"; export type test_types_Enum2 = "A" | "B" | { enum_field: null }; export type test_types_Enum3 = { a: string }; export type test_types_EnumMacroAttributes = string | number | { a: string; b: number }; export type test_types_EnumReferenceRecordKey = { a: Partial<{ [key in test_types_BasicEnum]: number }>, }; export type test_types_EnumRenameAllUppercase = "HelloWorld" | "VariantB" | "TestingWords"; export type test_types_EnumWithMultipleVariantAliases = "Variant" | "Other"; export type test_types_EnumWithVariantAlias = "Variant" | "Other"; export type test_types_EnumWithVariantAliasAndRename = "Variant" | "Other"; export type test_types_ExternallyTagged = "A" | { id: string; method: string } | string; export type test_types_ExtraBracketsInTupleVariant = string; export type test_types_ExtraBracketsInUnnamedStruct = string; export type test_types_First = { a: string, }; export type test_types_FlattenA = { a: number, b: number, }; export type test_types_FlattenB = { a: test_types_FlattenA, c: number, }; export type test_types_FlattenC = { a: test_types_FlattenA, c: number, }; export type test_types_FlattenD = { a: test_types_FlattenA, c: number, }; export type test_types_FlattenE = { b: { a: test_types_FlattenA, c: number, }, d: number, }; export type test_types_FlattenEnum = "One" | "Two" | "Three"; export type test_types_FlattenEnumStruct = { outer: string, inner: test_types_FlattenEnum, }; export type test_types_FlattenF = { b: { a: test_types_FlattenA, c: number, }, d: number, }; export type test_types_FlattenG = { b: test_types_FlattenB, d: number, }; export type test_types_FlattenOnNestedEnum = { id: string, result: test_types_NestedEnum, }; export type test_types_FlattenedInner = { c: test_types_Inner, }; export type test_types_Fourth = { a: test_types_First, b: { a: string, }, }; export type test_types_Generic1 = { value: T, values: T[], }; export type test_types_Generic2 = A | [B, B, B] | C[] | A[][][] | { a: A; b: B; c: C } | number[] | number | number[][]; export type test_types_GenericAutoBound = { value: T, values: T[], }; export type test_types_GenericAutoBound2 = { value: T, values: T[], }; export type test_types_GenericDefault = { value: T, }; export type test_types_GenericDefaultSkipped = { value: T, }; export type test_types_GenericDefaultSkippedNonType = { value: number, }; export type test_types_GenericFlattened = { generic_flattened: T, }; export type test_types_GenericNewType1 = T[][]; export type test_types_GenericParameterOrderPreserved = { pair: test_types_Pair, }; export type test_types_GenericStruct = { arg: T, }; export type test_types_GenericStruct2 = { a: T, b: [T, T], c: [T, [T, T]], d: [T, T, T], e: [([T, T]), ([T, T]), ([T, T])], f: T[], g: T[][], h: ([([T, T]), ([T, T]), ([T, T])])[], }; export type test_types_GenericTuple = [T, T[], T[][]]; export type test_types_GenericTupleStruct = T; export type test_types_GenericType = "Undefined" | T; export type test_types_HasGenericAlias = { [key in number]: string }; export type test_types_InlineConstGenericContainer = { b: { data: [number, number], a: [number, number], d: [number, number, number], }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], }, d: [number, number], }; export type test_types_InlineEnumField = { a: string, }; export type test_types_InlineFlattenGenerics = { g: test_types_InlineFlattenGenericsG, gi: { t: string, }, t: test_types_InlineFlattenGenericsG, }; export type test_types_InlineFlattenGenericsG = { t: T, }; export type test_types_InlineOptionalType = { optional_field: { a: string, } | null, }; export type test_types_InlineRecursiveConstGeneric = { data: number[], a: number[], d: [number, number, number], e: test_types_InlineRecursiveConstGeneric, }; export type test_types_InlineRecursiveConstGenericContainer = { b: { data: [number, number], a: [number, number], d: [number, number, number], e: test_types_InlineRecursiveConstGeneric, }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], e: test_types_InlineRecursiveConstGeneric, }, d: [number, number], }; export type test_types_InlineStruct = { ref_struct: test_types_SimpleStruct, val: number, }; export type test_types_InlineTuple = { demo: [string, boolean], }; export type test_types_InlineTuple2 = { demo: [{ demo: [string, boolean], }, boolean], }; export type test_types_InlinerStruct = { inline_this: { ref_struct: test_types_SimpleStruct, val: number, }, dont_inline_this: test_types_RefStruct, }; export type test_types_Inner = { a: number, b: test_types_FlattenedInner, }; export type test_types_InternallyTaggedD = { [key in string]: string }; export type test_types_InternallyTaggedE = null; export type test_types_InternallyTaggedF = test_types_InternallyTaggedFInner; export type test_types_InternallyTaggedFInner = null; export type test_types_InternallyTaggedH = test_types_InternallyTaggedHInner; export type test_types_InternallyTaggedHInner = null; export type test_types_InternallyTaggedL = "A" | "B"; export type test_types_InternallyTaggedLInner = "A" | "B"; export type test_types_InternallyTaggedM = "A" | "B"; export type test_types_InternallyTaggedMInner = "A" | "B"; export type test_types_InternallyTaggedWithAlias = ({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }; export type test_types_InvalidToValidType = { cause: null, }; export type test_types_Issue221External = ({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }; export type test_types_Issue221UntaggedMixed = ({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never }; export type test_types_Issue221UntaggedSafe = ({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }; export type test_types_Issue281 = { default_unity_arguments: string[], }; export type test_types_KebabCase = { test_ing: string, }; export type test_types_LifetimeGenericEnum = T; export type test_types_LifetimeGenericStruct = { borrowed: T[], owned: T[], }; export type test_types_LoadProjectEvent = ({ project_name: string }) & { progress?: never; status?: never } | { project_name: string; status: string; progress: number }; export type test_types_MacroEnum = string | { demo2: string }; export type test_types_MacroStruct = string; export type test_types_MacroStruct2 = { demo: string, }; export type test_types_MaybeValidKey = T; export type test_types_MyEmptyInput = Record; export type test_types_MyEnum = string | number; export type test_types_MyEnumAdjacent = { inner: test_types_First }; export type test_types_MyEnumExternal = { inner: test_types_First }; export type test_types_MyEnumTagged = { inner: test_types_First }; export type test_types_MyEnumUntagged = { inner: test_types_First }; export type test_types_NamedConstGeneric = { data: number[], a: number[], d: [number, number], }; export type test_types_NamedConstGenericContainer = { a: test_types_NamedConstGeneric, b: test_types_NamedConstGeneric, d: [number, number], }; export type test_types_NestedEnum = string | number; export type test_types_Ninth = string | "B" | { a: string, } | test_types_First; export type test_types_NonOptional = string | null; export type test_types_OptionalInEnum = string | null | { a: string | null } | { a?: string | null }; export type test_types_OptionalOnNamedField = string | null; export type test_types_OptionalOnTransparentNamedField = { b: string | null, }; export type test_types_OverridenStruct = { overriden_field: string, }; export type test_types_Pair = { first: Z, second: A, }; export type test_types_PlaceholderInnerField = { a: string, }; export type tests_tests_types_Primitives = { i8: number, i16: number, i32: number, u8: number, u16: number, u32: number, f32: number, f64: number, bool: boolean, char: string, "Range": std_ops_Range, "RangeInclusive": std_ops_RangeInclusive, "()": null, "(String, i32)": [string, number], "(String, i32, bool)": [string, number, boolean], "((String, i32), (bool, char, bool), ())": [[string, number], [boolean, string, boolean], null], "(bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool)": [boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean], "(Vec, Vec)": [number[], boolean[]], String: string, PathBuf: string, IpAddr: string, Ipv4Addr: string, Ipv6Addr: string, SocketAddr: string, SocketAddrV4: string, SocketAddrV6: string, "Cow<'static, str>": string, "Cow<'static, i32>": number, "&'static str": string, "&'static bool": boolean, "&'static i32": number, "Vec": number[], "&'static [i32]": number[], "&'static [i32; 3]": [number, number, number], "[i32; 3]": [number, number, number], "Vec": test_types_MyEnum[], "&'static [MyEnum]": test_types_MyEnum[], "&'static [MyEnum; 6]": [test_types_MyEnum, test_types_MyEnum, test_types_MyEnum, test_types_MyEnum, test_types_MyEnum, test_types_MyEnum], "[MyEnum; 2]": [test_types_MyEnum, test_types_MyEnum], "&'static [i32; 1]": [number], "&'static [i32; 0]": [], "Option": number | null, "Option<()>": null, "Option>": number[] | null, "Result": std_result_Result, "Vec>>": (number | null)[], "Option>>": number[] | null, "[Vec; 3]": [string[], string[], string[]], "Option>": string | null, "Option>>": string | null, "PhantomData<()>": null, "PhantomData": null, Infallible: never, Unit1: test_types_Unit1, Unit2: test_types_Unit2, Unit3: test_types_Unit3, Unit4: test_types_Unit4, Unit5: test_types_Unit5, Unit6: test_types_Unit6, Unit7: test_types_Unit7, SimpleStruct: test_types_SimpleStruct, TupleStruct1: test_types_TupleStruct1, TupleStruct3: test_types_TupleStruct3, TestEnum: test_types_TestEnum, RefStruct: test_types_RefStruct, InlinerStruct: test_types_InlinerStruct, "GenericStruct": test_types_GenericStruct, "GenericStruct": test_types_GenericStruct, FlattenEnumStruct: test_types_FlattenEnumStruct, OverridenStruct: test_types_OverridenStruct, HasGenericAlias: test_types_HasGenericAlias, EnumMacroAttributes: test_types_EnumMacroAttributes, InlineEnumField: test_types_InlineEnumField, InlineOptionalType: test_types_InlineOptionalType, Rename: test_types_Rename, TransparentType: test_types_TransparentType, TransparentType2: test_types_TransparentType2, TransparentTypeWithOverride: test_types_TransparentTypeWithOverride, "[Option; 3]": [(number | null), (number | null), (number | null)], "HashMap": Partial<{ [key in test_types_BasicEnum]: null }>, "HashMap": Partial<{ [key in test_types_BasicEnum]: number }>, "Option>>>": number | null, "Vec": test_types_PlaceholderInnerField[], EnumReferenceRecordKey: test_types_EnumReferenceRecordKey, FlattenOnNestedEnum: test_types_FlattenOnNestedEnum, MyEmptyInput: test_types_MyEmptyInput, "(String)": string, "(String,)": [string], ExtraBracketsInTupleVariant: test_types_ExtraBracketsInTupleVariant, ExtraBracketsInUnnamedStruct: test_types_ExtraBracketsInUnnamedStruct, "Vec": test_types_MyEnum[], InlineTuple: test_types_InlineTuple, InlineTuple2: test_types_InlineTuple2, "Box": string, "Box": string, SkippedFieldWithinVariant: test_types_SkippedFieldWithinVariant, KebabCase: test_types_KebabCase, "&[&str]": string[], "Issue281<'_>": test_types_Issue281, "LifetimeGenericStruct<'_, i32>": test_types_LifetimeGenericStruct, "LifetimeGenericEnum<'_, i32>": test_types_LifetimeGenericEnum, RenameWithWeirdCharsField: test_types_RenameWithWeirdCharsField, RenameWithWeirdCharsVariant: test_types_RenameWithWeirdCharsVariant, RenamedFieldKeys: test_types_RenamedFieldKeys, RenamedVariantWithSkippedPayload: test_types_RenamedVariantWithSkippedPayload, "type_type::Type": test_types_type_type_Type, ActualType: test_types_ActualType, SpectaTypeOverride: test_types_SpectaTypeOverride, ContainerTypeOverrideStruct: test_types_ContainerTypeOverrideStruct, ContainerTypeOverrideEnum: test_types_ContainerTypeOverrideEnum, "ContainerTypeOverrideGeneric>": test_types_ContainerTypeOverrideGeneric, "ContainerTypeOverrideToGeneric": test_types_ContainerTypeOverrideToGeneric, ContainerTypeOverrideTuple: test_types_ContainerTypeOverrideTuple, "ContainerTypeOverrideTupleGeneric": test_types_ContainerTypeOverrideTupleGeneric, InvalidToValidType: test_types_InvalidToValidType, TupleStruct: test_types_TupleStruct, TupleStructWithRep: test_types_TupleStructWithRep, "GenericTupleStruct": test_types_GenericTupleStruct, BracedStruct: test_types_BracedStruct, Struct: test_types_Struct, Struct2: test_types_Struct2, Enum: test_types_Enum, Enum2: test_types_Enum2, Enum3: test_types_Enum3, StructRenameAllUppercase: test_types_StructRenameAllUppercase, RenameSerdeSpecialChar: test_types_RenameSerdeSpecialChar, EnumRenameAllUppercase: test_types_EnumRenameAllUppercase, Recursive: test_types_Recursive, RecursiveMapValue: test_types_RecursiveMapValue, RecursiveTransparent: test_types_RecursiveTransparent, RecursiveInEnum: test_types_RecursiveInEnum, NonOptional: test_types_NonOptional, OptionalOnNamedField: test_types_OptionalOnNamedField, OptionalOnTransparentNamedField: test_types_OptionalOnTransparentNamedField, OptionalInEnum: test_types_OptionalInEnum, UntaggedVariants: test_types_UntaggedVariants, UntaggedVariantsWithoutValue: test_types_UntaggedVariantsWithoutValue, UntaggedVariantsWithDuplicateBranches: test_types_UntaggedVariantsWithDuplicateBranches, "HashMap": { [key in string]: null }, Regular: test_types_Regular, "HashMap": { [key in never]: null }, "HashMap": { [key in test_types_TransparentStruct]: null }, "HashMap": Partial<{ [key in test_types_UnitVariants]: null }>, "HashMap": Partial<{ [key in test_types_UntaggedVariantsKey]: null }>, ValidMaybeValidKey: test_types_ValidMaybeValidKey, ValidMaybeValidKeyNested: test_types_ValidMaybeValidKeyNested, MacroStruct: test_types_MacroStruct, MacroStruct2: test_types_MacroStruct2, MacroEnum: test_types_MacroEnum, DeprecatedType: test_types_DeprecatedType, DeprecatedTypeWithMsg: test_types_DeprecatedTypeWithMsg, DeprecatedTypeWithMsg2: test_types_DeprecatedTypeWithMsg2, DeprecatedFields: test_types_DeprecatedFields, DeprecatedTupleVariant: test_types_DeprecatedTupleVariant, DeprecatedEnumVariants: test_types_DeprecatedEnumVariants, CommentedStruct: test_types_CommentedStruct, CommentedEnum: test_types_CommentedEnum, SingleLineComment: test_types_SingleLineComment, NonGeneric: test_types_Demo, "HalfGenericA": test_types_Demo, "HalfGenericB": test_types_Demo, "FullGeneric": test_types_Demo, "Another": test_types_Demo, "MapA": { [key in string]: number }, "MapB": { [key in number]: string }, "MapC": { [key in string]: test_types_AGenericStruct }, "AGenericStruct": test_types_AGenericStruct, A: test_types_A, DoubleFlattened: test_types_DoubleFlattened, FlattenedInner: test_types_FlattenedInner, BoxFlattened: test_types_BoxFlattened, BoxInline: test_types_BoxInline, First: test_types_First, Second: test_types_Second, Third: test_types_Third, Fourth: test_types_Fourth, TagOnStructWithInline: test_types_TagOnStructWithInline, Sixth: test_types_Sixth, Seventh: test_types_Seventh, Eight: test_types_Eight, Ninth: test_types_Ninth, Tenth: test_types_Tenth, MyEnumTagged: test_types_MyEnumTagged, MyEnumExternal: test_types_MyEnumExternal, MyEnumAdjacent: test_types_MyEnumAdjacent, MyEnumUntagged: test_types_MyEnumUntagged, EmptyStruct: test_types_EmptyStruct, EmptyStructWithTag: test_types_EmptyStructWithTag, AdjacentlyTagged: test_types_AdjacentlyTagged, LoadProjectEvent: test_types_LoadProjectEvent, ExternallyTagged: test_types_ExternallyTagged, Issue221External: test_types_Issue221External, InternallyTaggedD: test_types_InternallyTaggedD, InternallyTaggedE: test_types_InternallyTaggedE, InternallyTaggedF: test_types_InternallyTaggedF, InternallyTaggedH: test_types_InternallyTaggedH, InternallyTaggedL: test_types_InternallyTaggedL, InternallyTaggedM: test_types_InternallyTaggedM, StructWithAlias: test_types_StructWithAlias, StructWithMultipleAliases: test_types_StructWithMultipleAliases, StructWithAliasAndRename: test_types_StructWithAliasAndRename, EnumWithVariantAlias: test_types_EnumWithVariantAlias, EnumWithMultipleVariantAliases: test_types_EnumWithMultipleVariantAliases, EnumWithVariantAliasAndRename: test_types_EnumWithVariantAliasAndRename, InternallyTaggedWithAlias: test_types_InternallyTaggedWithAlias, AdjacentlyTaggedWithAlias: test_types_AdjacentlyTaggedWithAlias, UntaggedWithAlias: test_types_UntaggedWithAlias, Issue221UntaggedSafe: test_types_Issue221UntaggedSafe, Issue221UntaggedMixed: test_types_Issue221UntaggedMixed, EmptyEnum: test_types_EmptyEnum, EmptyEnumTagged: test_types_EmptyEnumTagged, EmptyEnumTaggedWContent: test_types_EmptyEnumTaggedWContent, EmptyEnumUntagged: test_types_EmptyEnumUntagged, SkipOnlyField: test_types_SkipOnlyField, SkipField: test_types_SkipField, SkipVariant: test_types_SkipVariant, SkipUnnamedFieldInVariant: test_types_SkipUnnamedFieldInVariant, SkipNamedFieldInVariant: test_types_SkipNamedFieldInVariant, TransparentWithSkip: test_types_TransparentWithSkip, TransparentWithSkip2: test_types_TransparentWithSkip2, TransparentWithSkip3: test_types_TransparentWithSkip3, SkipVariant2: test_types_SkipVariant2, SkipVariant3: test_types_SkipVariant3, SkipStructFields: test_types_SkipStructFields, SpectaSkipNonTypeField: test_types_SpectaSkipNonTypeField, FlattenA: test_types_FlattenA, FlattenB: test_types_FlattenB, FlattenC: test_types_FlattenC, FlattenD: test_types_FlattenD, FlattenE: test_types_FlattenE, FlattenF: test_types_FlattenF, FlattenG: test_types_FlattenG, TupleNested: test_types_TupleNested, "Generic1<()>": test_types_Generic1, "GenericAutoBound<()>": test_types_GenericAutoBound, "GenericAutoBound2<()>": test_types_GenericAutoBound2, Container1: test_types_Container1, "Generic2<(), String, i32>": test_types_Generic2, "GenericNewType1<()>": test_types_GenericNewType1, "GenericTuple<()>": test_types_GenericTuple, "GenericStruct2<()>": test_types_GenericStruct2, "InlineGenericNewtype": string, "InlineGenericNested": [string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | string | { value: string }], "InlineFlattenGenericsG<()>": test_types_InlineFlattenGenericsG, InlineFlattenGenerics: test_types_InlineFlattenGenerics, GenericDefault: test_types_GenericDefault, ChainedGenericDefault: test_types_ChainedGenericDefault, "ChainedGenericDefault": test_types_ChainedGenericDefault, "ChainedGenericDefault": test_types_ChainedGenericDefault, "ChainedGenericDefault": test_types_ChainedGenericDefault, GenericDefaultSkipped: test_types_GenericDefaultSkipped, GenericDefaultSkippedNonType: test_types_GenericDefaultSkippedNonType, GenericParameterOrderPreserved: test_types_GenericParameterOrderPreserved, ConstGenericInNonConstContainer: test_types_ConstGenericInNonConstContainer, ConstGenericInConstContainer: test_types_ConstGenericInConstContainer, NamedConstGenericContainer: test_types_NamedConstGenericContainer, InlineConstGenericContainer: test_types_InlineConstGenericContainer, InlineRecursiveConstGenericContainer: test_types_InlineRecursiveConstGenericContainer, TestCollectionRegister: test_types_TestCollectionRegister, TestCollectionRegister: test_types_TestCollectionRegister, }; export type std_ops_Range = { start: T, end: T, }; export type std_ops_RangeInclusive = { start: T, end: T, }; export type test_types_Recursive = { demo: test_types_Recursive, }; export type test_types_RecursiveInEnum = { demo: test_types_RecursiveInEnum }; export type test_types_RecursiveInline = { demo: test_types_RecursiveInline, }; export type test_types_RecursiveMapValue = { demo: { [key in string]: test_types_RecursiveMapValue }, }; export type test_types_RecursiveTransparent = test_types_RecursiveInline; export type test_types_RefStruct = test_types_TestEnum; export type test_types_Regular = { [key in string]: null }; export type test_types_Rename = "OneWord" | "TwoWords"; export type test_types_RenameSerdeSpecialChar = { b: number, }; export type test_types_RenameWithWeirdCharsField = { odata_context: string, }; export type test_types_RenameWithWeirdCharsVariant = string; export type test_types_RenamedFieldKeys = { empty: string, quote: string, backslash: string, newline: string, line_separator: string, paragraph_separator: string, }; export type test_types_RenamedVariantWithSkippedPayload = never; export type std_result_Result = { ok: T, err: E, }; export type test_types_Second = { a: number, }; export type test_types_Seventh = { a: test_types_First, b: test_types_Second, }; export type test_types_SimpleStruct = { a: number, b: string, c: [number, string, number], d: string[], e: string | null, }; /** Some single-line comment */ export type test_types_SingleLineComment = /** Some single-line comment */ number | /** Some single-line comment */ { /** Some single-line comment */ a: number }; export type test_types_Sixth = { a: test_types_First, b: test_types_First, }; export type test_types_SkipField = { b: number, }; export type test_types_SkipNamedFieldInVariant = Record | { b: number }; export type test_types_SkipOnlyField = Record; export type test_types_SkipStructFields = { a: number, }; export type test_types_SkipUnnamedFieldInVariant = never | [number]; export type test_types_SkipVariant = string; export type test_types_SkipVariant2 = string; export type test_types_SkipVariant3 = { a: string }; export type test_types_SkippedFieldWithinVariant = never | string; export type test_types_SpectaSkipNonTypeField = { a: number, }; export type test_types_SpectaTypeOverride = { string_ident: string, u32_ident: number, path: string, tuple: [string, number], }; export type test_types_Struct = { a: string, }; export type test_types_Struct2 = { a: string, }; export type test_types_StructRenameAllUppercase = { a: number, b: number, }; export type test_types_StructWithAlias = { field: string, }; export type test_types_StructWithAliasAndRename = { field: string, }; export type test_types_StructWithMultipleAliases = { field: string, }; export type test_types_TagOnStructWithInline = { a: test_types_First, b: { a: string, }, }; export type test_types_Tenth = string | "B" | { a: string, } | test_types_First; export type test_types_TestCollectionRegister = never; export type test_types_TestEnum = "Unit" | number | [number, number] | { a: number }; export type test_types_Third = { a: test_types_First, b: { [key in string]: string }, c: test_types_First, }; export type test_types_ToBeFlattened = { a: string, }; export type test_types_TransparentStruct = string; export type test_types_TransparentType = test_types_TransparentTypeInner; export type test_types_TransparentType2 = null; export type test_types_TransparentTypeInner = { inner: string, }; export type test_types_TransparentTypeWithOverride = string; export type test_types_TransparentWithSkip = null; export type test_types_TransparentWithSkip2 = string; export type test_types_TransparentWithSkip3 = string; export type test_types_TupleNested = [number[], [number[], number[]], [number[], number[], number[]]]; export type test_types_TupleStruct = string; export type test_types_TupleStruct1 = number; export type test_types_TupleStruct3 = [number, boolean, string]; export type test_types_TupleStructWithRep = string; export type test_types_type_type_Type = never; export type test_types_Unit1 = null; export type test_types_Unit2 = Record; export type test_types_Unit3 = []; export type test_types_Unit4 = null; export type test_types_Unit5 = "A"; export type test_types_Unit6 = []; export type test_types_Unit7 = Record; export type test_types_UnitVariants = "A" | "B" | "C"; export type test_types_UntaggedVariants = string | number | { id: string } | [string, boolean]; export type test_types_UntaggedVariantsKey = string | number; export type test_types_UntaggedVariantsWithDuplicateBranches = null | number; export type test_types_UntaggedVariantsWithoutValue = string | [number, string] | number; export type test_types_UntaggedWithAlias = ({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }; export type test_types_ValidMaybeValidKey = { [key in test_types_MaybeValidKey]: null }; export type test_types_ValidMaybeValidKeyNested = { [key in test_types_MaybeValidKey>]: null }; ════════════════════════════════════════ ================================================ FILE: tests/tests/snapshots/test__typescript__ts-export-to-moduleprefixedname-serde.snap ================================================ --- source: tests/tests/typescript.rs expression: output --- ts-export-to-moduleprefixedname-serde (32085 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. export type test_types_A = { a: test_types_B, b: { b: number, }, c: test_types_B, d: { flattened: number, }, e: { generic_flattened: number, }, }; export type test_types_AGenericStruct = { field: test_types_Demo, }; export type test_types_ActualType = { a: test_types_GenericType, }; export type test_types_AdjacentlyTagged = { t: "A" } | { t: "B"; c: { id: string, method: string, } } | { t: "C"; c: string }; export type test_types_AdjacentlyTaggedWithAlias = { type: "A"; data: { field: string, } } | { type: "B"; data: { other: number, } }; export type test_types_B = { b: number, }; export type test_types_BasicEnum = "A" | "B"; export type test_types_BoxFlattened = test_types_BoxedInner; export type test_types_BoxInline = { c: { a: number, }, }; export type test_types_BoxedInner = { a: number, }; export type test_types_BracedStruct = string; export type test_types_ChainedGenericDefault = { first: T, second: U, }; /** * Some triple-slash comment * Some more triple-slash comment */ export type test_types_CommentedEnum = /** * Some triple-slash comment * Some more triple-slash comment */ ({ A: number }) & { B?: never } | /** * Some triple-slash comment * Some more triple-slash comment */ ({ B: { /** * Some triple-slash comment * Some more triple-slash comment */ a: number, } }) & { A?: never }; /** * Some triple-slash comment * Some more triple-slash comment */ export type test_types_CommentedStruct = { /** * Some triple-slash comment * Some more triple-slash comment */ a: number, }; export type test_types_ConstGenericInConstContainer = { data: number[], a: number[], d: [number, number], }; export type test_types_ConstGenericInNonConstContainer = { data: [number], a: [number, number], d: [number, number], }; export type test_types_Container1 = { foo: test_types_Generic1, bar: test_types_Generic1[], baz: { [key in string]: test_types_Generic1 }, }; export type test_types_ContainerTypeOverrideEnum = string; export type test_types_ContainerTypeOverrideGeneric = string; export type test_types_ContainerTypeOverrideStruct = string; export type test_types_ContainerTypeOverrideToGeneric = T; export type test_types_ContainerTypeOverrideTuple = [string, number]; export type test_types_ContainerTypeOverrideTupleGeneric = [T, string]; export type test_types_D = { flattened: number, }; export type test_types_Demo = { a: A, b: B, }; export type test_types_DeprecatedEnumVariants = /** * @deprecated */ "A" | /** * @deprecated Nope */ "B" | /** * @deprecated Nope */ "C"; export type test_types_DeprecatedFields = { a: number, /** * @deprecated */ b: string, /** * @deprecated This field is cringe! */ c: string, /** * @deprecated This field is cringe! */ d: string, }; export type test_types_DeprecatedTupleVariant = [ /** * @deprecated */ string, /** * @deprecated Nope */ string, /** * @deprecated Nope */ number]; /** * @deprecated */ export type test_types_DeprecatedType = { a: number, }; /** * @deprecated Look at you big man using a deprecation message */ export type test_types_DeprecatedTypeWithMsg = { a: number, }; /** * @deprecated Look at you big man using a deprecation message */ export type test_types_DeprecatedTypeWithMsg2 = { a: number, }; export type test_types_DoubleFlattened = { a: test_types_ToBeFlattened, b: test_types_ToBeFlattened, }; export type test_types_Eight = { A: string } | "B"; export type test_types_EmptyEnum = never; export type test_types_EmptyEnumTagged = never; export type test_types_EmptyEnumTaggedWContent = never; export type test_types_EmptyEnumUntagged = never; export type test_types_EmptyStruct = Record; export type test_types_EmptyStructWithTag = { a: "EmptyStructWithTag", }; export type test_types_Enum = { t: "A" } | { t: "B" }; export type test_types_Enum2 = { t: "C" } | { t: "B" } | { t: "D"; enumField: null }; export type test_types_Enum3 = { t: "A"; b: string }; export type test_types_EnumMacroAttributes = ({ A: string }) & { D?: never; bbb?: never; cccc?: never } | ({ bbb: number }) & { A?: never; D?: never; cccc?: never } | ({ cccc: number }) & { A?: never; D?: never; bbb?: never } | ({ D: { a: string, bbbbbb: number, } }) & { A?: never; bbb?: never; cccc?: never }; export type test_types_EnumReferenceRecordKey = { a: Partial<{ [key in test_types_BasicEnum]: number }>, }; export type test_types_EnumRenameAllUppercase = "HELLOWORLD" | "VARIANTB" | "TESTINGWORDS"; export type test_types_EnumWithMultipleVariantAliases = "Variant" | "Other"; export type test_types_EnumWithVariantAlias = "Variant" | "Other"; export type test_types_EnumWithVariantAliasAndRename = "renamed_variant" | "Other"; export type test_types_ExternallyTagged = "A" | ({ B: { id: string, method: string, } }) & { C?: never } | ({ C: string }) & { B?: never }; export type test_types_ExtraBracketsInTupleVariant = { A: string }; export type test_types_ExtraBracketsInUnnamedStruct = string; export type test_types_First = { a: string, }; export type test_types_FlattenA = { a: number, b: number, }; export type test_types_FlattenB = { c: number, } & test_types_FlattenA; export type test_types_FlattenC = { c: number, } & test_types_FlattenA; export type test_types_FlattenD = { a: test_types_FlattenA, c: number, }; export type test_types_FlattenE = { b: ({ c: number, }) & (test_types_FlattenA), d: number, }; export type test_types_FlattenEnum = { tag: "One" } | { tag: "Two" } | { tag: "Three" }; export type test_types_FlattenEnumStruct = { outer: string, } & test_types_FlattenEnum; export type test_types_FlattenF = { b: ({ c: number, }) & (test_types_FlattenA), d: number, }; export type test_types_FlattenG = { b: test_types_FlattenB, d: number, }; export type test_types_FlattenOnNestedEnum = { id: string, } & test_types_NestedEnum; export type test_types_FlattenedInner = test_types_Inner; export type test_types_Fourth = { a: test_types_First, b: { a: string, }, }; export type test_types_Generic1 = { value: T, values: T[], }; export type test_types_Generic2 = ({ A: A }) & { B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ B: [B, B, B] }) & { A?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ C: C[] }) & { A?: never; B?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ D: A[][][] }) & { A?: never; B?: never; C?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ E: { a: A, b: B, c: C, } }) & { A?: never; B?: never; C?: never; D?: never; X?: never; Y?: never; Z?: never } | ({ X: number[] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; Y?: never; Z?: never } | ({ Y: number }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Z?: never } | ({ Z: number[][] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never }; export type test_types_GenericAutoBound = { value: T, values: T[], }; export type test_types_GenericAutoBound2 = { value: T, values: T[], }; export type test_types_GenericDefault = { value: T, }; export type test_types_GenericDefaultSkipped = { value: T, }; export type test_types_GenericDefaultSkippedNonType = { value: number, }; export type test_types_GenericFlattened = { generic_flattened: T, }; export type test_types_GenericNewType1 = T[][]; export type test_types_GenericParameterOrderPreserved = { pair: test_types_Pair, }; export type test_types_GenericStruct = { arg: T, }; export type test_types_GenericStruct2 = { a: T, b: [T, T], c: [T, [T, T]], d: [T, T, T], e: [([T, T]), ([T, T]), ([T, T])], f: T[], g: T[][], h: ([([T, T]), ([T, T]), ([T, T])])[], }; export type test_types_GenericTuple = [T, T[], T[][]]; export type test_types_GenericTupleStruct = T; export type test_types_GenericType = "Undefined" | T; export type test_types_HasGenericAlias = { [key in number]: string }; export type test_types_InlineConstGenericContainer = { b: { data: [number, number], a: [number, number], d: [number, number, number], }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], }, d: [number, number], }; export type test_types_InlineEnumField = { A: { a: string, } }; export type test_types_InlineFlattenGenerics = { g: test_types_InlineFlattenGenericsG, gi: { t: string, }, } & test_types_InlineFlattenGenericsG; export type test_types_InlineFlattenGenericsG = { t: T, }; export type test_types_InlineOptionalType = { optional_field: { a: string, } | null, }; export type test_types_InlineRecursiveConstGeneric = { data: number[], a: number[], d: [number, number, number], e: test_types_InlineRecursiveConstGeneric, }; export type test_types_InlineRecursiveConstGenericContainer = { b: { data: [number, number], a: [number, number], d: [number, number, number], e: test_types_InlineRecursiveConstGeneric, }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], e: test_types_InlineRecursiveConstGeneric, }, d: [number, number], }; export type test_types_InlineStruct = { ref_struct: test_types_SimpleStruct, val: number, }; export type test_types_InlineTuple = { demo: [string, boolean], }; export type test_types_InlineTuple2 = { demo: [{ demo: [string, boolean], }, boolean], }; export type test_types_InlinerStruct = { inline_this: { ref_struct: test_types_SimpleStruct, val: number, }, dont_inline_this: test_types_RefStruct, }; export type test_types_Inner = { a: number, } & test_types_FlattenedInner; export type test_types_InternallyTaggedD = { type: "A", } & { [key in string]: string }; export type test_types_InternallyTaggedE = { type: "A" }; export type test_types_InternallyTaggedF = { type: "A" }; export type test_types_InternallyTaggedFInner = null; export type test_types_InternallyTaggedH = { type: "A" }; export type test_types_InternallyTaggedHInner = null; export type test_types_InternallyTaggedL = { type: "A", } & { type: "A" } | { type: "B" }; export type test_types_InternallyTaggedLInner = { type: "A" } | { type: "B" }; export type test_types_InternallyTaggedM = { type: "A" }; export type test_types_InternallyTaggedMInner = "A" | "B"; export type test_types_InternallyTaggedWithAlias = { type: "A"; field: string } | { type: "B"; other: number }; export type test_types_InvalidToValidType = { cause: null, }; export type test_types_Issue221External = ({ A: { a: string, } }) & { B?: never } | ({ B: { b: string, } }) & { A?: never }; export type test_types_Issue221UntaggedMixed = ({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never }; export type test_types_Issue221UntaggedSafe = ({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }; export type test_types_Issue281 = { default_unity_arguments: string[], }; export type test_types_KebabCase = { "test-ing": string, }; export type test_types_LifetimeGenericEnum = ({ Borrowed: T }) & { Owned?: never } | ({ Owned: T }) & { Borrowed?: never }; export type test_types_LifetimeGenericStruct = { borrowed: T[], owned: T[], }; export type test_types_LoadProjectEvent = { event: "started"; data: { projectName: string, } } | { event: "progressTest"; data: { projectName: string, status: string, progress: number, } } | { event: "finished"; data: { projectName: string, } }; export type test_types_MacroEnum = ({ Demo: string }) & { Demo2?: never } | ({ Demo2: { demo2: string, } }) & { Demo?: never }; export type test_types_MacroStruct = string; export type test_types_MacroStruct2 = { demo: string, }; export type test_types_MaybeValidKey = T; export type test_types_MyEmptyInput = Record; export type test_types_MyEnum = ({ A: string }) & { B?: never } | ({ B: number }) & { A?: never }; export type test_types_MyEnumAdjacent = { t: "Variant"; c: { inner: test_types_First, } }; export type test_types_MyEnumExternal = { Variant: { inner: test_types_First, } }; export type test_types_MyEnumTagged = { type: "Variant"; inner: test_types_First }; export type test_types_MyEnumUntagged = { inner: test_types_First }; export type test_types_NamedConstGeneric = { data: number[], a: number[], d: [number, number], }; export type test_types_NamedConstGenericContainer = { a: test_types_NamedConstGeneric, b: test_types_NamedConstGeneric, d: [number, number], }; export type test_types_NestedEnum = { type: "a"; value: string } | { type: "b"; value: number }; export type test_types_Ninth = { t: "A"; c: string } | { t: "B" } | { t: "C"; c: { a: string, } } | { t: "D"; c: test_types_First }; export type test_types_NonOptional = string | null; export type test_types_OptionalInEnum = ({ A?: string | null }) & { B?: never; C?: never } | ({ B: { a: string | null, } }) & { A?: never; C?: never } | ({ C: { a?: string | null, } }) & { A?: never; B?: never }; export type test_types_OptionalOnNamedField = string | null; export type test_types_OptionalOnTransparentNamedField = { b: string | null, }; export type test_types_OverridenStruct = { overriden_field: string, }; export type test_types_Pair = { first: Z, second: A, }; export type test_types_PlaceholderInnerField = { a: string, }; export type tests_tests_types_Primitives = { i8: number, i16: number, i32: number, u8: number, u16: number, u32: number, f32: number, f64: number, bool: boolean, char: string, "Range": std_ops_Range, "RangeInclusive": std_ops_RangeInclusive, "()": null, "(String, i32)": [string, number], "(String, i32, bool)": [string, number, boolean], "((String, i32), (bool, char, bool), ())": [[string, number], [boolean, string, boolean], null], "(bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool)": [boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean], "(Vec, Vec)": [number[], boolean[]], String: string, PathBuf: string, IpAddr: string, Ipv4Addr: string, Ipv6Addr: string, SocketAddr: string, SocketAddrV4: string, SocketAddrV6: string, "Cow<'static, str>": string, "Cow<'static, i32>": number, "&'static str": string, "&'static bool": boolean, "&'static i32": number, "Vec": number[], "&'static [i32]": number[], "&'static [i32; 3]": [number, number, number], "[i32; 3]": [number, number, number], "Vec": test_types_MyEnum[], "&'static [MyEnum]": test_types_MyEnum[], "&'static [MyEnum; 6]": [test_types_MyEnum, test_types_MyEnum, test_types_MyEnum, test_types_MyEnum, test_types_MyEnum, test_types_MyEnum], "[MyEnum; 2]": [test_types_MyEnum, test_types_MyEnum], "&'static [i32; 1]": [number], "&'static [i32; 0]": [], "Option": number | null, "Option<()>": null, "Option>": number[] | null, "Result": std_result_Result, "Vec>>": (number | null)[], "Option>>": number[] | null, "[Vec; 3]": [string[], string[], string[]], "Option>": string | null, "Option>>": string | null, "PhantomData<()>": null, "PhantomData": null, Infallible: never, Unit1: test_types_Unit1, Unit2: test_types_Unit2, Unit3: test_types_Unit3, Unit4: test_types_Unit4, Unit5: test_types_Unit5, Unit6: test_types_Unit6, Unit7: test_types_Unit7, SimpleStruct: test_types_SimpleStruct, TupleStruct1: test_types_TupleStruct1, TupleStruct3: test_types_TupleStruct3, TestEnum: test_types_TestEnum, RefStruct: test_types_RefStruct, InlinerStruct: test_types_InlinerStruct, "GenericStruct": test_types_GenericStruct, "GenericStruct": test_types_GenericStruct, FlattenEnumStruct: test_types_FlattenEnumStruct, OverridenStruct: test_types_OverridenStruct, HasGenericAlias: test_types_HasGenericAlias, EnumMacroAttributes: test_types_EnumMacroAttributes, InlineEnumField: test_types_InlineEnumField, InlineOptionalType: test_types_InlineOptionalType, Rename: test_types_Rename, TransparentType: test_types_TransparentType, TransparentType2: test_types_TransparentType2, TransparentTypeWithOverride: test_types_TransparentTypeWithOverride, "[Option; 3]": [(number | null), (number | null), (number | null)], "HashMap": Partial<{ [key in test_types_BasicEnum]: null }>, "HashMap": Partial<{ [key in test_types_BasicEnum]: number }>, "Option>>>": number | null, "Vec": test_types_PlaceholderInnerField[], EnumReferenceRecordKey: test_types_EnumReferenceRecordKey, FlattenOnNestedEnum: test_types_FlattenOnNestedEnum, MyEmptyInput: test_types_MyEmptyInput, "(String)": string, "(String,)": [string], ExtraBracketsInTupleVariant: test_types_ExtraBracketsInTupleVariant, ExtraBracketsInUnnamedStruct: test_types_ExtraBracketsInUnnamedStruct, "Vec": test_types_MyEnum[], InlineTuple: test_types_InlineTuple, InlineTuple2: test_types_InlineTuple2, "Box": string, "Box": string, SkippedFieldWithinVariant: test_types_SkippedFieldWithinVariant, KebabCase: test_types_KebabCase, "&[&str]": string[], "Issue281<'_>": test_types_Issue281, "LifetimeGenericStruct<'_, i32>": test_types_LifetimeGenericStruct, "LifetimeGenericEnum<'_, i32>": test_types_LifetimeGenericEnum, RenameWithWeirdCharsField: test_types_RenameWithWeirdCharsField, RenameWithWeirdCharsVariant: test_types_RenameWithWeirdCharsVariant, RenamedFieldKeys: test_types_RenamedFieldKeys, RenamedVariantWithSkippedPayload: test_types_RenamedVariantWithSkippedPayload, "type_type::Type": test_types_type_type_Type, ActualType: test_types_ActualType, SpectaTypeOverride: test_types_SpectaTypeOverride, ContainerTypeOverrideStruct: test_types_ContainerTypeOverrideStruct, ContainerTypeOverrideEnum: test_types_ContainerTypeOverrideEnum, "ContainerTypeOverrideGeneric>": test_types_ContainerTypeOverrideGeneric, "ContainerTypeOverrideToGeneric": test_types_ContainerTypeOverrideToGeneric, ContainerTypeOverrideTuple: test_types_ContainerTypeOverrideTuple, "ContainerTypeOverrideTupleGeneric": test_types_ContainerTypeOverrideTupleGeneric, InvalidToValidType: test_types_InvalidToValidType, TupleStruct: test_types_TupleStruct, TupleStructWithRep: test_types_TupleStructWithRep, "GenericTupleStruct": test_types_GenericTupleStruct, BracedStruct: test_types_BracedStruct, Struct: test_types_StructNew, Struct2: test_types_Struct2, Enum: test_types_Enum, Enum2: test_types_Enum2, Enum3: test_types_Enum3, StructRenameAllUppercase: test_types_StructRenameAllUppercase, RenameSerdeSpecialChar: test_types_RenameSerdeSpecialChar, EnumRenameAllUppercase: test_types_EnumRenameAllUppercase, Recursive: test_types_Recursive, RecursiveMapValue: test_types_RecursiveMapValue, RecursiveTransparent: test_types_RecursiveTransparent, RecursiveInEnum: test_types_RecursiveInEnum, NonOptional: test_types_NonOptional, OptionalOnNamedField: test_types_OptionalOnNamedField, OptionalOnTransparentNamedField: test_types_OptionalOnTransparentNamedField, OptionalInEnum: test_types_OptionalInEnum, UntaggedVariants: test_types_UntaggedVariants, UntaggedVariantsWithoutValue: test_types_UntaggedVariantsWithoutValue, UntaggedVariantsWithDuplicateBranches: test_types_UntaggedVariantsWithDuplicateBranches, "HashMap": { [key in string]: null }, Regular: test_types_Regular, "HashMap": { [key in never]: null }, "HashMap": { [key in test_types_TransparentStruct]: null }, "HashMap": Partial<{ [key in test_types_UnitVariants]: null }>, "HashMap": Partial<{ [key in test_types_UntaggedVariantsKey]: null }>, ValidMaybeValidKey: test_types_ValidMaybeValidKey, ValidMaybeValidKeyNested: test_types_ValidMaybeValidKeyNested, MacroStruct: test_types_MacroStruct, MacroStruct2: test_types_MacroStruct2, MacroEnum: test_types_MacroEnum, DeprecatedType: test_types_DeprecatedType, DeprecatedTypeWithMsg: test_types_DeprecatedTypeWithMsg, DeprecatedTypeWithMsg2: test_types_DeprecatedTypeWithMsg2, DeprecatedFields: test_types_DeprecatedFields, DeprecatedTupleVariant: test_types_DeprecatedTupleVariant, DeprecatedEnumVariants: test_types_DeprecatedEnumVariants, CommentedStruct: test_types_CommentedStruct, CommentedEnum: test_types_CommentedEnum, SingleLineComment: test_types_SingleLineComment, NonGeneric: test_types_Demo, "HalfGenericA": test_types_Demo, "HalfGenericB": test_types_Demo, "FullGeneric": test_types_Demo, "Another": test_types_Demo, "MapA": { [key in string]: number }, "MapB": { [key in number]: string }, "MapC": { [key in string]: test_types_AGenericStruct }, "AGenericStruct": test_types_AGenericStruct, A: test_types_A, DoubleFlattened: test_types_DoubleFlattened, FlattenedInner: test_types_FlattenedInner, BoxFlattened: test_types_BoxFlattened, BoxInline: test_types_BoxInline, First: test_types_First, Second: test_types_Second, Third: test_types_Third, Fourth: test_types_Fourth, TagOnStructWithInline: test_types_TagOnStructWithInline, Sixth: test_types_Sixth, Seventh: test_types_Seventh, Eight: test_types_Eight, Ninth: test_types_Ninth, Tenth: test_types_Tenth, MyEnumTagged: test_types_MyEnumTagged, MyEnumExternal: test_types_MyEnumExternal, MyEnumAdjacent: test_types_MyEnumAdjacent, MyEnumUntagged: test_types_MyEnumUntagged, EmptyStruct: test_types_EmptyStruct, EmptyStructWithTag: test_types_EmptyStructWithTag, AdjacentlyTagged: test_types_AdjacentlyTagged, LoadProjectEvent: test_types_LoadProjectEvent, ExternallyTagged: test_types_ExternallyTagged, Issue221External: test_types_Issue221External, InternallyTaggedD: test_types_InternallyTaggedD, InternallyTaggedE: test_types_InternallyTaggedE, InternallyTaggedF: test_types_InternallyTaggedF, InternallyTaggedH: test_types_InternallyTaggedH, InternallyTaggedL: test_types_InternallyTaggedL, InternallyTaggedM: test_types_InternallyTaggedM, StructWithAlias: test_types_StructWithAlias, StructWithMultipleAliases: test_types_StructWithMultipleAliases, StructWithAliasAndRename: test_types_StructWithAliasAndRename, EnumWithVariantAlias: test_types_EnumWithVariantAlias, EnumWithMultipleVariantAliases: test_types_EnumWithMultipleVariantAliases, EnumWithVariantAliasAndRename: test_types_EnumWithVariantAliasAndRename, InternallyTaggedWithAlias: test_types_InternallyTaggedWithAlias, AdjacentlyTaggedWithAlias: test_types_AdjacentlyTaggedWithAlias, UntaggedWithAlias: test_types_UntaggedWithAlias, Issue221UntaggedSafe: test_types_Issue221UntaggedSafe, Issue221UntaggedMixed: test_types_Issue221UntaggedMixed, EmptyEnum: test_types_EmptyEnum, EmptyEnumTagged: test_types_EmptyEnumTagged, EmptyEnumTaggedWContent: test_types_EmptyEnumTaggedWContent, EmptyEnumUntagged: test_types_EmptyEnumUntagged, SkipOnlyField: test_types_SkipOnlyField, SkipField: test_types_SkipField, SkipVariant: test_types_SkipVariant, SkipUnnamedFieldInVariant: test_types_SkipUnnamedFieldInVariant, SkipNamedFieldInVariant: test_types_SkipNamedFieldInVariant, TransparentWithSkip: test_types_TransparentWithSkip, TransparentWithSkip2: test_types_TransparentWithSkip2, TransparentWithSkip3: test_types_TransparentWithSkip3, SkipVariant2: test_types_SkipVariant2, SkipVariant3: test_types_SkipVariant3, SkipStructFields: test_types_SkipStructFields, SpectaSkipNonTypeField: test_types_SpectaSkipNonTypeField, FlattenA: test_types_FlattenA, FlattenB: test_types_FlattenB, FlattenC: test_types_FlattenC, FlattenD: test_types_FlattenD, FlattenE: test_types_FlattenE, FlattenF: test_types_FlattenF, FlattenG: test_types_FlattenG, TupleNested: test_types_TupleNested, "Generic1<()>": test_types_Generic1, "GenericAutoBound<()>": test_types_GenericAutoBound, "GenericAutoBound2<()>": test_types_GenericAutoBound2, Container1: test_types_Container1, "Generic2<(), String, i32>": test_types_Generic2, "GenericNewType1<()>": test_types_GenericNewType1, "GenericTuple<()>": test_types_GenericTuple, "GenericStruct2<()>": test_types_GenericStruct2, "InlineGenericNewtype": string, "InlineGenericNested": [string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | ({ Unnamed: string }) & { Named?: never } | ({ Named: { value: string, } }) & { Unnamed?: never }], "InlineFlattenGenericsG<()>": test_types_InlineFlattenGenericsG, InlineFlattenGenerics: test_types_InlineFlattenGenerics, GenericDefault: test_types_GenericDefault, ChainedGenericDefault: test_types_ChainedGenericDefault, "ChainedGenericDefault": test_types_ChainedGenericDefault, "ChainedGenericDefault": test_types_ChainedGenericDefault, "ChainedGenericDefault": test_types_ChainedGenericDefault, GenericDefaultSkipped: test_types_GenericDefaultSkipped, GenericDefaultSkippedNonType: test_types_GenericDefaultSkippedNonType, GenericParameterOrderPreserved: test_types_GenericParameterOrderPreserved, ConstGenericInNonConstContainer: test_types_ConstGenericInNonConstContainer, ConstGenericInConstContainer: test_types_ConstGenericInConstContainer, NamedConstGenericContainer: test_types_NamedConstGenericContainer, InlineConstGenericContainer: test_types_InlineConstGenericContainer, InlineRecursiveConstGenericContainer: test_types_InlineRecursiveConstGenericContainer, TestCollectionRegister: test_types_TestCollectionRegister, TestCollectionRegister: test_types_TestCollectionRegister, }; export type std_ops_Range = { start: T, end: T, }; export type std_ops_RangeInclusive = { start: T, end: T, }; export type test_types_Recursive = { demo: test_types_Recursive, }; export type test_types_RecursiveInEnum = { A: { demo: test_types_RecursiveInEnum, } }; export type test_types_RecursiveInline = test_types_RecursiveInline; export type test_types_RecursiveMapValue = { demo: { [key in string]: test_types_RecursiveMapValue }, }; export type test_types_RecursiveTransparent = test_types_RecursiveInline; export type test_types_RefStruct = test_types_TestEnum; export type test_types_Regular = { [key in string]: null }; export type test_types_Rename = "OneWord" | "Two words"; export type test_types_RenameSerdeSpecialChar = { "a/b": number, }; export type test_types_RenameWithWeirdCharsField = { "@odata.context": string, }; export type test_types_RenameWithWeirdCharsVariant = { "@odata.context": string }; export type test_types_RenamedFieldKeys = { "": string, "a\"b": string, "a\\b": string, "line\nbreak": string, "line\u2028break": string, "line\u2029break": string, }; export type test_types_RenamedVariantWithSkippedPayload = "a-b"; export type std_result_Result = { ok: T, err: E, }; export type test_types_Second = { a: number, }; export type test_types_Seventh = { a: test_types_First, b: test_types_Second, }; export type test_types_SimpleStruct = { a: number, b: string, c: [number, string, number], d: string[], e: string | null, }; /** Some single-line comment */ export type test_types_SingleLineComment = /** Some single-line comment */ ({ A: number }) & { B?: never } | /** Some single-line comment */ ({ B: { /** Some single-line comment */ a: number, } }) & { A?: never }; export type test_types_Sixth = { a: test_types_First, b: test_types_First, }; export type test_types_SkipField = { b: number, }; export type test_types_SkipNamedFieldInVariant = ({ A: Record }) & { B?: never } | ({ B: { b: number, } }) & { A?: never }; export type test_types_SkipOnlyField = Record; export type test_types_SkipStructFields = { a: number, }; export type test_types_SkipUnnamedFieldInVariant = "A" | { B: [number] }; export type test_types_SkipVariant = { A: string }; export type test_types_SkipVariant2 = { tag: "A"; data: string }; export type test_types_SkipVariant3 = { A: { a: string, } }; export type test_types_SkippedFieldWithinVariant = { type: "A" } | { type: "B"; data: string }; export type test_types_SpectaSkipNonTypeField = { a: number, }; export type test_types_SpectaTypeOverride = { string_ident: string, u32_ident: number, path: string, tuple: [string, number], }; export type test_types_Struct2 = { b: string, }; export type test_types_StructNew = { t: "StructNew", a: string, }; export type test_types_StructRenameAllUppercase = { A: number, B: number, }; export type test_types_StructWithAlias = { field: string, }; export type test_types_StructWithAliasAndRename = { renamed_field: string, }; export type test_types_StructWithMultipleAliases = { field: string, }; export type test_types_TagOnStructWithInline = { type: "TagOnStructWithInline", a: test_types_First, b: { a: string, }, }; export type test_types_Tenth = string | "B" | { a: string, } | test_types_First; export type test_types_TestCollectionRegister = never; export type test_types_TestEnum = "Unit" | ({ Single: number }) & { Multiple?: never; Struct?: never } | ({ Multiple: [number, number] }) & { Single?: never; Struct?: never } | ({ Struct: { a: number, } }) & { Multiple?: never; Single?: never }; export type test_types_Third = { b: { [key in string]: string }, c: test_types_First, } & test_types_First; export type test_types_ToBeFlattened = { a: string, }; export type test_types_TransparentStruct = string; export type test_types_TransparentType = test_types_TransparentTypeInner; export type test_types_TransparentType2 = null; export type test_types_TransparentTypeInner = { inner: string, }; export type test_types_TransparentTypeWithOverride = string; export type test_types_TransparentWithSkip = null; export type test_types_TransparentWithSkip2 = string; export type test_types_TransparentWithSkip3 = string; export type test_types_TupleNested = [number[], [number[], number[]], [number[], number[], number[]]]; export type test_types_TupleStruct = string; export type test_types_TupleStruct1 = number; export type test_types_TupleStruct3 = [number, boolean, string]; export type test_types_TupleStructWithRep = string; export type test_types_type_type_Type = never; export type test_types_Unit1 = null; export type test_types_Unit2 = Record; export type test_types_Unit3 = []; export type test_types_Unit4 = null; export type test_types_Unit5 = "A"; export type test_types_Unit6 = { A: null }; export type test_types_Unit7 = { A: Record }; export type test_types_UnitVariants = "A" | "B" | "C"; export type test_types_UntaggedVariants = string | number | { id: string } | [string, boolean]; export type test_types_UntaggedVariantsKey = string | number; export type test_types_UntaggedVariantsWithDuplicateBranches = null | number; export type test_types_UntaggedVariantsWithoutValue = string | [number, string] | number; export type test_types_UntaggedWithAlias = ({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }; export type test_types_ValidMaybeValidKey = { [key in test_types_MaybeValidKey]: null }; export type test_types_ValidMaybeValidKeyNested = { [key in test_types_MaybeValidKey>]: null }; ════════════════════════════════════════ ================================================ FILE: tests/tests/snapshots/test__typescript__ts-export-to-moduleprefixedname-serde_phases.snap ================================================ --- source: tests/tests/typescript.rs expression: output --- ts-export-to-moduleprefixedname-serde_phases (33265 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. export type test_types_A = { a: test_types_B, b: { b: number, }, c: test_types_B, d: { flattened: number, }, e: { generic_flattened: number, }, }; export type test_types_AGenericStruct = { field: test_types_Demo, }; export type test_types_ActualType = { a: test_types_GenericType, }; export type test_types_AdjacentlyTagged = { t: "A" } | { t: "B"; c: { id: string, method: string, } } | { t: "C"; c: string }; export type test_types_AdjacentlyTaggedWithAlias = { type: "A"; data: { field: string, } } | { type: "B"; data: { other: number, } }; export type test_types_B = { b: number, }; export type test_types_BasicEnum = "A" | "B"; export type test_types_BoxFlattened = test_types_BoxedInner; export type test_types_BoxInline = { c: { a: number, }, }; export type test_types_BoxedInner = { a: number, }; export type test_types_BracedStruct = string; export type test_types_ChainedGenericDefault = { first: T, second: U, }; /** * Some triple-slash comment * Some more triple-slash comment */ export type test_types_CommentedEnum = /** * Some triple-slash comment * Some more triple-slash comment */ ({ A: number }) & { B?: never } | /** * Some triple-slash comment * Some more triple-slash comment */ ({ B: { /** * Some triple-slash comment * Some more triple-slash comment */ a: number, } }) & { A?: never }; /** * Some triple-slash comment * Some more triple-slash comment */ export type test_types_CommentedStruct = { /** * Some triple-slash comment * Some more triple-slash comment */ a: number, }; export type test_types_ConstGenericInConstContainer = { data: number[], a: number[], d: [number, number], }; export type test_types_ConstGenericInNonConstContainer = { data: [number], a: [number, number], d: [number, number], }; export type test_types_Container1 = { foo: test_types_Generic1, bar: test_types_Generic1[], baz: { [key in string]: test_types_Generic1 }, }; export type test_types_ContainerTypeOverrideEnum = string; export type test_types_ContainerTypeOverrideGeneric = string; export type test_types_ContainerTypeOverrideStruct = string; export type test_types_ContainerTypeOverrideToGeneric = T; export type test_types_ContainerTypeOverrideTuple = [string, number]; export type test_types_ContainerTypeOverrideTupleGeneric = [T, string]; export type test_types_D = { flattened: number, }; export type test_types_Demo = { a: A, b: B, }; export type test_types_DeprecatedEnumVariants = /** * @deprecated */ "A" | /** * @deprecated Nope */ "B" | /** * @deprecated Nope */ "C"; export type test_types_DeprecatedFields = { a: number, /** * @deprecated */ b: string, /** * @deprecated This field is cringe! */ c: string, /** * @deprecated This field is cringe! */ d: string, }; export type test_types_DeprecatedTupleVariant = [ /** * @deprecated */ string, /** * @deprecated Nope */ string, /** * @deprecated Nope */ number]; /** * @deprecated */ export type test_types_DeprecatedType = { a: number, }; /** * @deprecated Look at you big man using a deprecation message */ export type test_types_DeprecatedTypeWithMsg = { a: number, }; /** * @deprecated Look at you big man using a deprecation message */ export type test_types_DeprecatedTypeWithMsg2 = { a: number, }; export type test_types_DoubleFlattened = { a: test_types_ToBeFlattened, b: test_types_ToBeFlattened, }; export type test_types_Eight = { A: string } | "B"; export type test_types_EmptyEnum = never; export type test_types_EmptyEnumTagged = never; export type test_types_EmptyEnumTaggedWContent = never; export type test_types_EmptyEnumUntagged = never; export type test_types_EmptyStruct = Record; export type test_types_EmptyStructWithTag = { a: "EmptyStructWithTag", }; export type test_types_Enum = { t: "A" } | { t: "B" }; export type test_types_Enum2 = { t: "C" } | { t: "B" } | { t: "D"; enumField: null }; export type test_types_Enum3 = { t: "A"; b: string }; export type test_types_EnumMacroAttributes = ({ A: string }) & { D?: never; bbb?: never; cccc?: never } | ({ bbb: number }) & { A?: never; D?: never; cccc?: never } | ({ cccc: number }) & { A?: never; D?: never; bbb?: never } | ({ D: { a: string, bbbbbb: number, } }) & { A?: never; bbb?: never; cccc?: never }; export type test_types_EnumReferenceRecordKey = { a: Partial<{ [key in test_types_BasicEnum]: number }>, }; export type test_types_EnumRenameAllUppercase = "HELLOWORLD" | "VARIANTB" | "TESTINGWORDS"; export type test_types_EnumWithMultipleVariantAliases = "Variant" | "Other"; export type test_types_EnumWithVariantAlias = "Variant" | "Other"; export type test_types_EnumWithVariantAliasAndRename = "renamed_variant" | "Other"; export type test_types_ExternallyTagged = "A" | ({ B: { id: string, method: string, } }) & { C?: never } | ({ C: string }) & { B?: never }; export type test_types_ExtraBracketsInTupleVariant = { A: string }; export type test_types_ExtraBracketsInUnnamedStruct = string; export type test_types_First = { a: string, }; export type test_types_FlattenA = { a: number, b: number, }; export type test_types_FlattenB = { c: number, } & test_types_FlattenA; export type test_types_FlattenC = { c: number, } & test_types_FlattenA; export type test_types_FlattenD = { a: test_types_FlattenA, c: number, }; export type test_types_FlattenE = { b: ({ c: number, }) & (test_types_FlattenA), d: number, }; export type test_types_FlattenEnum = { tag: "One" } | { tag: "Two" } | { tag: "Three" }; export type test_types_FlattenEnumStruct = { outer: string, } & test_types_FlattenEnum; export type test_types_FlattenF = { b: ({ c: number, }) & (test_types_FlattenA), d: number, }; export type test_types_FlattenG = { b: test_types_FlattenB, d: number, }; export type test_types_FlattenOnNestedEnum = { id: string, } & test_types_NestedEnum; export type test_types_FlattenedInner = test_types_Inner; export type test_types_Fourth = { a: test_types_First, b: { a: string, }, }; export type test_types_Generic1 = { value: T, values: T[], }; export type test_types_Generic2 = ({ A: A }) & { B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ B: [B, B, B] }) & { A?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ C: C[] }) & { A?: never; B?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ D: A[][][] }) & { A?: never; B?: never; C?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ E: { a: A, b: B, c: C, } }) & { A?: never; B?: never; C?: never; D?: never; X?: never; Y?: never; Z?: never } | ({ X: number[] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; Y?: never; Z?: never } | ({ Y: number }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Z?: never } | ({ Z: number[][] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never }; export type test_types_GenericAutoBound = { value: T, values: T[], }; export type test_types_GenericAutoBound2 = { value: T, values: T[], }; export type test_types_GenericDefault = { value: T, }; export type test_types_GenericDefaultSkipped = { value: T, }; export type test_types_GenericDefaultSkippedNonType = { value: number, }; export type test_types_GenericFlattened = { generic_flattened: T, }; export type test_types_GenericNewType1 = T[][]; export type test_types_GenericParameterOrderPreserved = { pair: test_types_Pair, }; export type test_types_GenericStruct = { arg: T, }; export type test_types_GenericStruct2 = { a: T, b: [T, T], c: [T, [T, T]], d: [T, T, T], e: [([T, T]), ([T, T]), ([T, T])], f: T[], g: T[][], h: ([([T, T]), ([T, T]), ([T, T])])[], }; export type test_types_GenericTuple = [T, T[], T[][]]; export type test_types_GenericTupleStruct = T; export type test_types_GenericType = "Undefined" | T; export type test_types_HasGenericAlias = { [key in number]: string }; export type test_types_InlineConstGenericContainer = { b: { data: [number, number], a: [number, number], d: [number, number, number], }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], }, d: [number, number], }; export type test_types_InlineEnumField = { A: { a: string, } }; export type test_types_InlineFlattenGenerics = { g: test_types_InlineFlattenGenericsG, gi: { t: string, }, } & test_types_InlineFlattenGenericsG; export type test_types_InlineFlattenGenericsG = { t: T, }; export type test_types_InlineOptionalType = { optional_field: { a: string, } | null, }; export type test_types_InlineRecursiveConstGeneric = { data: number[], a: number[], d: [number, number, number], e: test_types_InlineRecursiveConstGeneric, }; export type test_types_InlineRecursiveConstGenericContainer = { b: { data: [number, number], a: [number, number], d: [number, number, number], e: test_types_InlineRecursiveConstGeneric, }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], e: test_types_InlineRecursiveConstGeneric, }, d: [number, number], }; export type test_types_InlineStruct = { ref_struct: test_types_SimpleStruct, val: number, }; export type test_types_InlineTuple = { demo: [string, boolean], }; export type test_types_InlineTuple2 = { demo: [{ demo: [string, boolean], }, boolean], }; export type test_types_InlinerStruct = { inline_this: { ref_struct: test_types_SimpleStruct, val: number, }, dont_inline_this: test_types_RefStruct, }; export type test_types_Inner = { a: number, } & test_types_FlattenedInner; export type test_types_InternallyTaggedD = { type: "A", } & { [key in string]: string }; export type test_types_InternallyTaggedE = { type: "A" }; export type test_types_InternallyTaggedF = { type: "A" }; export type test_types_InternallyTaggedFInner = null; export type test_types_InternallyTaggedH = { type: "A" }; export type test_types_InternallyTaggedHInner = null; export type test_types_InternallyTaggedL = { type: "A", } & { type: "A" } | { type: "B" }; export type test_types_InternallyTaggedLInner = { type: "A" } | { type: "B" }; export type test_types_InternallyTaggedM = { type: "A" }; export type test_types_InternallyTaggedMInner = "A" | "B"; export type test_types_InternallyTaggedWithAlias = { type: "A"; field: string } | { type: "B"; other: number }; export type test_types_InvalidToValidType = { cause: null, }; export type test_types_Issue221External = ({ A: { a: string, } }) & { B?: never } | ({ B: { b: string, } }) & { A?: never }; export type test_types_Issue221UntaggedMixed = ({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never }; export type test_types_Issue221UntaggedSafe = ({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }; export type test_types_Issue281 = { default_unity_arguments: string[], }; /** https://github.com/specta-rs/specta/issues/374 */ export type test_types_Issue374 = test_types_Issue374_Serialize | test_types_Issue374_Deserialize; /** https://github.com/specta-rs/specta/issues/374 */ export type test_types_Issue374_Deserialize = { foo?: boolean, bar?: boolean, }; /** https://github.com/specta-rs/specta/issues/374 */ export type test_types_Issue374_Serialize = { foo?: boolean, bar?: boolean, }; export type test_types_KebabCase = { "test-ing": string, }; export type test_types_LifetimeGenericEnum = ({ Borrowed: T }) & { Owned?: never } | ({ Owned: T }) & { Borrowed?: never }; export type test_types_LifetimeGenericStruct = { borrowed: T[], owned: T[], }; export type test_types_LoadProjectEvent = { event: "started"; data: { projectName: string, } } | { event: "progressTest"; data: { projectName: string, status: string, progress: number, } } | { event: "finished"; data: { projectName: string, } }; export type test_types_MacroEnum = ({ Demo: string }) & { Demo2?: never } | ({ Demo2: { demo2: string, } }) & { Demo?: never }; export type test_types_MacroStruct = string; export type test_types_MacroStruct2 = { demo: string, }; export type test_types_MaybeValidKey = T; export type test_types_MyEmptyInput = Record; export type test_types_MyEnum = ({ A: string }) & { B?: never } | ({ B: number }) & { A?: never }; export type test_types_MyEnumAdjacent = { t: "Variant"; c: { inner: test_types_First, } }; export type test_types_MyEnumExternal = { Variant: { inner: test_types_First, } }; export type test_types_MyEnumTagged = { type: "Variant"; inner: test_types_First }; export type test_types_MyEnumUntagged = { inner: test_types_First }; export type test_types_NamedConstGeneric = { data: number[], a: number[], d: [number, number], }; export type test_types_NamedConstGenericContainer = { a: test_types_NamedConstGeneric, b: test_types_NamedConstGeneric, d: [number, number], }; export type test_types_NestedEnum = { type: "a"; value: string } | { type: "b"; value: number }; export type test_types_Ninth = { t: "A"; c: string } | { t: "B" } | { t: "C"; c: { a: string, } } | { t: "D"; c: test_types_First }; export type test_types_NonOptional = string | null; export type test_types_Optional = test_types_Optional_Serialize | test_types_Optional_Deserialize; export type test_types_OptionalInEnum = ({ A?: string | null }) & { B?: never; C?: never } | ({ B: { a: string | null, } }) & { A?: never; C?: never } | ({ C: { a?: string | null, } }) & { A?: never; B?: never }; export type test_types_OptionalOnNamedField = string | null; export type test_types_OptionalOnTransparentNamedField = { b: string | null, }; export type test_types_Optional_Deserialize = { a: number | null, b?: number | null, c: string | null, d?: boolean, }; export type test_types_Optional_Serialize = { a: number | null, b?: number | null, c?: string | null, d: boolean, }; export type test_types_OverridenStruct = { overriden_field: string, }; export type test_types_Pair = { first: Z, second: A, }; export type test_types_PlaceholderInnerField = { a: string, }; export type tests_tests_types_Primitives = { i8: number, i16: number, i32: number, u8: number, u16: number, u32: number, f32: number, f64: number, bool: boolean, char: string, "Range": std_ops_Range, "RangeInclusive": std_ops_RangeInclusive, "()": null, "(String, i32)": [string, number], "(String, i32, bool)": [string, number, boolean], "((String, i32), (bool, char, bool), ())": [[string, number], [boolean, string, boolean], null], "(bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool)": [boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean], "(Vec, Vec)": [number[], boolean[]], String: string, PathBuf: string, IpAddr: string, Ipv4Addr: string, Ipv6Addr: string, SocketAddr: string, SocketAddrV4: string, SocketAddrV6: string, "Cow<'static, str>": string, "Cow<'static, i32>": number, "&'static str": string, "&'static bool": boolean, "&'static i32": number, "Vec": number[], "&'static [i32]": number[], "&'static [i32; 3]": [number, number, number], "[i32; 3]": [number, number, number], "Vec": test_types_MyEnum[], "&'static [MyEnum]": test_types_MyEnum[], "&'static [MyEnum; 6]": [test_types_MyEnum, test_types_MyEnum, test_types_MyEnum, test_types_MyEnum, test_types_MyEnum, test_types_MyEnum], "[MyEnum; 2]": [test_types_MyEnum, test_types_MyEnum], "&'static [i32; 1]": [number], "&'static [i32; 0]": [], "Option": number | null, "Option<()>": null, "Option>": number[] | null, "Result": std_result_Result, "Vec>>": (number | null)[], "Option>>": number[] | null, "[Vec; 3]": [string[], string[], string[]], "Option>": string | null, "Option>>": string | null, "PhantomData<()>": null, "PhantomData": null, Infallible: never, Unit1: test_types_Unit1, Unit2: test_types_Unit2, Unit3: test_types_Unit3, Unit4: test_types_Unit4, Unit5: test_types_Unit5, Unit6: test_types_Unit6, Unit7: test_types_Unit7, SimpleStruct: test_types_SimpleStruct, TupleStruct1: test_types_TupleStruct1, TupleStruct3: test_types_TupleStruct3, TestEnum: test_types_TestEnum, RefStruct: test_types_RefStruct, InlinerStruct: test_types_InlinerStruct, "GenericStruct": test_types_GenericStruct, "GenericStruct": test_types_GenericStruct, FlattenEnumStruct: test_types_FlattenEnumStruct, OverridenStruct: test_types_OverridenStruct, HasGenericAlias: test_types_HasGenericAlias, EnumMacroAttributes: test_types_EnumMacroAttributes, InlineEnumField: test_types_InlineEnumField, InlineOptionalType: test_types_InlineOptionalType, Rename: test_types_Rename, TransparentType: test_types_TransparentType, TransparentType2: test_types_TransparentType2, TransparentTypeWithOverride: test_types_TransparentTypeWithOverride, "[Option; 3]": [(number | null), (number | null), (number | null)], "HashMap": Partial<{ [key in test_types_BasicEnum]: null }>, "HashMap": Partial<{ [key in test_types_BasicEnum]: number }>, "Option>>>": number | null, "Vec": test_types_PlaceholderInnerField[], EnumReferenceRecordKey: test_types_EnumReferenceRecordKey, FlattenOnNestedEnum: test_types_FlattenOnNestedEnum, MyEmptyInput: test_types_MyEmptyInput, "(String)": string, "(String,)": [string], ExtraBracketsInTupleVariant: test_types_ExtraBracketsInTupleVariant, ExtraBracketsInUnnamedStruct: test_types_ExtraBracketsInUnnamedStruct, "Vec": test_types_MyEnum[], InlineTuple: test_types_InlineTuple, InlineTuple2: test_types_InlineTuple2, "Box": string, "Box": string, SkippedFieldWithinVariant: test_types_SkippedFieldWithinVariant, KebabCase: test_types_KebabCase, "&[&str]": string[], "Issue281<'_>": test_types_Issue281, "LifetimeGenericStruct<'_, i32>": test_types_LifetimeGenericStruct, "LifetimeGenericEnum<'_, i32>": test_types_LifetimeGenericEnum, RenameWithWeirdCharsField: test_types_RenameWithWeirdCharsField, RenameWithWeirdCharsVariant: test_types_RenameWithWeirdCharsVariant, RenamedFieldKeys: test_types_RenamedFieldKeys, RenamedVariantWithSkippedPayload: test_types_RenamedVariantWithSkippedPayload, "type_type::Type": test_types_type_type_Type, ActualType: test_types_ActualType, SpectaTypeOverride: test_types_SpectaTypeOverride, ContainerTypeOverrideStruct: test_types_ContainerTypeOverrideStruct, ContainerTypeOverrideEnum: test_types_ContainerTypeOverrideEnum, "ContainerTypeOverrideGeneric>": test_types_ContainerTypeOverrideGeneric, "ContainerTypeOverrideToGeneric": test_types_ContainerTypeOverrideToGeneric, ContainerTypeOverrideTuple: test_types_ContainerTypeOverrideTuple, "ContainerTypeOverrideTupleGeneric": test_types_ContainerTypeOverrideTupleGeneric, InvalidToValidType: test_types_InvalidToValidType, TupleStruct: test_types_TupleStruct, TupleStructWithRep: test_types_TupleStructWithRep, "GenericTupleStruct": test_types_GenericTupleStruct, BracedStruct: test_types_BracedStruct, Struct: test_types_StructNew, Struct2: test_types_Struct2, Enum: test_types_Enum, Enum2: test_types_Enum2, Enum3: test_types_Enum3, StructRenameAllUppercase: test_types_StructRenameAllUppercase, RenameSerdeSpecialChar: test_types_RenameSerdeSpecialChar, EnumRenameAllUppercase: test_types_EnumRenameAllUppercase, Recursive: test_types_Recursive, RecursiveMapValue: test_types_RecursiveMapValue, RecursiveTransparent: test_types_RecursiveTransparent, RecursiveInEnum: test_types_RecursiveInEnum, NonOptional: test_types_NonOptional, OptionalOnNamedField: test_types_OptionalOnNamedField, OptionalOnTransparentNamedField: test_types_OptionalOnTransparentNamedField, OptionalInEnum: test_types_OptionalInEnum, UntaggedVariants: test_types_UntaggedVariants, UntaggedVariantsWithoutValue: test_types_UntaggedVariantsWithoutValue, UntaggedVariantsWithDuplicateBranches: test_types_UntaggedVariantsWithDuplicateBranches, "HashMap": { [key in string]: null }, Regular: test_types_Regular, "HashMap": { [key in never]: null }, "HashMap": { [key in test_types_TransparentStruct]: null }, "HashMap": Partial<{ [key in test_types_UnitVariants]: null }>, "HashMap": Partial<{ [key in test_types_UntaggedVariantsKey]: null }>, ValidMaybeValidKey: test_types_ValidMaybeValidKey, ValidMaybeValidKeyNested: test_types_ValidMaybeValidKeyNested, MacroStruct: test_types_MacroStruct, MacroStruct2: test_types_MacroStruct2, MacroEnum: test_types_MacroEnum, DeprecatedType: test_types_DeprecatedType, DeprecatedTypeWithMsg: test_types_DeprecatedTypeWithMsg, DeprecatedTypeWithMsg2: test_types_DeprecatedTypeWithMsg2, DeprecatedFields: test_types_DeprecatedFields, DeprecatedTupleVariant: test_types_DeprecatedTupleVariant, DeprecatedEnumVariants: test_types_DeprecatedEnumVariants, CommentedStruct: test_types_CommentedStruct, CommentedEnum: test_types_CommentedEnum, SingleLineComment: test_types_SingleLineComment, NonGeneric: test_types_Demo, "HalfGenericA": test_types_Demo, "HalfGenericB": test_types_Demo, "FullGeneric": test_types_Demo, "Another": test_types_Demo, "MapA": { [key in string]: number }, "MapB": { [key in number]: string }, "MapC": { [key in string]: test_types_AGenericStruct }, "AGenericStruct": test_types_AGenericStruct, A: test_types_A, DoubleFlattened: test_types_DoubleFlattened, FlattenedInner: test_types_FlattenedInner, BoxFlattened: test_types_BoxFlattened, BoxInline: test_types_BoxInline, First: test_types_First, Second: test_types_Second, Third: test_types_Third, Fourth: test_types_Fourth, TagOnStructWithInline: test_types_TagOnStructWithInline, Sixth: test_types_Sixth, Seventh: test_types_Seventh, Eight: test_types_Eight, Ninth: test_types_Ninth, Tenth: test_types_Tenth, MyEnumTagged: test_types_MyEnumTagged, MyEnumExternal: test_types_MyEnumExternal, MyEnumAdjacent: test_types_MyEnumAdjacent, MyEnumUntagged: test_types_MyEnumUntagged, EmptyStruct: test_types_EmptyStruct, EmptyStructWithTag: test_types_EmptyStructWithTag, AdjacentlyTagged: test_types_AdjacentlyTagged, LoadProjectEvent: test_types_LoadProjectEvent, ExternallyTagged: test_types_ExternallyTagged, Issue221External: test_types_Issue221External, InternallyTaggedD: test_types_InternallyTaggedD, InternallyTaggedE: test_types_InternallyTaggedE, InternallyTaggedF: test_types_InternallyTaggedF, InternallyTaggedH: test_types_InternallyTaggedH, InternallyTaggedL: test_types_InternallyTaggedL, InternallyTaggedM: test_types_InternallyTaggedM, StructWithAlias: test_types_StructWithAlias, StructWithMultipleAliases: test_types_StructWithMultipleAliases, StructWithAliasAndRename: test_types_StructWithAliasAndRename, EnumWithVariantAlias: test_types_EnumWithVariantAlias, EnumWithMultipleVariantAliases: test_types_EnumWithMultipleVariantAliases, EnumWithVariantAliasAndRename: test_types_EnumWithVariantAliasAndRename, InternallyTaggedWithAlias: test_types_InternallyTaggedWithAlias, AdjacentlyTaggedWithAlias: test_types_AdjacentlyTaggedWithAlias, UntaggedWithAlias: test_types_UntaggedWithAlias, Issue221UntaggedSafe: test_types_Issue221UntaggedSafe, Issue221UntaggedMixed: test_types_Issue221UntaggedMixed, EmptyEnum: test_types_EmptyEnum, EmptyEnumTagged: test_types_EmptyEnumTagged, EmptyEnumTaggedWContent: test_types_EmptyEnumTaggedWContent, EmptyEnumUntagged: test_types_EmptyEnumUntagged, SkipOnlyField: test_types_SkipOnlyField, SkipField: test_types_SkipField, SkipVariant: test_types_SkipVariant, SkipUnnamedFieldInVariant: test_types_SkipUnnamedFieldInVariant, SkipNamedFieldInVariant: test_types_SkipNamedFieldInVariant, TransparentWithSkip: test_types_TransparentWithSkip, TransparentWithSkip2: test_types_TransparentWithSkip2, TransparentWithSkip3: test_types_TransparentWithSkip3, SkipVariant2: test_types_SkipVariant2, SkipVariant3: test_types_SkipVariant3, SkipStructFields: test_types_SkipStructFields, SpectaSkipNonTypeField: test_types_SpectaSkipNonTypeField, FlattenA: test_types_FlattenA, FlattenB: test_types_FlattenB, FlattenC: test_types_FlattenC, FlattenD: test_types_FlattenD, FlattenE: test_types_FlattenE, FlattenF: test_types_FlattenF, FlattenG: test_types_FlattenG, TupleNested: test_types_TupleNested, "Generic1<()>": test_types_Generic1, "GenericAutoBound<()>": test_types_GenericAutoBound, "GenericAutoBound2<()>": test_types_GenericAutoBound2, Container1: test_types_Container1, "Generic2<(), String, i32>": test_types_Generic2, "GenericNewType1<()>": test_types_GenericNewType1, "GenericTuple<()>": test_types_GenericTuple, "GenericStruct2<()>": test_types_GenericStruct2, "InlineGenericNewtype": string, "InlineGenericNested": [string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | ({ Unnamed: string }) & { Named?: never } | ({ Named: { value: string, } }) & { Unnamed?: never }], "InlineFlattenGenericsG<()>": test_types_InlineFlattenGenericsG, InlineFlattenGenerics: test_types_InlineFlattenGenerics, GenericDefault: test_types_GenericDefault, ChainedGenericDefault: test_types_ChainedGenericDefault, "ChainedGenericDefault": test_types_ChainedGenericDefault, "ChainedGenericDefault": test_types_ChainedGenericDefault, "ChainedGenericDefault": test_types_ChainedGenericDefault, GenericDefaultSkipped: test_types_GenericDefaultSkipped, GenericDefaultSkippedNonType: test_types_GenericDefaultSkippedNonType, GenericParameterOrderPreserved: test_types_GenericParameterOrderPreserved, ConstGenericInNonConstContainer: test_types_ConstGenericInNonConstContainer, ConstGenericInConstContainer: test_types_ConstGenericInConstContainer, NamedConstGenericContainer: test_types_NamedConstGenericContainer, InlineConstGenericContainer: test_types_InlineConstGenericContainer, InlineRecursiveConstGenericContainer: test_types_InlineRecursiveConstGenericContainer, TestCollectionRegister: test_types_TestCollectionRegister, TestCollectionRegister: test_types_TestCollectionRegister, }; export type std_ops_Range = { start: T, end: T, }; export type std_ops_RangeInclusive = { start: T, end: T, }; export type test_types_Recursive = { demo: test_types_Recursive, }; export type test_types_RecursiveInEnum = { A: { demo: test_types_RecursiveInEnum, } }; export type test_types_RecursiveInline = test_types_RecursiveInline; export type test_types_RecursiveMapValue = { demo: { [key in string]: test_types_RecursiveMapValue }, }; export type test_types_RecursiveTransparent = test_types_RecursiveInline; export type test_types_RefStruct = test_types_TestEnum; export type test_types_Regular = { [key in string]: null }; export type test_types_Rename = "OneWord" | "Two words"; export type test_types_RenameSerdeSpecialChar = { "a/b": number, }; export type test_types_RenameWithWeirdCharsField = { "@odata.context": string, }; export type test_types_RenameWithWeirdCharsVariant = { "@odata.context": string }; export type test_types_RenamedFieldKeys = { "": string, "a\"b": string, "a\\b": string, "line\nbreak": string, "line\u2028break": string, "line\u2029break": string, }; export type test_types_RenamedVariantWithSkippedPayload = "a-b"; export type std_result_Result = { ok: T, err: E, }; export type test_types_Second = { a: number, }; export type test_types_Seventh = { a: test_types_First, b: test_types_Second, }; export type test_types_SimpleStruct = { a: number, b: string, c: [number, string, number], d: string[], e: string | null, }; /** Some single-line comment */ export type test_types_SingleLineComment = /** Some single-line comment */ ({ A: number }) & { B?: never } | /** Some single-line comment */ ({ B: { /** Some single-line comment */ a: number, } }) & { A?: never }; export type test_types_Sixth = { a: test_types_First, b: test_types_First, }; export type test_types_SkipField = { b: number, }; export type test_types_SkipNamedFieldInVariant = ({ A: Record }) & { B?: never } | ({ B: { b: number, } }) & { A?: never }; export type test_types_SkipOnlyField = Record; export type test_types_SkipStructFields = { a: number, }; export type test_types_SkipUnnamedFieldInVariant = "A" | { B: [number] }; export type test_types_SkipVariant = { A: string }; export type test_types_SkipVariant2 = { tag: "A"; data: string }; export type test_types_SkipVariant3 = { A: { a: string, } }; export type test_types_SkippedFieldWithinVariant = { type: "A" } | { type: "B"; data: string }; export type test_types_SpectaSkipNonTypeField = { a: number, }; export type test_types_SpectaTypeOverride = { string_ident: string, u32_ident: number, path: string, tuple: [string, number], }; export type test_types_Struct2 = { b: string, }; export type test_types_StructNew = { t: "StructNew", a: string, }; export type test_types_StructPhaseSpecificRename = test_types_StructPhaseSpecificRenameSerialize | test_types_StructPhaseSpecificRenameDeserialize; export type test_types_StructPhaseSpecificRenameDeserialize = { kind: "StructPhaseSpecificRenameDeserialize", der: string, }; export type test_types_StructPhaseSpecificRenameSerialize = { kind: "StructPhaseSpecificRenameSerialize", ser: string, }; export type test_types_StructRenameAllUppercase = { A: number, B: number, }; export type test_types_StructWithAlias = { field: string, }; export type test_types_StructWithAliasAndRename = { renamed_field: string, }; export type test_types_StructWithMultipleAliases = { field: string, }; export type test_types_TagOnStructWithInline = { type: "TagOnStructWithInline", a: test_types_First, b: { a: string, }, }; export type test_types_Tenth = string | "B" | { a: string, } | test_types_First; export type test_types_TestCollectionRegister = never; export type test_types_TestEnum = "Unit" | ({ Single: number }) & { Multiple?: never; Struct?: never } | ({ Multiple: [number, number] }) & { Single?: never; Struct?: never } | ({ Struct: { a: number, } }) & { Multiple?: never; Single?: never }; export type test_types_Third = { b: { [key in string]: string }, c: test_types_First, } & test_types_First; export type test_types_ToBeFlattened = { a: string, }; export type test_types_TransparentStruct = string; export type test_types_TransparentType = test_types_TransparentTypeInner; export type test_types_TransparentType2 = null; export type test_types_TransparentTypeInner = { inner: string, }; export type test_types_TransparentTypeWithOverride = string; export type test_types_TransparentWithSkip = null; export type test_types_TransparentWithSkip2 = string; export type test_types_TransparentWithSkip3 = string; export type test_types_TupleNested = [number[], [number[], number[]], [number[], number[], number[]]]; export type test_types_TupleStruct = string; export type test_types_TupleStruct1 = number; export type test_types_TupleStruct3 = [number, boolean, string]; export type test_types_TupleStructWithRep = string; export type test_types_type_type_Type = never; export type test_types_Unit1 = null; export type test_types_Unit2 = Record; export type test_types_Unit3 = []; export type test_types_Unit4 = null; export type test_types_Unit5 = "A"; export type test_types_Unit6 = { A: null }; export type test_types_Unit7 = { A: Record }; export type test_types_UnitVariants = "A" | "B" | "C"; export type test_types_UntaggedVariants = string | number | { id: string } | [string, boolean]; export type test_types_UntaggedVariantsKey = string | number; export type test_types_UntaggedVariantsWithDuplicateBranches = null | number; export type test_types_UntaggedVariantsWithoutValue = string | [number, string] | number; export type test_types_UntaggedWithAlias = ({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }; export type test_types_ValidMaybeValidKey = { [key in test_types_MaybeValidKey]: null }; export type test_types_ValidMaybeValidKeyNested = { [key in test_types_MaybeValidKey>]: null }; ════════════════════════════════════════ ================================================ FILE: tests/tests/snapshots/test__typescript__ts-export-to-namespaces-raw.snap ================================================ --- source: tests/tests/typescript.rs expression: output --- ts-export-to-namespaces-raw (31739 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. namespace $s$ { export namespace std { export namespace ops { export type Range = { start: T, end: T, }; export type RangeInclusive = { start: T, end: T, }; } export namespace result { export type Result = { ok: T, err: E, }; } } export namespace test { export namespace types { export type A = { a: $s$.test.types.B, b: { b: number, }, c: $s$.test.types.B, d: { flattened: number, }, e: { generic_flattened: number, }, }; export type AGenericStruct = { field: $s$.test.types.Demo, }; export type ActualType = { a: $s$.test.types.GenericType, }; export type AdjacentlyTagged = "A" | { id: string; method: string } | string; export type AdjacentlyTaggedWithAlias = ({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }; export type B = { b: number, }; export type BasicEnum = "A" | "B"; export type BoxFlattened = { b: $s$.test.types.BoxedInner, }; export type BoxInline = { c: { a: number, }, }; export type BoxedInner = { a: number, }; export type BracedStruct = string; export type ChainedGenericDefault = { first: T, second: U, }; /** * Some triple-slash comment * Some more triple-slash comment */ export type CommentedEnum = /** * Some triple-slash comment * Some more triple-slash comment */ number | /** * Some triple-slash comment * Some more triple-slash comment */ { /** * Some triple-slash comment * Some more triple-slash comment */ a: number }; /** * Some triple-slash comment * Some more triple-slash comment */ export type CommentedStruct = { /** * Some triple-slash comment * Some more triple-slash comment */ a: number, }; export type ConstGenericInConstContainer = { data: number[], a: number[], d: [number, number], }; export type ConstGenericInNonConstContainer = { data: [number], a: [number, number], d: [number, number], }; export type Container1 = { foo: $s$.test.types.Generic1, bar: $s$.test.types.Generic1[], baz: { [key in string]: $s$.test.types.Generic1 }, }; export type ContainerTypeOverrideEnum = string; export type ContainerTypeOverrideGeneric = string; export type ContainerTypeOverrideStruct = string; export type ContainerTypeOverrideToGeneric = T; export type ContainerTypeOverrideTuple = [string, number]; export type ContainerTypeOverrideTupleGeneric = [T, string]; export type D = { flattened: number, }; export type Demo = { a: A, b: B, }; export type DeprecatedEnumVariants = /** * @deprecated */ "A" | /** * @deprecated Nope */ "B" | /** * @deprecated Nope */ "C"; export type DeprecatedFields = { a: number, /** * @deprecated */ b: string, /** * @deprecated This field is cringe! */ c: string, /** * @deprecated This field is cringe! */ d: string, }; export type DeprecatedTupleVariant = [ /** * @deprecated */ string, /** * @deprecated Nope */ string, /** * @deprecated Nope */ number]; /** * @deprecated */ export type DeprecatedType = { a: number, }; /** * @deprecated Look at you big man using a deprecation message */ export type DeprecatedTypeWithMsg = { a: number, }; /** * @deprecated Look at you big man using a deprecation message */ export type DeprecatedTypeWithMsg2 = { a: number, }; export type DoubleFlattened = { a: $s$.test.types.ToBeFlattened, b: $s$.test.types.ToBeFlattened, }; export type Eight = string | "B"; export type EmptyEnum = never; export type EmptyEnumTagged = never; export type EmptyEnumTaggedWContent = never; export type EmptyEnumUntagged = never; export type EmptyStruct = Record; export type EmptyStructWithTag = Record; export type Enum = "A" | "B"; export type Enum2 = "A" | "B" | { enum_field: null }; export type Enum3 = { a: string }; export type EnumMacroAttributes = string | number | { a: string; b: number }; export type EnumReferenceRecordKey = { a: Partial<{ [key in $s$.test.types.BasicEnum]: number }>, }; export type EnumRenameAllUppercase = "HelloWorld" | "VariantB" | "TestingWords"; export type EnumWithMultipleVariantAliases = "Variant" | "Other"; export type EnumWithVariantAlias = "Variant" | "Other"; export type EnumWithVariantAliasAndRename = "Variant" | "Other"; export type ExternallyTagged = "A" | { id: string; method: string } | string; export type ExtraBracketsInTupleVariant = string; export type ExtraBracketsInUnnamedStruct = string; export type First = { a: string, }; export type FlattenA = { a: number, b: number, }; export type FlattenB = { a: $s$.test.types.FlattenA, c: number, }; export type FlattenC = { a: $s$.test.types.FlattenA, c: number, }; export type FlattenD = { a: $s$.test.types.FlattenA, c: number, }; export type FlattenE = { b: { a: $s$.test.types.FlattenA, c: number, }, d: number, }; export type FlattenEnum = "One" | "Two" | "Three"; export type FlattenEnumStruct = { outer: string, inner: $s$.test.types.FlattenEnum, }; export type FlattenF = { b: { a: $s$.test.types.FlattenA, c: number, }, d: number, }; export type FlattenG = { b: $s$.test.types.FlattenB, d: number, }; export type FlattenOnNestedEnum = { id: string, result: $s$.test.types.NestedEnum, }; export type FlattenedInner = { c: $s$.test.types.Inner, }; export type Fourth = { a: $s$.test.types.First, b: { a: string, }, }; export type Generic1 = { value: T, values: T[], }; export type Generic2 = A | [B, B, B] | C[] | A[][][] | { a: A; b: B; c: C } | number[] | number | number[][]; export type GenericAutoBound = { value: T, values: T[], }; export type GenericAutoBound2 = { value: T, values: T[], }; export type GenericDefault = { value: T, }; export type GenericDefaultSkipped = { value: T, }; export type GenericDefaultSkippedNonType = { value: number, }; export type GenericFlattened = { generic_flattened: T, }; export type GenericNewType1 = T[][]; export type GenericParameterOrderPreserved = { pair: $s$.test.types.Pair, }; export type GenericStruct = { arg: T, }; export type GenericStruct2 = { a: T, b: [T, T], c: [T, [T, T]], d: [T, T, T], e: [([T, T]), ([T, T]), ([T, T])], f: T[], g: T[][], h: ([([T, T]), ([T, T]), ([T, T])])[], }; export type GenericTuple = [T, T[], T[][]]; export type GenericTupleStruct = T; export type GenericType = "Undefined" | T; export type HasGenericAlias = { [key in number]: string }; export type InlineConstGenericContainer = { b: { data: [number, number], a: [number, number], d: [number, number, number], }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], }, d: [number, number], }; export type InlineEnumField = { a: string, }; export type InlineFlattenGenerics = { g: $s$.test.types.InlineFlattenGenericsG, gi: { t: string, }, t: $s$.test.types.InlineFlattenGenericsG, }; export type InlineFlattenGenericsG = { t: T, }; export type InlineOptionalType = { optional_field: { a: string, } | null, }; export type InlineRecursiveConstGeneric = { data: number[], a: number[], d: [number, number, number], e: $s$.test.types.InlineRecursiveConstGeneric, }; export type InlineRecursiveConstGenericContainer = { b: { data: [number, number], a: [number, number], d: [number, number, number], e: $s$.test.types.InlineRecursiveConstGeneric, }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], e: $s$.test.types.InlineRecursiveConstGeneric, }, d: [number, number], }; export type InlineStruct = { ref_struct: $s$.test.types.SimpleStruct, val: number, }; export type InlineTuple = { demo: [string, boolean], }; export type InlineTuple2 = { demo: [{ demo: [string, boolean], }, boolean], }; export type InlinerStruct = { inline_this: { ref_struct: $s$.test.types.SimpleStruct, val: number, }, dont_inline_this: $s$.test.types.RefStruct, }; export type Inner = { a: number, b: $s$.test.types.FlattenedInner, }; export type InternallyTaggedD = { [key in string]: string }; export type InternallyTaggedE = null; export type InternallyTaggedF = $s$.test.types.InternallyTaggedFInner; export type InternallyTaggedFInner = null; export type InternallyTaggedH = $s$.test.types.InternallyTaggedHInner; export type InternallyTaggedHInner = null; export type InternallyTaggedL = "A" | "B"; export type InternallyTaggedLInner = "A" | "B"; export type InternallyTaggedM = "A" | "B"; export type InternallyTaggedMInner = "A" | "B"; export type InternallyTaggedWithAlias = ({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }; export type InvalidToValidType = { cause: null, }; export type Issue221External = ({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }; export type Issue221UntaggedMixed = ({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never }; export type Issue221UntaggedSafe = ({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }; export type Issue281 = { default_unity_arguments: string[], }; export type KebabCase = { test_ing: string, }; export type LifetimeGenericEnum = T; export type LifetimeGenericStruct = { borrowed: T[], owned: T[], }; export type LoadProjectEvent = ({ project_name: string }) & { progress?: never; status?: never } | { project_name: string; status: string; progress: number }; export type MacroEnum = string | { demo2: string }; export type MacroStruct = string; export type MacroStruct2 = { demo: string, }; export type MaybeValidKey = T; export type MyEmptyInput = Record; export type MyEnum = string | number; export type MyEnumAdjacent = { inner: $s$.test.types.First }; export type MyEnumExternal = { inner: $s$.test.types.First }; export type MyEnumTagged = { inner: $s$.test.types.First }; export type MyEnumUntagged = { inner: $s$.test.types.First }; export type NamedConstGeneric = { data: number[], a: number[], d: [number, number], }; export type NamedConstGenericContainer = { a: $s$.test.types.NamedConstGeneric, b: $s$.test.types.NamedConstGeneric, d: [number, number], }; export type NestedEnum = string | number; export type Ninth = string | "B" | { a: string, } | $s$.test.types.First; export type NonOptional = string | null; export type OptionalInEnum = string | null | { a: string | null } | { a?: string | null }; export type OptionalOnNamedField = string | null; export type OptionalOnTransparentNamedField = { b: string | null, }; export type OverridenStruct = { overriden_field: string, }; export type Pair = { first: Z, second: A, }; export type PlaceholderInnerField = { a: string, }; export type Recursive = { demo: $s$.test.types.Recursive, }; export type RecursiveInEnum = { demo: $s$.test.types.RecursiveInEnum }; export type RecursiveInline = { demo: $s$.test.types.RecursiveInline, }; export type RecursiveMapValue = { demo: { [key in string]: $s$.test.types.RecursiveMapValue }, }; export type RecursiveTransparent = $s$.test.types.RecursiveInline; export type RefStruct = $s$.test.types.TestEnum; export type Regular = { [key in string]: null }; export type Rename = "OneWord" | "TwoWords"; export type RenameSerdeSpecialChar = { b: number, }; export type RenameWithWeirdCharsField = { odata_context: string, }; export type RenameWithWeirdCharsVariant = string; export type RenamedFieldKeys = { empty: string, quote: string, backslash: string, newline: string, line_separator: string, paragraph_separator: string, }; export type RenamedVariantWithSkippedPayload = never; export type Second = { a: number, }; export type Seventh = { a: $s$.test.types.First, b: $s$.test.types.Second, }; export type SimpleStruct = { a: number, b: string, c: [number, string, number], d: string[], e: string | null, }; /** Some single-line comment */ export type SingleLineComment = /** Some single-line comment */ number | /** Some single-line comment */ { /** Some single-line comment */ a: number }; export type Sixth = { a: $s$.test.types.First, b: $s$.test.types.First, }; export type SkipField = { b: number, }; export type SkipNamedFieldInVariant = Record | { b: number }; export type SkipOnlyField = Record; export type SkipStructFields = { a: number, }; export type SkipUnnamedFieldInVariant = never | [number]; export type SkipVariant = string; export type SkipVariant2 = string; export type SkipVariant3 = { a: string }; export type SkippedFieldWithinVariant = never | string; export type SpectaSkipNonTypeField = { a: number, }; export type SpectaTypeOverride = { string_ident: string, u32_ident: number, path: string, tuple: [string, number], }; export type Struct = { a: string, }; export type Struct2 = { a: string, }; export type StructRenameAllUppercase = { a: number, b: number, }; export type StructWithAlias = { field: string, }; export type StructWithAliasAndRename = { field: string, }; export type StructWithMultipleAliases = { field: string, }; export type TagOnStructWithInline = { a: $s$.test.types.First, b: { a: string, }, }; export type Tenth = string | "B" | { a: string, } | $s$.test.types.First; export type TestCollectionRegister = never; export type TestEnum = "Unit" | number | [number, number] | { a: number }; export type Third = { a: $s$.test.types.First, b: { [key in string]: string }, c: $s$.test.types.First, }; export type ToBeFlattened = { a: string, }; export type TransparentStruct = string; export type TransparentType = $s$.test.types.TransparentTypeInner; export type TransparentType2 = null; export type TransparentTypeInner = { inner: string, }; export type TransparentTypeWithOverride = string; export type TransparentWithSkip = null; export type TransparentWithSkip2 = string; export type TransparentWithSkip3 = string; export type TupleNested = [number[], [number[], number[]], [number[], number[], number[]]]; export type TupleStruct = string; export type TupleStruct1 = number; export type TupleStruct3 = [number, boolean, string]; export type TupleStructWithRep = string; export type Unit1 = null; export type Unit2 = Record; export type Unit3 = []; export type Unit4 = null; export type Unit5 = "A"; export type Unit6 = []; export type Unit7 = Record; export type UnitVariants = "A" | "B" | "C"; export type UntaggedVariants = string | number | { id: string } | [string, boolean]; export type UntaggedVariantsKey = string | number; export type UntaggedVariantsWithDuplicateBranches = null | number; export type UntaggedVariantsWithoutValue = string | [number, string] | number; export type UntaggedWithAlias = ({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }; export type ValidMaybeValidKey = { [key in $s$.test.types.MaybeValidKey]: null }; export type ValidMaybeValidKeyNested = { [key in $s$.test.types.MaybeValidKey<$s$.test.types.MaybeValidKey>]: null }; export namespace type_type { export type Type = never; } } } export namespace tests { export namespace tests { export namespace types { export type Primitives = { i8: number, i16: number, i32: number, u8: number, u16: number, u32: number, f32: number, f64: number, bool: boolean, char: string, "Range": $s$.std.ops.Range, "RangeInclusive": $s$.std.ops.RangeInclusive, "()": null, "(String, i32)": [string, number], "(String, i32, bool)": [string, number, boolean], "((String, i32), (bool, char, bool), ())": [[string, number], [boolean, string, boolean], null], "(bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool)": [boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean], "(Vec, Vec)": [number[], boolean[]], String: string, PathBuf: string, IpAddr: string, Ipv4Addr: string, Ipv6Addr: string, SocketAddr: string, SocketAddrV4: string, SocketAddrV6: string, "Cow<'static, str>": string, "Cow<'static, i32>": number, "&'static str": string, "&'static bool": boolean, "&'static i32": number, "Vec": number[], "&'static [i32]": number[], "&'static [i32; 3]": [number, number, number], "[i32; 3]": [number, number, number], "Vec": $s$.test.types.MyEnum[], "&'static [MyEnum]": $s$.test.types.MyEnum[], "&'static [MyEnum; 6]": [$s$.test.types.MyEnum, $s$.test.types.MyEnum, $s$.test.types.MyEnum, $s$.test.types.MyEnum, $s$.test.types.MyEnum, $s$.test.types.MyEnum], "[MyEnum; 2]": [$s$.test.types.MyEnum, $s$.test.types.MyEnum], "&'static [i32; 1]": [number], "&'static [i32; 0]": [], "Option": number | null, "Option<()>": null, "Option>": number[] | null, "Result": $s$.std.result.Result, "Vec>>": (number | null)[], "Option>>": number[] | null, "[Vec; 3]": [string[], string[], string[]], "Option>": string | null, "Option>>": string | null, "PhantomData<()>": null, "PhantomData": null, Infallible: never, Unit1: $s$.test.types.Unit1, Unit2: $s$.test.types.Unit2, Unit3: $s$.test.types.Unit3, Unit4: $s$.test.types.Unit4, Unit5: $s$.test.types.Unit5, Unit6: $s$.test.types.Unit6, Unit7: $s$.test.types.Unit7, SimpleStruct: $s$.test.types.SimpleStruct, TupleStruct1: $s$.test.types.TupleStruct1, TupleStruct3: $s$.test.types.TupleStruct3, TestEnum: $s$.test.types.TestEnum, RefStruct: $s$.test.types.RefStruct, InlinerStruct: $s$.test.types.InlinerStruct, "GenericStruct": $s$.test.types.GenericStruct, "GenericStruct": $s$.test.types.GenericStruct, FlattenEnumStruct: $s$.test.types.FlattenEnumStruct, OverridenStruct: $s$.test.types.OverridenStruct, HasGenericAlias: $s$.test.types.HasGenericAlias, EnumMacroAttributes: $s$.test.types.EnumMacroAttributes, InlineEnumField: $s$.test.types.InlineEnumField, InlineOptionalType: $s$.test.types.InlineOptionalType, Rename: $s$.test.types.Rename, TransparentType: $s$.test.types.TransparentType, TransparentType2: $s$.test.types.TransparentType2, TransparentTypeWithOverride: $s$.test.types.TransparentTypeWithOverride, "[Option; 3]": [(number | null), (number | null), (number | null)], "HashMap": Partial<{ [key in $s$.test.types.BasicEnum]: null }>, "HashMap": Partial<{ [key in $s$.test.types.BasicEnum]: number }>, "Option>>>": number | null, "Vec": $s$.test.types.PlaceholderInnerField[], EnumReferenceRecordKey: $s$.test.types.EnumReferenceRecordKey, FlattenOnNestedEnum: $s$.test.types.FlattenOnNestedEnum, MyEmptyInput: $s$.test.types.MyEmptyInput, "(String)": string, "(String,)": [string], ExtraBracketsInTupleVariant: $s$.test.types.ExtraBracketsInTupleVariant, ExtraBracketsInUnnamedStruct: $s$.test.types.ExtraBracketsInUnnamedStruct, "Vec": $s$.test.types.MyEnum[], InlineTuple: $s$.test.types.InlineTuple, InlineTuple2: $s$.test.types.InlineTuple2, "Box": string, "Box": string, SkippedFieldWithinVariant: $s$.test.types.SkippedFieldWithinVariant, KebabCase: $s$.test.types.KebabCase, "&[&str]": string[], "Issue281<'_>": $s$.test.types.Issue281, "LifetimeGenericStruct<'_, i32>": $s$.test.types.LifetimeGenericStruct, "LifetimeGenericEnum<'_, i32>": $s$.test.types.LifetimeGenericEnum, RenameWithWeirdCharsField: $s$.test.types.RenameWithWeirdCharsField, RenameWithWeirdCharsVariant: $s$.test.types.RenameWithWeirdCharsVariant, RenamedFieldKeys: $s$.test.types.RenamedFieldKeys, RenamedVariantWithSkippedPayload: $s$.test.types.RenamedVariantWithSkippedPayload, "type_type::Type": $s$.test.types.type_type.Type, ActualType: $s$.test.types.ActualType, SpectaTypeOverride: $s$.test.types.SpectaTypeOverride, ContainerTypeOverrideStruct: $s$.test.types.ContainerTypeOverrideStruct, ContainerTypeOverrideEnum: $s$.test.types.ContainerTypeOverrideEnum, "ContainerTypeOverrideGeneric>": $s$.test.types.ContainerTypeOverrideGeneric, "ContainerTypeOverrideToGeneric": $s$.test.types.ContainerTypeOverrideToGeneric, ContainerTypeOverrideTuple: $s$.test.types.ContainerTypeOverrideTuple, "ContainerTypeOverrideTupleGeneric": $s$.test.types.ContainerTypeOverrideTupleGeneric, InvalidToValidType: $s$.test.types.InvalidToValidType, TupleStruct: $s$.test.types.TupleStruct, TupleStructWithRep: $s$.test.types.TupleStructWithRep, "GenericTupleStruct": $s$.test.types.GenericTupleStruct, BracedStruct: $s$.test.types.BracedStruct, Struct: $s$.test.types.Struct, Struct2: $s$.test.types.Struct2, Enum: $s$.test.types.Enum, Enum2: $s$.test.types.Enum2, Enum3: $s$.test.types.Enum3, StructRenameAllUppercase: $s$.test.types.StructRenameAllUppercase, RenameSerdeSpecialChar: $s$.test.types.RenameSerdeSpecialChar, EnumRenameAllUppercase: $s$.test.types.EnumRenameAllUppercase, Recursive: $s$.test.types.Recursive, RecursiveMapValue: $s$.test.types.RecursiveMapValue, RecursiveTransparent: $s$.test.types.RecursiveTransparent, RecursiveInEnum: $s$.test.types.RecursiveInEnum, NonOptional: $s$.test.types.NonOptional, OptionalOnNamedField: $s$.test.types.OptionalOnNamedField, OptionalOnTransparentNamedField: $s$.test.types.OptionalOnTransparentNamedField, OptionalInEnum: $s$.test.types.OptionalInEnum, UntaggedVariants: $s$.test.types.UntaggedVariants, UntaggedVariantsWithoutValue: $s$.test.types.UntaggedVariantsWithoutValue, UntaggedVariantsWithDuplicateBranches: $s$.test.types.UntaggedVariantsWithDuplicateBranches, "HashMap": { [key in string]: null }, Regular: $s$.test.types.Regular, "HashMap": { [key in never]: null }, "HashMap": { [key in $s$.test.types.TransparentStruct]: null }, "HashMap": Partial<{ [key in $s$.test.types.UnitVariants]: null }>, "HashMap": Partial<{ [key in $s$.test.types.UntaggedVariantsKey]: null }>, ValidMaybeValidKey: $s$.test.types.ValidMaybeValidKey, ValidMaybeValidKeyNested: $s$.test.types.ValidMaybeValidKeyNested, MacroStruct: $s$.test.types.MacroStruct, MacroStruct2: $s$.test.types.MacroStruct2, MacroEnum: $s$.test.types.MacroEnum, DeprecatedType: $s$.test.types.DeprecatedType, DeprecatedTypeWithMsg: $s$.test.types.DeprecatedTypeWithMsg, DeprecatedTypeWithMsg2: $s$.test.types.DeprecatedTypeWithMsg2, DeprecatedFields: $s$.test.types.DeprecatedFields, DeprecatedTupleVariant: $s$.test.types.DeprecatedTupleVariant, DeprecatedEnumVariants: $s$.test.types.DeprecatedEnumVariants, CommentedStruct: $s$.test.types.CommentedStruct, CommentedEnum: $s$.test.types.CommentedEnum, SingleLineComment: $s$.test.types.SingleLineComment, NonGeneric: $s$.test.types.Demo, "HalfGenericA": $s$.test.types.Demo, "HalfGenericB": $s$.test.types.Demo, "FullGeneric": $s$.test.types.Demo, "Another": $s$.test.types.Demo, "MapA": { [key in string]: number }, "MapB": { [key in number]: string }, "MapC": { [key in string]: $s$.test.types.AGenericStruct }, "AGenericStruct": $s$.test.types.AGenericStruct, A: $s$.test.types.A, DoubleFlattened: $s$.test.types.DoubleFlattened, FlattenedInner: $s$.test.types.FlattenedInner, BoxFlattened: $s$.test.types.BoxFlattened, BoxInline: $s$.test.types.BoxInline, First: $s$.test.types.First, Second: $s$.test.types.Second, Third: $s$.test.types.Third, Fourth: $s$.test.types.Fourth, TagOnStructWithInline: $s$.test.types.TagOnStructWithInline, Sixth: $s$.test.types.Sixth, Seventh: $s$.test.types.Seventh, Eight: $s$.test.types.Eight, Ninth: $s$.test.types.Ninth, Tenth: $s$.test.types.Tenth, MyEnumTagged: $s$.test.types.MyEnumTagged, MyEnumExternal: $s$.test.types.MyEnumExternal, MyEnumAdjacent: $s$.test.types.MyEnumAdjacent, MyEnumUntagged: $s$.test.types.MyEnumUntagged, EmptyStruct: $s$.test.types.EmptyStruct, EmptyStructWithTag: $s$.test.types.EmptyStructWithTag, AdjacentlyTagged: $s$.test.types.AdjacentlyTagged, LoadProjectEvent: $s$.test.types.LoadProjectEvent, ExternallyTagged: $s$.test.types.ExternallyTagged, Issue221External: $s$.test.types.Issue221External, InternallyTaggedD: $s$.test.types.InternallyTaggedD, InternallyTaggedE: $s$.test.types.InternallyTaggedE, InternallyTaggedF: $s$.test.types.InternallyTaggedF, InternallyTaggedH: $s$.test.types.InternallyTaggedH, InternallyTaggedL: $s$.test.types.InternallyTaggedL, InternallyTaggedM: $s$.test.types.InternallyTaggedM, StructWithAlias: $s$.test.types.StructWithAlias, StructWithMultipleAliases: $s$.test.types.StructWithMultipleAliases, StructWithAliasAndRename: $s$.test.types.StructWithAliasAndRename, EnumWithVariantAlias: $s$.test.types.EnumWithVariantAlias, EnumWithMultipleVariantAliases: $s$.test.types.EnumWithMultipleVariantAliases, EnumWithVariantAliasAndRename: $s$.test.types.EnumWithVariantAliasAndRename, InternallyTaggedWithAlias: $s$.test.types.InternallyTaggedWithAlias, AdjacentlyTaggedWithAlias: $s$.test.types.AdjacentlyTaggedWithAlias, UntaggedWithAlias: $s$.test.types.UntaggedWithAlias, Issue221UntaggedSafe: $s$.test.types.Issue221UntaggedSafe, Issue221UntaggedMixed: $s$.test.types.Issue221UntaggedMixed, EmptyEnum: $s$.test.types.EmptyEnum, EmptyEnumTagged: $s$.test.types.EmptyEnumTagged, EmptyEnumTaggedWContent: $s$.test.types.EmptyEnumTaggedWContent, EmptyEnumUntagged: $s$.test.types.EmptyEnumUntagged, SkipOnlyField: $s$.test.types.SkipOnlyField, SkipField: $s$.test.types.SkipField, SkipVariant: $s$.test.types.SkipVariant, SkipUnnamedFieldInVariant: $s$.test.types.SkipUnnamedFieldInVariant, SkipNamedFieldInVariant: $s$.test.types.SkipNamedFieldInVariant, TransparentWithSkip: $s$.test.types.TransparentWithSkip, TransparentWithSkip2: $s$.test.types.TransparentWithSkip2, TransparentWithSkip3: $s$.test.types.TransparentWithSkip3, SkipVariant2: $s$.test.types.SkipVariant2, SkipVariant3: $s$.test.types.SkipVariant3, SkipStructFields: $s$.test.types.SkipStructFields, SpectaSkipNonTypeField: $s$.test.types.SpectaSkipNonTypeField, FlattenA: $s$.test.types.FlattenA, FlattenB: $s$.test.types.FlattenB, FlattenC: $s$.test.types.FlattenC, FlattenD: $s$.test.types.FlattenD, FlattenE: $s$.test.types.FlattenE, FlattenF: $s$.test.types.FlattenF, FlattenG: $s$.test.types.FlattenG, TupleNested: $s$.test.types.TupleNested, "Generic1<()>": $s$.test.types.Generic1, "GenericAutoBound<()>": $s$.test.types.GenericAutoBound, "GenericAutoBound2<()>": $s$.test.types.GenericAutoBound2, Container1: $s$.test.types.Container1, "Generic2<(), String, i32>": $s$.test.types.Generic2, "GenericNewType1<()>": $s$.test.types.GenericNewType1, "GenericTuple<()>": $s$.test.types.GenericTuple, "GenericStruct2<()>": $s$.test.types.GenericStruct2, "InlineGenericNewtype": string, "InlineGenericNested": [string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | string | { value: string }], "InlineFlattenGenericsG<()>": $s$.test.types.InlineFlattenGenericsG, InlineFlattenGenerics: $s$.test.types.InlineFlattenGenerics, GenericDefault: $s$.test.types.GenericDefault, ChainedGenericDefault: $s$.test.types.ChainedGenericDefault, "ChainedGenericDefault": $s$.test.types.ChainedGenericDefault, "ChainedGenericDefault": $s$.test.types.ChainedGenericDefault, "ChainedGenericDefault": $s$.test.types.ChainedGenericDefault, GenericDefaultSkipped: $s$.test.types.GenericDefaultSkipped, GenericDefaultSkippedNonType: $s$.test.types.GenericDefaultSkippedNonType, GenericParameterOrderPreserved: $s$.test.types.GenericParameterOrderPreserved, ConstGenericInNonConstContainer: $s$.test.types.ConstGenericInNonConstContainer, ConstGenericInConstContainer: $s$.test.types.ConstGenericInConstContainer, NamedConstGenericContainer: $s$.test.types.NamedConstGenericContainer, InlineConstGenericContainer: $s$.test.types.InlineConstGenericContainer, InlineRecursiveConstGenericContainer: $s$.test.types.InlineRecursiveConstGenericContainer, TestCollectionRegister: $s$.test.types.TestCollectionRegister, TestCollectionRegister: $s$.test.types.TestCollectionRegister, }; } } } } export import std = $s$.std; export import test = $s$.test; export import tests = $s$.tests; ════════════════════════════════════════ ================================================ FILE: tests/tests/snapshots/test__typescript__ts-export-to-namespaces-serde.snap ================================================ --- source: tests/tests/typescript.rs expression: output --- ts-export-to-namespaces-serde (33948 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. namespace $s$ { export namespace std { export namespace ops { export type Range = { start: T, end: T, }; export type RangeInclusive = { start: T, end: T, }; } export namespace result { export type Result = { ok: T, err: E, }; } } export namespace test { export namespace types { export type A = { a: $s$.test.types.B, b: { b: number, }, c: $s$.test.types.B, d: { flattened: number, }, e: { generic_flattened: number, }, }; export type AGenericStruct = { field: $s$.test.types.Demo, }; export type ActualType = { a: $s$.test.types.GenericType, }; export type AdjacentlyTagged = { t: "A" } | { t: "B"; c: { id: string, method: string, } } | { t: "C"; c: string }; export type AdjacentlyTaggedWithAlias = { type: "A"; data: { field: string, } } | { type: "B"; data: { other: number, } }; export type B = { b: number, }; export type BasicEnum = "A" | "B"; export type BoxFlattened = $s$.test.types.BoxedInner; export type BoxInline = { c: { a: number, }, }; export type BoxedInner = { a: number, }; export type BracedStruct = string; export type ChainedGenericDefault = { first: T, second: U, }; /** * Some triple-slash comment * Some more triple-slash comment */ export type CommentedEnum = /** * Some triple-slash comment * Some more triple-slash comment */ ({ A: number }) & { B?: never } | /** * Some triple-slash comment * Some more triple-slash comment */ ({ B: { /** * Some triple-slash comment * Some more triple-slash comment */ a: number, } }) & { A?: never }; /** * Some triple-slash comment * Some more triple-slash comment */ export type CommentedStruct = { /** * Some triple-slash comment * Some more triple-slash comment */ a: number, }; export type ConstGenericInConstContainer = { data: number[], a: number[], d: [number, number], }; export type ConstGenericInNonConstContainer = { data: [number], a: [number, number], d: [number, number], }; export type Container1 = { foo: $s$.test.types.Generic1, bar: $s$.test.types.Generic1[], baz: { [key in string]: $s$.test.types.Generic1 }, }; export type ContainerTypeOverrideEnum = string; export type ContainerTypeOverrideGeneric = string; export type ContainerTypeOverrideStruct = string; export type ContainerTypeOverrideToGeneric = T; export type ContainerTypeOverrideTuple = [string, number]; export type ContainerTypeOverrideTupleGeneric = [T, string]; export type D = { flattened: number, }; export type Demo = { a: A, b: B, }; export type DeprecatedEnumVariants = /** * @deprecated */ "A" | /** * @deprecated Nope */ "B" | /** * @deprecated Nope */ "C"; export type DeprecatedFields = { a: number, /** * @deprecated */ b: string, /** * @deprecated This field is cringe! */ c: string, /** * @deprecated This field is cringe! */ d: string, }; export type DeprecatedTupleVariant = [ /** * @deprecated */ string, /** * @deprecated Nope */ string, /** * @deprecated Nope */ number]; /** * @deprecated */ export type DeprecatedType = { a: number, }; /** * @deprecated Look at you big man using a deprecation message */ export type DeprecatedTypeWithMsg = { a: number, }; /** * @deprecated Look at you big man using a deprecation message */ export type DeprecatedTypeWithMsg2 = { a: number, }; export type DoubleFlattened = { a: $s$.test.types.ToBeFlattened, b: $s$.test.types.ToBeFlattened, }; export type Eight = { A: string } | "B"; export type EmptyEnum = never; export type EmptyEnumTagged = never; export type EmptyEnumTaggedWContent = never; export type EmptyEnumUntagged = never; export type EmptyStruct = Record; export type EmptyStructWithTag = { a: "EmptyStructWithTag", }; export type Enum = { t: "A" } | { t: "B" }; export type Enum2 = { t: "C" } | { t: "B" } | { t: "D"; enumField: null }; export type Enum3 = { t: "A"; b: string }; export type EnumMacroAttributes = ({ A: string }) & { D?: never; bbb?: never; cccc?: never } | ({ bbb: number }) & { A?: never; D?: never; cccc?: never } | ({ cccc: number }) & { A?: never; D?: never; bbb?: never } | ({ D: { a: string, bbbbbb: number, } }) & { A?: never; bbb?: never; cccc?: never }; export type EnumReferenceRecordKey = { a: Partial<{ [key in $s$.test.types.BasicEnum]: number }>, }; export type EnumRenameAllUppercase = "HELLOWORLD" | "VARIANTB" | "TESTINGWORDS"; export type EnumWithMultipleVariantAliases = "Variant" | "Other"; export type EnumWithVariantAlias = "Variant" | "Other"; export type EnumWithVariantAliasAndRename = "renamed_variant" | "Other"; export type ExternallyTagged = "A" | ({ B: { id: string, method: string, } }) & { C?: never } | ({ C: string }) & { B?: never }; export type ExtraBracketsInTupleVariant = { A: string }; export type ExtraBracketsInUnnamedStruct = string; export type First = { a: string, }; export type FlattenA = { a: number, b: number, }; export type FlattenB = { c: number, } & $s$.test.types.FlattenA; export type FlattenC = { c: number, } & $s$.test.types.FlattenA; export type FlattenD = { a: $s$.test.types.FlattenA, c: number, }; export type FlattenE = { b: ({ c: number, }) & ($s$.test.types.FlattenA), d: number, }; export type FlattenEnum = { tag: "One" } | { tag: "Two" } | { tag: "Three" }; export type FlattenEnumStruct = { outer: string, } & $s$.test.types.FlattenEnum; export type FlattenF = { b: ({ c: number, }) & ($s$.test.types.FlattenA), d: number, }; export type FlattenG = { b: $s$.test.types.FlattenB, d: number, }; export type FlattenOnNestedEnum = { id: string, } & $s$.test.types.NestedEnum; export type FlattenedInner = $s$.test.types.Inner; export type Fourth = { a: $s$.test.types.First, b: { a: string, }, }; export type Generic1 = { value: T, values: T[], }; export type Generic2 = ({ A: A }) & { B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ B: [B, B, B] }) & { A?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ C: C[] }) & { A?: never; B?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ D: A[][][] }) & { A?: never; B?: never; C?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ E: { a: A, b: B, c: C, } }) & { A?: never; B?: never; C?: never; D?: never; X?: never; Y?: never; Z?: never } | ({ X: number[] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; Y?: never; Z?: never } | ({ Y: number }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Z?: never } | ({ Z: number[][] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never }; export type GenericAutoBound = { value: T, values: T[], }; export type GenericAutoBound2 = { value: T, values: T[], }; export type GenericDefault = { value: T, }; export type GenericDefaultSkipped = { value: T, }; export type GenericDefaultSkippedNonType = { value: number, }; export type GenericFlattened = { generic_flattened: T, }; export type GenericNewType1 = T[][]; export type GenericParameterOrderPreserved = { pair: $s$.test.types.Pair, }; export type GenericStruct = { arg: T, }; export type GenericStruct2 = { a: T, b: [T, T], c: [T, [T, T]], d: [T, T, T], e: [([T, T]), ([T, T]), ([T, T])], f: T[], g: T[][], h: ([([T, T]), ([T, T]), ([T, T])])[], }; export type GenericTuple = [T, T[], T[][]]; export type GenericTupleStruct = T; export type GenericType = "Undefined" | T; export type HasGenericAlias = { [key in number]: string }; export type InlineConstGenericContainer = { b: { data: [number, number], a: [number, number], d: [number, number, number], }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], }, d: [number, number], }; export type InlineEnumField = { A: { a: string, } }; export type InlineFlattenGenerics = { g: $s$.test.types.InlineFlattenGenericsG, gi: { t: string, }, } & $s$.test.types.InlineFlattenGenericsG; export type InlineFlattenGenericsG = { t: T, }; export type InlineOptionalType = { optional_field: { a: string, } | null, }; export type InlineRecursiveConstGeneric = { data: number[], a: number[], d: [number, number, number], e: $s$.test.types.InlineRecursiveConstGeneric, }; export type InlineRecursiveConstGenericContainer = { b: { data: [number, number], a: [number, number], d: [number, number, number], e: $s$.test.types.InlineRecursiveConstGeneric, }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], e: $s$.test.types.InlineRecursiveConstGeneric, }, d: [number, number], }; export type InlineStruct = { ref_struct: $s$.test.types.SimpleStruct, val: number, }; export type InlineTuple = { demo: [string, boolean], }; export type InlineTuple2 = { demo: [{ demo: [string, boolean], }, boolean], }; export type InlinerStruct = { inline_this: { ref_struct: $s$.test.types.SimpleStruct, val: number, }, dont_inline_this: $s$.test.types.RefStruct, }; export type Inner = { a: number, } & $s$.test.types.FlattenedInner; export type InternallyTaggedD = { type: "A", } & { [key in string]: string }; export type InternallyTaggedE = { type: "A" }; export type InternallyTaggedF = { type: "A" }; export type InternallyTaggedFInner = null; export type InternallyTaggedH = { type: "A" }; export type InternallyTaggedHInner = null; export type InternallyTaggedL = { type: "A", } & { type: "A" } | { type: "B" }; export type InternallyTaggedLInner = { type: "A" } | { type: "B" }; export type InternallyTaggedM = { type: "A" }; export type InternallyTaggedMInner = "A" | "B"; export type InternallyTaggedWithAlias = { type: "A"; field: string } | { type: "B"; other: number }; export type InvalidToValidType = { cause: null, }; export type Issue221External = ({ A: { a: string, } }) & { B?: never } | ({ B: { b: string, } }) & { A?: never }; export type Issue221UntaggedMixed = ({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never }; export type Issue221UntaggedSafe = ({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }; export type Issue281 = { default_unity_arguments: string[], }; export type KebabCase = { "test-ing": string, }; export type LifetimeGenericEnum = ({ Borrowed: T }) & { Owned?: never } | ({ Owned: T }) & { Borrowed?: never }; export type LifetimeGenericStruct = { borrowed: T[], owned: T[], }; export type LoadProjectEvent = { event: "started"; data: { projectName: string, } } | { event: "progressTest"; data: { projectName: string, status: string, progress: number, } } | { event: "finished"; data: { projectName: string, } }; export type MacroEnum = ({ Demo: string }) & { Demo2?: never } | ({ Demo2: { demo2: string, } }) & { Demo?: never }; export type MacroStruct = string; export type MacroStruct2 = { demo: string, }; export type MaybeValidKey = T; export type MyEmptyInput = Record; export type MyEnum = ({ A: string }) & { B?: never } | ({ B: number }) & { A?: never }; export type MyEnumAdjacent = { t: "Variant"; c: { inner: $s$.test.types.First, } }; export type MyEnumExternal = { Variant: { inner: $s$.test.types.First, } }; export type MyEnumTagged = { type: "Variant"; inner: $s$.test.types.First }; export type MyEnumUntagged = { inner: $s$.test.types.First }; export type NamedConstGeneric = { data: number[], a: number[], d: [number, number], }; export type NamedConstGenericContainer = { a: $s$.test.types.NamedConstGeneric, b: $s$.test.types.NamedConstGeneric, d: [number, number], }; export type NestedEnum = { type: "a"; value: string } | { type: "b"; value: number }; export type Ninth = { t: "A"; c: string } | { t: "B" } | { t: "C"; c: { a: string, } } | { t: "D"; c: $s$.test.types.First }; export type NonOptional = string | null; export type OptionalInEnum = ({ A?: string | null }) & { B?: never; C?: never } | ({ B: { a: string | null, } }) & { A?: never; C?: never } | ({ C: { a?: string | null, } }) & { A?: never; B?: never }; export type OptionalOnNamedField = string | null; export type OptionalOnTransparentNamedField = { b: string | null, }; export type OverridenStruct = { overriden_field: string, }; export type Pair = { first: Z, second: A, }; export type PlaceholderInnerField = { a: string, }; export type Recursive = { demo: $s$.test.types.Recursive, }; export type RecursiveInEnum = { A: { demo: $s$.test.types.RecursiveInEnum, } }; export type RecursiveInline = $s$.test.types.RecursiveInline; export type RecursiveMapValue = { demo: { [key in string]: $s$.test.types.RecursiveMapValue }, }; export type RecursiveTransparent = $s$.test.types.RecursiveInline; export type RefStruct = $s$.test.types.TestEnum; export type Regular = { [key in string]: null }; export type Rename = "OneWord" | "Two words"; export type RenameSerdeSpecialChar = { "a/b": number, }; export type RenameWithWeirdCharsField = { "@odata.context": string, }; export type RenameWithWeirdCharsVariant = { "@odata.context": string }; export type RenamedFieldKeys = { "": string, "a\"b": string, "a\\b": string, "line\nbreak": string, "line\u2028break": string, "line\u2029break": string, }; export type RenamedVariantWithSkippedPayload = "a-b"; export type Second = { a: number, }; export type Seventh = { a: $s$.test.types.First, b: $s$.test.types.Second, }; export type SimpleStruct = { a: number, b: string, c: [number, string, number], d: string[], e: string | null, }; /** Some single-line comment */ export type SingleLineComment = /** Some single-line comment */ ({ A: number }) & { B?: never } | /** Some single-line comment */ ({ B: { /** Some single-line comment */ a: number, } }) & { A?: never }; export type Sixth = { a: $s$.test.types.First, b: $s$.test.types.First, }; export type SkipField = { b: number, }; export type SkipNamedFieldInVariant = ({ A: Record }) & { B?: never } | ({ B: { b: number, } }) & { A?: never }; export type SkipOnlyField = Record; export type SkipStructFields = { a: number, }; export type SkipUnnamedFieldInVariant = "A" | { B: [number] }; export type SkipVariant = { A: string }; export type SkipVariant2 = { tag: "A"; data: string }; export type SkipVariant3 = { A: { a: string, } }; export type SkippedFieldWithinVariant = { type: "A" } | { type: "B"; data: string }; export type SpectaSkipNonTypeField = { a: number, }; export type SpectaTypeOverride = { string_ident: string, u32_ident: number, path: string, tuple: [string, number], }; export type Struct2 = { b: string, }; export type StructNew = { t: "StructNew", a: string, }; export type StructRenameAllUppercase = { A: number, B: number, }; export type StructWithAlias = { field: string, }; export type StructWithAliasAndRename = { renamed_field: string, }; export type StructWithMultipleAliases = { field: string, }; export type TagOnStructWithInline = { type: "TagOnStructWithInline", a: $s$.test.types.First, b: { a: string, }, }; export type Tenth = string | "B" | { a: string, } | $s$.test.types.First; export type TestCollectionRegister = never; export type TestEnum = "Unit" | ({ Single: number }) & { Multiple?: never; Struct?: never } | ({ Multiple: [number, number] }) & { Single?: never; Struct?: never } | ({ Struct: { a: number, } }) & { Multiple?: never; Single?: never }; export type Third = { b: { [key in string]: string }, c: $s$.test.types.First, } & $s$.test.types.First; export type ToBeFlattened = { a: string, }; export type TransparentStruct = string; export type TransparentType = $s$.test.types.TransparentTypeInner; export type TransparentType2 = null; export type TransparentTypeInner = { inner: string, }; export type TransparentTypeWithOverride = string; export type TransparentWithSkip = null; export type TransparentWithSkip2 = string; export type TransparentWithSkip3 = string; export type TupleNested = [number[], [number[], number[]], [number[], number[], number[]]]; export type TupleStruct = string; export type TupleStruct1 = number; export type TupleStruct3 = [number, boolean, string]; export type TupleStructWithRep = string; export type Unit1 = null; export type Unit2 = Record; export type Unit3 = []; export type Unit4 = null; export type Unit5 = "A"; export type Unit6 = { A: null }; export type Unit7 = { A: Record }; export type UnitVariants = "A" | "B" | "C"; export type UntaggedVariants = string | number | { id: string } | [string, boolean]; export type UntaggedVariantsKey = string | number; export type UntaggedVariantsWithDuplicateBranches = null | number; export type UntaggedVariantsWithoutValue = string | [number, string] | number; export type UntaggedWithAlias = ({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }; export type ValidMaybeValidKey = { [key in $s$.test.types.MaybeValidKey]: null }; export type ValidMaybeValidKeyNested = { [key in $s$.test.types.MaybeValidKey<$s$.test.types.MaybeValidKey>]: null }; export namespace type_type { export type Type = never; } } } export namespace tests { export namespace tests { export namespace types { export type Primitives = { i8: number, i16: number, i32: number, u8: number, u16: number, u32: number, f32: number, f64: number, bool: boolean, char: string, "Range": $s$.std.ops.Range, "RangeInclusive": $s$.std.ops.RangeInclusive, "()": null, "(String, i32)": [string, number], "(String, i32, bool)": [string, number, boolean], "((String, i32), (bool, char, bool), ())": [[string, number], [boolean, string, boolean], null], "(bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool)": [boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean], "(Vec, Vec)": [number[], boolean[]], String: string, PathBuf: string, IpAddr: string, Ipv4Addr: string, Ipv6Addr: string, SocketAddr: string, SocketAddrV4: string, SocketAddrV6: string, "Cow<'static, str>": string, "Cow<'static, i32>": number, "&'static str": string, "&'static bool": boolean, "&'static i32": number, "Vec": number[], "&'static [i32]": number[], "&'static [i32; 3]": [number, number, number], "[i32; 3]": [number, number, number], "Vec": $s$.test.types.MyEnum[], "&'static [MyEnum]": $s$.test.types.MyEnum[], "&'static [MyEnum; 6]": [$s$.test.types.MyEnum, $s$.test.types.MyEnum, $s$.test.types.MyEnum, $s$.test.types.MyEnum, $s$.test.types.MyEnum, $s$.test.types.MyEnum], "[MyEnum; 2]": [$s$.test.types.MyEnum, $s$.test.types.MyEnum], "&'static [i32; 1]": [number], "&'static [i32; 0]": [], "Option": number | null, "Option<()>": null, "Option>": number[] | null, "Result": $s$.std.result.Result, "Vec>>": (number | null)[], "Option>>": number[] | null, "[Vec; 3]": [string[], string[], string[]], "Option>": string | null, "Option>>": string | null, "PhantomData<()>": null, "PhantomData": null, Infallible: never, Unit1: $s$.test.types.Unit1, Unit2: $s$.test.types.Unit2, Unit3: $s$.test.types.Unit3, Unit4: $s$.test.types.Unit4, Unit5: $s$.test.types.Unit5, Unit6: $s$.test.types.Unit6, Unit7: $s$.test.types.Unit7, SimpleStruct: $s$.test.types.SimpleStruct, TupleStruct1: $s$.test.types.TupleStruct1, TupleStruct3: $s$.test.types.TupleStruct3, TestEnum: $s$.test.types.TestEnum, RefStruct: $s$.test.types.RefStruct, InlinerStruct: $s$.test.types.InlinerStruct, "GenericStruct": $s$.test.types.GenericStruct, "GenericStruct": $s$.test.types.GenericStruct, FlattenEnumStruct: $s$.test.types.FlattenEnumStruct, OverridenStruct: $s$.test.types.OverridenStruct, HasGenericAlias: $s$.test.types.HasGenericAlias, EnumMacroAttributes: $s$.test.types.EnumMacroAttributes, InlineEnumField: $s$.test.types.InlineEnumField, InlineOptionalType: $s$.test.types.InlineOptionalType, Rename: $s$.test.types.Rename, TransparentType: $s$.test.types.TransparentType, TransparentType2: $s$.test.types.TransparentType2, TransparentTypeWithOverride: $s$.test.types.TransparentTypeWithOverride, "[Option; 3]": [(number | null), (number | null), (number | null)], "HashMap": Partial<{ [key in $s$.test.types.BasicEnum]: null }>, "HashMap": Partial<{ [key in $s$.test.types.BasicEnum]: number }>, "Option>>>": number | null, "Vec": $s$.test.types.PlaceholderInnerField[], EnumReferenceRecordKey: $s$.test.types.EnumReferenceRecordKey, FlattenOnNestedEnum: $s$.test.types.FlattenOnNestedEnum, MyEmptyInput: $s$.test.types.MyEmptyInput, "(String)": string, "(String,)": [string], ExtraBracketsInTupleVariant: $s$.test.types.ExtraBracketsInTupleVariant, ExtraBracketsInUnnamedStruct: $s$.test.types.ExtraBracketsInUnnamedStruct, "Vec": $s$.test.types.MyEnum[], InlineTuple: $s$.test.types.InlineTuple, InlineTuple2: $s$.test.types.InlineTuple2, "Box": string, "Box": string, SkippedFieldWithinVariant: $s$.test.types.SkippedFieldWithinVariant, KebabCase: $s$.test.types.KebabCase, "&[&str]": string[], "Issue281<'_>": $s$.test.types.Issue281, "LifetimeGenericStruct<'_, i32>": $s$.test.types.LifetimeGenericStruct, "LifetimeGenericEnum<'_, i32>": $s$.test.types.LifetimeGenericEnum, RenameWithWeirdCharsField: $s$.test.types.RenameWithWeirdCharsField, RenameWithWeirdCharsVariant: $s$.test.types.RenameWithWeirdCharsVariant, RenamedFieldKeys: $s$.test.types.RenamedFieldKeys, RenamedVariantWithSkippedPayload: $s$.test.types.RenamedVariantWithSkippedPayload, "type_type::Type": $s$.test.types.type_type.Type, ActualType: $s$.test.types.ActualType, SpectaTypeOverride: $s$.test.types.SpectaTypeOverride, ContainerTypeOverrideStruct: $s$.test.types.ContainerTypeOverrideStruct, ContainerTypeOverrideEnum: $s$.test.types.ContainerTypeOverrideEnum, "ContainerTypeOverrideGeneric>": $s$.test.types.ContainerTypeOverrideGeneric, "ContainerTypeOverrideToGeneric": $s$.test.types.ContainerTypeOverrideToGeneric, ContainerTypeOverrideTuple: $s$.test.types.ContainerTypeOverrideTuple, "ContainerTypeOverrideTupleGeneric": $s$.test.types.ContainerTypeOverrideTupleGeneric, InvalidToValidType: $s$.test.types.InvalidToValidType, TupleStruct: $s$.test.types.TupleStruct, TupleStructWithRep: $s$.test.types.TupleStructWithRep, "GenericTupleStruct": $s$.test.types.GenericTupleStruct, BracedStruct: $s$.test.types.BracedStruct, Struct: $s$.test.types.StructNew, Struct2: $s$.test.types.Struct2, Enum: $s$.test.types.Enum, Enum2: $s$.test.types.Enum2, Enum3: $s$.test.types.Enum3, StructRenameAllUppercase: $s$.test.types.StructRenameAllUppercase, RenameSerdeSpecialChar: $s$.test.types.RenameSerdeSpecialChar, EnumRenameAllUppercase: $s$.test.types.EnumRenameAllUppercase, Recursive: $s$.test.types.Recursive, RecursiveMapValue: $s$.test.types.RecursiveMapValue, RecursiveTransparent: $s$.test.types.RecursiveTransparent, RecursiveInEnum: $s$.test.types.RecursiveInEnum, NonOptional: $s$.test.types.NonOptional, OptionalOnNamedField: $s$.test.types.OptionalOnNamedField, OptionalOnTransparentNamedField: $s$.test.types.OptionalOnTransparentNamedField, OptionalInEnum: $s$.test.types.OptionalInEnum, UntaggedVariants: $s$.test.types.UntaggedVariants, UntaggedVariantsWithoutValue: $s$.test.types.UntaggedVariantsWithoutValue, UntaggedVariantsWithDuplicateBranches: $s$.test.types.UntaggedVariantsWithDuplicateBranches, "HashMap": { [key in string]: null }, Regular: $s$.test.types.Regular, "HashMap": { [key in never]: null }, "HashMap": { [key in $s$.test.types.TransparentStruct]: null }, "HashMap": Partial<{ [key in $s$.test.types.UnitVariants]: null }>, "HashMap": Partial<{ [key in $s$.test.types.UntaggedVariantsKey]: null }>, ValidMaybeValidKey: $s$.test.types.ValidMaybeValidKey, ValidMaybeValidKeyNested: $s$.test.types.ValidMaybeValidKeyNested, MacroStruct: $s$.test.types.MacroStruct, MacroStruct2: $s$.test.types.MacroStruct2, MacroEnum: $s$.test.types.MacroEnum, DeprecatedType: $s$.test.types.DeprecatedType, DeprecatedTypeWithMsg: $s$.test.types.DeprecatedTypeWithMsg, DeprecatedTypeWithMsg2: $s$.test.types.DeprecatedTypeWithMsg2, DeprecatedFields: $s$.test.types.DeprecatedFields, DeprecatedTupleVariant: $s$.test.types.DeprecatedTupleVariant, DeprecatedEnumVariants: $s$.test.types.DeprecatedEnumVariants, CommentedStruct: $s$.test.types.CommentedStruct, CommentedEnum: $s$.test.types.CommentedEnum, SingleLineComment: $s$.test.types.SingleLineComment, NonGeneric: $s$.test.types.Demo, "HalfGenericA": $s$.test.types.Demo, "HalfGenericB": $s$.test.types.Demo, "FullGeneric": $s$.test.types.Demo, "Another": $s$.test.types.Demo, "MapA": { [key in string]: number }, "MapB": { [key in number]: string }, "MapC": { [key in string]: $s$.test.types.AGenericStruct }, "AGenericStruct": $s$.test.types.AGenericStruct, A: $s$.test.types.A, DoubleFlattened: $s$.test.types.DoubleFlattened, FlattenedInner: $s$.test.types.FlattenedInner, BoxFlattened: $s$.test.types.BoxFlattened, BoxInline: $s$.test.types.BoxInline, First: $s$.test.types.First, Second: $s$.test.types.Second, Third: $s$.test.types.Third, Fourth: $s$.test.types.Fourth, TagOnStructWithInline: $s$.test.types.TagOnStructWithInline, Sixth: $s$.test.types.Sixth, Seventh: $s$.test.types.Seventh, Eight: $s$.test.types.Eight, Ninth: $s$.test.types.Ninth, Tenth: $s$.test.types.Tenth, MyEnumTagged: $s$.test.types.MyEnumTagged, MyEnumExternal: $s$.test.types.MyEnumExternal, MyEnumAdjacent: $s$.test.types.MyEnumAdjacent, MyEnumUntagged: $s$.test.types.MyEnumUntagged, EmptyStruct: $s$.test.types.EmptyStruct, EmptyStructWithTag: $s$.test.types.EmptyStructWithTag, AdjacentlyTagged: $s$.test.types.AdjacentlyTagged, LoadProjectEvent: $s$.test.types.LoadProjectEvent, ExternallyTagged: $s$.test.types.ExternallyTagged, Issue221External: $s$.test.types.Issue221External, InternallyTaggedD: $s$.test.types.InternallyTaggedD, InternallyTaggedE: $s$.test.types.InternallyTaggedE, InternallyTaggedF: $s$.test.types.InternallyTaggedF, InternallyTaggedH: $s$.test.types.InternallyTaggedH, InternallyTaggedL: $s$.test.types.InternallyTaggedL, InternallyTaggedM: $s$.test.types.InternallyTaggedM, StructWithAlias: $s$.test.types.StructWithAlias, StructWithMultipleAliases: $s$.test.types.StructWithMultipleAliases, StructWithAliasAndRename: $s$.test.types.StructWithAliasAndRename, EnumWithVariantAlias: $s$.test.types.EnumWithVariantAlias, EnumWithMultipleVariantAliases: $s$.test.types.EnumWithMultipleVariantAliases, EnumWithVariantAliasAndRename: $s$.test.types.EnumWithVariantAliasAndRename, InternallyTaggedWithAlias: $s$.test.types.InternallyTaggedWithAlias, AdjacentlyTaggedWithAlias: $s$.test.types.AdjacentlyTaggedWithAlias, UntaggedWithAlias: $s$.test.types.UntaggedWithAlias, Issue221UntaggedSafe: $s$.test.types.Issue221UntaggedSafe, Issue221UntaggedMixed: $s$.test.types.Issue221UntaggedMixed, EmptyEnum: $s$.test.types.EmptyEnum, EmptyEnumTagged: $s$.test.types.EmptyEnumTagged, EmptyEnumTaggedWContent: $s$.test.types.EmptyEnumTaggedWContent, EmptyEnumUntagged: $s$.test.types.EmptyEnumUntagged, SkipOnlyField: $s$.test.types.SkipOnlyField, SkipField: $s$.test.types.SkipField, SkipVariant: $s$.test.types.SkipVariant, SkipUnnamedFieldInVariant: $s$.test.types.SkipUnnamedFieldInVariant, SkipNamedFieldInVariant: $s$.test.types.SkipNamedFieldInVariant, TransparentWithSkip: $s$.test.types.TransparentWithSkip, TransparentWithSkip2: $s$.test.types.TransparentWithSkip2, TransparentWithSkip3: $s$.test.types.TransparentWithSkip3, SkipVariant2: $s$.test.types.SkipVariant2, SkipVariant3: $s$.test.types.SkipVariant3, SkipStructFields: $s$.test.types.SkipStructFields, SpectaSkipNonTypeField: $s$.test.types.SpectaSkipNonTypeField, FlattenA: $s$.test.types.FlattenA, FlattenB: $s$.test.types.FlattenB, FlattenC: $s$.test.types.FlattenC, FlattenD: $s$.test.types.FlattenD, FlattenE: $s$.test.types.FlattenE, FlattenF: $s$.test.types.FlattenF, FlattenG: $s$.test.types.FlattenG, TupleNested: $s$.test.types.TupleNested, "Generic1<()>": $s$.test.types.Generic1, "GenericAutoBound<()>": $s$.test.types.GenericAutoBound, "GenericAutoBound2<()>": $s$.test.types.GenericAutoBound2, Container1: $s$.test.types.Container1, "Generic2<(), String, i32>": $s$.test.types.Generic2, "GenericNewType1<()>": $s$.test.types.GenericNewType1, "GenericTuple<()>": $s$.test.types.GenericTuple, "GenericStruct2<()>": $s$.test.types.GenericStruct2, "InlineGenericNewtype": string, "InlineGenericNested": [string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | ({ Unnamed: string }) & { Named?: never } | ({ Named: { value: string, } }) & { Unnamed?: never }], "InlineFlattenGenericsG<()>": $s$.test.types.InlineFlattenGenericsG, InlineFlattenGenerics: $s$.test.types.InlineFlattenGenerics, GenericDefault: $s$.test.types.GenericDefault, ChainedGenericDefault: $s$.test.types.ChainedGenericDefault, "ChainedGenericDefault": $s$.test.types.ChainedGenericDefault, "ChainedGenericDefault": $s$.test.types.ChainedGenericDefault, "ChainedGenericDefault": $s$.test.types.ChainedGenericDefault, GenericDefaultSkipped: $s$.test.types.GenericDefaultSkipped, GenericDefaultSkippedNonType: $s$.test.types.GenericDefaultSkippedNonType, GenericParameterOrderPreserved: $s$.test.types.GenericParameterOrderPreserved, ConstGenericInNonConstContainer: $s$.test.types.ConstGenericInNonConstContainer, ConstGenericInConstContainer: $s$.test.types.ConstGenericInConstContainer, NamedConstGenericContainer: $s$.test.types.NamedConstGenericContainer, InlineConstGenericContainer: $s$.test.types.InlineConstGenericContainer, InlineRecursiveConstGenericContainer: $s$.test.types.InlineRecursiveConstGenericContainer, TestCollectionRegister: $s$.test.types.TestCollectionRegister, TestCollectionRegister: $s$.test.types.TestCollectionRegister, }; } } } } export import std = $s$.std; export import test = $s$.test; export import tests = $s$.tests; ════════════════════════════════════════ ================================================ FILE: tests/tests/snapshots/test__typescript__ts-export-to-namespaces-serde_phases.snap ================================================ --- source: tests/tests/typescript.rs expression: output --- ts-export-to-namespaces-serde_phases (35155 bytes) ──────────────────────────────────────── // This file has been generated by Specta. Do not edit this file manually. namespace $s$ { export namespace std { export namespace ops { export type Range = { start: T, end: T, }; export type RangeInclusive = { start: T, end: T, }; } export namespace result { export type Result = { ok: T, err: E, }; } } export namespace test { export namespace types { export type A = { a: $s$.test.types.B, b: { b: number, }, c: $s$.test.types.B, d: { flattened: number, }, e: { generic_flattened: number, }, }; export type AGenericStruct = { field: $s$.test.types.Demo, }; export type ActualType = { a: $s$.test.types.GenericType, }; export type AdjacentlyTagged = { t: "A" } | { t: "B"; c: { id: string, method: string, } } | { t: "C"; c: string }; export type AdjacentlyTaggedWithAlias = { type: "A"; data: { field: string, } } | { type: "B"; data: { other: number, } }; export type B = { b: number, }; export type BasicEnum = "A" | "B"; export type BoxFlattened = $s$.test.types.BoxedInner; export type BoxInline = { c: { a: number, }, }; export type BoxedInner = { a: number, }; export type BracedStruct = string; export type ChainedGenericDefault = { first: T, second: U, }; /** * Some triple-slash comment * Some more triple-slash comment */ export type CommentedEnum = /** * Some triple-slash comment * Some more triple-slash comment */ ({ A: number }) & { B?: never } | /** * Some triple-slash comment * Some more triple-slash comment */ ({ B: { /** * Some triple-slash comment * Some more triple-slash comment */ a: number, } }) & { A?: never }; /** * Some triple-slash comment * Some more triple-slash comment */ export type CommentedStruct = { /** * Some triple-slash comment * Some more triple-slash comment */ a: number, }; export type ConstGenericInConstContainer = { data: number[], a: number[], d: [number, number], }; export type ConstGenericInNonConstContainer = { data: [number], a: [number, number], d: [number, number], }; export type Container1 = { foo: $s$.test.types.Generic1, bar: $s$.test.types.Generic1[], baz: { [key in string]: $s$.test.types.Generic1 }, }; export type ContainerTypeOverrideEnum = string; export type ContainerTypeOverrideGeneric = string; export type ContainerTypeOverrideStruct = string; export type ContainerTypeOverrideToGeneric = T; export type ContainerTypeOverrideTuple = [string, number]; export type ContainerTypeOverrideTupleGeneric = [T, string]; export type D = { flattened: number, }; export type Demo = { a: A, b: B, }; export type DeprecatedEnumVariants = /** * @deprecated */ "A" | /** * @deprecated Nope */ "B" | /** * @deprecated Nope */ "C"; export type DeprecatedFields = { a: number, /** * @deprecated */ b: string, /** * @deprecated This field is cringe! */ c: string, /** * @deprecated This field is cringe! */ d: string, }; export type DeprecatedTupleVariant = [ /** * @deprecated */ string, /** * @deprecated Nope */ string, /** * @deprecated Nope */ number]; /** * @deprecated */ export type DeprecatedType = { a: number, }; /** * @deprecated Look at you big man using a deprecation message */ export type DeprecatedTypeWithMsg = { a: number, }; /** * @deprecated Look at you big man using a deprecation message */ export type DeprecatedTypeWithMsg2 = { a: number, }; export type DoubleFlattened = { a: $s$.test.types.ToBeFlattened, b: $s$.test.types.ToBeFlattened, }; export type Eight = { A: string } | "B"; export type EmptyEnum = never; export type EmptyEnumTagged = never; export type EmptyEnumTaggedWContent = never; export type EmptyEnumUntagged = never; export type EmptyStruct = Record; export type EmptyStructWithTag = { a: "EmptyStructWithTag", }; export type Enum = { t: "A" } | { t: "B" }; export type Enum2 = { t: "C" } | { t: "B" } | { t: "D"; enumField: null }; export type Enum3 = { t: "A"; b: string }; export type EnumMacroAttributes = ({ A: string }) & { D?: never; bbb?: never; cccc?: never } | ({ bbb: number }) & { A?: never; D?: never; cccc?: never } | ({ cccc: number }) & { A?: never; D?: never; bbb?: never } | ({ D: { a: string, bbbbbb: number, } }) & { A?: never; bbb?: never; cccc?: never }; export type EnumReferenceRecordKey = { a: Partial<{ [key in $s$.test.types.BasicEnum]: number }>, }; export type EnumRenameAllUppercase = "HELLOWORLD" | "VARIANTB" | "TESTINGWORDS"; export type EnumWithMultipleVariantAliases = "Variant" | "Other"; export type EnumWithVariantAlias = "Variant" | "Other"; export type EnumWithVariantAliasAndRename = "renamed_variant" | "Other"; export type ExternallyTagged = "A" | ({ B: { id: string, method: string, } }) & { C?: never } | ({ C: string }) & { B?: never }; export type ExtraBracketsInTupleVariant = { A: string }; export type ExtraBracketsInUnnamedStruct = string; export type First = { a: string, }; export type FlattenA = { a: number, b: number, }; export type FlattenB = { c: number, } & $s$.test.types.FlattenA; export type FlattenC = { c: number, } & $s$.test.types.FlattenA; export type FlattenD = { a: $s$.test.types.FlattenA, c: number, }; export type FlattenE = { b: ({ c: number, }) & ($s$.test.types.FlattenA), d: number, }; export type FlattenEnum = { tag: "One" } | { tag: "Two" } | { tag: "Three" }; export type FlattenEnumStruct = { outer: string, } & $s$.test.types.FlattenEnum; export type FlattenF = { b: ({ c: number, }) & ($s$.test.types.FlattenA), d: number, }; export type FlattenG = { b: $s$.test.types.FlattenB, d: number, }; export type FlattenOnNestedEnum = { id: string, } & $s$.test.types.NestedEnum; export type FlattenedInner = $s$.test.types.Inner; export type Fourth = { a: $s$.test.types.First, b: { a: string, }, }; export type Generic1 = { value: T, values: T[], }; export type Generic2 = ({ A: A }) & { B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ B: [B, B, B] }) & { A?: never; C?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ C: C[] }) & { A?: never; B?: never; D?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ D: A[][][] }) & { A?: never; B?: never; C?: never; E?: never; X?: never; Y?: never; Z?: never } | ({ E: { a: A, b: B, c: C, } }) & { A?: never; B?: never; C?: never; D?: never; X?: never; Y?: never; Z?: never } | ({ X: number[] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; Y?: never; Z?: never } | ({ Y: number }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Z?: never } | ({ Z: number[][] }) & { A?: never; B?: never; C?: never; D?: never; E?: never; X?: never; Y?: never }; export type GenericAutoBound = { value: T, values: T[], }; export type GenericAutoBound2 = { value: T, values: T[], }; export type GenericDefault = { value: T, }; export type GenericDefaultSkipped = { value: T, }; export type GenericDefaultSkippedNonType = { value: number, }; export type GenericFlattened = { generic_flattened: T, }; export type GenericNewType1 = T[][]; export type GenericParameterOrderPreserved = { pair: $s$.test.types.Pair, }; export type GenericStruct = { arg: T, }; export type GenericStruct2 = { a: T, b: [T, T], c: [T, [T, T]], d: [T, T, T], e: [([T, T]), ([T, T]), ([T, T])], f: T[], g: T[][], h: ([([T, T]), ([T, T]), ([T, T])])[], }; export type GenericTuple = [T, T[], T[][]]; export type GenericTupleStruct = T; export type GenericType = "Undefined" | T; export type HasGenericAlias = { [key in number]: string }; export type InlineConstGenericContainer = { b: { data: [number, number], a: [number, number], d: [number, number, number], }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], }, d: [number, number], }; export type InlineEnumField = { A: { a: string, } }; export type InlineFlattenGenerics = { g: $s$.test.types.InlineFlattenGenericsG, gi: { t: string, }, } & $s$.test.types.InlineFlattenGenericsG; export type InlineFlattenGenericsG = { t: T, }; export type InlineOptionalType = { optional_field: { a: string, } | null, }; export type InlineRecursiveConstGeneric = { data: number[], a: number[], d: [number, number, number], e: $s$.test.types.InlineRecursiveConstGeneric, }; export type InlineRecursiveConstGenericContainer = { b: { data: [number, number], a: [number, number], d: [number, number, number], e: $s$.test.types.InlineRecursiveConstGeneric, }, c: { data: [number, number, number], a: [number, number], d: [number, number, number], e: $s$.test.types.InlineRecursiveConstGeneric, }, d: [number, number], }; export type InlineStruct = { ref_struct: $s$.test.types.SimpleStruct, val: number, }; export type InlineTuple = { demo: [string, boolean], }; export type InlineTuple2 = { demo: [{ demo: [string, boolean], }, boolean], }; export type InlinerStruct = { inline_this: { ref_struct: $s$.test.types.SimpleStruct, val: number, }, dont_inline_this: $s$.test.types.RefStruct, }; export type Inner = { a: number, } & $s$.test.types.FlattenedInner; export type InternallyTaggedD = { type: "A", } & { [key in string]: string }; export type InternallyTaggedE = { type: "A" }; export type InternallyTaggedF = { type: "A" }; export type InternallyTaggedFInner = null; export type InternallyTaggedH = { type: "A" }; export type InternallyTaggedHInner = null; export type InternallyTaggedL = { type: "A", } & { type: "A" } | { type: "B" }; export type InternallyTaggedLInner = { type: "A" } | { type: "B" }; export type InternallyTaggedM = { type: "A" }; export type InternallyTaggedMInner = "A" | "B"; export type InternallyTaggedWithAlias = { type: "A"; field: string } | { type: "B"; other: number }; export type InvalidToValidType = { cause: null, }; export type Issue221External = ({ A: { a: string, } }) & { B?: never } | ({ B: { b: string, } }) & { A?: never }; export type Issue221UntaggedMixed = ({ a: string }) & { b?: never; values?: never } | ({ b: string }) & { a?: never; values?: never } | ({ values: { [key in string]: string } }) & { a?: never; b?: never }; export type Issue221UntaggedSafe = ({ a: string }) & { b?: never } | ({ b: string }) & { a?: never }; export type Issue281 = { default_unity_arguments: string[], }; /** https://github.com/specta-rs/specta/issues/374 */ export type Issue374 = $s$.test.types.Issue374_Serialize | $s$.test.types.Issue374_Deserialize; /** https://github.com/specta-rs/specta/issues/374 */ export type Issue374_Deserialize = { foo?: boolean, bar?: boolean, }; /** https://github.com/specta-rs/specta/issues/374 */ export type Issue374_Serialize = { foo?: boolean, bar?: boolean, }; export type KebabCase = { "test-ing": string, }; export type LifetimeGenericEnum = ({ Borrowed: T }) & { Owned?: never } | ({ Owned: T }) & { Borrowed?: never }; export type LifetimeGenericStruct = { borrowed: T[], owned: T[], }; export type LoadProjectEvent = { event: "started"; data: { projectName: string, } } | { event: "progressTest"; data: { projectName: string, status: string, progress: number, } } | { event: "finished"; data: { projectName: string, } }; export type MacroEnum = ({ Demo: string }) & { Demo2?: never } | ({ Demo2: { demo2: string, } }) & { Demo?: never }; export type MacroStruct = string; export type MacroStruct2 = { demo: string, }; export type MaybeValidKey = T; export type MyEmptyInput = Record; export type MyEnum = ({ A: string }) & { B?: never } | ({ B: number }) & { A?: never }; export type MyEnumAdjacent = { t: "Variant"; c: { inner: $s$.test.types.First, } }; export type MyEnumExternal = { Variant: { inner: $s$.test.types.First, } }; export type MyEnumTagged = { type: "Variant"; inner: $s$.test.types.First }; export type MyEnumUntagged = { inner: $s$.test.types.First }; export type NamedConstGeneric = { data: number[], a: number[], d: [number, number], }; export type NamedConstGenericContainer = { a: $s$.test.types.NamedConstGeneric, b: $s$.test.types.NamedConstGeneric, d: [number, number], }; export type NestedEnum = { type: "a"; value: string } | { type: "b"; value: number }; export type Ninth = { t: "A"; c: string } | { t: "B" } | { t: "C"; c: { a: string, } } | { t: "D"; c: $s$.test.types.First }; export type NonOptional = string | null; export type Optional = $s$.test.types.Optional_Serialize | $s$.test.types.Optional_Deserialize; export type OptionalInEnum = ({ A?: string | null }) & { B?: never; C?: never } | ({ B: { a: string | null, } }) & { A?: never; C?: never } | ({ C: { a?: string | null, } }) & { A?: never; B?: never }; export type OptionalOnNamedField = string | null; export type OptionalOnTransparentNamedField = { b: string | null, }; export type Optional_Deserialize = { a: number | null, b?: number | null, c: string | null, d?: boolean, }; export type Optional_Serialize = { a: number | null, b?: number | null, c?: string | null, d: boolean, }; export type OverridenStruct = { overriden_field: string, }; export type Pair = { first: Z, second: A, }; export type PlaceholderInnerField = { a: string, }; export type Recursive = { demo: $s$.test.types.Recursive, }; export type RecursiveInEnum = { A: { demo: $s$.test.types.RecursiveInEnum, } }; export type RecursiveInline = $s$.test.types.RecursiveInline; export type RecursiveMapValue = { demo: { [key in string]: $s$.test.types.RecursiveMapValue }, }; export type RecursiveTransparent = $s$.test.types.RecursiveInline; export type RefStruct = $s$.test.types.TestEnum; export type Regular = { [key in string]: null }; export type Rename = "OneWord" | "Two words"; export type RenameSerdeSpecialChar = { "a/b": number, }; export type RenameWithWeirdCharsField = { "@odata.context": string, }; export type RenameWithWeirdCharsVariant = { "@odata.context": string }; export type RenamedFieldKeys = { "": string, "a\"b": string, "a\\b": string, "line\nbreak": string, "line\u2028break": string, "line\u2029break": string, }; export type RenamedVariantWithSkippedPayload = "a-b"; export type Second = { a: number, }; export type Seventh = { a: $s$.test.types.First, b: $s$.test.types.Second, }; export type SimpleStruct = { a: number, b: string, c: [number, string, number], d: string[], e: string | null, }; /** Some single-line comment */ export type SingleLineComment = /** Some single-line comment */ ({ A: number }) & { B?: never } | /** Some single-line comment */ ({ B: { /** Some single-line comment */ a: number, } }) & { A?: never }; export type Sixth = { a: $s$.test.types.First, b: $s$.test.types.First, }; export type SkipField = { b: number, }; export type SkipNamedFieldInVariant = ({ A: Record }) & { B?: never } | ({ B: { b: number, } }) & { A?: never }; export type SkipOnlyField = Record; export type SkipStructFields = { a: number, }; export type SkipUnnamedFieldInVariant = "A" | { B: [number] }; export type SkipVariant = { A: string }; export type SkipVariant2 = { tag: "A"; data: string }; export type SkipVariant3 = { A: { a: string, } }; export type SkippedFieldWithinVariant = { type: "A" } | { type: "B"; data: string }; export type SpectaSkipNonTypeField = { a: number, }; export type SpectaTypeOverride = { string_ident: string, u32_ident: number, path: string, tuple: [string, number], }; export type Struct2 = { b: string, }; export type StructNew = { t: "StructNew", a: string, }; export type StructPhaseSpecificRename = $s$.test.types.StructPhaseSpecificRenameSerialize | $s$.test.types.StructPhaseSpecificRenameDeserialize; export type StructPhaseSpecificRenameDeserialize = { kind: "StructPhaseSpecificRenameDeserialize", der: string, }; export type StructPhaseSpecificRenameSerialize = { kind: "StructPhaseSpecificRenameSerialize", ser: string, }; export type StructRenameAllUppercase = { A: number, B: number, }; export type StructWithAlias = { field: string, }; export type StructWithAliasAndRename = { renamed_field: string, }; export type StructWithMultipleAliases = { field: string, }; export type TagOnStructWithInline = { type: "TagOnStructWithInline", a: $s$.test.types.First, b: { a: string, }, }; export type Tenth = string | "B" | { a: string, } | $s$.test.types.First; export type TestCollectionRegister = never; export type TestEnum = "Unit" | ({ Single: number }) & { Multiple?: never; Struct?: never } | ({ Multiple: [number, number] }) & { Single?: never; Struct?: never } | ({ Struct: { a: number, } }) & { Multiple?: never; Single?: never }; export type Third = { b: { [key in string]: string }, c: $s$.test.types.First, } & $s$.test.types.First; export type ToBeFlattened = { a: string, }; export type TransparentStruct = string; export type TransparentType = $s$.test.types.TransparentTypeInner; export type TransparentType2 = null; export type TransparentTypeInner = { inner: string, }; export type TransparentTypeWithOverride = string; export type TransparentWithSkip = null; export type TransparentWithSkip2 = string; export type TransparentWithSkip3 = string; export type TupleNested = [number[], [number[], number[]], [number[], number[], number[]]]; export type TupleStruct = string; export type TupleStruct1 = number; export type TupleStruct3 = [number, boolean, string]; export type TupleStructWithRep = string; export type Unit1 = null; export type Unit2 = Record; export type Unit3 = []; export type Unit4 = null; export type Unit5 = "A"; export type Unit6 = { A: null }; export type Unit7 = { A: Record }; export type UnitVariants = "A" | "B" | "C"; export type UntaggedVariants = string | number | { id: string } | [string, boolean]; export type UntaggedVariantsKey = string | number; export type UntaggedVariantsWithDuplicateBranches = null | number; export type UntaggedVariantsWithoutValue = string | [number, string] | number; export type UntaggedWithAlias = ({ field: string }) & { other?: never } | ({ other: number }) & { field?: never }; export type ValidMaybeValidKey = { [key in $s$.test.types.MaybeValidKey]: null }; export type ValidMaybeValidKeyNested = { [key in $s$.test.types.MaybeValidKey<$s$.test.types.MaybeValidKey>]: null }; export namespace type_type { export type Type = never; } } } export namespace tests { export namespace tests { export namespace types { export type Primitives = { i8: number, i16: number, i32: number, u8: number, u16: number, u32: number, f32: number, f64: number, bool: boolean, char: string, "Range": $s$.std.ops.Range, "RangeInclusive": $s$.std.ops.RangeInclusive, "()": null, "(String, i32)": [string, number], "(String, i32, bool)": [string, number, boolean], "((String, i32), (bool, char, bool), ())": [[string, number], [boolean, string, boolean], null], "(bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool)": [boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean], "(Vec, Vec)": [number[], boolean[]], String: string, PathBuf: string, IpAddr: string, Ipv4Addr: string, Ipv6Addr: string, SocketAddr: string, SocketAddrV4: string, SocketAddrV6: string, "Cow<'static, str>": string, "Cow<'static, i32>": number, "&'static str": string, "&'static bool": boolean, "&'static i32": number, "Vec": number[], "&'static [i32]": number[], "&'static [i32; 3]": [number, number, number], "[i32; 3]": [number, number, number], "Vec": $s$.test.types.MyEnum[], "&'static [MyEnum]": $s$.test.types.MyEnum[], "&'static [MyEnum; 6]": [$s$.test.types.MyEnum, $s$.test.types.MyEnum, $s$.test.types.MyEnum, $s$.test.types.MyEnum, $s$.test.types.MyEnum, $s$.test.types.MyEnum], "[MyEnum; 2]": [$s$.test.types.MyEnum, $s$.test.types.MyEnum], "&'static [i32; 1]": [number], "&'static [i32; 0]": [], "Option": number | null, "Option<()>": null, "Option>": number[] | null, "Result": $s$.std.result.Result, "Vec>>": (number | null)[], "Option>>": number[] | null, "[Vec; 3]": [string[], string[], string[]], "Option>": string | null, "Option>>": string | null, "PhantomData<()>": null, "PhantomData": null, Infallible: never, Unit1: $s$.test.types.Unit1, Unit2: $s$.test.types.Unit2, Unit3: $s$.test.types.Unit3, Unit4: $s$.test.types.Unit4, Unit5: $s$.test.types.Unit5, Unit6: $s$.test.types.Unit6, Unit7: $s$.test.types.Unit7, SimpleStruct: $s$.test.types.SimpleStruct, TupleStruct1: $s$.test.types.TupleStruct1, TupleStruct3: $s$.test.types.TupleStruct3, TestEnum: $s$.test.types.TestEnum, RefStruct: $s$.test.types.RefStruct, InlinerStruct: $s$.test.types.InlinerStruct, "GenericStruct": $s$.test.types.GenericStruct, "GenericStruct": $s$.test.types.GenericStruct, FlattenEnumStruct: $s$.test.types.FlattenEnumStruct, OverridenStruct: $s$.test.types.OverridenStruct, HasGenericAlias: $s$.test.types.HasGenericAlias, EnumMacroAttributes: $s$.test.types.EnumMacroAttributes, InlineEnumField: $s$.test.types.InlineEnumField, InlineOptionalType: $s$.test.types.InlineOptionalType, Rename: $s$.test.types.Rename, TransparentType: $s$.test.types.TransparentType, TransparentType2: $s$.test.types.TransparentType2, TransparentTypeWithOverride: $s$.test.types.TransparentTypeWithOverride, "[Option; 3]": [(number | null), (number | null), (number | null)], "HashMap": Partial<{ [key in $s$.test.types.BasicEnum]: null }>, "HashMap": Partial<{ [key in $s$.test.types.BasicEnum]: number }>, "Option>>>": number | null, "Vec": $s$.test.types.PlaceholderInnerField[], EnumReferenceRecordKey: $s$.test.types.EnumReferenceRecordKey, FlattenOnNestedEnum: $s$.test.types.FlattenOnNestedEnum, MyEmptyInput: $s$.test.types.MyEmptyInput, "(String)": string, "(String,)": [string], ExtraBracketsInTupleVariant: $s$.test.types.ExtraBracketsInTupleVariant, ExtraBracketsInUnnamedStruct: $s$.test.types.ExtraBracketsInUnnamedStruct, "Vec": $s$.test.types.MyEnum[], InlineTuple: $s$.test.types.InlineTuple, InlineTuple2: $s$.test.types.InlineTuple2, "Box": string, "Box": string, SkippedFieldWithinVariant: $s$.test.types.SkippedFieldWithinVariant, KebabCase: $s$.test.types.KebabCase, "&[&str]": string[], "Issue281<'_>": $s$.test.types.Issue281, "LifetimeGenericStruct<'_, i32>": $s$.test.types.LifetimeGenericStruct, "LifetimeGenericEnum<'_, i32>": $s$.test.types.LifetimeGenericEnum, RenameWithWeirdCharsField: $s$.test.types.RenameWithWeirdCharsField, RenameWithWeirdCharsVariant: $s$.test.types.RenameWithWeirdCharsVariant, RenamedFieldKeys: $s$.test.types.RenamedFieldKeys, RenamedVariantWithSkippedPayload: $s$.test.types.RenamedVariantWithSkippedPayload, "type_type::Type": $s$.test.types.type_type.Type, ActualType: $s$.test.types.ActualType, SpectaTypeOverride: $s$.test.types.SpectaTypeOverride, ContainerTypeOverrideStruct: $s$.test.types.ContainerTypeOverrideStruct, ContainerTypeOverrideEnum: $s$.test.types.ContainerTypeOverrideEnum, "ContainerTypeOverrideGeneric>": $s$.test.types.ContainerTypeOverrideGeneric, "ContainerTypeOverrideToGeneric": $s$.test.types.ContainerTypeOverrideToGeneric, ContainerTypeOverrideTuple: $s$.test.types.ContainerTypeOverrideTuple, "ContainerTypeOverrideTupleGeneric": $s$.test.types.ContainerTypeOverrideTupleGeneric, InvalidToValidType: $s$.test.types.InvalidToValidType, TupleStruct: $s$.test.types.TupleStruct, TupleStructWithRep: $s$.test.types.TupleStructWithRep, "GenericTupleStruct": $s$.test.types.GenericTupleStruct, BracedStruct: $s$.test.types.BracedStruct, Struct: $s$.test.types.StructNew, Struct2: $s$.test.types.Struct2, Enum: $s$.test.types.Enum, Enum2: $s$.test.types.Enum2, Enum3: $s$.test.types.Enum3, StructRenameAllUppercase: $s$.test.types.StructRenameAllUppercase, RenameSerdeSpecialChar: $s$.test.types.RenameSerdeSpecialChar, EnumRenameAllUppercase: $s$.test.types.EnumRenameAllUppercase, Recursive: $s$.test.types.Recursive, RecursiveMapValue: $s$.test.types.RecursiveMapValue, RecursiveTransparent: $s$.test.types.RecursiveTransparent, RecursiveInEnum: $s$.test.types.RecursiveInEnum, NonOptional: $s$.test.types.NonOptional, OptionalOnNamedField: $s$.test.types.OptionalOnNamedField, OptionalOnTransparentNamedField: $s$.test.types.OptionalOnTransparentNamedField, OptionalInEnum: $s$.test.types.OptionalInEnum, UntaggedVariants: $s$.test.types.UntaggedVariants, UntaggedVariantsWithoutValue: $s$.test.types.UntaggedVariantsWithoutValue, UntaggedVariantsWithDuplicateBranches: $s$.test.types.UntaggedVariantsWithDuplicateBranches, "HashMap": { [key in string]: null }, Regular: $s$.test.types.Regular, "HashMap": { [key in never]: null }, "HashMap": { [key in $s$.test.types.TransparentStruct]: null }, "HashMap": Partial<{ [key in $s$.test.types.UnitVariants]: null }>, "HashMap": Partial<{ [key in $s$.test.types.UntaggedVariantsKey]: null }>, ValidMaybeValidKey: $s$.test.types.ValidMaybeValidKey, ValidMaybeValidKeyNested: $s$.test.types.ValidMaybeValidKeyNested, MacroStruct: $s$.test.types.MacroStruct, MacroStruct2: $s$.test.types.MacroStruct2, MacroEnum: $s$.test.types.MacroEnum, DeprecatedType: $s$.test.types.DeprecatedType, DeprecatedTypeWithMsg: $s$.test.types.DeprecatedTypeWithMsg, DeprecatedTypeWithMsg2: $s$.test.types.DeprecatedTypeWithMsg2, DeprecatedFields: $s$.test.types.DeprecatedFields, DeprecatedTupleVariant: $s$.test.types.DeprecatedTupleVariant, DeprecatedEnumVariants: $s$.test.types.DeprecatedEnumVariants, CommentedStruct: $s$.test.types.CommentedStruct, CommentedEnum: $s$.test.types.CommentedEnum, SingleLineComment: $s$.test.types.SingleLineComment, NonGeneric: $s$.test.types.Demo, "HalfGenericA": $s$.test.types.Demo, "HalfGenericB": $s$.test.types.Demo, "FullGeneric": $s$.test.types.Demo, "Another": $s$.test.types.Demo, "MapA": { [key in string]: number }, "MapB": { [key in number]: string }, "MapC": { [key in string]: $s$.test.types.AGenericStruct }, "AGenericStruct": $s$.test.types.AGenericStruct, A: $s$.test.types.A, DoubleFlattened: $s$.test.types.DoubleFlattened, FlattenedInner: $s$.test.types.FlattenedInner, BoxFlattened: $s$.test.types.BoxFlattened, BoxInline: $s$.test.types.BoxInline, First: $s$.test.types.First, Second: $s$.test.types.Second, Third: $s$.test.types.Third, Fourth: $s$.test.types.Fourth, TagOnStructWithInline: $s$.test.types.TagOnStructWithInline, Sixth: $s$.test.types.Sixth, Seventh: $s$.test.types.Seventh, Eight: $s$.test.types.Eight, Ninth: $s$.test.types.Ninth, Tenth: $s$.test.types.Tenth, MyEnumTagged: $s$.test.types.MyEnumTagged, MyEnumExternal: $s$.test.types.MyEnumExternal, MyEnumAdjacent: $s$.test.types.MyEnumAdjacent, MyEnumUntagged: $s$.test.types.MyEnumUntagged, EmptyStruct: $s$.test.types.EmptyStruct, EmptyStructWithTag: $s$.test.types.EmptyStructWithTag, AdjacentlyTagged: $s$.test.types.AdjacentlyTagged, LoadProjectEvent: $s$.test.types.LoadProjectEvent, ExternallyTagged: $s$.test.types.ExternallyTagged, Issue221External: $s$.test.types.Issue221External, InternallyTaggedD: $s$.test.types.InternallyTaggedD, InternallyTaggedE: $s$.test.types.InternallyTaggedE, InternallyTaggedF: $s$.test.types.InternallyTaggedF, InternallyTaggedH: $s$.test.types.InternallyTaggedH, InternallyTaggedL: $s$.test.types.InternallyTaggedL, InternallyTaggedM: $s$.test.types.InternallyTaggedM, StructWithAlias: $s$.test.types.StructWithAlias, StructWithMultipleAliases: $s$.test.types.StructWithMultipleAliases, StructWithAliasAndRename: $s$.test.types.StructWithAliasAndRename, EnumWithVariantAlias: $s$.test.types.EnumWithVariantAlias, EnumWithMultipleVariantAliases: $s$.test.types.EnumWithMultipleVariantAliases, EnumWithVariantAliasAndRename: $s$.test.types.EnumWithVariantAliasAndRename, InternallyTaggedWithAlias: $s$.test.types.InternallyTaggedWithAlias, AdjacentlyTaggedWithAlias: $s$.test.types.AdjacentlyTaggedWithAlias, UntaggedWithAlias: $s$.test.types.UntaggedWithAlias, Issue221UntaggedSafe: $s$.test.types.Issue221UntaggedSafe, Issue221UntaggedMixed: $s$.test.types.Issue221UntaggedMixed, EmptyEnum: $s$.test.types.EmptyEnum, EmptyEnumTagged: $s$.test.types.EmptyEnumTagged, EmptyEnumTaggedWContent: $s$.test.types.EmptyEnumTaggedWContent, EmptyEnumUntagged: $s$.test.types.EmptyEnumUntagged, SkipOnlyField: $s$.test.types.SkipOnlyField, SkipField: $s$.test.types.SkipField, SkipVariant: $s$.test.types.SkipVariant, SkipUnnamedFieldInVariant: $s$.test.types.SkipUnnamedFieldInVariant, SkipNamedFieldInVariant: $s$.test.types.SkipNamedFieldInVariant, TransparentWithSkip: $s$.test.types.TransparentWithSkip, TransparentWithSkip2: $s$.test.types.TransparentWithSkip2, TransparentWithSkip3: $s$.test.types.TransparentWithSkip3, SkipVariant2: $s$.test.types.SkipVariant2, SkipVariant3: $s$.test.types.SkipVariant3, SkipStructFields: $s$.test.types.SkipStructFields, SpectaSkipNonTypeField: $s$.test.types.SpectaSkipNonTypeField, FlattenA: $s$.test.types.FlattenA, FlattenB: $s$.test.types.FlattenB, FlattenC: $s$.test.types.FlattenC, FlattenD: $s$.test.types.FlattenD, FlattenE: $s$.test.types.FlattenE, FlattenF: $s$.test.types.FlattenF, FlattenG: $s$.test.types.FlattenG, TupleNested: $s$.test.types.TupleNested, "Generic1<()>": $s$.test.types.Generic1, "GenericAutoBound<()>": $s$.test.types.GenericAutoBound, "GenericAutoBound2<()>": $s$.test.types.GenericAutoBound2, Container1: $s$.test.types.Container1, "Generic2<(), String, i32>": $s$.test.types.Generic2, "GenericNewType1<()>": $s$.test.types.GenericNewType1, "GenericTuple<()>": $s$.test.types.GenericTuple, "GenericStruct2<()>": $s$.test.types.GenericStruct2, "InlineGenericNewtype": string, "InlineGenericNested": [string, string[], [string, string], { [key in string]: string }, string | null, "Unit" | ({ Unnamed: string }) & { Named?: never } | ({ Named: { value: string, } }) & { Unnamed?: never }], "InlineFlattenGenericsG<()>": $s$.test.types.InlineFlattenGenericsG, InlineFlattenGenerics: $s$.test.types.InlineFlattenGenerics, GenericDefault: $s$.test.types.GenericDefault, ChainedGenericDefault: $s$.test.types.ChainedGenericDefault, "ChainedGenericDefault": $s$.test.types.ChainedGenericDefault, "ChainedGenericDefault": $s$.test.types.ChainedGenericDefault, "ChainedGenericDefault": $s$.test.types.ChainedGenericDefault, GenericDefaultSkipped: $s$.test.types.GenericDefaultSkipped, GenericDefaultSkippedNonType: $s$.test.types.GenericDefaultSkippedNonType, GenericParameterOrderPreserved: $s$.test.types.GenericParameterOrderPreserved, ConstGenericInNonConstContainer: $s$.test.types.ConstGenericInNonConstContainer, ConstGenericInConstContainer: $s$.test.types.ConstGenericInConstContainer, NamedConstGenericContainer: $s$.test.types.NamedConstGenericContainer, InlineConstGenericContainer: $s$.test.types.InlineConstGenericContainer, InlineRecursiveConstGenericContainer: $s$.test.types.InlineRecursiveConstGenericContainer, TestCollectionRegister: $s$.test.types.TestCollectionRegister, TestCollectionRegister: $s$.test.types.TestCollectionRegister, }; } } } } export import std = $s$.std; export import test = $s$.test; export import tests = $s$.tests; ════════════════════════════════════════ ================================================ FILE: tests/tests/swift.rs ================================================ use std::borrow::Cow; use serde::{Deserialize, Serialize}; use specta::{Format, Type, Types}; use specta_swift::Swift; struct IdentityFormat; impl Format for IdentityFormat { fn map_types(&'_ self, types: &Types) -> Result, specta::FormatError> { Ok(Cow::Owned(types.clone())) } fn map_type( &'_ self, _: &Types, dt: &specta::datatype::DataType, ) -> Result, specta::FormatError> { Ok(Cow::Owned(dt.clone())) } } fn phase_collections(types: Types) -> Vec<(&'static str, Box, Types)> { vec![ ("raw", Box::new(IdentityFormat), types.clone()), ("serde", Box::new(specta_serde::Format), types.clone()), ("serde_phases", Box::new(specta_serde::PhasesFormat), types), ] } fn phase_output(types: &Types, format: impl Format + 'static) -> String { Swift::default().export(types, format).unwrap() } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(rename_all = "snake_case")] enum JobStatus { Queued, PendingApproval, } #[derive(Type)] #[specta(collect = false)] enum RegularEnum { VariantOne, VariantTwo, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(rename_all = "snake_case")] enum MixedEnum { Unit, WithData(String), } #[test] fn swift_export() { let types = Types::default() .register::() .register::() .register::(); for (mode, format, types) in phase_collections(types) { insta::assert_snapshot!(format!("swift-export-{mode}"), phase_output(&types, format)); } } ================================================ FILE: tests/tests/types.rs ================================================ #![allow(deprecated)] use std::{ any::Any, borrow::Cow, cell::RefCell, collections::{BTreeMap, HashMap, HashSet}, convert::Infallible, marker::PhantomData, net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}, ops::{Range, RangeInclusive}, path::PathBuf, rc::Rc, }; use serde::{Deserialize, Serialize}; use specta::{Type, Types, datatype::DataType}; /// A macro to collect up the types for better testing. /// /// In a real-world application you should prefer the `Types::register` method instead of this. /// In this case we can't use it because we intent to test `NamedDataType` and `DataType`'s. /// `Types` only registers `NamedDataType` as those are the only types that aren't built-in. #[macro_export] macro_rules! types { ($($t:ty),* $(,)?) => {{ let mut types = specta::Types::default(); let mut dts = Vec::new(); let mut s = specta::datatype::Struct::named(); $({ let ty = <$t as specta::Type>::definition(&mut types); // Like `Types::register` we are relying on the side-effect of `definition`. // but unlike it also storing the resulting `DataType` for testing the primitives. dts.push((stringify!($t), ty.clone())); s = s.field(stringify!($t), specta::datatype::Field::new(ty)); })* // This allows us to end-to-end test primitives. // Many types won't be directly added to the `Types`, as they are not named. specta::datatype::NamedDataType::new("Primitives", &mut types, |_, ndt| { ndt.ty = Some(s.build()); }); // Test `selection!` { #[derive(Clone)] #[allow(dead_code)] struct User { id: i32, name: &'static str, email: &'static str, age: i32, password: &'static str, } fn register(types: &mut specta::Types, _: T) { types.register_mut::(); } let user = User { id: 1, name: "Monty Beaumont".into(), email: "monty@otbeaumont.me".into(), age: 7, password: "password123".into(), }; let s1 = specta_util::selection!(user.clone(), { name, age } as UserSelection); assert_eq!(s1.name, "Monty Beaumont"); assert_eq!(s1.age, 7); register(&mut types, s1); let s2 = specta_util::selection!(vec![user; 3], [{ name, age }] as UserListSelection); assert_eq!(s2[0].name, "Monty Beaumont"); assert_eq!(s2[0].age, 7); register(&mut types, s2); } (types, dts) }}; } #[rustfmt::skip] pub fn types() -> (Types, Vec<(&'static str, DataType)>) { types!( i8, i16, i32, u8, u16, u32, f32, f64, bool, char, // Serde is so mega cringe for this. Lack of support and the fact that `0..5` == `0..=5` is so dumb. Range, // 0..5, // 0.., // .., RangeInclusive, // 0..=5, // ..5, // ..=5, (), (String, i32), (String, i32, bool), ((String, i32), (bool, char, bool), ()), (bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool), (Vec, Vec), String, PathBuf, IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, Cow<'static, str>, Cow<'static, i32>, &'static str, &'static bool, &'static i32, Vec, &'static [i32], &'static [i32; 3], [i32; 3], Vec, &'static [MyEnum], &'static [MyEnum; 6], [MyEnum; 2], &'static [i32; 1], &'static [i32; 0], Option, Option<()>, Option>, Result, Vec>>, Option>>, [Vec; 3], Option>, Option>>, PhantomData<()>, PhantomData, Infallible, // https://github.com/specta-rs/specta/issues/88 Unit1, Unit2, Unit3, Unit4, Unit5, Unit6, Unit7, SimpleStruct, TupleStruct1, TupleStruct3, TestEnum, RefStruct, InlinerStruct, GenericStruct, GenericStruct, FlattenEnumStruct, OverridenStruct, HasGenericAlias, EnumMacroAttributes, InlineEnumField, InlineOptionalType, Rename, TransparentType, TransparentType2, TransparentTypeWithOverride, // https://github.com/specta-rs/specta/issues/66 [Option; 3], // https://github.com/specta-rs/specta/issues/65 HashMap, HashMap, // https://github.com/specta-rs/specta/issues/60 Option>>>, // https://github.com/specta-rs/specta/issues/71 Vec, EnumReferenceRecordKey, FlattenOnNestedEnum, MyEmptyInput, // https://github.com/specta-rs/specta/issues/142 (String), (String,), // https://github.com/specta-rs/specta/issues/148 ExtraBracketsInTupleVariant, ExtraBracketsInUnnamedStruct, // https://github.com/specta-rs/specta/issues/156 Vec, InlineTuple, InlineTuple2, // https://github.com/specta-rs/specta/issues/220 Box, Box, SkippedFieldWithinVariant, // https://github.com/specta-rs/specta/issues/239 KebabCase, // https://github.com/specta-rs/specta/issues/281 &[&str], Issue281<'_>, // https://github.com/specta-rs/specta/issues/317 LifetimeGenericStruct<'_, i32>, LifetimeGenericEnum<'_, i32>, // https://github.com/specta-rs/specta/issues/90 RenameWithWeirdCharsField, RenameWithWeirdCharsVariant, RenamedFieldKeys, RenamedVariantWithSkippedPayload, // https://github.com/specta-rs/specta/issues/386 type_type::Type, // https://github.com/specta-rs/specta/issues/171 ActualType, SpectaTypeOverride, ContainerTypeOverrideStruct, ContainerTypeOverrideEnum, ContainerTypeOverrideGeneric>, ContainerTypeOverrideToGeneric, ContainerTypeOverrideTuple, ContainerTypeOverrideTupleGeneric, InvalidToValidType, // `#[specta(transparent)]` TupleStruct, TupleStructWithRep, GenericTupleStruct, BracedStruct, // `#[serde(rename)]` Struct, Struct2, Enum, Enum2, Enum3, StructRenameAllUppercase, RenameSerdeSpecialChar, EnumRenameAllUppercase, // Recursive types Recursive, RecursiveMapValue, RecursiveTransparent, RecursiveInEnum, // `#[serde(optional)]` NonOptional, OptionalOnNamedField, OptionalOnTransparentNamedField, OptionalInEnum, UntaggedVariants, UntaggedVariantsWithoutValue, UntaggedVariantsWithDuplicateBranches, // Valid Map keys HashMap, Regular, HashMap, HashMap, HashMap, HashMap, ValidMaybeValidKey, ValidMaybeValidKeyNested, // `macro_rules!` in decl MacroStruct, MacroStruct2, MacroEnum, // Deprecated DeprecatedType, DeprecatedTypeWithMsg, DeprecatedTypeWithMsg2, DeprecatedFields, DeprecatedTupleVariant, DeprecatedEnumVariants, // Comments CommentedStruct, CommentedEnum, SingleLineComment, // Type aliases NonGeneric, HalfGenericA, HalfGenericB, FullGeneric, Another, MapA, MapB, MapC, AGenericStruct, A, DoubleFlattened, FlattenedInner, BoxFlattened, BoxInline, // Flatten and inline First, Second, Third, Fourth, TagOnStructWithInline, Sixth, Seventh, Eight, Ninth, Tenth, // Test for issue #393 - flatten in enum variants MyEnumTagged, MyEnumExternal, MyEnumAdjacent, MyEnumUntagged, // https://github.com/specta-rs/specta/issues/174 EmptyStruct, EmptyStructWithTag, // Serde - Adjacently Tagged AdjacentlyTagged, LoadProjectEvent, // Serde - Externally Tagged ExternallyTagged, Issue221External, // Serde - Internally Tagged InternallyTaggedD, InternallyTaggedE, InternallyTaggedF, InternallyTaggedH, InternallyTaggedL, InternallyTaggedM, // Alias StructWithAlias, StructWithMultipleAliases, StructWithAliasAndRename, EnumWithVariantAlias, EnumWithMultipleVariantAliases, EnumWithVariantAliasAndRename, InternallyTaggedWithAlias, AdjacentlyTaggedWithAlias, UntaggedWithAlias, Issue221UntaggedSafe, Issue221UntaggedMixed, // https://github.com/specta-rs/specta/issues/174 // `never & { tag = "a" }` would coalesce to `never` so we don't need to include it. EmptyEnum, EmptyEnumTagged, EmptyEnumTaggedWContent, EmptyEnumUntagged, // Skip SkipOnlyField, SkipField, SkipVariant, SkipUnnamedFieldInVariant, SkipNamedFieldInVariant, TransparentWithSkip, TransparentWithSkip2, TransparentWithSkip3, SkipVariant2, SkipVariant3, SkipStructFields, SpectaSkipNonTypeField, // Flatten FlattenA, FlattenB, FlattenC, FlattenD, FlattenE, FlattenF, FlattenG, // Generic Fields TupleNested, // Generic Generic1<()>, GenericAutoBound<()>, GenericAutoBound2<()>, Container1, Generic2<(), String, i32>, GenericNewType1<()>, GenericTuple<()>, GenericStruct2<()>, InlineGenericNewtype, InlineGenericNested, InlineFlattenGenericsG<()>, InlineFlattenGenerics, GenericDefault, ChainedGenericDefault, ChainedGenericDefault, ChainedGenericDefault, ChainedGenericDefault, GenericDefaultSkipped, GenericDefaultSkippedNonType, GenericParameterOrderPreserved, // Tests for handling of const generics // Especially when inlining and flattening as it changes. ConstGenericInNonConstContainer, ConstGenericInConstContainer, NamedConstGenericContainer, InlineConstGenericContainer, InlineRecursiveConstGenericContainer, // Test that the types don't get duplicated in the type map. // (these will be duplicated in dts tests as that doesn't use the typemap) TestCollectionRegister, TestCollectionRegister, ) } #[rustfmt::skip] pub fn types_phased() -> (Types, Vec<(&'static str, DataType)>) { let mut types = Types::default(); let mut dts = Vec::new(); // https://github.com/specta-rs/specta/issues/374 register!(types, dts; Issue374, Optional, StructPhaseSpecificRename, ); (types, dts) } #[derive(Type)] #[specta(collect = false)] pub enum TestCollectionRegister {} #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct Unit1; #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct Unit2 {} #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct Unit3(); #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct Unit4(()); #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] enum Unit5 { A, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] enum Unit6 { A(), } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] enum Unit7 { A {}, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct SimpleStruct { a: i32, b: String, c: (i32, String, RefCell), d: Vec, e: Option, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct TupleStruct1(i32); #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct TupleStruct3(i32, bool, String); #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(rename = "HasBeenRenamed")] struct RenamedStruct; #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] enum TestEnum { Unit, Single(i32), Multiple(i32, i32), Struct { a: i32 }, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct RefStruct(TestEnum); #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct InlineStruct { ref_struct: SimpleStruct, val: i32, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct InlinerStruct { #[specta(inline)] inline_this: InlineStruct, dont_inline_this: RefStruct, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct GenericStruct { arg: T, } #[derive(Serialize, Type)] #[specta(collect = false)] struct FlattenEnumStruct { outer: String, #[serde(flatten)] inner: FlattenEnum, } #[derive(Serialize, Type)] #[specta(collect = false)] #[serde(tag = "tag", content = "test")] enum FlattenEnum { One, Two, Three, } #[derive(Serialize, Type)] #[specta(collect = false)] struct OverridenStruct { #[specta(type = String)] overriden_field: i32, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct HasGenericAlias(GenericAlias); type GenericAlias = std::collections::HashMap; #[derive(Serialize, Type)] #[specta(collect = false)] enum SkipVariant { A(String), #[serde(skip)] B(i32), #[specta(skip)] C(i32), } #[derive(Serialize, Type)] #[specta(collect = false)] #[serde(tag = "tag", content = "data")] enum SkipVariant2 { A(String), #[serde(skip)] B(i32), #[specta(skip)] C(i32), } #[derive(Serialize, Type)] #[specta(collect = false)] enum SkipVariant3 { A { a: String, }, #[serde(skip)] B { b: i32, }, #[specta(skip)] C { b: i32, }, } #[derive(Type, Serialize)] #[specta(collect = false)] struct SkipStructFields { a: i32, #[specta(skip)] b: String, #[serde(skip)] d: Box, // `!Type` } #[derive(Type)] #[specta(collect = false)] struct SpectaSkipNonTypeField { a: i32, #[specta(skip)] d: Box, // `!Type` } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] enum EnumMacroAttributes { A(#[specta(type = String)] i32), #[serde(rename = "bbb")] B(i32), #[serde(rename = "cccc")] C(#[specta(type = i32)] String), D { #[specta(type = String)] a: i32, #[serde(rename = "bbbbbb")] b: i32, }, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct PlaceholderInnerField { a: String, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] enum InlineEnumField { #[specta(inline)] A(PlaceholderInnerField), } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct InlineOptionalType { #[specta(inline)] optional_field: Option, } // Regression test for https://github.com/specta-rs/specta/issues/56 #[derive(Type, Serialize)] #[specta(collect = false)] enum Rename { OneWord, #[serde(rename = "Two words")] TwoWords, } #[derive(Type, Serialize)] #[specta(collect = false)] struct TransparentTypeInner { inner: String, } #[derive(Type, Serialize)] #[specta(collect = false)] #[serde(transparent)] struct TransparentType(TransparentTypeInner); #[derive(Type, Serialize)] #[specta(collect = false)] #[serde(transparent)] struct TransparentType2(()); #[derive(Serialize)] struct NonTypeType; #[derive(Type, Serialize)] #[specta(collect = false)] #[serde(transparent)] struct TransparentTypeWithOverride(#[specta(type = String)] NonTypeType); #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] enum BasicEnum { A, B, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(tag = "type", content = "value", rename_all = "camelCase")] enum NestedEnum { A(String), B(i32), } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(rename_all = "camelCase")] struct FlattenOnNestedEnum { id: String, #[serde(flatten)] result: NestedEnum, } #[derive(Type, Serialize)] #[specta(collect = false)] struct EnumReferenceRecordKey { a: HashMap, } // https://github.com/specta-rs/specta/issues/88 #[derive(Default, Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(rename_all = "camelCase")] #[serde(default)] struct MyEmptyInput {} #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct EmptyStruct {} #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(tag = "a")] struct EmptyStructWithTag {} #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[allow(unused_parens)] enum ExtraBracketsInTupleVariant { A((String)), } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct ExtraBracketsInUnnamedStruct((String)); #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[allow(unused_parens)] struct RenameWithWeirdCharsField { #[serde(rename = "@odata.context")] odata_context: String, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct RenamedFieldKeys { #[serde(rename = "")] empty: String, #[serde(rename = "a\"b")] quote: String, #[serde(rename = "a\\b")] backslash: String, #[serde(rename = "line\nbreak")] newline: String, #[serde(rename = "line\u{2028}break")] line_separator: String, #[serde(rename = "line\u{2029}break")] paragraph_separator: String, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] enum RenamedVariantWithSkippedPayload { #[serde(rename = "a-b")] A(#[serde(skip)] String), } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[allow(unused_parens)] enum RenameWithWeirdCharsVariant { #[serde(rename = "@odata.context")] A(String), } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(rename = "@odata.context")] struct RenameWithWeirdCharsStruct(String); #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(rename = "@odata.context")] enum RenameWithWeirdCharsEnum {} #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] enum MyEnum { A(String), B(u32), } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct InlineTuple { #[specta(inline)] demo: (String, bool), } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct InlineTuple2 { #[specta(inline)] demo: (InlineTuple, bool), } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(tag = "type", content = "data")] enum SkippedFieldWithinVariant { A(#[serde(skip)] String), B(String), } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(rename_all = "kebab-case")] struct KebabCase { test_ing: String, } // https://github.com/specta-rs/specta/issues/281 #[derive(Type)] #[specta(collect = false)] struct Issue281<'a> { default_unity_arguments: &'a [&'a str], } // https://github.com/specta-rs/specta/issues/317 #[derive(Type)] #[specta(collect = false)] struct LifetimeGenericStruct<'a, T> { borrowed: &'a [T], owned: Vec, } #[derive(Type)] #[specta(collect = false)] enum LifetimeGenericEnum<'a, T> { Borrowed(&'a T), Owned(T), } /// https://github.com/specta-rs/specta/issues/374 #[derive(Type, Serialize)] #[specta(collect = false)] struct Issue374 { #[serde(default, skip_serializing_if = "std::ops::Not::not")] foo: bool, #[serde(skip_serializing_if = "std::ops::Not::not", default)] bar: bool, } // https://github.com/specta-rs/specta/issues/386 // We put this test in a separate module because the parent module has `use specta::Type`, // so it clashes with our user-defined `Type`. mod type_type { #[derive(specta::Type)] #[specta(collect = false)] pub(super) enum Type {} } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(untagged)] enum GenericType { Undefined, Value(T), } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct ActualType { a: GenericType, } #[derive(Type)] #[specta(collect = false)] struct SpectaTypeOverride { #[specta(type = String)] // Ident string_ident: (), #[specta(type = u32)] // Ident u32_ident: (), #[specta(type = ::std::string::String)] // Path path: (), #[specta(type = (String, i32))] // Non-path type tuple: (), } #[derive(Type)] #[specta(collect = false, type = String)] struct ContainerTypeOverrideStruct { cause: Box, } #[derive(Type)] #[specta(collect = false, type = String)] enum ContainerTypeOverrideEnum { A(Box), } #[derive(Type)] #[specta(collect = false, type = String)] struct ContainerTypeOverrideGeneric(std::marker::PhantomData); #[derive(Type)] #[specta(collect = false, type = T)] struct ContainerTypeOverrideToGeneric(std::marker::PhantomData); #[derive(Type)] #[specta(collect = false, type = (String, i32))] struct ContainerTypeOverrideTuple { cause: Box, } #[derive(Type)] #[specta(collect = false, type = (T, String))] struct ContainerTypeOverrideTupleGeneric(std::marker::PhantomData); // Checking that you can override the type of a field that is invalid. This is to ensure user code can override Specta in the case we have a bug/unsupported type. #[derive(Type)] #[specta(collect = false)] struct InvalidToValidType { #[specta(type = Option<()>)] cause: Option>, } #[derive(Type)] #[specta(collect = false, transparent)] struct TupleStruct(String); #[repr(transparent)] #[derive(Type)] #[specta(collect = false)] struct TupleStructWithRep(String); #[derive(Type)] #[specta(collect = false, transparent)] struct GenericTupleStruct(T); #[derive(Type)] #[specta(collect = false, transparent)] struct BracedStruct { a: String, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(rename = "StructNew", tag = "t")] struct Struct { a: String, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct Struct2 { #[serde(rename = "b")] a: String, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(rename = "EnumNew", tag = "t")] enum Enum { A, B, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(rename = "EnumNew", tag = "t")] enum Enum2 { #[serde(rename = "C")] A, B, #[serde(rename_all = "camelCase")] D { enum_field: (), }, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(rename_all = "UPPERCASE")] struct StructRenameAllUppercase { a: i32, b: i32, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(rename_all = "UPPERCASE")] enum EnumRenameAllUppercase { HelloWorld, VariantB, TestingWords, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(tag = "kind")] #[serde(rename( serialize = "StructPhaseSpecificRenameSerialize", deserialize = "StructPhaseSpecificRenameDeserialize" ))] struct StructPhaseSpecificRename { #[serde(rename(serialize = "ser", deserialize = "der"))] a: String, } #[derive(serde::Serialize, Type)] #[specta(collect = false)] struct RenameSerdeSpecialChar { #[serde(rename = "a/b")] b: i32, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(rename = "EnumNew", tag = "t")] enum Enum3 { A { #[serde(rename = "b")] a: String, }, } #[derive(Type)] #[specta(collect = false)] struct Recursive { demo: Box, } #[derive(Type)] #[specta(collect = false)] struct RecursiveMapValue { demo: HashMap, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct RecursiveInline { #[serde(flatten)] demo: Box, } #[derive(Type, Serialize, Deserialize)] #[specta(transparent, collect = false)] struct RecursiveTransparent(Box); #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] enum RecursiveInEnum { A { #[serde(flatten)] demo: Box, }, } #[derive(Type)] #[specta(collect = false)] struct NonOptional(Option); #[derive(Type)] #[specta(collect = false)] struct OptionalOnNamedField(#[specta(optional)] Option); // Should do nothing #[derive(Type)] #[specta(collect = false, transparent, inline)] struct OptionalOnTransparentNamedFieldInner(#[specta(optional)] Option); #[derive(Type)] #[specta(collect = false)] struct OptionalOnTransparentNamedField { // Now it should work b: OptionalOnTransparentNamedFieldInner, } #[derive(Type)] #[specta(collect = false)] enum OptionalInEnum { // Should do nothing A(#[specta(optional)] Option), // Base case without `optional` B { a: Option, }, // Should add `?` on field C { #[specta(optional)] a: Option, }, } // Export needs a `NamedDataType` but uses `Type::reference` instead of `Type::inline` so we test it. #[derive(Type, Serialize)] #[specta(collect = false)] struct Regular(HashMap); #[derive(Type, Serialize)] #[specta(collect = false)] struct RegularStruct { a: String, } #[derive(Type, Serialize)] #[specta(collect = false)] #[serde(transparent)] struct TransparentStruct(String); #[derive(Type, Serialize)] #[specta(collect = false)] enum UnitVariants { A, B, C, } #[derive(Type, Serialize)] #[specta(collect = false)] #[serde(untagged)] enum UntaggedVariantsKey { A(String), B(i32), C(u8), } #[derive(Type, Serialize)] #[specta(collect = false)] #[serde(untagged)] enum UntaggedVariants { A(String), B(i32), C(u8), D { id: String }, E(String, bool), } #[derive(Type, Serialize)] #[specta(collect = false)] #[serde(untagged)] enum UntaggedVariantsWithoutValue { A(String), B(i32, String), C(u8), } #[derive(Type, Serialize)] #[specta(collect = false)] #[serde(untagged)] enum UntaggedVariantsWithDuplicateBranches { A(()), B(i32), C(()), } #[derive(Type, Serialize)] #[specta(collect = false)] #[serde(untagged)] enum InvalidUntaggedVariants { A(String), B(i32, String), C(u8), } #[derive(Type, Serialize)] #[specta(collect = false)] enum Variants { A(String), B(i32), C(u8), } #[derive(Type, Serialize)] #[specta(collect = false)] #[serde(transparent)] struct MaybeValidKey(T); #[derive(Type, Serialize)] #[specta(collect = false)] #[serde(transparent)] struct ValidMaybeValidKey(HashMap, ()>); #[derive(Type, Serialize)] #[specta(collect = false)] #[serde(transparent)] struct ValidMaybeValidKeyNested(HashMap>, ()>); macro_rules! field_ty_macro { () => { String }; } #[derive(Type)] #[specta(collect = false)] struct MacroStruct(field_ty_macro!()); #[derive(Type)] #[specta(collect = false)] struct MacroStruct2 { demo: field_ty_macro!(), } #[derive(Type)] #[specta(collect = false)] enum MacroEnum { Demo(field_ty_macro!()), Demo2 { demo2: field_ty_macro!() }, } #[derive(Type)] #[specta(collect = false)] #[deprecated] struct DeprecatedType { a: i32, } #[derive(Type)] #[specta(collect = false)] #[deprecated = "Look at you big man using a deprecation message"] struct DeprecatedTypeWithMsg { a: i32, } #[derive(Type)] #[specta(collect = false)] #[deprecated(note = "Look at you big man using a deprecation message")] struct DeprecatedTypeWithMsg2 { a: i32, } #[derive(Type)] #[specta(collect = false)] struct DeprecatedFields { a: i32, #[deprecated] b: String, #[deprecated = "This field is cringe!"] c: String, #[deprecated(note = "This field is cringe!")] d: String, } #[derive(Type)] #[specta(collect = false)] struct DeprecatedTupleVariant( #[deprecated] String, #[deprecated = "Nope"] String, #[deprecated(note = "Nope")] i32, ); #[derive(Type)] #[specta(collect = false)] enum DeprecatedEnumVariants { #[deprecated] A, #[deprecated = "Nope"] B, #[deprecated(note = "Nope")] C, } // Some double-slash comment which is ignored /// Some triple-slash comment /// Some more triple-slash comment #[derive(Type)] #[specta(collect = false)] struct CommentedStruct { // Some double-slash comment which is ignored /// Some triple-slash comment /// Some more triple-slash comment a: i32, } // Some double-slash comment which is ignored /// Some triple-slash comment /// Some more triple-slash comment #[derive(Type)] #[specta(collect = false)] enum CommentedEnum { // Some double-slash comment which is ignored /// Some triple-slash comment /// Some more triple-slash comment A(i32), // Some double-slash comment which is ignored /// Some triple-slash comment /// Some more triple-slash comment B { // Some double-slash comment which is ignored /// Some triple-slash comment /// Some more triple-slash comment a: i32, }, } /// Some single-line comment #[derive(Type)] #[specta(collect = false)] enum SingleLineComment { /// Some single-line comment A(i32), /// Some single-line comment B { /// Some single-line comment a: i32, }, } #[derive(Type)] #[specta(collect = false)] struct Demo { a: A, b: B, } type NonGeneric = Demo; type HalfGenericA = Demo; type HalfGenericB = Demo; type FullGeneric = Demo; type Another = FullGeneric; type MapA
= HashMap; type MapB = HashMap; type MapC = HashMap>; #[derive(Type)] #[specta(collect = false)] struct AGenericStruct { field: HalfGenericA, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct D { flattened: u32, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct GenericFlattened { generic_flattened: T, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct C { a: u32, #[serde(flatten)] b: D, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct B { b: u32, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct A { a: B, #[specta(inline)] b: B, c: B, #[specta(inline)] d: D, #[specta(inline)] e: GenericFlattened, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct ToBeFlattened { a: String, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct DoubleFlattened { a: ToBeFlattened, b: ToBeFlattened, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct Inner { a: i32, #[serde(flatten)] b: Box, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct FlattenedInner { #[serde(flatten)] c: Inner, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct BoxedInner { a: i32, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct BoxFlattened { #[serde(flatten)] b: Box, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct BoxInline { #[specta(inline)] c: Box, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct First { a: String, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct Second { a: i32, } #[derive(Type, Serialize)] #[specta(collect = false)] struct Third { #[serde(flatten)] a: First, b: HashMap, c: Box, } #[derive(Type)] #[specta(collect = false)] struct Fourth { a: First, #[specta(inline)] b: First, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(tag = "type")] struct TagOnStructWithInline { a: First, #[specta(inline)] b: First, } // Flattening a struct multiple times #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct Sixth { a: First, b: First, } // Two fields with the same name (`a`) but different types #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct Seventh { a: First, b: Second, } // Serde can't serialize this #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] enum Eight { A(String), B, } // Test for issue #393 - flatten in enum variant with internal tag #[derive(Type, Serialize)] #[specta(collect = false)] #[serde(tag = "type")] enum MyEnumTagged { Variant { #[serde(flatten)] inner: First, }, } // Test for issue #393 - flatten in enum variant with external tag #[derive(Type, Serialize)] #[specta(collect = false)] enum MyEnumExternal { Variant { #[serde(flatten)] inner: First, }, } // Test for issue #393 - flatten in enum variant with adjacent tag #[derive(Type, Serialize)] #[specta(collect = false)] #[serde(tag = "t", content = "c")] enum MyEnumAdjacent { Variant { #[serde(flatten)] inner: First, }, } // Test for issue #393 - flatten in enum variant with untagged #[derive(Type, Serialize)] #[specta(collect = false)] #[serde(untagged)] enum MyEnumUntagged { Variant { #[serde(flatten)] inner: First, }, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(tag = "t", content = "c")] enum Ninth { A(String), B, #[specta(inline)] C(First), D(First), } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(untagged)] enum Tenth { A(String), B, #[specta(inline)] C(First), D(First), } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct Optional { a: Option, #[specta(optional)] b: Option, #[serde(skip_serializing_if = "Option::is_none")] c: Option, #[serde(default)] d: bool, } #[derive(Type, Serialize, Deserialize, Default)] #[specta(collect = false)] #[serde(default)] struct ContainerDefault { value: String, flag: bool, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct FieldDefault { name: String, #[serde(default)] enabled: bool, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(tag = "kind")] enum MixedTaggedAndUntagged { Tagged { value: String, }, #[serde(untagged)] Raw(String), #[serde(untagged)] Empty, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(tag = "kind")] enum MixedTaggedAndUntaggedStruct { Tagged { value: String, }, #[serde(untagged)] Raw { raw_value: String, }, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(tag = "kind")] enum MixedTaggedAndUntaggedPhased { Tagged { value: String, }, #[serde(untagged, skip_serializing)] DeserializeOnly(String), #[serde(untagged, skip_deserializing)] SerializeOnly(bool), } // Test that attributes with format strings are properly parsed // This tests the fix for parsing attributes like #[error("io error: {0}")] // which were causing "expected ident" errors in the lower_attr.rs parser #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[allow(dead_code)] enum TypeWithComplexAttributes { // These attributes will be parsed by lower_attr.rs and should not cause errors #[doc = "This is a variant with format-like strings in docs: {0}"] A(String), #[doc = "Another variant: {line} {msg}"] B { line: usize, msg: String }, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(tag = "t", content = "c")] enum AdjacentlyTagged { A, B { id: String, method: String }, C(String), } // Test for https://github.com/specta-rs/specta/issues/395 // The `rename_all_fields = "camelCase"` should convert field names to camelCase #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde( rename_all = "camelCase", rename_all_fields = "camelCase", tag = "event", content = "data" )] enum LoadProjectEvent { Started { project_name: String, }, ProgressTest { project_name: String, status: String, progress: i32, }, Finished { project_name: String, }, } #[derive(Type)] #[specta(collect = false)] enum ExternallyTagged { A, B { id: String, method: String }, C(String), } // https://github.com/specta-rs/specta/issues/221 #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] enum Issue221External { A { a: String }, B { b: String }, } // Test struct with field alias #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct StructWithAlias { #[serde(alias = "bruh")] field: String, } // Test struct with multiple aliases on same field #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct StructWithMultipleAliases { #[serde(alias = "bruh", alias = "alternative", alias = "another")] field: String, } // Test struct with alias and rename #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct StructWithAliasAndRename { #[serde(rename = "renamed_field", alias = "bruh")] field: String, } // Test enum variant with alias #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] enum EnumWithVariantAlias { #[serde(alias = "bruh")] Variant, Other, } // Test enum with multiple variant aliases #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] enum EnumWithMultipleVariantAliases { #[serde(alias = "bruh", alias = "alternative")] Variant, Other, } // Test enum variant with alias and rename #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] enum EnumWithVariantAliasAndRename { #[serde(rename = "renamed_variant", alias = "bruh")] Variant, Other, } // Test internally tagged enum with field alias #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(tag = "type")] enum InternallyTaggedWithAlias { A { #[serde(alias = "bruh")] field: String, }, B { other: i32, }, } // Test adjacently tagged enum with field alias #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(tag = "type", content = "data")] enum AdjacentlyTaggedWithAlias { A { #[serde(alias = "bruh")] field: String, }, B { other: i32, }, } // Test untagged enum with field alias #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(untagged)] enum UntaggedWithAlias { A { #[serde(alias = "bruh")] field: String, }, B { other: i32, }, } // https://github.com/specta-rs/specta/issues/221 #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(untagged)] enum Issue221UntaggedSafe { A { a: String }, B { b: String }, } // https://github.com/specta-rs/specta/issues/221 #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(untagged)] enum Issue221UntaggedMixed { A { a: String, }, B { b: String, }, Unsafe { #[serde(flatten)] values: BTreeMap, }, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] enum EmptyEnum {} #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(tag = "a")] enum EmptyEnumTagged {} #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(tag = "a", content = "b")] enum EmptyEnumTaggedWContent {} #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(untagged)] enum EmptyEnumUntagged {} #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct UnitStruct; #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct EmptyBracedStruct {} #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct EmptyTupleStruct(); #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(tag = "a")] enum TaggedEnumOfUnitStruct { A(UnitStruct), B(UnitStruct), } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(tag = "a")] enum TaggedEnumOfEmptyBracedStruct { A(EmptyBracedStruct), B(EmptyBracedStruct), } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(tag = "a")] enum TaggedEnumOfEmptyTupleStruct { A(EmptyTupleStruct), B(EmptyTupleStruct), } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(tag = "a")] enum TaggedEnumOfEmptyTupleBracedStructs { #[specta(skip)] A(EmptyTupleStruct), B(EmptyBracedStruct), } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false, transparent)] struct TupleStructWithTuple(()); #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(tag = "a")] enum TaggedStructOfStructWithTuple { A(TupleStructWithTuple), B(TupleStructWithTuple), } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(tag = "type")] enum InternallyTaggedB { // Is not a map-type so invalid. A(String), } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(tag = "type")] enum InternallyTaggedC { // Is not a map-type so invalid. A(Vec), } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(tag = "type")] enum InternallyTaggedD { // Is a map type so valid. A(HashMap), } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(tag = "type")] enum InternallyTaggedE { // Null is valid (although it's not a map-type) A(()), } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(tag = "type")] enum InternallyTaggedF { // `FInner` is untagged so this is *only* valid if it is (which it is) A(InternallyTaggedFInner), } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(untagged)] enum InternallyTaggedFInner { A(()), } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(tag = "type")] enum InternallyTaggedG { // `GInner` is untagged so this is *only* valid if it is (which it is not) A(InternallyTaggedGInner), } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(untagged)] enum InternallyTaggedGInner { A(String), } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(tag = "type")] enum InternallyTaggedH { // `HInner` is transparent so this is *only* valid if it is (which it is) A(InternallyTaggedHInner), } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(transparent)] struct InternallyTaggedHInner(()); #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(tag = "type")] enum InternallyTaggedI { // `IInner` is transparent so this is *only* valid if it is (which it is not) A(InternallyTaggedIInner), } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(transparent)] struct InternallyTaggedIInner(String); #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(tag = "type")] enum InternallyTaggedL { // Internally tag enum with inlined field that is itself internally tagged #[specta(inline)] A(InternallyTaggedLInner), } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(tag = "type")] enum InternallyTaggedLInner { A, B, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(tag = "type")] enum InternallyTaggedM { // Internally tag enum with inlined field that is untagged // `MInner` is `null` - Test `B` in `untagged.rs` #[specta(inline)] A(InternallyTaggedMInner), } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(untagged)] enum InternallyTaggedMInner { A, B, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct SkipOnlyField { #[specta(skip)] a: String, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct SkipField { #[specta(skip)] a: String, b: i32, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] enum SkipOnlyVariantExternallyTagged { #[specta(skip)] A(String), } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(tag = "t")] enum SkipOnlyVariantInternallyTagged { #[specta(skip)] A(String), } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(tag = "t", content = "c")] enum SkipOnlyVariantAdjacentlyTagged { #[specta(skip)] A(String), } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(untagged)] enum SkipOnlyVariantUntagged { #[specta(skip)] A(String), } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] enum SkipUnnamedFieldInVariant { // only field A(#[serde(skip)] String), // not only field // // This will `B(String)` == `String` in TS whether this will be `[String]`. This is why `#[serde(skip)]` is processed at runtime not in the macro. B(#[serde(skip)] String, i32), } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] enum SkipNamedFieldInVariant { // only field A { #[specta(skip)] a: String, }, // not only field B { #[specta(skip)] a: String, b: i32, }, } // https://github.com/specta-rs/specta/issues/170 #[derive(Type, Serialize, Deserialize)] #[specta(transparent, collect = false)] struct TransparentWithSkip((), #[specta(skip)] String); // https://github.com/specta-rs/specta/issues/170 #[derive(Type, Serialize, Deserialize)] #[specta(transparent, collect = false)] struct TransparentWithSkip2(#[specta(skip)] (), String); // https://github.com/specta-rs/specta/issues/170 #[derive(Type)] #[specta(transparent, collect = false)] struct TransparentWithSkip3(#[specta(type = String)] Box); /// This is intentionally just a compile or not compile test /// https://github.com/specta-rs/specta/issues/167 #[derive(Type, Serialize)] #[specta(collect = false)] enum LazilySkip { #[serde(skip)] A(Box), B(#[serde(skip)] Box), C { #[serde(skip)] a: Box, }, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct FlattenA { a: i32, b: i32, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct FlattenB { #[serde(flatten)] a: FlattenA, c: i32, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct FlattenC { #[serde(flatten)] a: FlattenA, c: i32, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct FlattenD { a: FlattenA, c: i32, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct FlattenE { #[specta(inline)] b: FlattenB, d: i32, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct FlattenF { #[specta(inline = true)] b: FlattenB, d: i32, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct FlattenG { #[specta(inline = false)] b: FlattenB, d: i32, } #[derive(Type)] #[specta(collect = false)] struct TupleNested(Vec, (Vec, Vec), [Vec; 3]); #[derive(Type)] #[specta(collect = false)] struct Generic1 { value: T, values: Vec, } #[derive(Type)] #[specta(collect = false)] struct GenericAutoBound { value: T, values: Vec, } #[derive(Type)] #[specta(collect = false)] struct GenericAutoBound2 { value: T, values: Vec, } #[derive(Type)] #[specta(collect = false)] struct Container1 { foo: Generic1, bar: HashSet>, baz: BTreeMap>>, } #[derive(Type)] #[specta(collect = false)] enum Generic2 { A(A), B(B, B, B), C(Vec), D(Vec>>), E { a: A, b: B, c: C }, X(Vec), Y(i32), Z(Vec>), } #[derive(Type)] #[specta(collect = false)] struct GenericStruct2 { a: T, b: (T, T), c: (T, (T, T)), d: [T; 3], e: [(T, T); 3], f: Vec, g: Vec>, h: Vec<[(T, T); 3]>, } #[derive(Type)] #[specta(collect = false)] struct GenericNewType1(Vec>); #[derive(Type)] #[specta(collect = false)] struct GenericTuple(T, Vec, Vec>); #[derive(Type)] #[specta(collect = false, inline)] struct InlineGenericNewtype(T); #[derive(Type)] #[specta(collect = false, inline)] enum InlineGenericEnum { Unit, Unnamed(T), Named { value: T }, } #[derive(Type)] #[specta(collect = false, inline)] struct InlineGenericNested( InlineGenericNewtype, Vec, (T, T), HashMap, Option, InlineGenericEnum, ); #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct InlineFlattenGenericsG { t: T, } // not currently possible in ts-rs hehe #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct InlineFlattenGenerics { g: InlineFlattenGenericsG, #[specta(inline)] gi: InlineFlattenGenericsG, #[serde(flatten)] t: InlineFlattenGenericsG, } #[derive(Type)] #[specta(collect = false)] struct GenericDefault { value: T, } #[derive(Type)] #[specta(collect = false)] struct ChainedGenericDefault { first: T, second: U, } #[derive(Type)] #[specta(collect = false)] struct GenericDefaultSkipped<#[specta(skip_default_generic)] T = String> { value: T, } struct GenericDefaultSkippedNonTypeDefault; #[derive(Type)] #[specta(collect = false)] struct GenericDefaultSkippedNonType< #[specta(skip_default_generic)] T = GenericDefaultSkippedNonTypeDefault, > { value: i32, #[specta(skip)] _phantom: PhantomData, } // #[test] // fn default() { // #[derive(Type)] // #[specta(collect = false)] // struct A { // t: T, // } // assert_ts_export!( // ts_A::<()>, // "export type A = { t: T, }" // ); // #[derive(Type)] // #[specta(collect = false)] // struct B>> { // u: U, // } // assert_ts_export!( // ts_B::<()>, // "export type B | null> = { u: U, }" // ); // #[derive(Type)] // #[specta(collect = false)] // struct Y { // a1: A, // a2: A, // https://github.com/Aleph-Alpha/ts-rs/issues/56 // TODO: fixme // #[ts(inline)] // xi: X, // #[ts(inline)] // xi2: X // } // assert_ts_export!( // ts_Y, // "type Y = { a1: A, a2: A }" // ) // } // TODO // #[test] // fn test_generic_trait_bounds() { // #[derive(Type)] // struct A { // t: T, // } // assert_ts_export!(A::, "export type A = { t: T, }"); // #[derive(Type)] // struct B(T); // assert_ts_export!(B::<&'static str>, "export type B = T;"); // #[derive(Type)] // enum C { // A { t: T }, // B(T), // C, // D(T, K), // } // assert_ts_export!( // C::<&'static str, i32>, // "export type C = { A: { t: T, } } | { B: T } | \"C\" | { D: [T, K] };" // ); // #[derive(Type)] // struct D { // t: [T; N], // } // assert_ts_export!(D::<&str, 41>, "export type D = { t: Array, }") // } // https://github.com/specta-rs/specta/issues/400 #[derive(Type)] #[specta(collect = false)] struct Pair { first: Z, second: A, } #[derive(Type)] #[specta(collect = false)] struct GenericParameterOrderPreserved { pair: Pair, } const CONST_LEN: usize = 1; #[derive(Type)] #[specta(collect = false)] struct ConstGenericInNonConstContainer { data: [u32; CONST_LEN], a: [u8; 2], #[specta(type = specta_util::FixedArray<2, u8>)] d: [u8; 2], } // This is a duplicate of `NamedConstGeneric` but we keep it separate as it's a better test // or the global export ty that is registered. #[derive(Type)] #[specta(collect = false)] struct ConstGenericInConstContainer { data: [u32; N], a: [u8; 2], #[specta(type = specta_util::FixedArray<2, u8>)] d: [u8; 2], } #[derive(Type)] #[specta(collect = false)] struct NamedConstGeneric { data: [u32; N], a: [u8; 2], #[specta(type = specta_util::FixedArray<2, u8>)] d: [u8; 2], } #[derive(Type)] #[specta(collect = false)] struct NamedConstGenericContainer { a: NamedConstGeneric, b: NamedConstGeneric<2>, d: [u8; 2], } #[derive(Type)] #[specta(collect = false, inline)] struct InlineConstGeneric { #[specta(type = [u32; N])] data: (), a: [u8; 2], #[specta(type = specta_util::FixedArray<3, u8>)] d: [u8; 3], } #[derive(Type)] #[specta(collect = false)] struct InlineConstGenericContainer { #[specta(inline)] b: InlineConstGeneric<2>, #[specta(inline)] c: InlineConstGeneric<3>, d: [u8; 2], } #[derive(Type)] #[specta(collect = false)] struct InlineRecursiveConstGeneric { #[specta(type = [u32; N])] data: (), a: [u8; 2], #[specta(type = specta_util::FixedArray<3, u8>)] d: [u8; 3], e: Box>, } #[derive(Type)] #[specta(collect = false)] struct InlineRecursiveConstGenericContainer { #[specta(inline)] b: InlineRecursiveConstGeneric<2>, #[specta(inline)] c: InlineRecursiveConstGeneric<3>, d: [u8; 2], } // mod type_overrides { // #![allow(dead_code)] // use std::time::Instant; // use specta::Type; // struct Unsupported(T); // struct Unsupported2; // #[test] // fn simple() { // #[derive(Type)] // #[specta(collect = false)] // struct Override { // a: i32, // #[specta(type = String)] // x: Instant, // #[specta(type = String)] // y: Unsupported>, // #[specta(type = Option)] // z: Option, // } // insta::assert_snapshot!(crate::ts::inline::(&Default::default()).unwrap(), @"{ a: number; x: string; y: string; z: string | null }"); // } // #[test] // fn newtype() { // #[derive(Type)] // #[specta(collect = false)] // struct New1(#[specta(type = String)] Unsupported2); // #[derive(Type)] // #[specta(collect = false)] // struct New2(#[specta(type = Option)] Unsupported); // insta::assert_snapshot!(crate::ts::inline::(&Default::default()).unwrap(), @r#"string"#); // insta::assert_snapshot!(crate::ts::inline::(&Default::default()).unwrap(), @r#"string | null"#); // } // } // mod union_serde { // use serde::{Deserialize, Serialize}; // use specta::Type; // #[derive(Type, Serialize, Deserialize)] // #[specta(collect = false)] // #[serde(tag = "kind", content = "d")] // enum SimpleEnumA { // A, // B, // } // #[derive(Type, Serialize, Deserialize)] // #[specta(collect = false)] // #[serde(tag = "kind", content = "data")] // enum ComplexEnum { // A, // B { foo: String, bar: f64 }, // W(SimpleEnumA), // F { nested: SimpleEnumA }, // T(i32, SimpleEnumA), // } // #[derive(Type, Serialize, Deserialize)] // #[specta(collect = false)] // #[serde(untagged)] // enum Untagged { // Foo(String), // Bar(i32), // None, // } // #[test] // fn test_serde_enum() { // insta::assert_snapshot!(crate::ts::inline::(&Default::default()).unwrap(), @r#"{ kind: "A" } | { kind: "B" }"#); // insta::assert_snapshot!(crate::ts::inline::(&Default::default()).unwrap(), @r#"{ kind: "A" } | { kind: "B"; data: { foo: string; bar: number } } | { kind: "W"; data: SimpleEnumA } | { kind: "F"; data: { nested: SimpleEnumA } } | { kind: "T"; data: [number, SimpleEnumA] }"#); // insta::assert_snapshot!(crate::ts::inline::(&Default::default()).unwrap(), @r#"string | number | null"#); // } // } // mod union_with_serde { // use serde::Serialize; // use specta::Type; // #[derive(Type, Serialize)] // #[specta(collect = false)] // struct Bar { // field: i32, // } // #[derive(Type, Serialize)] // #[specta(collect = false)] // struct Foo { // bar: Bar, // } // #[derive(Type, Serialize)] // #[specta(collect = false)] // enum SimpleEnum2 { // A(String), // B(i32), // C, // D(String, i32), // E(Foo), // F { a: i32, b: String }, // } // #[test] // fn test_stateful_enum() { // insta::assert_snapshot!(crate::ts::inline::(&Default::default()).unwrap(), @r#"{ field: number }"#); // insta::assert_snapshot!(crate::ts::inline::(&Default::default()).unwrap(), @r#"{ bar: Bar }"#); // insta::assert_snapshot!(crate::ts::inline::(&Default::default()).unwrap(), @r#"{ A: string } | { B: number } | "C" | { D: [string, number] } | { E: Foo } | { F: { a: number; b: string } }"#); // } // } // mod union_with_internal_tag { // use serde::{Deserialize, Serialize}; // use specta::Type; // #[derive(Type, Serialize, Deserialize)] // #[specta(collect = false)] // #[serde(tag = "type")] // enum EnumWithInternalTag { // A { foo: String }, // B { bar: i32 }, // } // #[derive(Type, Serialize, Deserialize)] // #[specta(collect = false)] // struct InnerA { // foo: String, // } // #[derive(Type, Serialize, Deserialize)] // #[specta(collect = false)] // struct InnerB { // bar: i32, // } // #[derive(Type, Serialize, Deserialize)] // #[specta(collect = false)] // #[serde(tag = "type")] // enum EnumWithInternalTag2 { // A(InnerA), // B(InnerB), // } // #[test] // fn test_enums_with_internal_tags() { // insta::assert_snapshot!(crate::ts::inline::(&Default::default()).unwrap(), @r#"{ type: "A"; foo: string } | { type: "B"; bar: number }"#); // insta::assert_snapshot!(crate::ts::inline::(&Default::default()).unwrap(), @r#"({ type: "A" } & InnerA) | ({ type: "B" } & InnerB)"#); // } // } // Transparent wrappers should have distinct type IDs (regression test for linker ICF bug) #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(transparent)] struct TransparentA(String); #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(transparent)] struct TransparentB(String); #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] struct UsesTransparent { a: TransparentA, b: TransparentB, } #[test] fn transparent_wrappers_have_distinct_ids() { let mut types = Types::default(); let id_a = TransparentA::definition(&mut types); let id_b = TransparentB::definition(&mut types); let names = types .into_unsorted_iter() .map(|ndt| ndt.name.as_ref()) .collect::>(); assert_ne!(format!("{:?}", id_a), format!("{:?}", id_b)); assert!(names.contains(&"TransparentA")); assert!(names.contains(&"TransparentB")); } #[test] fn struct_collects_all_transparent_field_types() { let mut types = Types::default(); UsesTransparent::definition(&mut types); let names = types .into_unsorted_iter() .map(|ndt| ndt.name.as_ref()) .collect::>(); assert!(names.contains(&"UsesTransparent")); assert!(names.contains(&"TransparentA")); assert!(names.contains(&"TransparentB")); } #[test] fn container_default_marks_all_fields_optional_in_unified_mode() { let ts = specta_typescript::Typescript::default() .export( &Types::default().register::(), specta_serde::Format, ) .expect("typescript export should succeed"); insta::assert_snapshot!("serde-default-container-typescript", ts); } #[test] fn field_default_still_marks_only_that_field_optional() { let ts = specta_typescript::Typescript::default() .export( &Types::default().register::(), specta_serde::Format, ) .expect("typescript export should succeed"); insta::assert_snapshot!("serde-default-field-typescript", ts); } #[test] fn mixed_tagged_and_untagged_variants_export_in_unified_mode() { let ts = specta_typescript::Typescript::default() .export( &Types::default().register::(), specta_serde::Format, ) .expect("typescript export should succeed"); insta::assert_snapshot!("serde-mixed-untagged-typescript", ts); } #[test] fn mixed_tagged_and_untagged_struct_variants_export_in_unified_mode() { let ts = specta_typescript::Typescript::default() .export( &Types::default().register::(), specta_serde::Format, ) .expect("typescript export should succeed"); insta::assert_snapshot!("serde-mixed-untagged-struct-typescript", ts); } #[test] fn phased_mixed_untagged_variants_split_per_phase() { let ts = specta_typescript::Typescript::default() .export( &Types::default().register::(), specta_serde::PhasesFormat, ) .expect("typescript export should succeed"); insta::assert_snapshot!("serde-mixed-untagged-phased-typescript", ts); } ================================================ FILE: tests/tests/typescript.rs ================================================ use std::{ borrow::Cow, collections::HashMap, iter, path::Path, time::{Duration, SystemTime}, }; use specta::{ Format, Type, Types, datatype::{DataType, Reference}, }; use specta_typescript::{Layout, Typescript, primitives}; use tempfile::TempDir; use crate::fs_to_string; fn typescript_types() -> (Types, Vec<(&'static str, DataType)>) { let mut types = Types::default(); let mut dts = Vec::new(); register!(types, dts; specta_typescript::Any, specta_typescript::Any, specta_typescript::Unknown, specta_typescript::Unknown, specta_typescript::Never, specta_typescript::Never, ); let _ = as Type>::definition(&mut types); (types, dts) } pub type PhaseCollection = ( &'static str, Box, Vec<(&'static str, DataType)>, Types, ); struct IdentityFormat; impl Format for IdentityFormat { fn map_types(&'_ self, types: &Types) -> Result, specta::FormatError> { Ok(Cow::Owned(types.clone())) } fn map_type( &'_ self, _: &Types, dt: &DataType, ) -> Result, specta::FormatError> { Ok(Cow::Owned(dt.clone())) } } pub fn phase_collections() -> Vec { let (types, dts) = { let (mut types, mut dts) = crate::types(); let (types2, dts2) = typescript_types(); types.extend(&types2); dts.extend(dts2); (types, dts) }; let (phased_types, phased_dts) = { let (mut types2, mut dts2) = crate::types_phased(); types2.extend(&types); dts2.extend(dts.iter().cloned()); (types2, dts2) }; vec![ ("raw", Box::new(IdentityFormat), dts.clone(), types.clone()), ("serde", Box::new(specta_serde::Format), dts, types), ( "serde_phases", Box::new(specta_serde::PhasesFormat), phased_dts, phased_types, ), ] } #[test] fn typescript_export() { for (mode, format, _, types) in phase_collections() { insta::assert_snapshot!( format!("ts-export-{mode}"), Typescript::default().export(&types, format).unwrap() ); } } #[test] fn typescript_export_serde_errors() { fn assert_serde_error(failures: &mut Vec, name: &str, expected_error: &str) { fn assert_expected_error( failures: &mut Vec, name: &str, mode: &str, stage: &str, expected_error: &str, err: impl std::fmt::Display, ) { let err = err.to_string(); if !err.contains(expected_error) { failures.push(format!( "{name} ({mode}) [{stage}]: expected error containing '{expected_error}', got '{err}'" )); } } let mut types = Types::default(); let dt = T::definition(&mut types); for (mode, format) in [ ("serde", Box::new(specta_serde::Format) as Box), ("serde_phases", Box::new(specta_serde::PhasesFormat)), ] { match Typescript::default().export(&types, format) { Ok(_) => failures.push(format!( "{name} ({mode}) [export]: expected error containing '{expected_error}', but export succeeded" )), Err(err) => { assert_expected_error(failures, name, mode, "export", expected_error, err) } } } } fn assert_serde_export_ok(failures: &mut Vec, name: &str) { let mut types = Types::default(); let dt = T::definition(&mut types); for (mode, format) in [ ("serde", Box::new(specta_serde::Format) as Box), ("serde_phases", Box::new(specta_serde::PhasesFormat)), ] { if let Err(err) = format.map_type(&types, &dt) { failures.push(format!( "{name} ({mode}) [map_type]: expected export to succeed, got '{err}'" )); } } } #[derive(Type, serde::Serialize)] #[specta(collect = false)] #[serde(tag = "type")] enum InternallyTaggedB { A(String), } #[derive(Type, serde::Serialize)] #[specta(collect = false)] #[serde(tag = "type")] enum InternallyTaggedC { A(Vec), } #[derive(Type, serde::Serialize)] #[specta(collect = false)] #[serde(tag = "type")] enum InternallyTaggedG { A(InternallyTaggedGInner), } #[derive(Type, serde::Serialize)] #[specta(collect = false)] #[serde(untagged)] enum InternallyTaggedGInner { A(String), } #[derive(Type, serde::Serialize)] #[specta(collect = false)] #[serde(tag = "type")] enum InternallyTaggedI { A(InternallyTaggedIInner), } #[derive(Type, serde::Serialize)] #[specta(collect = false)] #[serde(transparent)] struct InternallyTaggedIInner(String); #[derive(Type, serde::Serialize)] #[specta(collect = false)] #[serde(tag = "a")] enum TaggedEnumOfEmptyTupleStruct { A(EmptyTupleStruct), B(EmptyTupleStruct), } #[derive(Type, serde::Serialize)] #[specta(collect = false)] struct EmptyTupleStruct(); #[derive(Type, serde::Serialize)] #[specta(collect = false)] enum SkipOnlyVariantExternallyTagged { #[serde(skip)] A(String), } #[derive(Type, serde::Serialize)] #[specta(collect = false)] #[serde(tag = "t")] enum SkipOnlyVariantInternallyTagged { #[serde(skip)] A(String), } #[derive(Type, serde::Serialize)] #[specta(collect = false)] #[serde(tag = "t", content = "c")] enum SkipOnlyVariantAdjacentlyTagged { #[serde(skip)] A(String), } #[derive(Type, serde::Serialize)] #[specta(collect = false)] #[serde(untagged)] enum SkipOnlyVariantUntagged { #[serde(skip)] A(String), } #[derive(Type, serde::Serialize)] #[specta(collect = false)] struct RegularStruct { a: String, } #[derive(Type, serde::Serialize)] #[specta(collect = false)] enum Variants { A(String), B(i32), C(u8), } #[derive(Type, serde::Serialize)] #[specta(collect = false)] #[serde(transparent)] struct MaybeValidKey(T); #[derive(Type, serde::Serialize)] #[specta(collect = false)] #[serde(transparent)] struct InvalidMaybeValidKey(HashMap, ()>); #[derive(Type, serde::Serialize)] #[specta(collect = false)] #[serde(transparent)] struct InvalidMaybeValidKeyNested(HashMap>, ()>); #[derive(Type)] #[specta(transparent, collect = false)] struct RecursiveMapKeyTrick(RecursiveMapKey); #[derive(Type)] #[specta(collect = false)] struct RecursiveMapKey { demo: HashMap, } #[derive(Type, serde::Serialize)] #[specta(collect = false)] #[serde(tag = "type")] enum InternallyTaggedBoxedStruct { // Regression test for https://github.com/specta-rs/specta/issues/482 // `Box` is transparent to serde, so this must validate like `T`. A(Box), } #[derive(Type, serde::Serialize)] #[specta(collect = false)] struct InternallyTaggedBoxedStructPayload { message: String, } let mut failures = Vec::new(); assert_serde_export_ok::( &mut failures, "InternallyTaggedBoxedStruct", ); // Serde Error: "cannot serialize tagged newtype variant InternallyTaggedB::A containing a string" assert_serde_error::( &mut failures, "InternallyTaggedB", "Invalid internally tagged enum", ); // Serde Error: "cannot serialize tagged newtype variant InternallyTaggedC::A containing a sequence" assert_serde_error::( &mut failures, "InternallyTaggedC", "Invalid internally tagged enum", ); // Serde Error: "cannot serialize tagged newtype variant InternallyTaggedG::A containing a string" assert_serde_error::( &mut failures, "InternallyTaggedG", "Invalid internally tagged enum", ); // Serde Error: "cannot serialize tagged newtype variant InternallyTaggedI::A containing a string" assert_serde_error::( &mut failures, "InternallyTaggedI", "Invalid internally tagged enum", ); // Serde Error: "cannot serialize tagged newtype variant TaggedEnumOfEmptyTupleStruct::A containing a tuple struct" assert_serde_error::( &mut failures, "TaggedEnumOfEmptyTupleStruct", "Invalid internally tagged enum", ); // Serde Error: "the enum variant SkipOnlyVariantExternallyTagged::A cannot be serialized" assert_serde_error::( &mut failures, "SkipOnlyVariantExternallyTagged", "Invalid usage of #[serde(skip)]", ); // Serde Error: "the enum variant SkipOnlyVariantInternallyTagged::A cannot be serialized" assert_serde_error::( &mut failures, "SkipOnlyVariantInternallyTagged", "Invalid usage of #[serde(skip)]", ); // Serde Error: "the enum variant SkipOnlyVariantAdjacentlyTagged::A cannot be serialized" assert_serde_error::( &mut failures, "SkipOnlyVariantAdjacentlyTagged", "Invalid usage of #[serde(skip)]", ); // Serde Error: "the enum variant SkipOnlyVariantUntagged::A cannot be serialized" assert_serde_error::( &mut failures, "SkipOnlyVariantUntagged", "Invalid usage of #[serde(skip)]", ); // These need to be named data types so they are exported by `Typescript::export` { #[derive(Type)] #[specta(collect = false)] pub struct A(HashMap<(), ()>); assert_serde_error::( &mut failures, "A(HashMap<() /* `null` */, ()>)", "tuple keys are not supported by serde_json map key serialization", ); } { #[derive(Type)] #[specta(collect = false)] pub struct B(HashMap); assert_serde_error::( &mut failures, "B(HashMap)", "struct keys must serialize as a newtype struct to be valid serde_json map keys", ); } { #[derive(Type)] #[specta(collect = false)] pub struct C(HashMap); assert_serde_error::( &mut failures, "C(HashMap)", "enum key variant 'A' serializes as a struct variant, which serde_json rejects", ); } assert_serde_error::( &mut failures, "InvalidMaybeValidKey", "tuple keys are not supported by serde_json map key serialization", ); assert_serde_error::( &mut failures, "InvalidMaybeValidKeyNested", "tuple keys are not supported by serde_json map key serialization", ); assert_serde_error::( &mut failures, "RecursiveMapKey", "struct keys must serialize as a newtype struct to be valid serde_json map keys", ); assert!( failures.is_empty(), "Unexpected TypeScript serde export behavior:\n{}", failures.join("\n") ); } #[test] fn typescript_export_bigint_errors() { fn assert_bigint_error(failures: &mut Vec, name: &str) { let ts = Typescript::default(); let mut types = Types::default(); let dt = T::definition(&mut types); match primitives::inline(&ts, &types, &dt) { Ok(ty) => failures.push(format!( "{name} [inline]: expected BigInt error, but export succeeded with '{ty}'" )), Err(err) if err .to_string() .contains("forbids exporting BigInt-style types") => {} Err(err) => failures.push(format!("{name} [inline]: unexpected error '{err}'")), } if types.is_empty() { return; } match ts.export(&types, specta_serde::Format) { Ok(output) => failures.push(format!( "{name} [export]: expected BigInt error, but export succeeded with '{output}'" )), Err(err) if err .to_string() .contains("forbids exporting BigInt-style types") => {} Err(err) => failures.push(format!("{name} [export]: unexpected error '{err}'")), } } fn assert_inline_bigint_error(failures: &mut Vec, name: &str) { let ts = Typescript::default(); let mut types = Types::default(); let dt = T::definition(&mut types); match primitives::inline(&ts, &types, &dt) { Ok(ty) => failures.push(format!( "{name} [inline]: expected BigInt error, but export succeeded with '{ty}'" )), Err(err) if err .to_string() .contains("forbids exporting BigInt-style types") => {} Err(err) => failures.push(format!("{name} [inline]: unexpected error '{err}'")), } } macro_rules! for_bigint_types { (T -> $s:expr) => {{ for_bigint_types!(usize, isize, i64, u64, i128, u128; $s); }}; ($($i:ty),+; $s:expr) => {{ $({ type T = $i; $s(stringify!($i)); })* }}; } #[derive(Type)] #[specta(collect = false)] struct StructWithSystemTime { // https://github.com/specta-rs/specta/issues/77 #[specta(inline)] value: SystemTime, } #[derive(Type)] #[specta(collect = false)] struct StructWithDuration { // https://github.com/specta-rs/specta/issues/77 #[specta(inline)] value: Duration, } #[derive(Type)] #[specta(collect = false)] struct StructWithBigInt { a: i128, } #[derive(Type)] #[specta(collect = false)] struct StructWithStructWithBigInt { #[specta(inline)] abc: StructWithBigInt, } #[derive(Type)] #[specta(collect = false)] struct StructWithStructWithStructWithBigInt { #[specta(inline)] field1: StructWithStructWithBigInt, } #[derive(Type)] #[specta(collect = false)] struct StructWithOptionWithStructWithBigInt { #[specta(inline)] optional_field: Option, } #[derive(Type)] #[specta(collect = false)] enum EnumWithStructWithStructWithBigInt { #[specta(inline)] A(StructWithStructWithBigInt), } #[derive(Type)] #[specta(collect = false)] enum EnumWithInlineStructWithBigInt { #[specta(inline)] B { a: i128 }, } let mut failures = Vec::new(); for_bigint_types!(T -> |name| { assert_bigint_error::(&mut failures, name); }); for (name, assert) in [ ( "StructWithSystemTime", assert_bigint_error:: as fn(&mut Vec, &str), ), ( "StructWithDuration", assert_bigint_error:: as fn(&mut Vec, &str), ), ( "StructWithBigInt", assert_bigint_error:: as fn(&mut Vec, &str), ), ( "StructWithStructWithBigInt", assert_bigint_error:: as fn(&mut Vec, &str), ), ( "StructWithStructWithStructWithBigInt", assert_bigint_error:: as fn(&mut Vec, &str), ), ( "StructWithOptionWithStructWithBigInt", assert_bigint_error:: as fn(&mut Vec, &str), ), ( "EnumWithStructWithStructWithBigInt", assert_bigint_error:: as fn(&mut Vec, &str), ), ( "EnumWithInlineStructWithBigInt", assert_bigint_error:: as fn(&mut Vec, &str), ), ] { assert(&mut failures, name); } assert_inline_bigint_error::(&mut failures, "SystemTime"); assert_inline_bigint_error::(&mut failures, "Duration"); assert!( failures.is_empty(), "Unexpected TypeScript BigInt export behavior:\n{}", failures.join("\n") ); } #[test] fn typescript_export_to() { let temp = Path::new(env!("CARGO_MANIFEST_DIR")).join(".temp"); std::fs::create_dir_all(&temp).unwrap(); let temp = TempDir::new_in(temp).unwrap(); for layout in [ Layout::Files, Layout::FlatFile, Layout::ModulePrefixedName, Layout::Namespaces, ] { for (mode, format, _, types) in phase_collections() { let name = format!( "ts-export-to-{}-{}", layout.to_string().to_lowercase(), mode ); let output = (|| { let path = temp.path().join(&name); Typescript::default() .layout(layout) .export_to(&path, &types, format) .unwrap(); fs_to_string(&path).map_err(|err| err.to_string()) })() .unwrap(); insta::assert_snapshot!(name, output); } } temp.close().unwrap(); // TODO: Assert layouts error out with `export` method // TODO: Assert it errors if given the path to a file } #[test] fn primitives_export() { for (mode, format, dts, types) in phase_collections() { let types = format.map_types(&types).unwrap().into_owned(); let output = dts .iter() .filter_map(|(name, dt)| { let mut ndt = match dt { DataType::Reference(Reference::Named(r)) => types.get(r).unwrap().to_owned(), _ => return None, }; if let Some(ty) = &mut ndt.ty { *ty = format.map_type(&types, ty).unwrap().into_owned(); } Some( primitives::export(&Typescript::default(), &types, [ndt].iter(), "") .map(|ty| format!("{name}: {ty}")), ) }) .collect::, _>>() .map(|exports| exports.join("\n")) .unwrap(); insta::assert_snapshot!(format!("export-{mode}"), output); } } #[test] fn primitives_export_many() { for (mode, format, dts, types) in phase_collections() { let types = format.map_types(&types).unwrap().into_owned(); let output = primitives::export( &Typescript::default(), &types, dts.iter() .filter_map(|(_, ty)| match ty { DataType::Reference(Reference::Named(r)) => types.get(r).cloned(), _ => None, }) .map(|mut ndt| { if let Some(ty) = &mut ndt.ty { *ty = format.map_type(&types, ty).unwrap().into_owned(); } ndt }) .collect::>() .iter(), "", ) .unwrap(); insta::assert_snapshot!(format!("export-many-{mode}"), output); } } #[test] fn primitives_reference() { for (mode, format, dts, types) in phase_collections() { let types = format.map_types(&types).unwrap().into_owned(); let output = dts .iter() .filter_map(|(name, dt)| { let dt = format.map_type(&types, dt).unwrap().into_owned(); let reference = match dt { DataType::Reference(reference) => reference.clone(), _ => return None, }; Some( primitives::reference(&Typescript::default(), &types, &reference) .map(|ty| format!("{name}: {ty}")), ) }) .collect::, _>>() .map(|exports| exports.join("\n")) .unwrap(); insta::assert_snapshot!(format!("reference-{mode}"), output); } } #[test] fn primitives_inline() { for (mode, format, dts, types) in phase_collections() { let types = format.map_types(&types).unwrap().into_owned(); let output = dts .iter() .map(|(name, dt)| { let dt = format.map_type(&types, dt).unwrap().into_owned(); primitives::inline(&Typescript::default(), &types, &dt) .map(|ty| format!("{name}: {ty}")) }) .collect::, _>>() .map(|exports| exports.join("\n")) .unwrap(); insta::assert_snapshot!(format!("inline-{mode}"), output); } } #[test] fn reserved_names() { { #[derive(Type)] #[specta(collect = false)] #[allow(non_camel_case_types)] pub struct r#enum { a: String, } let mut types = Types::default(); let ndt = match r#enum::definition(&mut types) { DataType::Reference(Reference::Named(r)) => types.get(&r).unwrap(), _ => panic!("Failed to get reference"), }; insta::assert_snapshot!(primitives::export(&Typescript::default(), &types, iter::once(ndt), "").unwrap_err().to_string(), @r#"Attempted to export but was unable to due to name "enum" conflicting with a reserved keyword in Typescript. Try renaming it or using `#[specta(rename = "new name")]`"#); } { #[derive(Type)] #[specta(collect = false)] #[allow(non_camel_case_types)] pub struct r#enum(String); let mut types = Types::default(); let ndt = match r#enum::definition(&mut types) { DataType::Reference(Reference::Named(r)) => types.get(&r).unwrap(), _ => panic!("Failed to get reference"), }; insta::assert_snapshot!(primitives::export(&Typescript::default(), &types, iter::once(ndt), "").unwrap_err().to_string(), @r#"Attempted to export but was unable to due to name "enum" conflicting with a reserved keyword in Typescript. Try renaming it or using `#[specta(rename = "new name")]`"#); } { // Typescript reserved type name #[derive(Type)] #[specta(collect = false)] #[allow(non_camel_case_types)] pub enum r#enum { A(String), } let mut types = Types::default(); let ndt = match r#enum::definition(&mut types) { DataType::Reference(Reference::Named(r)) => types.get(&r).unwrap(), _ => panic!("Failed to get reference"), }; insta::assert_snapshot!(primitives::export(&Typescript::default(), &types, iter::once(ndt), "").unwrap_err().to_string(), @r#"Attempted to export but was unable to due to name "enum" conflicting with a reserved keyword in Typescript. Try renaming it or using `#[specta(rename = "new name")]`"#); } } // #[test] // fn duplicate_ty_name() { // mod one { // use super::*; // #[derive(Type)] // #[specta(collect = false)] // pub struct One { // pub a: String, // } // } // #[derive(Type)] // #[specta(collect = false)] // pub struct One { // pub one: one::One, // } // assert!( // Typescript::default() // .export(&Types::default().register::()) // .is_err_and(|err| err // .to_string() // .starts_with("Detected multiple types with the same name:")) // ); // } // TODO // // Break out testing of `specta_typescript` types from all languages (just jsdoc & typescript) // Make a `typescript` folder for extra testing on the Typescript exporter // // Testing different combos of feature flags + external impls. Can we come up with a proper multi-binary system for this??? // // BigInt checks // // Test frameworks API's. Eg. prelude and runtime for each layout. // Test framework references and code replacing // Test `Any`, etc for this and JSDoc // // TODO: For core: // Testing Specta macros in many basic cases. // Test `borrow`, `skip` and other Specta attributes // Testing all Serde features in the AST layer??? // Test that the macro attribute lowering system works. // // Tests for framework primitives (prelude, runtime, runtime imports, etc) // Tauri `Channel` tests ================================================ FILE: tests/tests/utils.rs ================================================ use std::{ borrow::Cow, fs, path::{Path, PathBuf}, }; /// Get a `String` representation of the filesystem. /// This is used for snapshot testing multi-file exports. pub fn fs_to_string(path: &Path) -> Result { let mut output = String::new(); // Handle single file case if path.is_file() { let contents = fs::read(path)?; let name = path.file_name().unwrap().to_string_lossy(); match String::from_utf8(contents) { Ok(text) => { let normalized = normalize_newlines(&text); output.push_str(&format!("{} ({} bytes)\n", name, normalized.len())); output.push_str("────────────────────────────────────────\n"); for line in normalized.lines() { output.push_str(&format!("{}\n", line)); } } Err(err) => { output.push_str(&format!("{} ({} bytes)\n", name, err.as_bytes().len())); output.push_str("────────────────────────────────────────\n"); output.push_str("[Binary file]\n"); } } output.push_str("════════════════════════════════════════\n"); } else { fs_to_string_impl(path, path, &mut output, "")?; } Ok(output) } fn fs_to_string_impl( root: &Path, current: &Path, output: &mut String, indent: &str, ) -> Result<(), std::io::Error> { let mut entries: Vec = fs::read_dir(current)? .filter_map(|entry| entry.ok()) .map(|entry| entry.path()) .collect(); // Sort entries: directories first, then files, both alphabetically entries.sort_by(|a, b| { let a_is_dir = a.is_dir(); let b_is_dir = b.is_dir(); match (a_is_dir, b_is_dir) { (true, false) => std::cmp::Ordering::Less, (false, true) => std::cmp::Ordering::Greater, _ => a.file_name().cmp(&b.file_name()), } }); for entry in entries { let name = entry.file_name().unwrap().to_string_lossy(); if entry.is_dir() { output.push_str(&format!("{}{}/\n", indent, name)); fs_to_string_impl(root, &entry, output, &format!("{} ", indent))?; } else { let contents = fs::read(&entry)?; // Try to read as UTF-8, otherwise show as binary match String::from_utf8(contents) { Ok(text) => { let normalized = normalize_newlines(&text); output.push_str(&format!( "{}{} ({} bytes)\n", indent, name, normalized.len() )); output.push_str(&format!( "{}────────────────────────────────────────\n", indent )); for line in normalized.lines() { output.push_str(&format!("{}{}\n", indent, line)); } } Err(err) => { output.push_str(&format!( "{}{} ({} bytes)\n", indent, name, err.as_bytes().len() )); output.push_str(&format!( "{}────────────────────────────────────────\n", indent )); output.push_str(&format!("{}[Binary file]\n", indent)); } } output.push_str(&format!( "{}════════════════════════════════════════\n\n", indent )); } } Ok(()) } fn normalize_newlines(text: &str) -> Cow<'_, str> { if text.contains("\r\n") { Cow::Owned(text.replace("\r\n", "\n")) } else { Cow::Borrowed(text) } } ================================================ FILE: tests/tests/zod.rs ================================================ use std::{iter, path::Path}; use serde::{Deserialize, Serialize}; use specta::{ Type, Types, datatype::{DataType, NamedDataType, Primitive, Reference}, }; use specta_typescript::Typescript; use specta_zod::{BigIntExportBehavior, Layout, Zod, primitives}; use tempfile::TempDir; macro_rules! for_bigint_types { (T -> $s:expr) => {{ for_bigint_types!(usize, isize, i64, u64, i128, u128; $s); }}; ($($i:ty),+; $s:expr) => {{ $({ type T = $i; $s(stringify!($i)); })* }}; } #[derive(Type)] #[specta(collect = false)] struct StructWithBigInt { a: i128, } #[derive(Type)] #[specta(collect = false)] struct StructWithStructWithBigInt { #[specta(inline)] abc: StructWithBigInt, } #[derive(Type)] #[specta(collect = false)] struct StructWithOptionWithStructWithBigInt { #[specta(inline)] optional_field: Option, } #[derive(Type)] #[specta(collect = false)] enum EnumWithInlineStructWithBigInt { #[specta(inline)] B { a: i128 }, } #[derive(Type)] struct Recursive { children: Vec, } #[derive(Type)] struct Testing { a: testing::Testing, } #[derive(Type)] struct Another { bruh: String, } #[derive(Type)] #[specta(collect = false)] struct EmptyStruct {} #[derive(Type)] #[specta(collect = false)] enum EmptyNamedVariant { A {}, } #[derive(Type, Serialize, Deserialize)] #[specta(collect = false)] #[serde(tag = "type", content = "data", rename_all = "snake_case")] enum SerdeTaggedEnum { Unit, StringValue(String), } #[derive(Type, Serialize)] #[specta(collect = false)] #[serde(tag = "type")] enum InvalidInternallyTaggedEnum { A(String), } mod testing { use super::*; #[derive(Type)] pub struct Testing { b: testing2::Testing, } pub mod testing2 { use super::*; #[derive(Type)] pub struct Testing { c: String, } } } fn inline_for(zod: &Zod) -> Result { let mut types = Types::default(); let dt = T::definition(&mut types); primitives::inline(zod, &types, &dt) } fn temp_root() -> std::path::PathBuf { let temp_root = Path::new(env!("CARGO_MANIFEST_DIR")).join(".temp"); std::fs::create_dir_all(&temp_root).unwrap(); temp_root } #[test] fn zod_export_smoke() { #[derive(Type)] struct Inner { value: String, } #[derive(Type)] struct Demo { inner: Inner, count: i32, maybe: Option, } let types = Types::default().register::(); let out = Zod::default() .bigint(BigIntExportBehavior::Number) .export(&types, specta_serde::Format) .unwrap(); assert!(out.contains("import { z } from \"zod\";")); assert!(out.contains("export const DemoSchema")); assert!(out.contains("export type Demo = z.infer;")); } #[test] fn zod_primitives_smoke() { let (types, dts) = crate::types(); let zod = Zod::default().bigint(BigIntExportBehavior::Number); for (_, ty) in &dts { let rendered = primitives::inline(&zod, &types, ty).unwrap(); assert!(!rendered.is_empty()); } let ndt = dts .iter() .find_map(|(_, ty)| match ty { DataType::Reference(Reference::Named(r)) => types.get(r), _ => None, }) .unwrap(); let rendered = primitives::export(&zod, &types, iter::once(ndt), "").unwrap(); assert!(rendered.contains("Schema")); } #[test] fn zod_bigint_export_behaviors() { for_bigint_types!(T -> |_| { assert!(inline_for::(&Zod::default()).is_err()); assert!(inline_for::(&Zod::default().bigint(BigIntExportBehavior::Fail)).is_err()); assert_eq!( inline_for::(&Zod::default().bigint(BigIntExportBehavior::String)).unwrap(), "z.string()" ); assert_eq!( inline_for::(&Zod::default().bigint(BigIntExportBehavior::Number)).unwrap(), "z.number()" ); assert_eq!( inline_for::(&Zod::default().bigint(BigIntExportBehavior::BigInt)).unwrap(), "z.bigint()" ); }); } #[test] fn zod_bigint_errors_propagate_from_nested_types() { for err in [ export_for::(), export_for::(), export_for::(), export_for::(), ] { let err = err.expect_err("bigint export should be rejected by default"); assert!( err.to_string().contains("forbids exporting BigInt types"), "unexpected error: {err}" ); } } #[test] fn zod_layout_duplicate_typenames() { let types = Types::default().register::().register::(); let err = Zod::default() .export(&types, specta_serde::Format) .unwrap_err(); assert!(err.to_string().contains("Detected multiple types")); let module_prefixed = Zod::default() .layout(Layout::ModulePrefixedName) .export(&types, specta_serde::Format) .unwrap(); assert!(module_prefixed.contains("TestingSchema")); assert!(module_prefixed.contains("testing2")); } #[test] fn zod_layout_files_export_to() { let types = Types::default().register::().register::(); let temp = temp_dir(); let path = temp.path().join("zod-layout-files"); Zod::default() .layout(Layout::Files) .export_to(&path, &types, specta_serde::Format) .unwrap(); let output = crate::fs_to_string(Path::new(&path)).unwrap(); assert!(output.contains(".ts")); assert!(output.contains("import { z } from \"zod\";")); } #[test] fn zod_uses_serde_transformed_resolved_types() { let types = Types::default().register::(); let serde_out = Zod::default().export(&types, specta_serde::Format).unwrap(); assert!(serde_out.contains("type: z.literal(\"unit\")")); assert!(serde_out.contains("type: z.literal(\"string_value\")")); assert!(serde_out.contains("data: z.string()")); } #[test] fn zod_empty_named_shapes_are_strict() { let empty_struct = export_for::().unwrap(); assert!(empty_struct.contains("z.object({}).strict()")); let empty_variant = export_for::().unwrap(); assert!(empty_variant.contains("z.object({}).strict()")); } #[test] fn zod_layout_files_preserves_unrelated_typescript_files() { let types = Types::default().register::().register::(); let temp = TempDir::new_in(temp_root()).unwrap(); let path = temp.path().join("zod-layout-files-preserve"); std::fs::create_dir_all(&path).unwrap(); let keep_path = path.join("keep.ts"); std::fs::write(&keep_path, "export const keep = true;\n").unwrap(); Zod::default() .layout(Layout::Files) .export_to(&path, &types, specta_serde::Format) .unwrap(); assert!(keep_path.exists()); assert!( std::fs::read_to_string(&keep_path) .unwrap() .contains("export const keep = true;") ); } #[test] fn typescript_layout_files_preserves_unrelated_typescript_files() { let types = Types::default().register::().register::(); let temp = TempDir::new_in(temp_root()).unwrap(); let path = temp.path().join("typescript-layout-files-preserve"); std::fs::create_dir_all(&path).unwrap(); let keep_path = path.join("keep.ts"); std::fs::write(&keep_path, "export const keep = true;\n").unwrap(); Typescript::default() .layout(specta_typescript::Layout::Files) .export_to(&path, &types, specta_serde::Format) .unwrap(); assert!(keep_path.exists()); assert!( std::fs::read_to_string(&keep_path) .unwrap() .contains("export const keep = true;") ); } #[test] fn zod_recursive_types_use_lazy() { let types = Types::default().register::(); let out = Zod::default() .export(&types, specta_serde::PhasesFormat) .unwrap(); assert!(out.contains("z.lazy(() => RecursiveSchema)")); } #[test] fn zod_reserved_type_name_errors() { let mut types = Types::default(); NamedDataType::new("class", &mut types, |_, ndt| { ndt.ty = Some(DataType::Primitive(Primitive::i8)); }); let err = Zod::default() .export(&types, specta_serde::Format) .unwrap_err(); assert!(err.to_string().contains("reserved keyword")); } #[test] fn zod_layout_files_errors_on_export() { let types = Types::default(); let err = Zod::default() .layout(Layout::Files) .export(&types, specta_serde::Format) .unwrap_err(); assert!(err.to_string().contains("Unable to export layout Files")); } fn temp_dir() -> TempDir { TempDir::new_in(temp_root()).unwrap() } fn export_for() -> Result { let types = Types::default().register::(); Zod::default().export(&types, specta_serde::Format) }