working rss feed to nostr publish

This commit is contained in:
2023-11-24 00:43:28 -05:00
parent 06edcb57ae
commit 88d2f9cfec
8396 changed files with 783105 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
export default crypto
+2
View File
@@ -0,0 +1,2 @@
export const TextEncoder = window.TextEncoder
export const TextDecoder = window.TextDecoder
Generated Vendored Executable
+128
View File
@@ -0,0 +1,128 @@
/**
* bellajs
* @ndaidong
**/
import {
isObject,
isArray,
isDate,
isString,
hasProperty
} from './utils/detection.js'
export const clone = (val, history = null) => {
const stack = history || new Set()
if (stack.has(val)) {
return val
}
stack.add(val)
if (isDate(val)) {
return new Date(val.valueOf())
}
const copyObject = (o) => {
const oo = Object.create({})
for (const k in o) {
if (hasProperty(o, k)) {
oo[k] = clone(o[k], stack)
}
}
return oo
}
const copyArray = (a) => {
return [...a].map((e) => {
if (isArray(e)) {
return copyArray(e)
} else if (isObject(e)) {
return copyObject(e)
}
return clone(e, stack)
})
}
if (isArray(val)) {
return copyArray(val)
}
if (isObject(val)) {
return copyObject(val)
}
return val
}
export const copies = (source, dest, matched = false, excepts = []) => {
for (const k in source) {
if (excepts.length > 0 && excepts.includes(k)) {
continue // eslint-disable-line no-continue
}
if (!matched || (matched && hasProperty(dest, k))) {
const oa = source[k]
const ob = dest[k]
if ((isObject(ob) && isObject(oa)) || (isArray(ob) && isArray(oa))) {
dest[k] = copies(oa, dest[k], matched, excepts)
} else {
dest[k] = clone(oa)
}
}
}
return dest
}
export const unique = (arr = []) => {
return [...new Set(arr)]
}
const fnSort = (a, b) => {
return a > b ? 1 : (a < b ? -1 : 0)
}
export const sort = (arr = [], sorting = null) => {
const tmp = [...arr]
const fn = sorting || fnSort
tmp.sort(fn)
return tmp
}
export const sortBy = (arr = [], order = 1, key = '') => {
if (!isString(key) || !hasProperty(arr[0], key)) {
return arr
}
return sort(arr, (m, n) => {
return m[key] > n[key] ? order : (m[key] < n[key] ? (-1 * order) : 0)
})
}
export const shuffle = (arr = []) => {
const input = [...arr]
const output = []
let inputLen = input.length
while (inputLen > 0) {
const index = Math.floor(Math.random() * inputLen)
output.push(input.splice(index, 1)[0])
inputLen--
}
return output
}
export const pick = (arr = [], count = 1) => {
const a = shuffle(arr)
const mc = Math.max(1, count)
const c = Math.min(mc, a.length - 1)
return a.splice(0, c)
}
export * from './utils/detection.js'
export * from './utils/string.js'
export * from './utils/random.js'
export * from './utils/date.js'
export * from './utils/curry.js'
export * from './utils/compose.js'
export * from './utils/pipe.js'
export * from './utils/maybe.js'
Generated Vendored Executable
+192
View File
@@ -0,0 +1,192 @@
// main.test
/* eslint-env jest */
import {
hasProperty,
clone,
copies,
unique,
sort,
sortBy,
pick
} from './main.js'
describe('test .clone() method:', () => {
test(' check if .clone(object) works correctly', () => {
const x = {
level: 4,
IQ: 140,
epouse: {
name: 'Alice',
age: 27,
},
birthday: new Date(),
a: 0,
clone: false,
reg: /^\w+@\s([a-z])$/gi,
}
const y = clone(x)
Object.keys(x).forEach((k) => {
expect(hasProperty(y, k)).toBeTruthy()
})
Object.keys(x.epouse).forEach((k) => {
expect(hasProperty(y.epouse, k)).toBeTruthy()
expect(y.epouse[k]).toEqual(x.epouse[k])
})
// check immutability
y.epouse.age = 25
expect(y.epouse.age).toEqual(25)
expect(x.epouse.age).toEqual(27)
})
test(' check if .clone(array) works correctly', () => {
const x = [
1,
5,
0,
'a',
-10,
'-10',
'',
{
a: 1,
b: 'Awesome',
},
[
5,
6,
8,
{
name: 'Lys',
age: 11,
},
],
]
const y = clone(x)
expect(y).toHaveLength(x.length)
for (let i = 0; i < x.length; i++) {
expect(x[i]).toEqual(y[i])
}
// check immutability
y[8][3].age = 10
expect(y[8][3].age).toEqual(10)
expect(x[8][3].age).toEqual(11)
})
})
describe('test .copies() method:', () => {
test(' check if .copies(source, dest) works correctly', () => {
const source = {
name: 'Toto',
age: 30,
level: 8,
nationality: {
name: 'America',
},
groups: [
'admin',
'accountant',
],
}
const dest = {
level: 4,
IQ: 140,
epouse: {
name: 'Alice',
age: 27,
},
nationality: {
name: 'Congo',
long: '18123.123123.12312',
lat: '98984771.134231.1234',
},
groups: [
'finance',
'manager',
],
}
copies(source, dest)
Object.keys(source).forEach((k) => {
expect(hasProperty(dest, k)).toBeTruthy()
})
expect(dest.nationality.name).toEqual(source.nationality.name)
})
test(' check if .copies(source, dest, matched, excepts) works correctly', () => {
const source = {
name: 'Kiwi',
age: 16,
gender: 'male',
}
const dest = {
name: 'Aline',
age: 20,
}
copies(source, dest, true, ['age'])
expect(hasProperty(dest, 'gender')).toBeFalsy()
expect(dest.name).toEqual(source.name)
expect(dest.age === source.age).toBeFalsy()
})
})
describe('test .unique() method:', () => {
test(' check if .unique(array) works correctly', () => {
const arr = [1, 1, 2, 2, 3, 4, 5, 5, 6, 3, 5, 4]
const uniqArr = unique(arr)
expect(uniqArr).toHaveLength(6)
})
})
describe('test .sort() method:', () => {
test(' check if .sort(array) works correctly', () => {
const arr = [6, 4, 8, 2]
const sortedArr = sort(arr)
expect(sortedArr.join('')).toEqual('2468')
})
})
describe('test .sortBy() method:', () => {
test(' check if .sortBy(array) works correctly', () => {
const arr = [
{ age: 5, name: 'E' },
{ age: 9, name: 'B' },
{ age: 3, name: 'A' },
{ age: 12, name: 'D' },
{ age: 7, name: 'C' },
]
const sortedByAge = [
{ age: 3, name: 'A' },
{ age: 5, name: 'E' },
{ age: 7, name: 'C' },
{ age: 9, name: 'B' },
{ age: 12, name: 'D' },
]
const sortedArr = sortBy(arr, 1, 'age')
expect(JSON.stringify(sortedArr) === JSON.stringify(sortedByAge)).toBeTruthy()
const sortedByNonStringKey = sortBy(arr, 1, 99)
expect(JSON.stringify(sortedByNonStringKey) === JSON.stringify(arr)).toBeTruthy()
const sortedByNonExistKey = sortBy(arr, 1, 'balance')
expect(JSON.stringify(sortedByNonExistKey) === JSON.stringify(arr)).toBeTruthy()
})
})
describe('test .pick() method:', () => {
test(' check if .pick(array) works correctly', () => {
const str = 'abcdefghijklmnopqrstuvwxyz'
const arr = str.split('')
const uniqChar = pick(arr)[0]
expect(str.includes(uniqChar)).toBeTruthy()
})
test(' check if .pick(array, count) works correctly', () => {
const str = 'abcdefghijklmnopqrstuvwxyz'
const arr = str.split('')
const picked = pick(arr, 10)
expect(picked).toHaveLength(10)
})
})
Generated Vendored Executable
+5
View File
@@ -0,0 +1,5 @@
// utils / compose
export const compose = (...fns) => {
return fns.reduce((f, g) => (x) => f(g(x)))
}
+44
View File
@@ -0,0 +1,44 @@
// compose.test
/* eslint-env jest */
import {
compose
} from './compose.js'
describe('test .compose() method:', () => {
const f1 = (name) => {
return `f1 ${name}`
}
const f2 = (name) => {
return `f2 ${name}`
}
const f3 = (name) => {
return `f3 ${name}`
}
const addDashes = compose(f1, f2, f3)
const add3 = (num) => {
return num + 3
}
const mul6 = (num) => {
return num * 6
}
const div2 = (num) => {
return num / 2
}
const sub5 = (num) => {
return num - 5
}
const calculate = compose(sub5, div2, mul6, add3)
test(' check if .compose() works correctly', () => {
expect(addDashes('Alice')).toEqual('f1 f2 f3 Alice')
expect(calculate(5)).toEqual(19)
})
})
Generated Vendored Executable
+14
View File
@@ -0,0 +1,14 @@
// utils / curry
export const curry = (fn) => {
const totalArguments = fn.length
const next = (argumentLength, rest) => {
if (argumentLength > 0) {
return (...args) => {
return next(argumentLength - args.length, [...rest, ...args])
}
}
return fn(...rest)
}
return next(totalArguments, [])
}
+20
View File
@@ -0,0 +1,20 @@
// curry.test
/* eslint-env jest */
import {
curry
} from './curry.js'
describe('test .curry() method:', () => {
const sum = curry((a, b, c) => {
return a + b + c
})
test(' check if .curry() works correctly', () => {
expect(sum(3)(2)(1)).toEqual(6)
expect(sum(1)(2)(3)).toEqual(6)
expect(sum(1, 2)(3)).toEqual(6)
expect(sum(1)(2, 3)).toEqual(6)
expect(sum(1, 2, 3)).toEqual(6)
})
})
Generated Vendored Executable
+69
View File
@@ -0,0 +1,69 @@
// utils / date
import {
isObject
} from './detection.js'
const getDateFormat = () => {
return {
dateStyle: 'medium',
timeStyle: 'long',
}
}
const getTimeConvers = () => {
return {
second: 1000,
minute: 60,
hour: 60,
day: 24,
week: 7,
month: 4,
year: 12,
}
}
const isValidLocal = (hl) => {
try {
const locale = new Intl.Locale(hl)
return locale.language !== ''
} catch (err) {
return false
}
}
export const formatDateString = (...args) => {
const input = args[0]
const lang = isValidLocal(args[1]) ? args[1] : 'en'
const dfmt = getDateFormat()
const opt = args.length >= 3
? args[2]
: args.length === 1
? dfmt
: isObject(args[1])
? args[1]
: dfmt
const dtf = new Intl.DateTimeFormat(lang, opt)
return dtf.format(new Date(input))
}
export const formatTimeAgo = (input, lang = 'en', justnow = 'just now') => {
const t = new Date(input)
let delta = Date.now() - t
const tcv = getTimeConvers()
if (delta <= tcv.second) {
return justnow
}
let unit = 'second'
for (const key in tcv) {
if (delta < tcv[key]) {
break
} else {
unit = key
delta /= tcv[key]
}
}
delta = Math.floor(delta)
const rel = new Intl.RelativeTimeFormat(lang)
return rel.format(-delta, unit)
}
Generated Vendored Executable
+62
View File
@@ -0,0 +1,62 @@
// date.test
/* eslint-env jest */
import { jest } from '@jest/globals'
import {
formatDateString,
formatTimeAgo
} from './date.js'
describe('test .formatDateString() method', () => {
const d = new Date()
test(' check .formatDateString() with default options', () => {
const result = formatDateString(d)
const reg = /^\w+\s\d+,\s+\d{4},\s\d+:\d+:\d+\s(AM|PM)\s(GMT)\+\d+$/
expect(result.match(reg) !== null).toBeTruthy()
})
test(' check .formatDateString() with custom options', () => {
const result = formatDateString(d, {
dateStyle: 'full',
timeStyle: 'medium',
hour12: true,
})
const reg = /^\w+,\s\w+\s\d+,\s+\d{4}\sat\s\d+:\d+:\d+\s(AM|PM)$/
expect(result.match(reg) !== null).toBeTruthy()
})
test(' check .formatDateString() with custom language and options', () => {
const result = formatDateString(d, 'en', {
dateStyle: 'full',
timeStyle: 'medium',
hour12: true,
})
const reg = /^\w+,\s\w+\s\d+,\s+\d{4}\sat\s\d+:\d+:\d+\s(AM|PM)$/
expect(result.match(reg) !== null).toBeTruthy()
})
})
describe('test .formatTimeAgo() method:', () => {
jest.useFakeTimers()
jest.spyOn(global, 'setTimeout')
const d = new Date()
test(' check if .formatTimeAgo() return "just now"', () => {
const result = formatTimeAgo(d)
expect(result === 'just now').toBeTruthy()
const justnowCustomMessage = formatTimeAgo(d, 'vi', 'vừa mới xong')
expect(justnowCustomMessage === 'vừa mới xong').toBeTruthy()
})
test(' check .formatTimeAgo() after 5s', () => {
setTimeout(() => {
const result = formatTimeAgo(d)
expect(result === '5 seconds ago').toBeTruthy()
}, 5000)
jest.advanceTimersByTime(5000)
})
})
+15
View File
@@ -0,0 +1,15 @@
// utils / defineProp
export const defineProp = (ob, key, val, config = {}) => {
const {
writable = false,
configurable = false,
enumerable = false,
} = config
Object.defineProperty(ob, key, {
value: val,
writable,
configurable,
enumerable,
})
}
Generated Vendored Executable
+77
View File
@@ -0,0 +1,77 @@
// utils / detection
const ob2Str = (val) => {
return {}.toString.call(val)
}
export const isInteger = (val) => {
return Number.isInteger(val)
}
export const isArray = (val) => {
return Array.isArray(val)
}
export const isString = (val) => {
return String(val) === val
}
export const isNumber = (val) => {
return Number(val) === val
}
export const isBoolean = (val) => {
return Boolean(val) === val
}
export const isNull = (val) => {
return ob2Str(val) === '[object Null]'
}
export const isUndefined = (val) => {
return ob2Str(val) === '[object Undefined]'
}
export const isNil = (val) => {
return isUndefined(val) || isNull(val)
}
export const isFunction = (val) => {
return ob2Str(val) === '[object Function]'
}
export const isObject = (val) => {
return ob2Str(val) === '[object Object]' && !isArray(val)
}
export const isDate = (val) => {
return val instanceof Date && !isNaN(val.valueOf())
}
export const isElement = (v) => {
return ob2Str(v).match(/^\[object HTML\w*Element]$/) !== null
}
export const isLetter = (val) => {
const re = /^[a-z]+$/i
return isString(val) && re.test(val)
}
export const isEmail = (val) => {
const re = /^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i
return isString(val) && re.test(val)
}
export const isEmpty = (val) => {
return !val || isNil(val) ||
(isString(val) && val === '') ||
(isArray(val) && val.length === 0) ||
(isObject(val) && Object.keys(val).length === 0)
}
export const hasProperty = (ob, k) => {
if (!ob || !k) {
return false
}
return Object.prototype.hasOwnProperty.call(ob, k)
}
+290
View File
@@ -0,0 +1,290 @@
// detection.test
/* eslint-env jest */
import {
isInteger,
isArray,
isString,
isNumber,
isBoolean,
isNull,
isUndefined,
isNil,
isFunction,
isObject,
isDate,
isElement,
isLetter,
isEmail,
isEmpty,
hasProperty
} from './detection.js'
describe('test .isInteger() method:', () => {
const positives = [1, 1000, 9999, 0, -3]
positives.forEach((val) => {
test(`test .isInteger(${val}) --> true`, () => {
expect(isInteger(val)).toBe(true)
})
})
const negatives = [1.5, -3.2, '', undefined]
negatives.forEach((val) => {
test(`test .isInteger(${val}) --> false`, () => {
expect(isInteger(val)).toBe(false)
})
})
})
describe('test .isArray() method:', () => {
const positives = [[], [1, 2, 3]]
positives.forEach((val) => {
test(`test .isArray(${val}) --> true`, () => {
expect(isArray(val)).toBe(true)
})
})
const negatives = [1.5, '', undefined]
negatives.forEach((val) => {
test(`test .isArray(${val}) --> false`, () => {
expect(isArray(val)).toBe(false)
})
})
})
describe('test .isString() method:', () => {
const positives = ['', 'abc xyz', '10000']
positives.forEach((val) => {
test(`test .isString(${val}) --> true`, () => {
expect(isString(val)).toBe(true)
})
})
const negatives = [{}, 30, [], 1.5, null, undefined]
negatives.forEach((val) => {
test(`test .isString(${val}) --> false`, () => {
expect(isString(val)).toBe(false)
})
})
})
describe('test .isNumber() method:', () => {
const positives = [1, 1.5, 0, 9999, -2]
positives.forEach((val) => {
test(`test .isNumber(${val}) --> true`, () => {
expect(isNumber(val)).toBe(true)
})
})
const negatives = [{}, [], '', null, undefined]
negatives.forEach((val) => {
test(`test .isNumber(${val}) --> false`, () => {
expect(isNumber(val)).toBe(false)
})
})
})
describe('test .isBoolean() method:', () => {
const positives = [true, false, 3 !== 2, 3 === 2]
positives.forEach((val) => {
test(`test .isBoolean(${val}) --> true`, () => {
expect(isBoolean(val)).toBe(true)
})
})
const negatives = [{}, [], '', 1, 0, null, undefined]
negatives.forEach((val) => {
test(`test .isBoolean(${val}) --> false`, () => {
expect(isBoolean(val)).toBe(false)
})
})
})
describe('test .isNull() method:', () => {
const positives = [null]
positives.forEach((val) => {
test(`test .isNull(${val}) --> true`, () => {
expect(isNull(val)).toBe(true)
})
})
const negatives = [{}, [], '', 0, undefined]
negatives.forEach((val) => {
test(`test .isNull(${val}) --> false`, () => {
expect(isNull(val)).toBe(false)
})
})
})
describe('test .isUndefined() method:', () => {
let v
const positives = [undefined, v]
positives.forEach((val) => {
test(`test .isUndefined(${val}) --> true`, () => {
expect(isUndefined(val)).toBe(true)
})
})
const negatives = [{}, [], '', 0, null]
negatives.forEach((val) => {
test(`test .isUndefined(${val}) --> false`, () => {
expect(isUndefined(val)).toBe(false)
})
})
})
describe('test .isNil() method:', () => {
let v
const positives = [undefined, v, null]
positives.forEach((val) => {
test(`test .isNil(${val}) --> true`, () => {
expect(isNil(val)).toBe(true)
})
})
const negatives = [{}, [], '', 0]
negatives.forEach((val) => {
test(`test .isNil(${val}) --> false`, () => {
expect(isNil(val)).toBe(false)
})
})
})
describe('test .isFunction() method:', () => {
const positives = [function () {}, () => {}]
positives.forEach((val) => {
test(`test .isFunction(${val}) --> true`, () => {
expect(isFunction(val)).toBe(true)
})
})
const negatives = [{}, [], '', 0, null]
negatives.forEach((val) => {
test(`test .isFunction(${val}) --> false`, () => {
expect(isFunction(val)).toBe(false)
})
})
})
describe('test .isObject() method:', () => {
const ob = new Object() // eslint-disable-line
const positives = [{}, ob, Object.create({})]
positives.forEach((val) => {
test(`test .isObject(${val}) --> true`, () => {
expect(isObject(val)).toBe(true)
})
})
const negatives = [17, [], '', 0, null, () => {}, true]
negatives.forEach((val) => {
test(`test .isObject(${val}) --> false`, () => {
expect(isObject(val)).toBe(false)
})
})
})
describe('test .isDate() method:', () => {
const dt = new Date()
const positives = [dt]
positives.forEach((val) => {
test(`test .isDate(${val}) --> true`, () => {
expect(isDate(val)).toBe(true)
})
})
const negatives = [17, [], '', 0, null, () => {}, true, {}, dt.toUTCString()]
negatives.forEach((val) => {
test(`test .isDate(${val}) --> false`, () => {
expect(isDate(val)).toBe(false)
})
})
})
describe('test .isElement() method:', () => {
const el = document.createElement('DIV')
const positives = [el]
positives.forEach((val) => {
test(`test .isElement(${val}) --> true`, () => {
expect(isElement(val)).toBe(true)
})
})
const negatives = [17, [], '', 0, null, () => {}, true, {}]
negatives.forEach((val) => {
test(`test .isElement(${val}) --> false`, () => {
expect(isElement(val)).toBe(false)
})
})
})
describe('test .isLetter() method:', () => {
const positives = ['a', 'A', 'sigma']
positives.forEach((val) => {
test(`test .isLetter(${val}) --> true`, () => {
expect(isLetter(val)).toBe(true)
})
})
const negatives = [{}, [], '', 0, undefined, 'a23b']
negatives.forEach((val) => {
test(`test .isLetter(${val}) --> false`, () => {
expect(isLetter(val)).toBe(false)
})
})
})
describe('test .isEmail() method:', () => {
const positives = ['admin@pwshub.com', 'abc@qtest.com']
positives.forEach((val) => {
test(`test .isEmail(${val}) --> true`, () => {
expect(isEmail(val)).toBe(true)
})
})
const negatives = [{}, [], '', 0, undefined, 'a23b@qtest@com']
negatives.forEach((val) => {
test(`test .isEmail(${val}) --> false`, () => {
expect(isEmail(val)).toBe(false)
})
})
})
describe('test .isEmpty() method:', () => {
const positives = ['', 0, {}, [], undefined, null]
positives.forEach((val) => {
test(`test .isEmpty(${val}) --> true`, () => {
expect(isEmpty(val)).toBe(true)
})
})
const negatives = [{ a: 1 }, '12', 9, [7, 1]]
negatives.forEach((val) => {
test(`test .isEmpty(${val}) --> false`, () => {
expect(isEmpty(val)).toBe(false)
})
})
})
describe('test .hasProperty() method:', () => {
const obj = {
name: 'alice',
age: 17,
}
const positives = ['name', 'age']
positives.forEach((val) => {
test(`test .hasProperty(${val}) --> true`, () => {
expect(hasProperty(obj, val)).toBe(true)
})
})
const negatives = [{ a: 1 }, 'email', 9, '__proto__']
negatives.forEach((val) => {
test(`test .hasProperty(${val}) --> false`, () => {
expect(hasProperty(obj, val)).toBe(false)
})
})
test('test .hasProperty(null) --> false', () => {
expect(hasProperty(null)).toBe(false)
})
})
Generated Vendored Executable
+33
View File
@@ -0,0 +1,33 @@
// utils / maybe
import {
defineProp
} from './defineProp.js'
export const maybe = (val) => {
const __val = val
const isNil = () => {
return __val === null || __val === undefined
}
const value = () => {
return __val
}
const getElse = (fn) => {
return maybe(__val || fn())
}
const filter = (fn) => {
return maybe(fn(__val) === true ? __val : null)
}
const map = (fn) => {
return maybe(isNil() ? null : fn(__val))
}
const output = Object.create({})
defineProp(output, '__value__', __val, { enumerable: true })
defineProp(output, '__type__', 'Maybe', { enumerable: true })
defineProp(output, 'isNil', isNil)
defineProp(output, 'value', value)
defineProp(output, 'map', map)
defineProp(output, 'if', filter)
defineProp(output, 'else', getElse)
return output
}
+35
View File
@@ -0,0 +1,35 @@
// maybe.test
/* eslint-env jest */
import {
maybe
} from './maybe.js'
describe('test .maybe() method:', () => {
const plus5 = (x) => x + 5
const minus2 = (x) => x - 2
const isNumber = (x) => Number(x) === x
const toString = (x) => 'The value is ' + String(x)
const getDefault = () => 'This is default value'
test(' check if .maybe() works correctly', () => {
const x1 = maybe(5)
.if(isNumber)
.map(plus5)
.map(minus2)
.map(toString)
.else(getDefault)
.value()
expect(x1).toEqual('The value is 8')
const x2 = maybe('nothing')
.if(isNumber)
.map(plus5)
.map(minus2)
.map(toString)
.else(getDefault)
.value()
expect(x2).toEqual('This is default value')
})
})
Generated Vendored Executable
+5
View File
@@ -0,0 +1,5 @@
// utils / pipe
export const pipe = (...fns) => {
return fns.reduce((f, g) => (x) => g(f(x)))
}
Generated Vendored Executable
+44
View File
@@ -0,0 +1,44 @@
// pipe.test
/* eslint-env jest */
import {
pipe
} from './pipe.js'
describe('test .pipe() method:', () => {
const f1 = (name) => {
return `f1 ${name}`
}
const f2 = (name) => {
return `f2 ${name}`
}
const f3 = (name) => {
return `f3 ${name}`
}
const addDashes = pipe(f1, f2, f3)
const add3 = (num) => {
return num + 3
}
const mul6 = (num) => {
return num * 6
}
const div2 = (num) => {
return num / 2
}
const sub5 = (num) => {
return num - 5
}
const calculate = pipe(add3, mul6, div2, sub5)
test(' check if .compose() works correctly', () => {
expect(addDashes('Alice')).toEqual('f3 f2 f1 Alice')
expect(calculate(5)).toEqual(19)
})
})
Generated Vendored Executable
+16
View File
@@ -0,0 +1,16 @@
// utils / random
export const randint = (min = 0, max = 1e6) => {
return Math.floor(Math.random() * (max - min + 1)) + min
}
export const genid = (len = 32, prefix = '') => {
let s = prefix
for (let i = 0; i < len; i++) {
const r = Math.random()
const k = Math.floor(r * 36)
const c = k.toString(36)
s += (k > 9 && r > 0.3 && r < 0.7) ? c.toUpperCase() : c
}
return s.substring(0, len)
}
+55
View File
@@ -0,0 +1,55 @@
// random.test
/* eslint-env jest */
import { randint, genid } from './random.js'
describe('test .randint() method:', () => {
const randArr = []
while (randArr.length < 20) {
randArr.push(randint())
}
test(`test .randint() after ${randArr.length} times`, () => {
expect(randArr).toHaveLength(20)
const uniqVal = Array.from(new Set(randArr))
expect(uniqVal.length).toBeGreaterThan(10)
})
test('test .randint() with same min/max', () => {
const q = randint(10, 10)
expect(q).toEqual(10)
})
const min = 50
const max = 80
test(`test .randint() between ${min} - ${max}`, () => {
for (let i = 0; i < 100; i++) {
const q = randint(min, max)
expect(q).toBeGreaterThanOrEqual(min)
expect(q).toBeLessThanOrEqual(max)
}
})
})
describe('test .genid() method:', () => {
test('check .genid() default param', () => {
const actual = genid()
expect(actual).toHaveLength(32)
})
test('check .genid(512)', () => {
const actual = genid(512)
expect(actual).toHaveLength(512)
})
const len = 100
const ids = []
while (ids.length < len) {
ids.push(genid())
}
const uniques = Array.from(new Set(ids))
test('check .genid() always return unique string', () => {
expect(ids).toHaveLength(len)
expect(uniques).toHaveLength(ids.length)
})
})
Generated Vendored Executable
+141
View File
@@ -0,0 +1,141 @@
// utils / string
import {
isArray,
isString,
isNumber,
hasProperty
} from './detection.js'
const toString = (input) => {
const s = isNumber(input) ? String(input) : input
if (!isString(s)) {
throw new Error('InvalidInput: String required.')
}
return s
}
export const truncate = (s, len = 140) => {
const txt = toString(s)
const txtlen = txt.length
if (txtlen <= len) {
return txt
}
const subtxt = txt.substring(0, len).trim()
const subtxtArr = subtxt.split(' ')
const subtxtLen = subtxtArr.length
if (subtxtLen > 1) {
subtxtArr.pop()
return subtxtArr.map(word => word.trim()).join(' ') + '...'
}
return subtxt.substring(0, len - 3) + '...'
}
export const stripTags = (s) => {
return toString(s).replace(/(<([^>]+)>)/ig, '').trim()
}
export const escapeHTML = (s) => {
return toString(s)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
}
export const unescapeHTML = (s) => {
return toString(s)
.replace(/&quot;/g, '"')
.replace(/&lt;/g, '<')
.replace(/&gt;/g, '>')
.replace(/&amp;/g, '&')
}
export const ucfirst = (s) => {
const x = toString(s).toLowerCase()
return x.length > 1 ? x.charAt(0).toUpperCase() + x.slice(1) : x.toUpperCase()
}
export const ucwords = (s) => {
return toString(s).split(' ').map((w) => {
return ucfirst(w)
}).join(' ')
}
export const replaceAll = (s, alpha, beta) => {
let x = toString(s)
const a = isNumber(alpha) ? String(alpha) : alpha
const b = isNumber(beta) ? String(beta) : beta
if (isString(a) && isString(b)) {
const aa = x.split(a)
x = aa.join(b)
} else if (isArray(a) && isString(b)) {
a.forEach((v) => {
x = replaceAll(x, v, b)
})
} else if (isArray(a) && isArray(b) && a.length === b.length) {
const k = a.length
if (k > 0) {
for (let i = 0; i < k; i++) {
const aaa = a[i]
const bb = b[i]
x = replaceAll(x, aaa, bb)
}
}
}
return x
}
const getCharMap = () => {
const lmap = {
a: 'á|à|ả|ã|ạ|ă|ắ|ặ|ằ|ẳ|ẵ|â|ấ|ầ|ẩ|ẫ|ậ|ä|æ',
c: 'ç',
d: 'đ|ð',
e: 'é|è|ẻ|ẽ|ẹ|ê|ế|ề|ể|ễ|ệ|ë',
i: 'í|ì|ỉ|ĩ|ị|ï|î',
n: 'ñ',
o: 'ó|ò|ỏ|õ|ọ|ô|ố|ồ|ổ|ỗ|ộ|ơ|ớ|ờ|ở|ỡ|ợ|ö|ø',
s: 'ß',
u: 'ú|ù|ủ|ũ|ụ|ư|ứ|ừ|ử|ữ|ự|û',
y: 'ý|ỳ|ỷ|ỹ|ỵ|ÿ',
}
const map = {
...lmap,
}
Object.keys(lmap).forEach((k) => {
const K = k.toUpperCase()
map[K] = lmap[k].toUpperCase()
})
return map
}
export const stripAccent = (s) => {
let x = toString(s)
const updateS = (ai, key) => {
x = replaceAll(x, ai, key)
}
const map = getCharMap()
for (const key in map) {
if (hasProperty(map, key)) {
const a = map[key].split('|')
a.forEach((item) => {
return updateS(item, key)
})
}
}
return x
}
export const slugify = (s, delimiter = '-') => {
return stripAccent(s)
.trim()
.toLowerCase()
.replace(/\W+/g, ' ')
.replace(/\s+/g, ' ')
.replace(/\s/g, delimiter)
}
+254
View File
@@ -0,0 +1,254 @@
// string.test
/* eslint-env jest */
import {
truncate,
stripTags,
escapeHTML,
unescapeHTML,
ucfirst,
ucwords,
replaceAll,
stripAccent,
slugify
} from './string.js'
describe('test .truncate() method:', () => {
const inputs = [
{
text: 'If a property is non-configurable, its writable attribute can only be changed to false.',
limit: 60,
expectation: 'If a property is non-configurable, its writable attribute...',
},
{
text: 'this string is less than limit',
limit: 100,
expectation: 'this string is less than limit',
},
{
text: 'uyyiyirwqyiyiyrihklhkjhskdjfhkahfiusayiyfiudyiyqwiyriuqyiouroiuyi',
limit: 20,
expectation: 'uyyiyirwqyiyiyrih...',
},
]
inputs.forEach(({ text, limit, expectation }, k) => {
test(` check .truncate(text, ${k})`, () => {
const actual = truncate(text, limit)
expect(actual).toEqual(expectation)
})
})
})
describe('test .stripTags() method:', () => {
const inputs = [
{
text: '<a>Hello <b>world</b></a>',
expectation: 'Hello world',
},
]
inputs.forEach(({ text, expectation }, k) => {
test(` check .stripTags(text, ${k})`, () => {
const actual = stripTags(text)
expect(actual).toEqual(expectation)
})
})
test(' check .stripTags(non-text)', () => {
expect(() => {
stripTags({})
}).toThrow()
})
})
describe('test .escapeHTML() method:', () => {
const inputs = [
{
text: '<a>Hello <b>world</b></a>',
expectation: '&lt;a&gt;Hello &lt;b&gt;world&lt;/b&gt;&lt;/a&gt;',
},
]
inputs.forEach(({ text, expectation }) => {
test(` check .escapeHTML(${text})`, () => {
const actual = escapeHTML(text)
expect(actual).toEqual(expectation)
})
})
})
describe('test .unescapeHTML() method:', () => {
const inputs = [
{
text: '&lt;a&gt;Hello &lt;b&gt;world&lt;/b&gt;&lt;/a&gt;',
expectation: '<a>Hello <b>world</b></a>',
},
]
inputs.forEach(({ text, expectation }) => {
test(` check .unescapeHTML(${text})`, () => {
const actual = unescapeHTML(text)
expect(actual).toEqual(expectation)
})
})
})
describe('test .ucfirst() method:', () => {
const inputs = [
{
text: 'HElLo wOrLd',
expectation: 'Hello world',
},
{
text: 'h',
expectation: 'H',
},
]
inputs.forEach(({ text, expectation }) => {
test(` check .ucfirst(${text})`, () => {
const actual = ucfirst(text)
expect(actual).toEqual(expectation)
})
})
})
describe('test .ucwords() method:', () => {
const inputs = [
{
text: 'HElLo wOrLd',
expectation: 'Hello World',
},
]
inputs.forEach(({ text, expectation }) => {
test(` check .ucwords(${text})`, () => {
const actual = ucwords(text)
expect(actual).toEqual(expectation)
})
})
})
describe('test .replaceAll() method:', () => {
const inputs = [
{
input: {
a: 'Hello world',
b: 'l',
c: '2',
},
expectation: 'He22o wor2d',
},
{
input: {
a: 'Hello world',
b: 'l',
c: 2,
},
expectation: 'He22o wor2d',
},
{
input: {
a: 798078967,
b: 7,
c: 1,
},
expectation: '198018961',
},
{
input: {
a: 'Hello world',
b: ['l', 'o'],
c: ['2', '0'],
},
expectation: 'He220 w0r2d',
},
{
input: {
a: 'Hello world',
b: ['l', 'o'],
c: '2',
},
expectation: 'He222 w2r2d',
},
{
input: {
a: 'Hello world',
b: ['l'],
c: ['2', '0'],
},
expectation: 'Hello world',
},
{
input: {
a: 'Hello world',
b: 'l',
},
expectation: 'Hello world',
},
{
input: {
a: 'Hello world',
},
expectation: 'Hello world',
},
{
input: {
a: 10000,
},
expectation: '10000',
},
{
input: {
a: 0,
},
expectation: '0',
},
]
inputs.forEach(({ input, expectation }) => {
const { a, b, c } = input
test(` check .replaceAll(${a}, ${b}, ${c})`, () => {
const actual = replaceAll(a, b, c)
expect(actual).toEqual(expectation)
})
})
})
describe('test .stripAccent() method:', () => {
const inputs = [
{
text: 'Sur l\'année 2015 - ủ Ù ỹ Ỹ',
expectation: 'Sur l\'annee 2015 - u U y Y',
},
]
inputs.forEach(({ text, expectation }) => {
test(` check .stripAccent(${text})`, () => {
const actual = stripAccent(text)
expect(actual).toEqual(expectation)
})
})
})
describe('test .slugify() method:', () => {
const inputs = [
{
text: 'Sur l\'année 2015',
expectation: 'sur-l-annee-2015',
},
{
text: 'Nghị luận tác phẩm "Đường kách mệnh" của Hồ Chí Minh',
expectation: 'nghi-luan-tac-pham-duong-kach-menh-cua-ho-chi-minh',
},
]
inputs.forEach(({ text, expectation }) => {
test(` check .slugify(${text})`, () => {
const actual = slugify(text)
expect(actual).toEqual(expectation)
})
})
})