{"version":3,"file":"index.cjs","sources":["../src/colors.ts","../src/validation.ts","../src/parsing/shared.ts","../src/parsing/json.ts","../src/parsing/search-params.ts","../src/EventEmitter/EventEmitter.ts","../src/version.ts","../src/logging.ts"],"sourcesContent":["/**\n * Color in format #RGB.\n */\nexport type RGBShort = `#${string}`;\n\n/**\n * Color in format #RRGGBB.\n */\nexport type RGB = `#${string}`;\n\n/**\n * Returns true in case, passed value has #RGB format.\n * @param value - value to check.\n */\nexport function isRGBShort(value: string): value is RGBShort {\n  return /^#[\\da-f]{3}$/i.test(value);\n}\n\n/**\n * Returns true in case, passed value has #RRGGBB format.\n * @param value - value to check.\n */\nexport function isRGB(value: string): value is RGB {\n  return /^#[\\da-f]{6}$/i.test(value);\n}\n\n/**\n * Converts passed value to #RRGGBB format. Accepts following color formats:\n * - `#RGB`\n * - `#RRGGBB`\n * - `rgb(1,2,3)`\n * - `rgba(1,2,3,4)`\n * @param value - value to convert.\n * @throws {Error} Passed value does not satisfy any of known RGB color formats.\n */\nexport function toRGB(value: string): RGB {\n  // Remove all spaces.\n  const clean = value.replace(/\\s/g, '');\n\n  // Value already has required format.\n  if (isRGB(clean)) {\n    return clean;\n  }\n\n  // Convert from #RGB.\n  if (isRGBShort(clean)) {\n    let color = '#';\n\n    for (let i = 0; i < 3; i++) {\n      color += clean[1 + i].repeat(2);\n    }\n    return color as RGB;\n  }\n\n  // Example valid values: rgb(0,3,10) rgba(32,114,8,0)\n  const match = clean.match(/^rgb\\((\\d{1,3}),(\\d{1,3}),(\\d{1,3})\\)$/)\n    || clean.match(/^rgba\\((\\d{1,3}),(\\d{1,3}),(\\d{1,3}),\\d{1,3}\\)$/);\n\n  // In case, this didn't work as well, we can't extract RGB color from passed\n  // text.\n  if (match === null) {\n    throw new Error(`Value \"${value}\" does not satisfy any of known RGB color formats.`);\n  }\n\n  // Otherwise, take R, G and B components, convert to hex and create #RRGGBB\n  // string.\n  return match.slice(1).reduce((acc, component) => {\n    const formatted = parseInt(component).toString(16);\n    return acc + (formatted.length === 1 ? '0' : '') + formatted;\n  }, '#') as RGB;\n}\n","/**\n * States that passed value is Record and not Array.\n * @param value - value to check.\n */\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n  return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n","/**\n * Schema expected by parser creators.\n */\nexport interface Schema<T extends string | Parser<any, any>> {\n  [field: string]: T | {\n    type: T;\n    from?: string;\n    optional?: boolean;\n  };\n}\n\n/**\n * Returns optional fields in schema.\n */\nexport type OptionalField<S extends Schema<any>> = {\n  [F in keyof S]: S[F] extends { optional: true } ? F : never;\n}[keyof S];\n\n/**\n * Returns non-optional fields in schema.\n */\nexport type NonOptionalField<S extends Schema<any>> = Exclude<keyof S, OptionalField<S>>;\n\n/**\n * Standard parser definition.\n */\nexport type Parser<V, R> = (value: V) => R;\n\nexport interface SchemaFieldParser<P> {\n  from: string;\n  to: string;\n  optional: boolean;\n  parser: P;\n}\n\n/**\n * Converts schema to array of parsers.\n * @param schema - schema definition.\n * @param knownTypesParses - list of known types and their parsers.\n */\nexport function schemaToParsers<P extends Parser<any, any>,\n  T extends string,\n  S extends Schema<T | P>>(\n  schema: S,\n  knownTypesParses: Record<T, P>\n): SchemaFieldParser<P>[] {\n  return Object.entries(schema).map<SchemaFieldParser<P>>(([to, def]) => {\n    let optional: boolean;\n    let from: string;\n    let parser: P;\n\n    if (typeof def === 'function' || typeof def === 'string') {\n      optional = false;\n      from = to;\n      parser = typeof def === 'function' ? def : knownTypesParses[def];\n    } else {\n      const {optional: _optional = false, from: _from = to, type} = def;\n      optional = _optional;\n      from = _from;\n      parser = typeof type === 'function' ? type : knownTypesParses[type];\n    }\n    return {optional, from, to, parser};\n  })\n}\n","import {isRecord} from '../validation';\nimport {isRGB, RGB} from '../colors';\nimport {\n  NonOptionalField,\n  OptionalField,\n  Parser,\n  Schema,\n  schemaToParsers,\n} from './shared';\n\n/**\n * Information about types, known by JSON parser. Key is type name and value\n * is corresponding parser expected result type.\n */\ninterface KnownTypeMap {\n  string: string;\n  boolean: boolean;\n  number: number;\n  rgb: RGB;\n}\n\n/**\n * Parser known type name.\n */\ntype KnownTypeName = keyof KnownTypeMap;\n\n/**\n * Standard parser definition.\n */\ntype FieldParser<R> = Parser<unknown, R>;\n\n/**\n * Json schema definition.\n */\ntype JsonSchema = Schema<KnownTypeName | FieldParser<any>>;\n\n/**\n * Calculates schema parser result type.\n */\ntype ComputeSchemaValue<Definition> = Definition extends { type: KnownTypeName }\n  ? KnownTypeMap[Definition['type']]\n  : Definition extends { type: FieldParser<infer R> } ? R : never;\n\n/**\n * Result of Json parser perform.\n */\ntype ParserResult<S extends JsonSchema> = {\n  [F in NonOptionalField<S>]: ComputeSchemaValue<S[F]>;\n} & {\n  [F in OptionalField<S>]?: ComputeSchemaValue<S[F]>;\n};\n\n/**\n * Schema parser definition.\n */\ntype SchemaParser<Schema extends JsonSchema> = (value: unknown) => ParserResult<Schema>;\n\n/**\n * Creates parser which uses \"typeof\" function.\n * @param type - known type name.\n */\nfunction createTypeOfParser<Type extends 'string' | 'boolean' | 'number'>(\n  type: Type,\n): FieldParser<KnownTypeMap[Type]> {\n  return value => {\n    if (typeof value !== type) {\n      throw new TypeError(\n        `Unable to parse value ${JSON.stringify(value)} as ${type}.`,\n      );\n    }\n    return value as KnownTypeMap[Type];\n  };\n}\n\n/**\n * Parses Json value as string.\n */\nexport const parseJsonValueAsString = createTypeOfParser('string');\n\n/**\n * Parses Json value as boolean.\n */\nexport const parseJsonValueAsBoolean = createTypeOfParser('boolean');\n\n/**\n * Parses Json value as number.\n */\nexport const parseJsonValueAsNumber = createTypeOfParser('number');\n\n/**\n * Parses Json value as RGB color.\n */\nexport function parseJsonValueAsRgb(value: unknown): RGB {\n  const str = parseJsonValueAsString(value);\n\n  if (!isRGB(str)) {\n    throw new TypeError(`Unable to parse value \"${str}\" as RGB.`);\n  }\n  return str;\n}\n\n/**\n * Parsers used for known types.\n */\nconst knownTypesParses = {\n  string: parseJsonValueAsString,\n  boolean: parseJsonValueAsBoolean,\n  number: parseJsonValueAsNumber,\n  rgb: parseJsonValueAsRgb,\n};\n\n/**\n * Creates new Json parser according to passed schema.\n * @param schema - object schema.\n */\nexport function createJsonParser<S extends JsonSchema>(schema: S): SchemaParser<S> {\n  // Transform schema to array of parsers.\n  const parsers = schemaToParsers<FieldParser<any>, KnownTypeName, S>(\n    schema, knownTypesParses,\n  );\n\n  return value => {\n    let json: any = value;\n\n    // Convert value to JSON in case, it is string. We expect value to be\n    // JSON string.\n    if (typeof json === 'string') {\n      try {\n        json = JSON.parse(json);\n      } catch (e) {\n        throw new TypeError('Value is not JSON object converted to string.');\n      }\n    }\n\n    // We expect json to be usual object.\n    if (!isRecord(json)) {\n      throw new TypeError('Value is not JSON object.');\n    }\n\n    return parsers.reduce((acc, {parser, optional, from, to}) => {\n      const value = json[from];\n\n      if (value === undefined) {\n        if (!optional) {\n          throw new Error(`Unable to parse field \"${from}\". Value is empty.`);\n        }\n        return acc;\n      }\n      try {\n        const parsed = parser(value);\n\n        if (parsed !== undefined) {\n          (acc as any)[to] = parsed;\n        }\n      } catch (cause) {\n        throw new Error(`Unable to parse field \"${from}\"`, {cause})\n      }\n      return acc;\n    }, {} as ParserResult<S>);\n  };\n}\n","import {\n  NonOptionalField,\n  OptionalField,\n  Parser,\n  Schema,\n  schemaToParsers,\n} from './shared';\n\n/**\n * Information about types, known by search params parser. Key is type name\n * and value is corresponding parser expected result type.\n */\ninterface KnownTypeMap {\n  string: string;\n  date: Date;\n}\n\n/**\n * Parser known type name.\n */\ntype KnownTypeName = keyof KnownTypeMap;\n\n/**\n * Standard parser definition.\n */\ntype FieldParser<R> = Parser<string, R>;\n\n/**\n * Search params schema definition.\n */\ntype SearchParamsSchema = Schema<KnownTypeName | FieldParser<any>>;\n\n/**\n * Calculates schema parser result type.\n */\ntype ComputeSchemaValue<Definition> = Definition extends { type: KnownTypeName }\n  ? KnownTypeMap[Definition['type']]\n  : Definition extends { type: FieldParser<infer R> } ? R : never;\n\n/**\n * Result of search params parser perform.\n */\ntype ParserResult<S extends SearchParamsSchema> = {\n  [F in NonOptionalField<S>]: ComputeSchemaValue<S[F]>;\n} & {\n  [F in OptionalField<S>]?: ComputeSchemaValue<S[F]>;\n};\n\n/**\n * Search params parser definition.\n */\ntype SchemaParser<Schema extends SearchParamsSchema> =\n  (value: unknown) => ParserResult<Schema>;\n\n/**\n * Parsers used for known types.\n */\nconst knownTypesParses = {\n  string: (value: string) => value,\n  date: (value: string) => {\n    if (value !== '') {\n      const asInt = Number(value);\n      const date = new Date(asInt.toString() === value ? asInt * 1000 : value);\n\n      if (date.toString() !== 'Invalid Date') {\n        return date;\n      }\n    }\n    throw new TypeError(`Unable to parse value \"${value}\" as Date.`);\n  },\n};\n\n/**\n * Creates new search params parser according to passed schema.\n * @param schema - object schema.\n */\nexport function createSearchParamsParser<S extends SearchParamsSchema>(\n  schema: S,\n): SchemaParser<S> {\n  // Transform schema to array of parsers.\n  const parsers = schemaToParsers<FieldParser<any>, KnownTypeName, S>(\n    schema, knownTypesParses,\n  );\n\n  return value => {\n    if (typeof value !== 'string' && !(value instanceof URLSearchParams)) {\n      throw new TypeError('Value has not processable type.');\n    }\n    const params = typeof value === 'string'\n      ? new URLSearchParams(value)\n      : value;\n\n    return parsers.reduce((acc, {parser, to, optional, from}) => {\n      const value = params.get(from);\n\n      if (value === null) {\n        if (!optional) {\n          throw new TypeError(`Unable to parse field \"${from}\". Value is empty.`);\n        }\n        return acc;\n      }\n      try {\n        const parsed = parser(value);\n\n        if (parsed !== undefined) {\n          (acc as any)[to] = parsed;\n        }\n      } catch (cause) {\n        throw new Error(`Unable to parse field \"${from}\"`, {cause})\n      }\n      return acc;\n    }, {} as ParserResult<S>);\n  };\n}\n","import {\n  AnySubscribeListener,\n  EmptyEventName,\n  EventListener, EventName,\n  EventParams, NonEmptyEventName,\n} from './types';\n\n/**\n * EventEmitter represents classic JavaScript event emitter. It allows usage\n * both known and unknown events.\n */\nexport class EventEmitter<Schema> {\n  private listeners: Record<string, EventListener<any[]>[]> = {};\n  private subscribeListeners: AnySubscribeListener<Schema>[] = [];\n\n  /**\n   * Emits known event which has no parameters.\n   * @param event - event name.\n   */\n  emit<E extends EmptyEventName<Schema>>(event: E): void;\n\n  /**\n   * Emits known event which has parameters.\n   * @param event - event name.\n   * @param args - list of event listener arguments.\n   */\n  emit<E extends NonEmptyEventName<Schema>>(\n    event: E,\n    ...args: EventParams<Schema[E]>\n  ): void;\n\n  emit(event: string, ...args: any[]): void {\n    // Emit global listeners.\n    this.subscribeListeners.forEach(l => (l as any)(event, ...args));\n\n    // Emit event specific listeners.\n    const listeners = this.listeners[event];\n    if (listeners === undefined) {\n      return;\n    }\n    listeners.forEach(l => l(...args));\n  }\n\n  /**\n   * Adds new known event to be listened.\n   * @param event - event name.\n   * @param listener - event listener.\n   */\n  on<E extends EventName<Schema>>(\n    event: E,\n    listener: EventListener<Schema[E]>,\n  ): void;\n\n  on(event: string, listener: (...args: any[]) => any): void {\n    const listeners = this.listeners[event];\n\n    if (listeners === undefined) {\n      this.listeners[event] = [listener];\n    } else {\n      listeners.push(listener);\n    }\n  }\n\n  /**\n   * Removes listener of known event.\n   * @param event - event name.\n   * @param listener - event listener.\n   */\n  off<E extends EventName<Schema>>(\n    event: E,\n    listener: EventListener<Schema[E]>,\n  ): void;\n\n  off(event: string, listener: (...args: any[]) => any): void {\n    const listeners = this.listeners[event];\n    if (listeners === undefined) {\n      return;\n    }\n\n    const idx = listeners.indexOf(listener);\n    if (idx >= 0) {\n      listeners.splice(idx, 1);\n    }\n  }\n\n  /**\n   * Subscribes to any events appearing.\n   * @param listener - events listener.\n   */\n  subscribe(listener: AnySubscribeListener<Schema>) {\n    this.subscribeListeners.push(listener);\n  }\n\n  /**\n   * Removes listener from global listeners.\n   * @param listener - events listener.\n   */\n  unsubscribe(listener: AnySubscribeListener<Schema>) {\n    const idx = this.subscribeListeners.indexOf(listener);\n    if (idx >= 0) {\n      this.subscribeListeners.splice(idx, 1);\n    }\n  }\n}\n","/**\n * Web App version in format like \"\\d+.\\d+\".\n */\nexport type Version = string;\n\n/**\n * Returns 1 in case, version \"a\" is greater than \"b\".\n * Returns 0 in case, version \"a\" equal to \"b\".\n * Returns -1 in case, version \"a\" is lower than \"b\".\n * @param a - first version.\n * @param b - second version.\n */\nexport function compareVersions(a: string, b: string): number {\n  const aParts = a.split('.');\n  const bParts = b.split('.');\n  const len = Math.max(aParts.length, bParts.length);\n\n  // Iterate over each part of version and compare them. In case, part is\n  // missing, assume its value is equal to 0.\n  for (let i = 0; i < len; i++) {\n    const aVal = parseInt(aParts[i] || '0');\n    const bVal = parseInt(bParts[i] || '0');\n\n    if (aVal === bVal) {\n      continue;\n    }\n    return aVal > bVal ? 1 : -1;\n  }\n  return 0;\n}\n","/**\n * Message log level.\n */\nexport type LogLevel = 'log' | 'error' | 'warn';\n\n/**\n * Logs message into console.\n * @param level - log level.\n * @param args - arguments.\n */\nexport function log(level: LogLevel, ...args: any[]): void {\n  const now = new Date();\n  const date = Intl\n    .DateTimeFormat('en-GB', {\n      hour: '2-digit',\n      minute: '2-digit',\n      second: '2-digit',\n      fractionalSecondDigits: 3,\n      timeZone: 'UTC',\n    })\n    .format(now);\n\n  console[level](`[${date}]`, ...args);\n}\n"],"names":["isRGBShort","value","test","isRGB","isRecord","Array","isArray","schemaToParsers","schema","knownTypesParses","Object","entries","map","to","def","optional","from","parser","_optional","_from","type","createTypeOfParser","TypeError","JSON","stringify","parseJsonValueAsString","parseJsonValueAsBoolean","parseJsonValueAsNumber","parseJsonValueAsRgb","str","string","boolean","number","rgb","date","asInt","Number","Date","toString","listeners","subscribeListeners","emit","event","args","this","forEach","l","undefined","on","listener","push","off","idx","indexOf","splice","subscribe","unsubscribe","a","b","aParts","split","bParts","len","Math","max","length","i","aVal","parseInt","bVal","parsers","json","parse","e","reduce","acc","Error","parsed","cause","URLSearchParams","params","get","level","now","Intl","DateTimeFormat","hour","minute","second","fractionalSecondDigits","timeZone","format","console","clean","replace","color","repeat","match","slice","component","formatted"],"mappings":"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"}