include node_modules so release .zip is deployable

This commit is contained in:
2023-11-24 17:44:25 -05:00
parent 6c86cfe5d2
commit 8b11c41267
8963 changed files with 874175 additions and 1 deletions
+2
View File
@@ -0,0 +1,2 @@
node_modules
dist
+122
View File
@@ -0,0 +1,122 @@
{
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"env": {
"es6": true,
"node": true,
"jest": true,
"browser": true
},
"globals": {
"globalThis": true,
"URLPattern": true
},
"plugins": [],
"overrides": [],
"extends": ["eslint:recommended"],
"rules": {
"arrow-spacing": ["error", { "before": true, "after": true }],
"block-spacing": ["error", "always"],
"brace-style": ["error", "1tbs", { "allowSingleLine": true }],
"camelcase": ["error", {
"allow": ["^UNSAFE_"],
"properties": "never",
"ignoreGlobals": true
}],
"comma-dangle": ["error", {
"arrays": "always-multiline",
"objects": "always-multiline",
"imports": "never",
"exports": "never",
"functions": "never"
}],
"comma-spacing": ["error", { "before": false, "after": true }],
"eol-last": "error",
"eqeqeq": ["error", "always", { "null": "ignore" }],
"func-call-spacing": ["error", "never"],
"indent": [
"error",
2,
{
"MemberExpression": 1,
"FunctionDeclaration": {
"body": 1,
"parameters": 2
},
"SwitchCase": 1
}
],
"key-spacing": ["error", { "beforeColon": false, "afterColon": true }],
"keyword-spacing": ["error", { "before": true, "after": true }],
"lines-between-class-members": ["error", "always", { "exceptAfterSingleLine": true }],
"max-len": [
"error",
{
"code": 120,
"ignoreTrailingComments": true,
"ignoreComments": true,
"ignoreUrls": true
}
],
"max-lines": [
"error",
{
"max": 360,
"skipBlankLines": true,
"skipComments": false
}
],
"max-lines-per-function": [
"error",
{
"max": 250,
"skipBlankLines": true
}
],
"max-params": ["error", 4],
"no-array-constructor": "error",
"no-mixed-spaces-and-tabs": "error",
"no-multi-spaces": "error",
"no-multi-str": "error",
"no-multiple-empty-lines": [
"error",
{
"max": 1,
"maxEOF": 0
}
],
"no-restricted-syntax": [
"error",
"WithStatement",
"BinaryExpression[operator='in']"
],
"no-trailing-spaces": "error",
"no-use-before-define": [
"error",
{
"functions": true,
"classes": true,
"variables": false
}
],
"no-var": "warn",
"object-curly-spacing": ["error", "always"],
"padded-blocks": [
"error",
{
"blocks": "never",
"switches": "never",
"classes": "never"
}
],
"quotes": ["error", "single"],
"space-before-blocks": ["error", "always"],
"space-before-function-paren": ["error", "always"],
"space-infix-ops": "error",
"space-unary-ops": ["error", { "words": true, "nonwords": false }],
"space-in-parens": ["error", "never"],
"semi": ["error", "never"]
}
}
Generated Vendored Executable
+21
View File
@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2016 Dong Nguyen
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Generated Vendored Executable
+525
View File
@@ -0,0 +1,525 @@
BellaJS
========
Lightweight util for handling data type, string... in your Node.js and browser apps.
[![NPM](https://badge.fury.io/js/bellajs.svg)](https://badge.fury.io/js/bellajs)
![CI test](https://github.com/ndaidong/bellajs/workflows/ci-test/badge.svg)
[![Coverage Status](https://coveralls.io/repos/github/ndaidong/bellajs/badge.svg)](https://coveralls.io/github/ndaidong/bellajs)
![CodeQL](https://github.com/ndaidong/bellajs/workflows/CodeQL/badge.svg)
[![CodeFactor](https://www.codefactor.io/repository/github/ndaidong/bellajs/badge)](https://www.codefactor.io/repository/github/ndaidong/bellajs)
# Contents
* [Setup](#setup)
* [APIs](#apis)
* [DataType detection](#datatype-detection)
* [String manipulation](#string-manipulation)
* [Data handling](#data-handling): [`clone`](#cloneanything-val), [`copies`](#copiesobject-source-object-target-boolean-requirematching-array-excepts)
* [Array utils](#array-utils): [`pick`](#pickarray-arr--number-count--1), [`sort`](#sortarray-arr--function-compare), [`sortBy`](#sortbyarray-arr-number-order-string-property), [`shuffle`](#shufflearray-arr), [`unique`](#uniquearray-arr)
* [Functional utils](#functional-utils): [`curry`](#curryfn), [`compose`](#composef1-f2-fn), [`pipe`](#pipef1-f2-fn), [`maybe`](#maybeanything-val)
* [Date utils](#date-utils): [`formatDateString`](#formatdatestringdate--timestamp--string-locale--object-options), [`formatTimeAgo`](#formattimeagodate--timestamp--string-locale--string-justnow)
* [Random utils](#random-utils): [`randint`](#randintnumber-min--number-max), [`genid`](#genidnumber-length--string-prefix)
* [Test](#test)
* [License](#license)
## Install & Usage
### Node.js
```bash
npm i bellajs
# pnpm
pnpm i bellajs
# yarn
yarn add bellajs
```
### Deno
```ts
import { genid } from 'https://esm.sh/bellajs'
console.log(genid())
```
### Browser
```html
<script type="module">
import { genid, slugify } from 'https://unpkg.com/bellajs/dist/bella.esm.js'
console.log(genid())
</script>
```
## APIs
### DataType detection
- `.isArray(Anything val)`
- `.isBoolean(Anything val)`
- `.isDate(Anything val)`
- `.isElement(Anything val)`
- `.isEmail(Anything val)`
- `.isEmpty(Anything val)`
- `.isFunction(Anything val)`
- `.isInteger(Anything val)`
- `.isLetter(Anything val)`
- `.isNil(Anything val)`
- `.isNull(Anything val)`
- `.isNumber(Anything val)`
- `.isObject(Anything val)`
- `.isString(Anything val)`
- `.isUndefined(Anything val)`
### String manipulation
- `.ucfirst(String s)`
- `.ucwords(String s)`
- `.escapeHTML(String s)`
- `.unescapeHTML(String s)`
- `.slugify(String s)`
- `.stripTags(String s)`
- `.stripAccent(String s)`
- `.truncate(String s, Number limit)`
- `.replaceAll(String s, String|Array search, String|Array replace)`
### Data handling
#### `clone(Anything val)`
Make a deep copy of a variable.
```js
import { clone } from 'bellajs'
const b = [
1, 5, 0, 'a', -10, '-10', '',
{
a: 1,
b: 'Awesome'
}
]
const cb = clone(b)
console.log(cb)
```
*cb* now has the same values as *b*, while the properties are standalone, not reference. So that:
```js
cb[7].a = 2
cb[7].b = 'Noop'
console.log(b[7])
```
What you get is still:
```js
{
a: 1,
b: 'Awesome'
}
```
#### `copies(Object source, Object target[[, Boolean requireMatching], Array excepts])`
Copy the properties from *source* to *target*.
- *requireMatching*: if true, BellaJS only copies the properties that are already exist in *target*.
- *excepts*: array of the properties properties in *source* that you don't want to copy.
After this action, target will be modified.
```js
import { copies } from 'bellajs'
const a = {
name: 'Toto',
age: 30,
level: 8,
nationality: {
name: 'America'
}
}
const b = {
level: 4,
IQ: 140,
epouse: {
name: 'Alice',
age: 27
},
nationality: {
long: '18123.123123.12312',
lat: '98984771.134231.1234'
}
}
copies(a, b)
console.log(b)
```
Output:
```js
{
level: 8,
IQ: 140,
epouse: {
name: 'Alice',
age: 27
},
nationality: {
long: '18123.123123.12312',
lat: '98984771.134231.1234',
name: 'America'
},
name: 'Toto',
age: 30
}
```
### Array utils
#### `pick(Array arr [, Number count = 1])`
Randomly choose N elements from array.
```js
import { pick } from 'bellajs'
const arr = [1, 3, 8, 2, 5, 7]
pick(arr, 2) // --> [3, 5]
pick(arr, 2) // --> [8, 1]
pick(arr) // --> [3]
pick(arr) // --> [7]
```
#### `sort(Array arr [, Function compare])`
Sort the array using a function.
```js
import { sort } from 'bellajs'
const fn = (a, b) => {
return a < b ? 1 : a > b ? -1 : 0
}
sort([3, 1, 5, 2], fn) // => [ 1, 2, 3, 5 ]
```
#### `sortBy(Array arr, Number order, String property)`
Sort the array by specific property and direction.
```js
import { sortBy } from 'bellajs'
const players = [
{
name: 'Jerome Nash',
age: 24
},
{
name: 'Jackson Valdez',
age: 21
},
{
name: 'Benjamin Cole',
age: 23
},
{
name: 'Manuel Delgado',
age: 33
},
{
name: 'Caleb McKinney',
age: 28
}
]
const result = sortBy(players, -1, 'age')
console.log(result)
```
#### `shuffle(Array arr)`
Shuffle the positions of elements in an array.
```js
import { shuffle } from 'bellajs'
shuffle([1, 3, 8, 2, 5, 7])
```
#### `unique(Array arr)`
Remove all duplicate elements from an array.
```js
import { unique } from 'bellajs'
unique([1, 2, 3, 2, 3, 1, 5]) // => [ 1, 2, 3, 5 ]
```
### Functional utils
#### `curry(fn)`
Make a curried function.
```js
import { curry } from 'bellajs'
const sum = curry((a, b, c) => {
return a + b + c
})
sum(3)(2)(1) // => 6
sum(1)(2)(3) // => 6
sum(1, 2)(3) // => 6
sum(1)(2, 3) // => 6
sum(1, 2, 3) // => 6
```
#### `compose(f1, f2, ...fN)`
Performs right-to-left function composition.
```js
import { compose } from 'bellajs'
const f1 = (name) => {
return `f1 ${name}`
}
const f2 = (name) => {
return `f2 ${name}`
}
const f3 = (name) => {
return `f3 ${name}`
}
const addF = compose(f1, f2, f3)
addF('Hello') // => 'f1 f2 f3 Hello'
const add1 = (num) => {
return num + 1
}
const mult2 = (num) => {
return num * 2
}
const add1AndMult2 = compose(add1, mult2)
add1AndMult2(3) // => 7
// because multiple to 2 first, then add 1 late => 3 * 2 + 1
```
#### `pipe(f1, f2, ...fN)`
Performs left-to-right function composition.
```js
import { pipe } from 'bellajs'
const f1 = (name) => {
return `f1 ${name}`
}
const f2 = (name) => {
return `f2 ${name}`
}
const f3 = (name) => {
return `f3 ${name}`
}
const addF = pipe(f1, f2, f3)
addF('Hello') // => 'f3 f2 f1 Hello'
const add1 = (num) => {
return num + 1
}
const mult2 = (num) => {
return num * 2
}
const add1AndMult2 = pipe(add1, mult2)
add1AndMult2(3) // => 8
// because add 1 first, then multiple to 2 late => (3 + 1) * 2
```
#### `maybe(Anything val)`
Return a static variant of `Maybe` monad.
```js
import { maybe } from 'bellajs'
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'
maybe(5)
.map(plus5)
.map(minus2)
.value() // 8
maybe('noop')
.map(plus5)
.map(minus2)
.value() // null
maybe(5)
.if(isNumber)
.map(plus5)
.map(minus2)
.else(getDefault)
.map(toString)
.value() // 'The value is 8'
maybe()
.if(isNumber)
.map(plus5)
.map(minus2)
.map(toString)
.value() // null
maybe()
.if(isNumber)
.map(plus5)
.map(minus2)
.else(getDefault)
.map(toString)
.value() // 'This is default value'
```
### Date utils
#### `formatDateString(Date | Timestamp [, String locale [, Object options]])`
```js
import {
formatDateString
} from 'bellajs'
const today = new Date()
formatDateString(today) // => Jan 3, 2022, 8:34:28 PM GMT+7
// custom format
formatDateString(today, {
dateStyle: 'short',
timeStyle: 'short',
hour12: true
}) // => 1/3/22, 8:34 PM
// custom locale
formatDateString(today, 'zh') // => 2022年1月3日 GMT+7 下午8:34:28
// custom lang and format
formatDateString(today, 'zh', {
dateStyle: 'short',
timeStyle: 'long',
hour12: true
}) // => 2022/1/3 GMT+7 下午8:34:28
formatDateString(today, 'vi') // => 20:34:28 GMT+7, 3 thg 1, 2022
formatDateString(today, 'vi', {
dateStyle: 'full',
timeStyle: 'full'
}) // => 20:34:28 Giờ Đông Dương Thứ Hai, 3 tháng 1, 2022
```
#### `formatTimeAgo(Date | Timestamp [, String locale [, String justnow]])`
```js
import {
formatTimeAgo
} from 'bellajs'
const today = new Date()
const yesterday = today.setDate(today.getDate() - 1)
formatTimeAgo(yesterday) // => 1 day ago
const current = new Date()
const aLittleWhile = current.setHours(current.getHours() - 3)
formatTimeAgo(aLittleWhile) // => 3 hours ago
// change locale
formatTimeAgo(aLittleWhile, 'zh') // => 3小时前
formatTimeAgo(aLittleWhile, 'vi') // => 3 giờ trước
```
The last param `justnow` can be used to display a custom 'just now' message, when the distance is lesser than 1s.
```js
const now = new Date()
const aJiff = now.setTime(now.getTime() - 100)
formatTimeAgo(aJiff) // => 'just now'
formatTimeAgo(aJiff, 'fr', 'à l\'instant') // => à l'instant
formatTimeAgo(aJiff, 'ja', 'すこし前') // => すこし前
```
These two functions based on recent features of built-in object `Intl`.
Please refer the following resources for more info:
- [Intl.DateTimeFormat() constructor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat)
- [Intl.RelativeTimeFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat)
- [Intl.Locale](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale)
### Random utils
#### `randint([Number min [, Number max]])`
Returns a number between `min` and `max`
```js
import { randint } from 'bellajs'
randint() // => a random integer
randint(1, 5) // => a random integer between 3 and 5, including 1 and 5
```
#### `genid([Number length [, String prefix]])`
Create random ID string.
```js
import { genid } from 'bellajs'
genid() // => random 32 chars
genid(16) // => random 16 chars
genid(5) // => random 5 chars
genid(5, 'X_') // => X_{random 3 chars}
```
## Test
```bash
git clone https://github.com/ndaidong/bellajs.git
cd bellajs
npm install
npm test
```
# License
The MIT License (MIT)
+2
View File
File diff suppressed because one or more lines are too long
+7
View File
File diff suppressed because one or more lines are too long
+2
View File
File diff suppressed because one or more lines are too long
+7
View File
File diff suppressed because one or more lines are too long
Generated Vendored Executable
+41
View File
@@ -0,0 +1,41 @@
{
"version": "11.1.2",
"name": "bellajs",
"description": "A useful helper for any javascript program",
"homepage": "https://www.npmjs.com/package/bellajs",
"repository": {
"type": "git",
"url": "https://github.com/ndaidong/bellajs"
},
"author": "@ndaidong",
"main": "./src/main.js",
"exports": {
"import": "./src/main.js",
"require": "./dist/bella.js"
},
"type": "module",
"engines": {
"node": ">= 14"
},
"scripts": {
"lint": "eslint .",
"lint:fix": "eslint --fix .",
"pretest": "npm run lint",
"test": "NODE_ENV=test NODE_OPTIONS=--experimental-vm-modules jest --verbose --coverage=true --env=jsdom",
"build": "node build.js src/main.js",
"reset": "node reset"
},
"devDependencies": {
"esbuild": "^0.17.10",
"eslint": "^8.35.0",
"jest": "^29.4.3",
"jest-environment-jsdom": "^29.4.3"
},
"keywords": [
"detection",
"manipulation",
"templating",
"utilities"
],
"license": "MIT"
}
+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)
})
})
})