working rss feed to nostr publish
This commit is contained in:
+2
@@ -0,0 +1,2 @@
|
||||
node_modules
|
||||
dist
|
||||
+122
@@ -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"]
|
||||
}
|
||||
}
|
||||
+21
@@ -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.
|
||||
+525
@@ -0,0 +1,525 @@
|
||||
BellaJS
|
||||
========
|
||||
|
||||
Lightweight util for handling data type, string... in your Node.js and browser apps.
|
||||
|
||||
[](https://badge.fury.io/js/bellajs)
|
||||

|
||||
[](https://coveralls.io/github/ndaidong/bellajs)
|
||||

|
||||
[](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
File diff suppressed because one or more lines are too long
+7
File diff suppressed because one or more lines are too long
+2
File diff suppressed because one or more lines are too long
+7
File diff suppressed because one or more lines are too long
+41
@@ -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
@@ -0,0 +1 @@
|
||||
export default crypto
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
export const TextEncoder = window.TextEncoder
|
||||
export const TextDecoder = window.TextDecoder
|
||||
+128
@@ -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'
|
||||
+192
@@ -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)
|
||||
})
|
||||
})
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// utils / compose
|
||||
|
||||
export const compose = (...fns) => {
|
||||
return fns.reduce((f, g) => (x) => f(g(x)))
|
||||
}
|
||||
+44
@@ -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)
|
||||
})
|
||||
})
|
||||
+14
@@ -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
@@ -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)
|
||||
})
|
||||
})
|
||||
+69
@@ -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)
|
||||
}
|
||||
+62
@@ -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
@@ -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,
|
||||
})
|
||||
}
|
||||
+77
@@ -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
@@ -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)
|
||||
})
|
||||
})
|
||||
+33
@@ -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
@@ -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')
|
||||
})
|
||||
})
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// utils / pipe
|
||||
|
||||
export const pipe = (...fns) => {
|
||||
return fns.reduce((f, g) => (x) => g(f(x)))
|
||||
}
|
||||
+44
@@ -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)
|
||||
})
|
||||
})
|
||||
+16
@@ -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
@@ -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)
|
||||
})
|
||||
})
|
||||
+141
@@ -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, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
}
|
||||
|
||||
export const unescapeHTML = (s) => {
|
||||
return toString(s)
|
||||
.replace(/"/g, '"')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/&/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
@@ -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: '<a>Hello <b>world</b></a>',
|
||||
},
|
||||
]
|
||||
|
||||
inputs.forEach(({ text, expectation }) => {
|
||||
test(` check .escapeHTML(${text})`, () => {
|
||||
const actual = escapeHTML(text)
|
||||
expect(actual).toEqual(expectation)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('test .unescapeHTML() method:', () => {
|
||||
const inputs = [
|
||||
{
|
||||
text: '<a>Hello <b>world</b></a>',
|
||||
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)
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user