/*!
 * TSBuffer Schema v2.2.0
 * -----------------------------------------
 * MIT LICENSE
 * KingWorks (C) Copyright 2022
 * https://github.com/k8w/tsbuffer-schema
 */

/**
 * TypeScript `any` type
 *
 * @remarks
 * See: {@link https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#any}
 *
 * @example
 * ```ts
 * type XXX = any;
 * ```
 */
export declare interface AnyTypeSchema {
    type: 'Any';
}

/**
 * TypeScript `Array` type
 *
 * @remarks
 * See: {@link https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#arrays}
 *
 * @example
 * ```ts
 * type A = string[];
 * type B = Array<A>;
 * ```
 */
export declare interface ArrayTypeSchema {
    type: 'Array';
    elementType: TSBufferSchema;
}

/** Encoded as 64-bit `int64` */
export declare type bigint64 = bigint;

/** Encoded as 64-bit `uint64` */
export declare type biguint64 = bigint;

/**
 * Primitive `boolean` type
 *
 * @example
 * ```ts
 * type A = boolean;
 * ```
 */
export declare interface BooleanTypeSchema {
    type: 'Boolean';
}

/**
 * Buffer type, include `ArrayBuffer` and typed arrays (e.g. `Uint8Array`, `Int32Array`...).
 *
 * @example
 * ```ts
 * type A = ArrayBuffer;
 * type B = Uint8Array;
 * ```
 */
export declare interface BufferTypeSchema {
    type: 'Buffer';
    /**
     * 有该字段，代表类型为该字段对应的TypedArray，否则该字段为ArrayBuffer
     */
    arrayType?: 'Int8Array' | 'Int16Array' | 'Int32Array' | 'BigInt64Array' | 'Uint8Array' | 'Uint16Array' | 'Uint32Array' | 'BigUint64Array' | 'Float32Array' | 'Float64Array';
}

/**
 * Custom type, used for custom validate / encode / decode methods.
 */
export declare interface CustomTypeSchema {
    type: 'Custom';
    /** Custom validate method */
    validate: (value: any) => {
        isSucc: true;
        errMsg?: undefined;
    } | {
        isSucc: false;
        errMsg: string;
    };
    /**
     * Custom encode method.
     * It is ensured that the method is called after validated successfully.
     */
    encode?: (value: any) => Uint8Array;
    /**
     * Custom decode method.
     * After decode, it would validate again.
     */
    decode?: (buf: Uint8Array) => any;
    /**
     * Custom encodeJSON method.
     * It is ensured that the method is called after validated successfully.
     */
    encodeJSON?: (value: any) => any;
    /**
     * Custom decodeJSON method.
     * After decode, it would validate again.
     */
    decodeJSON?: (json: any) => any;
}

/**
 * JavaScript `Date` type
 *
 * @example
 * ```ts
 * type A = Date;
 * ```
 */
export declare interface DateTypeSchema {
    type: 'Date';
}

/** Encoded as 64-bit `double` type */
export declare type double = number;

/**
 * TypeScript `enum` type
 *
 * @remarks
 * See: {@link https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#enums}
 *
 * @example
 * ```ts
 * enum JobName {
 *     Teacher,
 *     Doctor,
 *     Salesman
 * }
 *
 * enum Status {
 *     Normal = 'Normal',
 *     Expired = 'Expired'
 * }
 * ```
 */
export declare interface EnumTypeSchema {
    type: 'Enum';
    members: {
        /** Encoding identifier, generated according to the order */
        id: number;
        value: string | number;
    }[];
}

/**
 * TypeScript indexed access type
 *
 * @remarks
 * `XXX['a' | 'b']` is not a `IndexedAccessType`, which should be a `{@link UnionType}`.
 * (Equivalent to `XXX['a'] | XXX['b']`)
 *
 * {@link https://www.typescriptlang.org/docs/handbook/2/indexed-access-types.html}
 *
 * @example
 * ```ts
 * type A = SomeInterface['XXX']
 * ```
 */
export declare interface IndexedAccessTypeSchema {
    type: 'IndexedAccess';
    objectType: InterfaceTypeSchema | InterfaceReference;
    index: string;
}

/** Encoded as {@link https://developers.google.com/protocol-buffers/docs/encoding#varints | Varint} */
export declare type int = number;

export declare type InterfaceReference = TypeReference | PickTypeSchema | PartialTypeSchema | OverwriteTypeSchema | OmitTypeSchema;

/**
 * TypeScript `interface`
 *
 * @remarks
 * See: {@link https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#interfaces}
 *
 * @example
 * ```ts
 * interface AAA {
 *     a: string,
 *     b?: number[],
 *     c: {
 *         value: boolean
 *     }
 * }
 *
 * // Index Signature
 * interface BBB {
 *     [key: string]: string;
 * }
 * ```
 */
export declare interface InterfaceTypeSchema {
    type: 'Interface';
    /** Extends which interface */
    extends?: {
        id: number;
        type: InterfaceReference;
    }[];
    /** Self properties (not include extended) */
    properties?: {
        id: number;
        name: string;
        /** 可选字段 */
        optional?: boolean;
        type: TSBufferSchema;
    }[];
    /**
     * Index Signature
     * `undefined` represents no index signature, i.e. excess property is not allowed.
     * \{ [key: string]: xxx \}
     */
    indexSignature?: {
        keyType: 'String' | 'Number';
        type: TSBufferSchema;
    };
}

/**
 * TypeScript intersection type, like `A & B`
 *
 * @remarks
 * See: {@link https://www.typescriptlang.org/docs/handbook/2/objects.html#intersection-types}
 *
 * @example
 * ```ts
 * type X1 = A & B;
 * type X2 = A & (B | C);
 * ```
 */
export declare interface IntersectionTypeSchema {
    type: 'Intersection';
    members: {
        /** Encoding identifier, generated according to the order */
        id: number;
        type: TSBufferSchema;
    }[];
}

/**
 * TypeScript `keyof` feature, to get keys of an interface.
 *
 * @remarks
 * Type:
 * ```ts
 * interface ABC { a: string; b: string }
 * type Keys = keyof ABC;
 * ```
 *
 * Schema:
 * ```json
 * {
 *     type: "keys",
 *     target: {
 *         type: "Reference",
 *         target: "ABC"
 *     }
 * }
 * ```
 */
declare interface KeyofTypeSchema {
    type: 'Keyof';
    target: InterfaceReference;
}

/**
 * TypeScript literal type
 *
 * @remarks
 * See: {@link https://www.typescriptlang.org/docs/handbook/literal-types.html}
 *
 * Literal type is very useful to reduce encoded buffer size.
 * No matter how long the literal is, the encoded buffer is always less than 1 byte.
 *
 * @example
 * ```ts
 * type A = 'XXXX';
 *
 * // Always appears with UnionType, like:
 * type Gender = 'Male' | 'Female';
 * ```
 */
export declare interface LiteralTypeSchema {
    type: 'Literal';
    literal?: string | number | boolean | null | undefined;
}

/**
 * TypeScript `NonNullable<Type>`
 *
 * @remarks
 * See: {@link https://www.typescriptlang.org/docs/handbook/utility-types.html#nonnullabletype}
 *
 * @example
 * ```ts
 * type A = NonNullable<B>;
 * ```
 */
export declare interface NonNullableTypeSchema {
    type: 'NonNullable';
    /** 引用目标l */
    target: TSBufferSchema;
}

/**
 * Primitive `number` type, with specific scalar type (like `int`, `uint`)
 *
 * @remarks
 * See: {@link https://www.typescriptlang.org/docs/handbook/basic-types.html#number}
 *
 * Encoding:<br/>
 * - {@link https://developers.google.com/protocol-buffers/docs/encoding#varints | Varint}: `int`, `uint`<br/>
 * - Fixed 64 bit: `double`, `bigint`, `bigint64`, `biguint64`
 */
export declare interface NumberTypeSchema {
    type: 'Number';
    /**
     * @defaultValue 'double'
     */
    scalarType?: 'int' | 'uint' | 'bigint' | 'bigint64' | 'biguint64' | 'double';
}

/**
 * TypeScript `object` type
 *
 * Represents anything that is not `number`, `string`, `boolean`, `bigint`, `symbol`, `null`, or `undefined`.
 *
 * @remarks
 * See: {@link https://www.typescriptlang.org/docs/handbook/basic-types.html#object}
 *
 * NOTICE: Both `Object` and `Array` is valid.
 *
 * @example
 * ```ts
 * let a: object;
 * ```
 *
 */
export declare interface ObjectTypeSchema {
    type: 'Object';
}

/**
 * TypeScript `Omit` type,
 * represents omit some properties from a interface.
 *
 * @remarks
 * See: {@link https://www.typescriptlang.org/docs/handbook/utility-types.html#omittype-keys}
 *
 * @example
 * ```ts
 * interface AAA {
 *     a: string,
 *     b: string,
 *     c: string
 * }
 *
 * // Equivalent to `{ c: string }`
 * type BBB = Omit<AAA, 'a' | 'b'>;
 * ```
 */
export declare interface OmitTypeSchema {
    type: 'Omit';
    target: InterfaceTypeSchema | InterfaceReference | UnionTypeSchema | IntersectionTypeSchema;
    keys: string[];
}

/**
 * Overwrite some properties from a interface
 */
export declare type Overwrite<T, U> = T extends unknown ? Pick<T, Exclude<keyof T, keyof U>> & U : never;

/**
 * TSBuffer utility type, which represents overwrite some properties from a interface.
 *
 * @example
 * ```ts
 * import { Overwrite } from 'tsbuffer-schema';
 *
 * interface AAA {
 *     a: string,
 *     b: string
 * }
 *
 * // Equivalent to `{ a: string, b: number, c: number }`
 * type BBB = Overwrite<AAA, {
 *     b: number,
 *     c: number
 * }>
 * ```
 */
export declare interface OverwriteTypeSchema {
    type: 'Overwrite';
    target: InterfaceTypeSchema | InterfaceReference;
    overwrite: InterfaceTypeSchema | InterfaceReference;
}

/**
 * TypeScript `Partial<Type>`
 *
 * @remarks
 * See: {@link https://www.typescriptlang.org/docs/handbook/utility-types.html#partialtype}
 */
export declare interface PartialTypeSchema {
    type: 'Partial';
    target: InterfaceTypeSchema | InterfaceReference | UnionTypeSchema | IntersectionTypeSchema;
}

/**
 * TypeScript `Pick<Type>`
 * @remarks
 * See: {@link https://www.typescriptlang.org/docs/handbook/utility-types.html#picktype-keys}
 */
export declare interface PickTypeSchema {
    type: 'Pick';
    target: InterfaceTypeSchema | InterfaceReference | UnionTypeSchema | IntersectionTypeSchema;
    keys: string[];
}

/**
 * Type Reference, infers that this type should be equivalent to target type.
 *
 * @remarks
 * If target type is in a namespace, the schema should be like below.
 *
 * Type:
 * ```ts
 * import { SomeNS } from './some-ns';
 * type Reference = SomeNS.Target;
 * ```
 *
 * Schema:
 * ```json
 * {
 *     type: "Reference",
 *     target: "./some-ns/SomeNS.Target"
 * }
 * ```
 *
 * When parsing a type reference, if `target` includes point, namespace would be parsed by `target.split('.')`.
 * If `target` doesn't include point, it would be treated as a type name.
 */
export declare interface ReferenceTypeSchema {
    type: 'Reference';
    /** SchemaID of reference target */
    target: string;
}

/**
 * Enum for every possible `TSBufferSchema['type']`
 */
export declare class SchemaType {
    static Boolean: "Boolean";
    static Number: "Number";
    static String: "String";
    static Array: "Array";
    static Tuple: "Tuple";
    static Enum: "Enum";
    static Any: "Any";
    static Literal: "Literal";
    static Object: "Object";
    static Interface: "Interface";
    static Buffer: "Buffer";
    static IndexedAccess: "IndexedAccess";
    static Reference: "Reference";
    static Keyof: "Keyof";
    static Union: "Union";
    static Intersection: "Intersection";
    static NonNullable: "NonNullable";
    static Date: "Date";
    static Pick: "Pick";
    static Partial: "Partial";
    static Omit: "Omit";
    static Overwrite: "Overwrite";
    static Custom: "Custom";
}

/**
 * Primitive `string` type
 */
export declare interface StringTypeSchema {
    type: 'String';
}

/**
 * Collection of a group of `TSBufferSchema`
 */
export declare interface TSBufferProto {
    /**
     * [schemaId: string]: `{relativePath}/{namespace}/{typeName}`.
     * `path` is relative path to `baseDir`, without extension name.
     *
     * @example
     * a/b/c/index.ts:
     * ```ts
     * export interface Test {
     *     a: string;
     * }
     * ```
     * schemaId for `Test` is `a/b/c/index/Test`
     *
     * a/b/c/index.ts (with namespace)
     * ```ts
     * export namespace NS {
     *     export interface Test {
     *         value: string;
     *     }
     * }
     * ```
     * schemaId for `NS.Test` is `a/b/c/index/NS/Test`
     */
    [schemaId: string]: TSBufferSchema;
}

/**
 * Schema for TypeScript Types
 */
export declare type TSBufferSchema = (BooleanTypeSchema | NumberTypeSchema | StringTypeSchema | ArrayTypeSchema | TupleTypeSchema | EnumTypeSchema | AnyTypeSchema | LiteralTypeSchema | ObjectTypeSchema | InterfaceTypeSchema | BufferTypeSchema | IndexedAccessTypeSchema | ReferenceTypeSchema | KeyofTypeSchema | UnionTypeSchema | IntersectionTypeSchema | PickTypeSchema | PartialTypeSchema | OmitTypeSchema | OverwriteTypeSchema | NonNullableTypeSchema | DateTypeSchema | CustomTypeSchema) & {
    comment?: string;
};

/**
 * TypeScript `Tuple` type
 *
 * @remarks
 * It has less encoded size than `Array`.
 *
 * See: {@link https://www.typescriptlang.org/docs/handbook/2/objects.html#tuple-types}
 */
export declare interface TupleTypeSchema {
    type: 'Tuple';
    elementTypes: TSBufferSchema[];
    optionalStartIndex?: number;
}

export declare type TypeReference = ReferenceTypeSchema | IndexedAccessTypeSchema | KeyofTypeSchema;

/** Encoded as {@link https://developers.google.com/protocol-buffers/docs/encoding#varints | Varint} */
export declare type uint = number;

/**
 * TypeScript Union Types, like `A | B`
 *
 * @remarks
 * See: {@link https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#union-types}
 *
 * @example
 * ```ts
 * type X1 = A | B;
 * type X2 = A | null | undefined;
 * type Gender = 'Male' | 'Female';
 * ```
 */
export declare interface UnionTypeSchema {
    type: 'Union';
    members: {
        id: number;
        type: TSBufferSchema;
    }[];
}

export { }


