|
/** |
|
* Extensões de objetos nativos |
|
* As declarações TypeScript estão em src/extends.d.ts |
|
*/ |
|
|
|
export {}; |
|
|
|
Object.defineProperty(Array.prototype, 'contains', { |
|
enumerable: false, |
|
writable: false, |
|
configurable: false, |
|
value: function contains<T>(elem: T): boolean { |
|
return this.indexOf(elem) !== -1; |
|
}, |
|
}); |
|
|
|
Object.defineProperty(Array.prototype, 'containsIf', { |
|
enumerable: false, |
|
writable: false, |
|
configurable: false, |
|
value: function containsIf<T>(callback: (elem: T, index: number) => boolean): boolean { |
|
return this.findIndex(callback) !== -1; |
|
}, |
|
}); |
|
|
|
Object.defineProperty(Array.prototype, 'groupIntoMap', { |
|
enumerable: false, |
|
writable: false, |
|
configurable: false, |
|
value: function groupIntoMap<T, K extends keyof T>(fieldName: K): Map<T[K], T[]> { |
|
const groups = new Map<T[K], T[]>(); |
|
for (const elem of this) { |
|
if (!groups.has(elem[fieldName])) { |
|
groups.set(elem[fieldName], [elem]); |
|
} else { |
|
groups.get(elem[fieldName])!.push(elem); |
|
} |
|
} |
|
return groups; |
|
}, |
|
}); |
|
|
|
Object.defineProperty(Array.prototype, 'groupIntoObject', { |
|
enumerable: false, |
|
writable: false, |
|
configurable: false, |
|
value: function groupIntoObject< // https://stackoverflow.com/a/71068491 |
|
T extends Record<K, PropertyKey>, |
|
K extends keyof {[P in keyof T as T[P] extends PropertyKey ? P : never]: any;}, // eslint-disable-line @typescript-eslint/no-explicit-any |
|
>(fieldName: K): Record<T[K], T[]> { |
|
return this.reduce((accum: Record<T[K], T[]>, item: T) => { |
|
if (accum[item[fieldName]] === undefined) { |
|
accum[item[fieldName]] = [item]; |
|
} else { |
|
accum[item[fieldName]].push(item); |
|
} |
|
return accum; |
|
}, {} as Record<T[K], T[]>); |
|
}, |
|
}); |
|
|
|
Object.defineProperty(Array.prototype, 'isEmpty', { |
|
enumerable: false, |
|
writable: false, |
|
configurable: false, |
|
value: function isEmpty(): boolean { |
|
return this.length === 0; |
|
}, |
|
}); |
|
|
|
Object.defineProperty(Array.prototype, 'isNotEmpty', { |
|
enumerable: false, |
|
writable: false, |
|
configurable: false, |
|
value: function isNotEmpty(): boolean { |
|
return this.length > 0; |
|
}, |
|
}); |
|
|
|
Object.defineProperty(Array.prototype, 'last', { |
|
enumerable: false, |
|
writable: false, |
|
configurable: false, |
|
value: function last<T>(): T | undefined { |
|
return this.length === 0 ? undefined : this[this.length - 1]; |
|
}, |
|
}); |
|
|
|
Object.defineProperty(Array.prototype, 'remove', { |
|
enumerable: false, |
|
writable: false, |
|
configurable: false, |
|
value: function remove<T>(elem: T): void { |
|
for (;;) { |
|
const idx = this.indexOf(elem); |
|
if (idx === -1) break; |
|
this.splice(idx, 1); |
|
} |
|
}, |
|
}); |
|
|
|
Object.defineProperty(Array.prototype, 'removeIf', { |
|
enumerable: false, |
|
writable: false, |
|
configurable: false, |
|
value: function removeIf<T>(callback: (elem: T, index: number) => boolean): void { |
|
let idx = 0; |
|
while (idx < this.length) { |
|
if (callback(this[idx], idx)) { |
|
this.splice(idx, 1); |
|
} else { |
|
++idx; |
|
} |
|
} |
|
}, |
|
}); |
|
|
|
Object.defineProperty(Array.prototype, 'replaceIf', { |
|
enumerable: false, |
|
writable: false, |
|
configurable: false, |
|
value: function replaceIf<T>( |
|
callback: (elem: T, index: number) => boolean, |
|
newVal: T, |
|
): void { |
|
for (let i = 0; i < this.length; ++i) { |
|
if (callback(this[i], i)) { |
|
this[i] = newVal; |
|
} |
|
} |
|
}, |
|
}); |
|
|
|
Object.defineProperty(Array.prototype, 'unique', { |
|
enumerable: false, |
|
writable: false, |
|
configurable: false, |
|
value: function unique<T>(): T[] { |
|
const uniques = [] as T[]; |
|
for (const elem of this) { |
|
if (!uniques.contains(elem)) |
|
uniques.push(elem); |
|
} |
|
return uniques; |
|
}, |
|
}); |
|
|
|
//------------------------------------------------------------------------------ |
|
|
|
Object.defineProperty(Date.prototype, 'addDays', { |
|
enumerable: false, |
|
writable: false, |
|
configurable: false, |
|
value: function addDays(numDays: number): void { |
|
this.setUTCDate(this.getUTCDate() + numDays); |
|
}, |
|
}); |
|
|
|
Object.defineProperty(Date.prototype, 'fmtDataHoraCurta', { |
|
enumerable: false, |
|
writable: false, |
|
configurable: false, |
|
value: function fmtDataHoraCurta(): string { |
|
return this.getNomeDiaDaSemanaAbrev().capitalize() |
|
+ ' ' + this.getDate().toString().padStart(2, '0') |
|
+ '/' + (this.getMonth() + 1).toString().padStart(2, '0') |
|
+ '/' + this.getFullYear() |
|
+ ' ' + this.getHours().toString().padStart(2, '0') |
|
+ ':' + this.getMinutes().toString().padStart(2, '0'); |
|
}, |
|
}); |
|
|
|
Object.defineProperty(Date.prototype, 'getDaysInTheMonth', { |
|
enumerable: false, |
|
writable: false, |
|
configurable: false, |
|
value: function getDaysInTheMonth(): number { |
|
return new Date(this.getFullYear(), this.getMonth() + 1, 0).getDate(); |
|
}, |
|
}); |
|
|
|
Object.defineProperty(Date.prototype, 'getNextMonth', { |
|
enumerable: false, |
|
writable: false, |
|
configurable: false, |
|
value: function getNextMonth(numMonths: number): Date { |
|
return new Date(this.getFullYear(), this.getMonth() + numMonths, 1); |
|
}, |
|
}); |
|
|
|
Object.defineProperty(Date.prototype, 'getNextYear', { |
|
enumerable: false, |
|
writable: false, |
|
configurable: false, |
|
value: function getNextMonth(numYears: number): Date { |
|
return new Date(this.getFullYear() + numYears, this.getMonth(), 1); |
|
}, |
|
}); |
|
|
|
|
|
Object.defineProperty(Date.prototype, 'getNomeDiaDaSemana', { |
|
enumerable: false, |
|
writable: false, |
|
configurable: false, |
|
value: function getNomeDiaDaSemana(): string { |
|
return ['domingo', 'segunda', 'terça', 'quarta', 'quinta', 'sexta', 'sábado'][this.getDay()]; |
|
}, |
|
}); |
|
|
|
Object.defineProperty(Date.prototype, 'getNomeDiaDaSemanaAbrev', { |
|
enumerable: false, |
|
writable: false, |
|
configurable: false, |
|
value: function getNomeDiaDaSemanaAbrev(): string { |
|
return ['dom', 'seg', 'ter', 'qua', 'qui', 'sex', 'sáb'][this.getDay()]; |
|
}, |
|
}); |
|
|
|
Object.defineProperty(Date.prototype, 'getNomeMes', { |
|
enumerable: false, |
|
writable: false, |
|
configurable: false, |
|
value: function getNomeMes(): string { |
|
return ['janeiro', 'fevereiro', 'março', 'abril', 'maio', 'junho', |
|
'julho', 'agosto', 'setembro', 'outubro', 'novembro', 'dezembro'][this.getMonth()]; |
|
}, |
|
}); |
|
|
|
//------------------------------------------------------------------------------ |
|
|
|
Object.defineProperty(HTMLCollection.prototype, 'forEach', { |
|
enumerable: false, |
|
writable: false, |
|
configurable: false, |
|
value: function forEach<T>(callback: (elem: T, index: number) => void): void { |
|
for (let i = 0; i < this.length; ++i) |
|
callback(this[i], i); |
|
}, |
|
}); |
|
|
|
Object.defineProperty(HTMLCollection.prototype, 'isEmpty', { |
|
enumerable: false, |
|
writable: false, |
|
configurable: false, |
|
value: function isEmpty(): boolean { |
|
return this.length === 0; |
|
}, |
|
}); |
|
|
|
Object.defineProperty(HTMLCollection.prototype, 'isNotEmpty', { |
|
enumerable: false, |
|
writable: false, |
|
configurable: false, |
|
value: function isNotEmpty(): boolean { |
|
return this.length > 0; |
|
}, |
|
}); |
|
|
|
//------------------------------------------------------------------------------ |
|
|
|
Object.defineProperty(Map.prototype, 'isEmpty', { |
|
enumerable: false, |
|
writable: false, |
|
configurable: false, |
|
value: function isEmpty(): boolean { |
|
return this.size === 0; |
|
}, |
|
}); |
|
|
|
Object.defineProperty(Map.prototype, 'isNotEmpty', { |
|
enumerable: false, |
|
writable: false, |
|
configurable: false, |
|
value: function isNotEmpty(): boolean { |
|
return this.size > 0; |
|
}, |
|
}); |
|
|
|
Object.defineProperty(Map.prototype, 'keyCount', { |
|
enumerable: false, |
|
writable: false, |
|
configurable: false, |
|
value: function keyCount(): number { |
|
return Array.from(this.keys()).length; |
|
}, |
|
}); |
|
|
|
Object.defineProperty(Map.prototype, 'mapIntoArray', { |
|
enumerable: false, |
|
writable: false, |
|
configurable: false, |
|
value: function mapIntoArray<K, V, U>(callback: (key: K, value: V, index: number) => U): U[] { |
|
const result = [] as U[]; |
|
let count = 0; |
|
for (const [key, val] of this) { |
|
result.push(callback(key, val, count++)); |
|
} |
|
return result; |
|
}, |
|
}); |
|
|
|
Object.defineProperty(Map.prototype, 'mapKeys', { |
|
enumerable: false, |
|
writable: false, |
|
configurable: false, |
|
value: function mapKeys<K, V, U>(callback: (key: K, value: V) => U): Map<U, V> { |
|
const result = new Map<U, V>(); |
|
for (const [key, _val] of this) { |
|
const val = this.get(key); |
|
result.set(callback(key, val), val); |
|
} |
|
return result; |
|
}, |
|
}); |
|
|
|
Object.defineProperty(Map.prototype, 'mapValues', { |
|
enumerable: false, |
|
writable: false, |
|
configurable: false, |
|
value: function mapValues<K, V, U>(callback: (key: K, value: V) => U): Map<K, U> { |
|
const result = new Map<K, U>(); |
|
for (const [key, val] of this) { |
|
result.set(key, callback(key, val)); |
|
} |
|
return result; |
|
}, |
|
}); |
|
|
|
Object.defineProperty(Map.prototype, 'reduce', { |
|
enumerable: false, |
|
writable: false, |
|
configurable: false, |
|
value: function reduce<K, V, U>( |
|
callback: (accumulator: U, key: K, value: V, index: number) => U, |
|
initialValue: U, |
|
): U { |
|
let accum = initialValue; |
|
let count = 0; |
|
for (const [key, val] of this) { |
|
accum = callback(accum, key, val, count++); |
|
} |
|
return accum; |
|
}, |
|
}); |
|
|
|
Object.defineProperty(Map.prototype, 'sortKeys', { |
|
enumerable: false, |
|
writable: false, |
|
configurable: false, |
|
value: function sortKeys<K, V>(compareFn: (a: K, b: K) => number): Map<K, V> { |
|
const keys = Array.from(this.keys()) as K[]; |
|
const tmpMap = new Map<K, V>(); |
|
for (const sortedKey of keys.sort(compareFn)) { |
|
tmpMap.set(sortedKey, this.get(sortedKey)); |
|
} |
|
this.clear(); |
|
for (const [key, val] of tmpMap.entries()) { |
|
this.set(key, val); |
|
} |
|
return this; |
|
}, |
|
}); |
|
|
|
//------------------------------------------------------------------------------ |
|
|
|
Object.defineProperty(Number.prototype, 'fmtBr', { |
|
enumerable: false, |
|
writable: false, |
|
configurable: false, |
|
value: function fmtBr(casasDecimais = 0): string { |
|
return this.toLocaleString('pt-BR', { |
|
minimumFractionDigits: casasDecimais, |
|
maximumFractionDigits: casasDecimais, |
|
}); |
|
}, |
|
}); |
|
|
|
Object.defineProperty(Number.prototype, 'lpad', { |
|
enumerable: false, |
|
writable: false, |
|
configurable: false, |
|
value: function lpad(minLength: number): string { |
|
return this.toString().padStart(minLength, '0'); |
|
}, |
|
}); |
|
|
|
Object.defineProperty(Number.prototype, 'round', { |
|
enumerable: false, |
|
writable: false, |
|
configurable: false, |
|
value: function round(decimalPlaces: number): number { |
|
return Math.round((this + Number.EPSILON) * Math.pow(10, decimalPlaces)) |
|
/ Math.pow(10, decimalPlaces); |
|
}, |
|
}); |
|
|
|
//------------------------------------------------------------------------------ |
|
|
|
Object.isEmpty = function isEmpty(o: object): boolean { // https://stackoverflow.com/a/28020863/6923555 |
|
return Object.keys(o).length === 0; |
|
}; |
|
|
|
Object.isNotEmpty = function isNotEmpty(o: object): boolean { |
|
return Object.keys(o).length > 0; |
|
}; |
|
|
|
Object.mapIntoArray = function mapIntoArray<K extends PropertyKey, V, U>( |
|
o: Record<K, V>, |
|
callback: (key: K, value: V, index: number) => U, |
|
): U[] { |
|
const arr = []; |
|
let count = 0; |
|
for (const key in o) { |
|
arr.push(callback(key, o[key], count++)); |
|
} |
|
return arr; |
|
}; |
|
|
|
Object.mapValues = function mapValues<K extends PropertyKey, V, U>( |
|
o: Record<K, V>, |
|
callback: (key: K, value: V, index: number) => U, |
|
): Record<K, U> { |
|
const accum = {} as Record<K, U>; |
|
let count = 0; |
|
for (const key in o) { |
|
accum[key] = callback(key, o[key], count++); |
|
} |
|
return accum; |
|
}; |
|
|
|
Object.reduce = function reduce<K extends PropertyKey, V, U>( |
|
o: Record<K, V>, |
|
callback: (accumulator: U, key: K, value: V, index: number) => U, |
|
initialValue: U, |
|
): U { |
|
let accum = initialValue; |
|
let count = 0; |
|
for (const key in o) { |
|
accum = callback(accum, key, o[key], count++); |
|
} |
|
return accum; |
|
}; |
|
|
|
Object.removeIf = function<K extends PropertyKey, V>( |
|
o: Record<K, V>, |
|
callback: (key: K, value: V, index: number) => boolean, |
|
): void { |
|
let count = 0; |
|
for (const key in o) { |
|
if (callback(key, o[key], count++)) |
|
delete o[key]; |
|
} |
|
}; |
|
|
|
//------------------------------------------------------------------------------ |
|
|
|
Object.defineProperty(String.prototype, 'capitalize', { |
|
enumerable: false, |
|
writable: false, |
|
configurable: false, |
|
value: function capitalize(): string { |
|
return this.length === 0 ? '' |
|
: this.charAt(0).toUpperCase() + this.slice(1).toLowerCase(); |
|
}, |
|
}); |
|
|
|
Object.defineProperty(String.prototype, 'contains', { |
|
enumerable: false, |
|
writable: false, |
|
configurable: false, |
|
value: function contains(substr: string): boolean { |
|
return this.indexOf(substr) !== -1; |
|
}, |
|
}); |
|
|
|
Object.defineProperty(String.prototype, 'isBlank', { |
|
enumerable: false, |
|
writable: false, |
|
configurable: false, |
|
value: function isBlank(): boolean { |
|
return this.trim().length === 0; |
|
}, |
|
}); |
|
|
|
Object.defineProperty(String.prototype, 'isEmpty', { |
|
enumerable: false, |
|
writable: false, |
|
configurable: false, |
|
value: function isEmpty(): boolean { |
|
return this.length === 0; |
|
}, |
|
}); |
|
|
|
Object.defineProperty(String.prototype, 'isInteger', { |
|
enumerable: false, |
|
writable: false, |
|
configurable: false, |
|
value: function isInteger(): boolean { |
|
if (this.length === 0) return false; |
|
for (let i = 0; i < this.length; ++i) { |
|
const code = this.charCodeAt(i); |
|
const isNum = code >= 48 && code <= 57; // 0 to 9 |
|
if (i === 0) { |
|
if (this[0] !== '-' && !isNum) return false; // first char can be a minus sign |
|
} else { |
|
if (!isNum) return false; |
|
} |
|
} |
|
return true; |
|
}, |
|
}); |
|
|
|
Object.defineProperty(String.prototype, 'isNotBlank', { |
|
enumerable: false, |
|
writable: false, |
|
configurable: false, |
|
value: function isNotBlank(): boolean { |
|
return this.trim().length > 0; |
|
}, |
|
}); |
|
|
|
Object.defineProperty(String.prototype, 'isNotEmpty', { |
|
enumerable: false, |
|
writable: false, |
|
configurable: false, |
|
value: function isNotEmpty(): boolean { |
|
return this.length > 0; |
|
}, |
|
}); |
|
|
|
Object.defineProperty(String.prototype, 'isPositiveInteger', { |
|
enumerable: false, |
|
writable: false, |
|
configurable: false, |
|
value: function isPositiveInteger(): boolean { |
|
if (this.length === 0) return false; |
|
for (let i = 0; i < this.length; ++i) { |
|
const code = this.charCodeAt(i); |
|
const isNum = code >= 48 && code <= 57; // 0 to 9 |
|
if (!isNum) return false; |
|
} |
|
return true; |
|
}, |
|
}); |
|
|
|
Object.defineProperty(String.prototype, 'last', { |
|
enumerable: false, |
|
writable: false, |
|
configurable: false, |
|
value: function last(): string | undefined { |
|
return this.length === 0 ? undefined : this[this.length - 1]; |
|
}, |
|
}); |
|
|
|
//------------------------------------------------------------------------------ |
|
|
|
Object.defineProperty(URLSearchParams.prototype, 'map', { |
|
enumerable: false, |
|
writable: false, |
|
configurable: false, |
|
value: function map<U>(callback: (key: string, value: string, index: number) => U): U[] { |
|
const entries = Array.from(this.entries()) as [string, string][]; |
|
const result = [] as U[]; |
|
let count = 0; |
|
for (const [key, val] of entries) { |
|
result.push(callback(key, val, count++)); |
|
} |
|
return result; |
|
}, |
|
}); |