import { Type, Model, Scalar, Union, Program, ModelProperty } from "@typespec/compiler"; import { SampleEntry, FactoryEntry, MethodEntry, KnownAsEntry, DefaultForEntry, SerializationDirection } from "../decorators.js"; import type { CallableDispatch } from "./callable.js"; export interface TypeName { namespace: string; name: string; } export interface Coercion { scalar: string; expansion: { [key: string]: any; }; example?: any; title?: string; description?: string; } export declare class TypeNode { model: Model; typeName: TypeName; description: string; base: TypeName | null; childTypes: TypeNode[]; coercions: Coercion[]; properties: PropertyNode[]; isAbstract: boolean; isProtocol: boolean; /** * True when this model is a `@serializable` root: the emitter emits load/save * over its serialization closure (transitive property reach + discriminated * variant expansion). Populated from `StateKeys.serializable`. */ serializable: boolean; entryShorthand: string | null; isError: boolean; discriminator: string | undefined; factories: FactoryEntry[]; methods: MethodEntry[]; /** * Behavioral polymorphic dispatch metadata from `@dispatch`, populated when a * TypeSpec-native seam interface is projected as a protocol node. Absent for * plain protocol/interface nodes. */ dispatch?: CallableDispatch; /** Semantic group derived from the TSP source subfolder (e.g. "connection", "tools"). */ group: string; constructor(model: Model, description: string); retrievePolymorphicTypes(): any; getSanitizedObject(): Record; } export declare class PropertyNode { name: string; typeName: TypeName; description: string; samples: SampleEntry[]; knownAs: KnownAsEntry[]; defaultFor: DefaultForEntry[]; /** * Serialization directions this field is withheld from (`@sensitive`). Empty * when the field is not sensitive; otherwise the set of directions in which * the field is omitted. A field withheld from BOTH directions carries no * reachability for the serialization closure. */ sensitive: SerializationDirection[]; isScalar: boolean; isOptional: boolean; isCollection: boolean; isAny: boolean; isDict: boolean; dictValueType: string | null; defaultValue: string | number | boolean | null; hasExplicitDefault: boolean; allowedValues: string[]; parseAliases: Record; /** Name of the string-literal union alias (e.g., "Role"), null if unnamed or not an enum. */ enumName: string | null; /** True when the union includes a bare `string` variant (open enum — accepts any string). */ isOpenEnum: boolean; /** * True when this property is a keyed (property-bag) collection whose elements carry an * injected `name` — i.e. resolved from a `Record | Named[]` (or `Named | T`) * union. Its canonical wire form is a name-keyed MAP. This is tracked STRUCTURALLY because * the element type's `.type` (the `Named` wrapper that injects `name`) is only resolved * for the FIRST property of a given element type — a later sibling with the same element * type has `.type` undefined (cycle-prevention in resolveModel), so its injected-name-ness * cannot be recovered from the raw registry type (which lacks the injected `name`). */ isNamedCollection: boolean; property: ModelProperty; type: TypeNode | undefined; constructor(property: ModelProperty, description: string); getSanitizedObject(): Record; } export declare const enumerateTypes: (node: TypeNode, visited?: Set) => IterableIterator; export declare const resolveModel: (program: Program, model: Model, visited: Set | undefined, rootNamespace: string, rootAlias: string) => TypeNode; export declare const resolveModelChildren: (program: Program, model: Model, visited: Set, rootNamespace: string, rootAlias: string) => TypeNode[]; export declare const resolveProperty: (program: Program, property: ModelProperty, visited: Set, rootNamespace: string, rootAlias: string) => PropertyNode; export declare const resolveScalarProperty: (program: Program, property: ModelProperty, scalar: Scalar) => PropertyNode; export declare const resolveIntrinsicProperty: (program: Program, property: ModelProperty, intrinsic: Type, visited: Set) => PropertyNode; export declare const resolveModelProperty: (program: Program, property: ModelProperty, model: Model, visited: Set, rootNamespace: string, rootAlias: string) => PropertyNode; export declare const resolveUnionProperty: (program: Program, property: ModelProperty, union: Union, visited: Set, rootNamespace: string, rootAlias: string) => PropertyNode; /** * Context for rendering a single Python class. */ export interface PythonClassContext { /** The TypeNode being rendered */ node: TypeNode; /** Type mapping from TypeSpec types to Python types */ typeMapper: Record; /** Processed coercion representations for scalar-to-object constructors */ coercions: Array<{ scalar: string; alternate: string; }>; /** Polymorphic type information if this is a discriminated type */ polymorphicTypes: ReturnType | undefined; /** Import types needed from other modules */ imports: string[]; /** Collection properties with their nested type info for load_* methods */ collectionTypes: Array<{ prop: PropertyNode; type: string[]; }>; /** The property name that receives the scalar value in a coercion expansion */ coercionProperty: string | null; /** Maps factory.name → safe Python method name (prefixed with create_ on field collision) */ factoryNameMap: Record; /** Pre-rendered factory method bodies via expression IR */ renderedFactories: Array<{ name: string; safeName: string; params: Record; body: string; }>; /** Pre-rendered coercion expressions via expression IR */ renderedCoercions: Array<{ scalar: string; expression: string; }>; /** Type names referenced in factory expressions (for file-level import resolution) */ factoryTypeRefs: string[]; } /** * Context for rendering a Python file containing one or more classes. */ export interface PythonFileContext { /** Whether any class in the file is abstract */ containsAbstract: boolean; /** Python typing imports needed (e.g., "Any", "Callable", "Optional") */ typings: string[]; /** Grouped imports: each entry maps a module name to the types imported from it */ imports: Array<{ module: string; names: string[]; }>; /** Array of class contexts to render */ classes: PythonClassContext[]; /** Type mapping from TypeSpec types to Python types */ typeMapper: Record; } /** * Context for rendering a Python __init__.py file. */ export interface PythonInitContext { /** Base types (types without a parent) for top-level imports */ baseTypes: TypeNode[]; /** All types for __all__ export list */ types: TypeNode[]; } /** * Context for rendering Python test files. */ export interface PythonTestContext { /** The TypeNode being tested */ node: TypeNode; /** Flattened sample combinations for testing */ examples: Array<{ json: string[]; yaml: string[]; validation: Array<{ key: string; value: any; delimeter: string; }>; }>; /** Coercion representation tests */ coercions: Array<{ title: string; scalar: string; value: string; validation: Array<{ key: string; value: any; delimeter: string; }>; }>; } /** * Context for rendering the LoadContext file. */ export interface PythonLoadContextContext { /** File header comment */ header: string; /** Package name for imports in test file */ package?: string; } /** * Base render context interface - all language contexts should extend this. * This ensures consistency across emitters. */ export interface BaseRenderContext { /** The TypeNode being rendered */ node: TypeNode; /** Type mapping from TypeSpec types to target language types */ typeMapper: Record; } /** * Validation assertion for a single property in a test. */ export interface PropertyValidation { /** Original schema property name before target-language identifier normalization. */ sourceKey?: string; /** Property name in target language casing (PascalCase, snake_case, camelCase) */ key: string; /** Expected value after loading */ value: any; /** String delimiter for assertions (", """, etc.) */ delimiter: string; /** Whether property is optional/pointer (for Go, C# nullable) */ isOptional: boolean; /** * True when the field is withheld from the `save` direction (`@sensitive("save")` * or bare `@sensitive`). `save()` omits it, so it cannot survive a * load → save → load round-trip; its value must NOT be asserted on the reloaded * instance (the load/instance assertion still holds). */ withheldOnSave?: boolean; } /** * A single test example generated from @sample decorators. */ export interface TestExample { /** Raw sample object used for target-specific semantic assertions */ sample: Record; /** JSON representation as lines */ json: string[]; /** YAML representation as lines */ yaml: string[]; /** Property assertions to validate after loading */ validations: PropertyValidation[]; } /** * A coercion (scalar-to-object) representation test case. */ export interface CoercionTest { /** Human-readable test name/title */ title: string; /** Scalar type name in target language */ scalarType: string; /** Example scalar value as string literal */ value: string; /** Validations after expansion to full object */ validations: PropertyValidation[]; } /** * Base test context interface - all language test contexts should use this structure. * This ensures consistency in test generation across all emitters. */ export interface BaseTestContext { /** The TypeNode being tested */ node: TypeNode; /** Whether this is an abstract/polymorphic base type (skip direct instantiation tests) */ isAbstract: boolean; /** Package/namespace name for imports (optional - not used by all languages) */ package?: string; /** Test examples from @sample decorators */ examples: TestExample[]; /** Coercion (scalar-to-object) representation tests */ coercions: CoercionTest[]; /** Factory methods declared via @factory (for auto-generated factory tests) */ factories: FactoryEntry[]; }