/// <reference types="node" />
import { Select, ColumnRef } from 'node-sql-parser';
import { ParsedUrlQueryInput } from 'querystring';
import { UrlObject } from 'url';

type Maybe<T> = T | undefined | null;

declare function compareArray(arr1: string[], arr2: string[]): boolean;

declare const oneHour: number;
declare function getUTCDateAndTimeString(date: Date): string;
declare function getDateString(date: Date): string;
declare function getUTCDateString(date: Date): string;
declare function getUTCTimeString(date: Date): string;
declare function getNow(): Date;
declare function getDateMinusHours(date: Date, hours: number): Date;
declare function getUTCNowDateString(): string;
declare function getLongDateTimeString(d: Date): string;
declare function getTimeWithSeconds(date: Date): string;
declare function getTimeAgoString(oldDateTime: number): string;
declare function areTimeAgosEqual(a: Date, b: Date): boolean;
declare function convertToUTCDate(d: Date): Date;

declare function dedupe<T>(arr: T[]): T[];

/**
 * enumKeys takes an enum and returns an array of strongly typed keys. Useful to iterate over string enums.
 * @param obj The enum
 * @returns An array of strong typed keys
 * @example
 *
 * enum MyEnum {
 *  Key1 = "value1",
 *  Key2 = "value2",
 *  Key3 = "value3"
 * }
 *
 * // ks's type is ("Key1" || "Key2" || "Key3")[]
 * const ks = enumKeys(MyEnum);
 *
 * // keys' type is MyEnum[]
 * // Unfortunately, we can't do this inside enumKeys because there is no generic type constraint for enums.
 * const keys = ks.map(k => MyEnum[k])
 */
declare function enumKeys<O extends object, K extends keyof O = keyof O>(obj: O): K[];

declare function excerpt(str: string, len?: number): string;

declare function fakeEscapePress(): void;

declare function initialUppercase(s: string): string;

declare enum KeyCodes {
    BACKSPACE = 8,
    TAB = 9,
    ENTER = 13,
    SHIFT = 16,
    CTRL = 17,
    ALT = 18,
    PAUSE = 19,
    CAPS_LOCK = 20,
    ESCAPE = 27,
    SPACE = 32,
    PAGE_UP = 33,
    PAGE_DOWN = 34,
    END = 35,
    HOME = 36,
    LEFT_ARROW = 37,
    UP_ARROW = 38,
    RIGHT_ARROW = 39,
    DOWN_ARROW = 40,
    INSERT = 45,
    DELETE = 46,
    KEY_0 = 48,
    KEY_1 = 49,
    KEY_2 = 50,
    KEY_3 = 51,
    KEY_4 = 52,
    KEY_5 = 53,
    KEY_6 = 54,
    KEY_7 = 55,
    KEY_8 = 56,
    KEY_9 = 57,
    KEY_A = 65,
    KEY_B = 66,
    KEY_C = 67,
    KEY_D = 68,
    KEY_E = 69,
    KEY_F = 70,
    KEY_G = 71,
    KEY_H = 72,
    KEY_I = 73,
    KEY_J = 74,
    KEY_K = 75,
    KEY_L = 76,
    KEY_M = 77,
    KEY_N = 78,
    KEY_O = 79,
    KEY_P = 80,
    KEY_Q = 81,
    KEY_R = 82,
    KEY_S = 83,
    KEY_T = 84,
    KEY_U = 85,
    KEY_V = 86,
    KEY_W = 87,
    KEY_X = 88,
    KEY_Y = 89,
    KEY_Z = 90,
    LEFT_META = 91,
    RIGHT_META = 92,
    SELECT = 93,
    NUMPAD_0 = 96,
    NUMPAD_1 = 97,
    NUMPAD_2 = 98,
    NUMPAD_3 = 99,
    NUMPAD_4 = 100,
    NUMPAD_5 = 101,
    NUMPAD_6 = 102,
    NUMPAD_7 = 103,
    NUMPAD_8 = 104,
    NUMPAD_9 = 105,
    MULTIPLY = 106,
    ADD = 107,
    SUBTRACT = 109,
    DECIMAL = 110,
    DIVIDE = 111,
    F1 = 112,
    F2 = 113,
    F3 = 114,
    F4 = 115,
    F5 = 116,
    F6 = 117,
    F7 = 118,
    F8 = 119,
    F9 = 120,
    F10 = 121,
    F11 = 122,
    F12 = 123,
    NUM_LOCK = 144,
    SCROLL_LOCK = 145,
    SEMICOLON = 186,
    EQUALS = 187,
    COMMA = 188,
    DASH = 189,
    PERIOD = 190,
    FORWARD_SLASH = 191,
    GRAVE_ACCENT = 192,
    OPEN_BRACKET = 219,
    BACK_SLASH = 220,
    CLOSE_BRACKET = 221,
    SINGLE_QUOTE = 222
}

declare const loremer: {
    word: ({ trueSingleWord, minLength, maxLength, matchRegex, }?: {
        trueSingleWord?: boolean | undefined;
        matchRegex?: RegExp | undefined;
        minLength?: number | undefined;
        maxLength?: number | undefined;
    }) => string;
    words: (n: number) => string[];
    resourceNameSegment: () => string;
    sentence: (options?: {
        max?: number | undefined;
        min?: number | undefined;
    }) => string;
    sentences: (n: number) => string[];
    paragraph: () => string;
};

declare function nTimes<T>(n: number, operation: (...args: any[]) => T, args?: Parameters<typeof operation>): T[];
declare function nTimesWithIndex<T>(n: number, operation: (n: number) => T): T[];

declare const NULL_VALUE = "\uF5F2\uEB94NULL\uF5A8\uE6FF";
declare function isNullValue(dv: string): boolean;
declare function getDisplayValue(dv: string): string;
declare function getDisplayValueForApi(dv: string): string | null;

declare function formatNumber(num: number): string;
declare function formatToUsd(num: number): string;
declare function formatToRoundedUsd(num: number): string;

type TableColumn = {
    name: string;
    sourceTable?: Maybe<string>;
};
declare function parseSelectQuery(q: string): Select | null;
declare function requireTableNameForSelect(q: string): string[];
declare function getTableName(q?: string): Maybe<string>;
type Column = {
    expr: ColumnRef;
    as: string | null;
};
type Columns = any[] | "*" | Column[];
declare function getColumns(q: string): Columns | undefined;
declare function convertToSqlWithNewColNames(q: string, cols: string[] | "*", tableName: string): string;
declare function convertToSqlWithNewCols(q: string, cols: TableColumn[] | "*", tableNames?: string[]): string;
declare function convertToSqlWithNewCondition(query: string, column: string, value: string): string;
declare function convertToSqlWithOrderBy(query: string, column: string, type?: "ASC" | "DESC"): string;
declare function queryHasOrderBy(query: string, column: string, type?: "ASC" | "DESC"): boolean;
declare function isMutation(q?: string): boolean;
declare function removeColumnFromQuery(q: string, colNameToRemove: string, cols: TableColumn[]): string;
declare function makeQueryExecutable(q: string): string;
declare function isMultipleQueries(queryString: string): boolean;

declare function pluralize(num: number, str: string): string;

declare function prettyJSON(data: any): string;
declare function prettyJSONText(text: string): string;

declare function randomArrayItem<T>(arr: T[]): T;

declare function randomNum(min: number, max: number): number;

declare function safeJSONParse(text: string): any;

declare function tuplify<T extends any[]>(...elements: T): T;

type Url = string | UrlObject;
/**
 * __Route__
 *
 * `Route` class that handles adding static and dynamic route segments to
 * existing routes. `Route` can be initialized with a "href" string or
 * `UrlObject` and optional "as" string or `UrlObject`.
 *
 * @example
 * const routeA = new Route("/repositories");
 * routeA.hrefPathname() // "/repositories"
 * routeA.addDynamic("ownerName", "my-owner")
 * routeA.hrefPathname() // "repositories/[ownerName]"
 * routeA.asPathname() // "repositories/my-owner"
 *
 * const routeB = new Route(
 *   { pathname: "/repositories/[ownerName]", query: { refName: "main" } },
 *   { pathname: "/repositories/my-owner", query: { refName: "main" } },
 * )
 * routeB.hrefPathname() // "/repositories/[ownerName]"
 * routeB.asPathname() // "repositories/my-owner"
 * routeB.getQuery() // { refName: "main" }
 */
declare class Route {
    href: Url;
    as: Url;
    constructor(href: Url, as?: Url);
    /**
     * __hrefPathname__
     *
     * Gets pathname string from href string or `UrlObject`.
     *
     * @param addFrag Optional route fragment string to add to `href` pathname
     *
     * @returns `href` pathname string, with added route fragment if provided
     *
     * @example
     * const routeA = new Route("/repositories");
     * routeA.hrefPathname() // "/repositories"
     * routeA.hrefPathname("[ownerName]") // "repositories/[ownerName]"
     *
     * const routeB = new Route({ pathname: "/repositories" })
     * routeB.hrefPathname() // "/repositories"
     * routeB.hrefPathname("[ownerName]") // "repositories/[ownerName]"
     */
    hrefPathname(addFrag?: string): string;
    /**
     *  __asPathname__
     *
     * Gets pathname string from as string or `UrlObject`.
     *
     * @param addFrag Optional route fragment string to add to `as` pathname
     *
     * @returns `as` pathname string, with added route fragment if provided
     *
     * @example
     * const routeA = new Route("/repositories");
     * routeA.asPathname() // "/repositories"
     * routeA.asPathname("my-username") // "repositories/my-username"
     *
     * const routeB = new Route(
     *   { pathname: "/repositories/[ownerName]" },
     *   { pathname: "/repositories/my-username" },
     * );
     * routeB.asPathname() // "/repositories/my-username"
     * routeB.asPathname("data") // "repositories/my-username/data"
     */
    asPathname(addFrag?: string): string;
    /**
     * __getQuery__
     *
     * Gets query object from the href `UrlObject`.
     *
     * @returns query object
     *
     * @example
     * const route = new Route("/repositories");
     * route.withQuery({ refName: "main" })
     * route.getQuery() // { refName: "main" }
     */
    getQuery(): string | ParsedUrlQueryInput | undefined | null;
    /**
     * __getHash__
     *
     * Gets hash string from the href `UrlObject`.
     *
     * @returns hash string
     *
     * @example
     * const route = new Route("/repositories");
     * route.withHash("commitA")
     * route.getHash() // "commitA"
     */
    getHash(): string;
    /**
     * __addStatic__
     *
     * Adds static route fragment string to a `Route`. Static route fragments look like:
     * ```ts
     * { href: "/repositories", as: "/repositories" }
     * ```
     * As opposed to dynamic route fragments which look like:
     * ```ts
     * { href: "/[ownerName]", as: "/owner-value" }
     * ```
     *
     * @param pathFrag Route fragment string to add to the url. "/" is automatically prepended.
     *
     * @returns new instance of `Route`
     *
     * @example
     * const route = new Route("/repositories");
     * route.addStatic("data")
     * route.hrefPathname() // "/repositories/data"
     * route.asPathname() // "/repositories/data"
     */
    addStatic(pathFrag: string): Route;
    /**
     * __maybeAddStatic__
     *
     * Maybe adds static route fragment string to a `Route`.
     *
     * @see this.addStatic
     *
     * @param pathFrag Optional route fragment string to add to the url. "/" is automatically prepended.
     *
     * @example
     * const route = new Route("/repositories");
     * route.maybeAddStatic("data")
     * route.hrefPathname() // "/repositories/data"
     * route.maybeAddStatic()
     * route.hrefPathname() // "/repositories"
     */
    maybeAddStatic(pathFrag?: string): Route;
    /**
     * __addDynamic__
     *
     * Adds dynamic route fragment string to a Route.
     * Dynamic route fragments look like:
     * ```ts
     * { href: "/[ownerName]", as: "/owner-value" }
     * ```
     * As opposed to static route fragments which look like:
     *
     * ```ts
     * { href: "/repositories", as: "/repositories" }
     * ```
     *
     * @param param String fragment to add to the href path. This value will be wrapped in square brackets. "/" is automatically prepended.
     * @param as Value of the `param` to be added to the `as` path. "/" is automatically prepended.
     * @param encode Default false. If true, encodes a `as` param value string as a valid component of a Uniform Resource Identifier (URI).
     *
     * @returns new instance of `Route`
     *
     * @example
     * const route = new Route("/repositories");
     * route.addDynamic("ownerName", "my-owner-name")
     * route.hrefPathname() // "/repositories/[ownerName]"
     * route.asPathname() // "/repositories/my-owner-name"
     */
    addDynamic(param: string, as: string, encode?: boolean): Route;
    /**
     * __withQuery__
     *
     * Adds query object to a `Route`. Looks like "?refName=main&active=Tables"
     * when url is formatted.
     *
     * @param q Record with fields that will be added to the query string.
     *
     * @returns new instance of `Route`
     *
     * @example
     * const route = new Route("/repositories/[ownerName]", "/repositories/my-owner");
     * route.withQuery({ refName: "main", active: undefined })
     * route.hrefPathname() // { pathname: "/repositories/[ownerName]", query: { refName: "main" } }
     * route.asPathname() // { pathname: "/repositories/my-owner", query: { refName: "main" } }
     */
    withQuery(q: Record<string, string | undefined | null>): Route;
    /**
     * __withHash__
     *
     * Adds hash string to a `Route`. Looks like "#hash-value" when url is formatted.
     *
     * @param hash Optional hash string
     *
     * @returns new instance of Route
     *
     * @example
     * const route = new Route("/repositories/[ownerName]", "/repositories/my-owner");
     * route.withHash({ commitId: "commitA" })
     * route.hrefPathname() // { pathname: "/repositories/[ownerName]", hash: { commitId: "commitA" } }
     * route.asPathname() // { pathname: "/repositories/my-owner", hash: { commitId: "commitA" } }
     */
    withHash(hash?: string): Route;
}

declare function emailValidator(s: string): {
    isValid: boolean;
    errorMsg: string;
};
declare function usernameValidator(s: string): {
    isValid: boolean;
    errorMsg: string;
    detailedErrorMsg: string;
};

export { KeyCodes, type Maybe, NULL_VALUE, Route, areTimeAgosEqual, compareArray, convertToSqlWithNewColNames, convertToSqlWithNewCols, convertToSqlWithNewCondition, convertToSqlWithOrderBy, convertToUTCDate, dedupe, emailValidator, enumKeys, excerpt, fakeEscapePress, formatNumber, formatToRoundedUsd, formatToUsd, getColumns, getDateMinusHours, getDateString, getDisplayValue, getDisplayValueForApi, getLongDateTimeString, getNow, getTableName, getTimeAgoString, getTimeWithSeconds, getUTCDateAndTimeString, getUTCDateString, getUTCNowDateString, getUTCTimeString, initialUppercase, isMultipleQueries, isMutation, isNullValue, loremer, makeQueryExecutable, nTimes, nTimesWithIndex, oneHour, parseSelectQuery, pluralize, prettyJSON, prettyJSONText, queryHasOrderBy, randomArrayItem, randomNum, removeColumnFromQuery, requireTableNameForSelect, safeJSONParse, tuplify, usernameValidator };
