Skip to content

Commit

Permalink
Merge branch 'main' into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
Aybrea committed Nov 1, 2024
2 parents 1b82b87 + e635da2 commit a0dc915
Show file tree
Hide file tree
Showing 16 changed files with 628 additions and 85 deletions.
24 changes: 23 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,26 @@
## [0.0.4](https://github.com/varletjs/rattail/compare/v0.0.3...v0.0.4) (2024-10-29)
## [0.0.6](https://github.com/varletjs/rattail/compare/v0.0.5...v0.0.6) (2024-10-31)


### Bug Fixes

* fix imported ([c7eabd3](https://github.com/varletjs/rattail/commit/c7eabd3c01373e317ce41f15057ba22e187116e6))



## [0.0.5](https://github.com/varletjs/rattail/compare/v0.0.3...v0.0.5) (2024-10-31)


### Bug Fixes

* fix lint error ([aad4f13](https://github.com/varletjs/rattail/commit/aad4f134e806dd8768f96fae2b28df61f0c824c6))
* improve the type of parameter `fn` ([07922bf](https://github.com/varletjs/rattail/commit/07922bf5dbb173ddfcd9c27c5579ac3e290bea03))


### Features

* support clone ([9e42734](https://github.com/varletjs/rattail/commit/9e42734f187378c62645e66a09290f66095aab24))
* support lowerFirst and upperFirst ([6d48399](https://github.com/varletjs/rattail/commit/6d4839989392fc495afd45bce2b7e02ae452bf35))
* support more utils ([0d44ea9](https://github.com/varletjs/rattail/commit/0d44ea98e9c10ed5657b364c5f3ca55d9dea6403))


### Performance Improvements
Expand Down
3 changes: 2 additions & 1 deletion docs/.vitepress/items/string.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export const stringItems = [
{ text: 'camelize', link: '/string/camelize' },
{ text: 'kebabCase', link: '/string/kebab-case' },
{ text: 'pascalCase', link: '/string/pascal-case' },
{ text: 'capitalizeFirstLetter', link: '/string/capitalize-first-letter' },
{ text: 'upperFirst', link: '/string/upper-first' },
{ text: 'lowerFirst', link: '/string/lower-first' },
{ text: 'slash', link: '/string/slash' },
]
2 changes: 1 addition & 1 deletion docs/function/debounce.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ window.addEventListener('resize', debouncedFn)
| Arg | Type | Defaults |
| ------- | :--------: | -------: |
| `fn` | `Function` | |
| `delay` | `number` | 0 |
| `delay` | `number` | `0` |

### Return

Expand Down
24 changes: 24 additions & 0 deletions docs/string/lower-first.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# lowerFirst

Lowercase the `first letter` of the `string` and keep the rest unchanged.

### Usage

```ts
import { upperFirst } from 'rattail'

upperFirst('Hello') // return 'hello'
upperFirst('Rattail') // return 'rattail'
```

### Arguments

| Arg | Type | Defaults |
| ------- | :------: | -------: |
| `value` | `string` | |

### Return

| Type |
| :------: |
| `string` |
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# capitalizeFirstLetter
# upperFirst

Capitalize the `first letter` of a `string`, leaving the rest of the string unchanged.

### Usage

```ts
import { capitalizeFirstLetter } from 'rattail'
import { upperFirst } from 'rattail'

capitalizeFirstLetter('hello world') // return 'Hello world'
capitalizeFirstLetter('rattail') // return 'Rattail'
upperFirst('hello world') // return 'Hello world'
upperFirst('rattail') // return 'Rattail'
```

### Arguments
Expand Down
2 changes: 1 addition & 1 deletion docs/zh/function/debounce.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ window.addEventListener('resize', debouncedFn)
| 参数 | 类型 | 默认值 |
| ------- | :--------: | -----: |
| `fn` | `Function` | |
| `delay` | `number` | 0 |
| `delay` | `number` | `0` |

### 返回值

Expand Down
24 changes: 24 additions & 0 deletions docs/zh/string/lower-first.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# lowerFirst

`字符串``首字母`小写,其余部分保持不变。

### 使用

```ts
import { lowerFirst } from 'rattail'

upperFirst('Hello') // return 'hello'
upperFirst('Rattail') // return 'rattail'
```

### 参数列表

| 参数 | 类型 | 默认值 |
| ------- | :------: | -----: |
| `value` | `string` | |

### 返回值

| 类型 |
| :------: |
| `string` |
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# capitalizeFirstLetter
# upperFirst

`字符串``首字母`大写,其余部分保持不变。

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "rattail",
"version": "0.0.4",
"version": "0.0.6",
"type": "module",
"main": "lib/index.cjs",
"module": "lib/index.js",
Expand Down
140 changes: 131 additions & 9 deletions src/collection.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
import { hasOwn, isArray, isObject } from './general'
import {
hasOwn,
isArray,
isDate,
isMap,
isObject,
isPlainObject,
isSet,
isWeakSet,
toRawType,
isArrayBuffer,
isDataView,
isRegExp,
isTypedArray,
isWeakMap,
} from './general'

export function mergeWith<TObject extends Record<string, any>, TSource extends Record<string, any>>(
object: TObject,
source: TSource,
callback: (
objValue: any,
srcValue: any,
key: string | number | symbol,
object?: TObject,
source?: TSource,
) => any | void,
fn: (objValue: any, srcValue: any, key: string | number | symbol, object?: TObject, source?: TSource) => any,
): TObject & TSource {
function baseMerge(target: any, src: any): any {
// eslint-disable-next-line no-restricted-syntax
Expand All @@ -18,7 +27,7 @@ export function mergeWith<TObject extends Record<string, any>, TSource extends R
const srcValue = src[key]
const targetValue = target[key]

const customResult = callback(targetValue, srcValue, key, object, source)
const customResult = fn(targetValue, srcValue, key, object, source)

if (customResult !== undefined) {
target[key] = customResult
Expand All @@ -45,3 +54,116 @@ export function merge<TObject extends Record<string, any>, TSource extends Recor
) {
return mergeWith(object, source, () => undefined)
}

export function cloneDeep<T>(value: T): T {
return cloneDeepWith(value, () => undefined)
}

export function cloneDeepWith<T>(value: T, fn: (value: any) => any): T {
const cache = new WeakMap()

function baseCloneDeep(value: any, cache: WeakMap<any, any>): any {
const customResult = fn(value)

if (customResult !== undefined) {
return customResult
}

if (!isObject(value)) {
return value
}

if (cache.has(value)) {
return cache.get(value)
}

if (isDate(value)) {
return new Date(value)
}

if (isRegExp(value)) {
return new RegExp(value)
}

if (isMap(value)) {
const result = new Map()
cache.set(value, result)

value.forEach((val: any, key: any) => {
result.set(baseCloneDeep(key, cache), baseCloneDeep(val, cache))
})

return result
}

if (isSet(value)) {
const result = new Set()
cache.set(value, result)

value.forEach((val: any) => {
result.add(baseCloneDeep(val, cache))
})

return result
}

if (toRawType(value) === 'String' || toRawType(value) === 'Number' || toRawType(value) === 'Boolean') {
return newConstructor(value, value.valueOf())
}

if (isWeakMap(value) || isWeakSet(value)) {
return {}
}

if (isTypedArray(value)) {
return newConstructor(value, baseCloneArrayBuffer(value.buffer), value.byteOffset, value.length)
}

if (isDataView(value)) {
return newConstructor(value, baseCloneArrayBuffer(value.buffer), value.byteOffset, value.byteLength)
}

if (isArrayBuffer(value)) {
return baseCloneArrayBuffer(value)
}

if (isArray(value)) {
const result: any[] = []
cache.set(value, result)

value.forEach((value, index) => {
result[index] = baseCloneDeep(value, cache)
})

return result
}

if (isPlainObject(value)) {
const result: Record<string, any> = Object.create(Reflect.getPrototypeOf(value))
cache.set(value, result)

// eslint-disable-next-line no-restricted-syntax
for (const key in value) {
if (hasOwn(value, key)) {
result[key] = baseCloneDeep(value[key], cache)
}
}

return result
}

return value
}

function baseCloneArrayBuffer(value: ArrayBuffer): ArrayBuffer {
const result = new ArrayBuffer(value.byteLength)
new Uint8Array(result).set(new Uint8Array(value))
return result
}

function newConstructor(value: any, ...args: any[]) {
return new value.constructor(...args)
}

return baseCloneDeep(value, cache)
}
40 changes: 36 additions & 4 deletions src/general.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,19 +37,51 @@ export function isPromise<T = any>(val: unknown): val is Promise<T> {
}

export function isMap(val: unknown): val is Map<any, any> {
return toTypeString(val) === '[object Map]'
return toRawType(val) === 'Map'
}

export function isSet(val: unknown): val is Set<any> {
return toTypeString(val) === '[object Set]'
return toRawType(val) === 'Set'
}

export function isDate(val: unknown): val is Date {
return toTypeString(val) === '[object Date]'
return toRawType(val) === 'Date'
}

export function isRegExp(val: unknown): val is RegExp {
return toTypeString(val) === '[object RegExp]'
return toRawType(val) === 'RegExp'
}

export function isWeakMap(val: unknown): val is WeakMap<any, any> {
return toRawType(val) === 'WeakMap'
}

export function isWeakSet(val: unknown): val is WeakSet<any> {
return toRawType(val) === 'WeakSet'
}

export function isArrayBuffer(val: unknown): val is ArrayBuffer {
return toRawType(val) === 'ArrayBuffer'
}

export function isTypedArray(val: unknown) {
return [
'Int8Array',
'Uint8Array',
'Uint8ClampedArray',
'Int16Array',
'Uint16Array',
'Int32Array',
'Uint32Array',
'Float32Array',
'Float64Array',
'BigInt64Array',
'BigUint64Array',
].includes(toRawType(val))
}

export function isDataView(val: unknown): val is DataView {
return toRawType(val) === 'DataView'
}

export function toRawType(value: unknown): string {
Expand Down
6 changes: 5 additions & 1 deletion src/string.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ export function genStringKey() {
return `generated-key-${key++}`
}

export function capitalizeFirstLetter(s: string) {
export function upperFirst(s: string) {
return s.charAt(0).toUpperCase() + s.slice(1)
}

export function lowerFirst(s: string) {
return s.charAt(0).toLowerCase() + s.slice(1)
}
Loading

0 comments on commit a0dc915

Please sign in to comment.