export interface LintError {
    id: string;
    raw: string;
    code: string;
    evidence: string;
    line: number;
    character: number;
    scope: string;
    reason: string;
    a?: any;
    b?: any;
    c?: any;
    d?: any;
}

export type LintOptions = Record<string, any>;

export interface LintFunction {
    name: string;
    param: any;
    line: number;
    character: number;
    last: number;
    lastcharacter: number;
    metrics: {
        complexity: number;
        parameters: number;
        statements: number;
    };
}

export interface LintUnused {
    name: string;
    line: number;
    character: number;
}

export interface LintData {
    functions?: LintFunction[] | undefined;
    options?: LintOptions | undefined;
    errors?: LintError[] | undefined;
    globals?: string[] | undefined;
    unused?: LintUnused[] | undefined;
    member?: any;
    implieds?: any;
    /* istanbul ignore next */
    json?: any;
}

export type ModuleFunction = (api: ExtensionAPI) => void;

export interface ExtensionAPI {
    readonly isJSON: boolean;
    getOption(name: string): unknown | null;
}

/**
 * @param source The input JavaScript source code.
 * Type: string or an array of strings (each element is interpreted as a newline)
 * @example `JSHINT(["'use strict';", "console.log('hello, world!');"]);`
 *
 * @param options The linting options to use when analyzing the source code.
 * Type: an object whose property names are the desired options to use and whose property values are the configuration values for those properties.
 * @example `JSHINT(mySource, { undef: true });`
 *
 * @param predef variables defined outside of the current file; the behavior of this argument is identical to the globals linting option.
 * Type: an object whose property names are the global variable identifiers and whose property values control whether each variable should be considered read-only
 * @example `JSHINT(mySource, myOptions, { jQuery: false });`
 */
export function JSHINT(source: string | string[], options?: LintOptions, predef?: Record<string, boolean>): boolean;

export namespace JSHINT {
    /** An array of warnings and errors generated by the most recent invocation of JSHINT. */
    const errors: LintError[];

    /** Generate a report containing details about the most recent invocation of JSHINT. */
    function data(): LintData | null | undefined;

    function addModule(func: ModuleFunction): void;

    // Circular reference from jshint.JSHINT
    const jshint: typeof JSHINT;
}
