helpers.ts 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. // =============================================================================
  2. // Helper functions
  3. // =============================================================================
  4. import { ALL_WEEKDAYS, WeekdayStr } from './weekday'
  5. export const isPresent = function <T>(
  6. value?: T | null | undefined
  7. ): value is T {
  8. return value !== null && value !== undefined
  9. }
  10. export const isNumber = function (value: unknown): value is number {
  11. return typeof value === 'number'
  12. }
  13. export const isWeekdayStr = function (value: unknown): value is WeekdayStr {
  14. return typeof value === 'string' && ALL_WEEKDAYS.includes(value as WeekdayStr)
  15. }
  16. export const isArray = Array.isArray
  17. /**
  18. * Simplified version of python's range()
  19. */
  20. export const range = function (start: number, end: number = start): number[] {
  21. if (arguments.length === 1) {
  22. end = start
  23. start = 0
  24. }
  25. const rang = []
  26. for (let i = start; i < end; i++) rang.push(i)
  27. return rang
  28. }
  29. export const clone = function <T>(array: T[]): T[] {
  30. return ([] as T[]).concat(array)
  31. }
  32. export const repeat = function <T>(value: T | T[], times: number): (T | T[])[] {
  33. let i = 0
  34. const array: (T | T[])[] = []
  35. if (isArray(value)) {
  36. for (; i < times; i++) array[i] = ([] as T[]).concat(value)
  37. } else {
  38. for (; i < times; i++) array[i] = value
  39. }
  40. return array
  41. }
  42. export const toArray = function <T>(item: T | T[]): T[] {
  43. if (isArray(item)) {
  44. return item
  45. }
  46. return [item]
  47. }
  48. export function padStart(
  49. item: string | number,
  50. targetLength: number,
  51. padString = ' '
  52. ) {
  53. const str = String(item)
  54. targetLength = targetLength >> 0
  55. if (str.length > targetLength) {
  56. return String(str)
  57. }
  58. targetLength = targetLength - str.length
  59. if (targetLength > padString.length) {
  60. padString += repeat(padString, targetLength / padString.length)
  61. }
  62. return padString.slice(0, targetLength) + String(str)
  63. }
  64. /**
  65. * Python like split
  66. */
  67. export const split = function (str: string, sep: string, num: number) {
  68. const splits = str.split(sep)
  69. return num
  70. ? splits.slice(0, num).concat([splits.slice(num).join(sep)])
  71. : splits
  72. }
  73. /**
  74. * closure/goog/math/math.js:modulo
  75. * Copyright 2006 The Closure Library Authors.
  76. * The % operator in JavaScript returns the remainder of a / b, but differs from
  77. * some other languages in that the result will have the same sign as the
  78. * dividend. For example, -1 % 8 == -1, whereas in some other languages
  79. * (such as Python) the result would be 7. This function emulates the more
  80. * correct modulo behavior, which is useful for certain applications such as
  81. * calculating an offset index in a circular list.
  82. *
  83. * @param {number} a The dividend.
  84. * @param {number} b The divisor.
  85. * @return {number} a % b where the result is between 0 and b (either 0 <= x < b
  86. * or b < x <= 0, depending on the sign of b).
  87. */
  88. export const pymod = function (a: number, b: number) {
  89. const r = a % b
  90. // If r and b differ in sign, add b to wrap the result to the correct sign.
  91. return r * b < 0 ? r + b : r
  92. }
  93. /**
  94. * @see: <http://docs.python.org/library/functions.html#divmod>
  95. */
  96. export const divmod = function (a: number, b: number) {
  97. return { div: Math.floor(a / b), mod: pymod(a, b) }
  98. }
  99. export const empty = function <T>(obj: T[] | null | undefined) {
  100. return !isPresent(obj) || obj.length === 0
  101. }
  102. /**
  103. * Python-like boolean
  104. *
  105. * @return {Boolean} value of an object/primitive, taking into account
  106. * the fact that in Python an empty list's/tuple's
  107. * boolean value is False, whereas in JS it's true
  108. */
  109. export const notEmpty = function <T>(obj: T[] | null | undefined): obj is T[] {
  110. return !empty(obj)
  111. }
  112. /**
  113. * Return true if a value is in an array
  114. */
  115. export const includes = function <T>(arr: T[] | null | undefined, val: T) {
  116. return notEmpty(arr) && arr.indexOf(val) !== -1
  117. }