import type { Mapping } from '@volar/source-map';
import type { LinkedCodeMap } from './linkedCodeMap';
export interface Mapper {
    mappings: Mapping<CodeInformation>[];
    toSourceRange(start: number, end: number, fallbackToAnyMatch: boolean, filter?: (data: CodeInformation) => boolean): Generator<readonly [number, number, Mapping<CodeInformation>, Mapping<CodeInformation>]>;
    toGeneratedRange(start: number, end: number, fallbackToAnyMatch: boolean, filter?: (data: CodeInformation) => boolean): Generator<readonly [number, number, Mapping<CodeInformation>, Mapping<CodeInformation>]>;
    toSourceLocation(generatedOffset: number, filter?: (data: CodeInformation) => boolean): Generator<readonly [number, Mapping<CodeInformation>]>;
    toGeneratedLocation(sourceOffset: number, filter?: (data: CodeInformation) => boolean): Generator<readonly [number, Mapping<CodeInformation>]>;
}
export type MapperFactory = (mappings: Mapping<CodeInformation>[]) => Mapper;
export interface Language<T = unknown> {
    mapperFactory: MapperFactory;
    plugins: LanguagePlugin<T>[];
    scripts: {
        get(id: T, includeFsFiles?: boolean, shouldRegister?: boolean): SourceScript<T> | undefined;
        set(id: T, snapshot: IScriptSnapshot, languageId?: string, plugins?: LanguagePlugin<T>[]): SourceScript<T> | undefined;
        delete(id: T): void;
        fromVirtualCode(virtualCode: VirtualCode): SourceScript<T>;
    };
    maps: {
        get(virtualCode: VirtualCode, sourceScript: SourceScript<T>): Mapper;
        forEach(virtualCode: VirtualCode): Generator<[sourceScript: SourceScript<T>, map: Mapper]>;
    };
    linkedCodeMaps: {
        get(virtualCode: VirtualCode): LinkedCodeMap | undefined;
    };
}
export interface SourceScript<T = unknown> {
    id: T;
    languageId: string;
    snapshot: IScriptSnapshot;
    targetIds: Set<T>;
    associatedIds: Set<T>;
    associatedOnly: boolean;
    isAssociationDirty?: boolean;
    generated?: {
        root: VirtualCode;
        languagePlugin: LanguagePlugin<T>;
        embeddedCodes: Map<string, VirtualCode>;
    };
}
export type CodeMapping = Mapping<CodeInformation>;
export interface VirtualCode {
    id: string;
    languageId: string;
    snapshot: IScriptSnapshot;
    mappings: CodeMapping[];
    associatedScriptMappings?: Map<unknown, CodeMapping[]>;
    embeddedCodes?: VirtualCode[];
    linkedCodeMappings?: Mapping[];
}
/**
 * CodeInformation is a configuration object attached to each CodeMapping (between source code and generated code,
 * e.g. between the template code in a .vue file and the type-checkable TS code generated from it) that
 * determines what code/language features are expected to be available for the mapping.
 *
 * Due to the dynamic nature of code generation and the fact that, for example, things like Code Actions
 * and auto-complete shouldn't be triggerable on certain "in-between" regions of generated code, we need
 * a way to shut off certain features in certain regions, while leaving them enabled in others.
 */
export interface CodeInformation {
    /** virtual code is expected to support verification, where verification includes:
     *
     * - diagnostics (syntactic, semantic, and others, such as those generated by the TypeScript language service on generated TS code)
     * - code actions (refactorings, quick fixes,etc.)
     */
    verification?: boolean | {
        /**
         * when present, `shouldReport` callback is invoked to determine whether a diagnostic
         * raised in the generated code should be propagated back to the original source code.
         * Note that when this callback is present, diagnostic processing (e.g. typechecking) will
         * still be performed, but the results will not be reported back to the original source code. */
        shouldReport?(source: string | undefined, code: string | number | undefined): boolean;
    };
    /** virtual code is expected to support assisted completion */
    completion?: boolean | {
        isAdditional?: boolean;
        onlyImport?: boolean;
    };
    /** virtual code is expected correctly reflect semantic of the source code. Specifically this controls the following langauge features:
     *
     * - hover
     * - inlay hints
     * - code lens
     * - semantic tokens
     * - others
     *
     * Note that semantic diagnostics (e.g. TS type-checking) are covered by the `verification` property above.
     */
    semantic?: boolean | {
        shouldHighlight?(): boolean;
    };
    /** virtual code is expected correctly reflect reference relationships of the source code */
    navigation?: boolean | {
        shouldHighlight?(): boolean;
        shouldRename?(): boolean;
        resolveRenameNewName?(newName: string): string;
        resolveRenameEditText?(newText: string): string;
    };
    /** virtual code is expected correctly reflect the structural information of the source code */
    structure?: boolean;
    /** virtual code is expected correctly reflect the format information of the source code */
    format?: boolean;
}
export interface LanguagePlugin<T = unknown, K extends VirtualCode = VirtualCode> {
    /**
     * For files that are not opened in the IDE, the language ID will not be synchronized to the language server, so a hook is needed to parse the language ID of files that are known extension but not opened in the IDE.
     */
    getLanguageId(scriptId: T): string | undefined;
    /**
     * Generate a virtual code.
     */
    createVirtualCode?(scriptId: T, languageId: string, snapshot: IScriptSnapshot, ctx: CodegenContext<T>): K | undefined;
    /**
     * Incremental update a virtual code. If not provide, call createVirtualCode again.
     */
    updateVirtualCode?(scriptId: T, virtualCode: K, newSnapshot: IScriptSnapshot, ctx: CodegenContext<T>): K | undefined;
    /**
     * Cleanup a virtual code.
     */
    disposeVirtualCode?(scriptId: T, virtualCode: K): void;
    /**
     * Some file types should not be parsed or processed as TypeScript files,
     * as they are used only as sources for generated files.
     *
     * This functionality is required only in TS plugin mode.
     */
    isAssociatedFileOnly?(scriptId: T, languageId: string): boolean;
}
export interface CodegenContext<T = unknown> {
    getAssociatedScript(scriptId: T): SourceScript<T> | undefined;
}
export interface IScriptSnapshot {
    /** Gets a portion of the script snapshot specified by [start, end). */
    getText(start: number, end: number): string;
    /** Gets the length of this script snapshot. */
    getLength(): number;
    /**
     * Gets the TextChangeRange that describe how the text changed between this text and
     * an older version.  This information is used by the incremental parser to determine
     * what sections of the script need to be re-parsed.  'undefined' can be returned if the
     * change range cannot be determined.  However, in that case, incremental parsing will
     * not happen and the entire document will be re - parsed.
     */
    getChangeRange(oldSnapshot: IScriptSnapshot): TextChangeRange | undefined;
    /** Releases all resources held by this script snapshot */
    dispose?(): void;
}
export interface TextChangeRange {
    span: TextSpan;
    newLength: number;
}
export interface TextSpan {
    start: number;
    length: number;
}
