feat(isJSONObject, isJSONValue, isJSONArray): Implement isJSONObject, isJSONValue, isJSONArray (#563)
Some checks failed
CI / codecov (push) Has been cancelled
Release / release (push) Has been cancelled

* feat:init

* feat

* fix:use prettier

* feat(isPlainObject): Update signature of isPlainObject

* feat: Add isJSONValue, isJSONArray, and refactor isJSONObject

* remove from functions

* docs: Update docs

* docs: Update docs

* docs: Update docs

* docs: Update docs

* docs: Update docs

* docs: Update docs

* docs: Update docs

---------

Co-authored-by: Sojin Park <raon0211@gmail.com>
Co-authored-by: Sojin Park <raon0211@toss.im>
This commit is contained in:
knott 2024-09-29 19:42:50 +08:00 committed by GitHub
parent 0c7d88973f
commit ded56755f3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
26 changed files with 608 additions and 24 deletions

View File

@ -0,0 +1,12 @@
import { bench, describe } from 'vitest';
import { isJSONObject as isJSONObjectToolkit } from 'es-toolkit';
describe('isJSONObject', () => {
bench('es-toolkit/isJSONObject', () => {
isJSONObjectToolkit({ nested: { boolean: true, array: [1, 2, 3], string: 'test', null: null } });
isJSONObjectToolkit({ date: new Date() });
isJSONObjectToolkit({ nested: { a: function* () {} } });
isJSONObjectToolkit(undefined);
isJSONObjectToolkit(/test/);
});
});

View File

@ -93,7 +93,9 @@
"some",
"sortBy"
],
"date": ["now"],
"date": [
"now"
],
"function": [
"after",
"ary",
@ -194,7 +196,11 @@
"sum",
"sumBy"
],
"number": ["clamp", "inRange", "random"],
"number": [
"clamp",
"inRange",
"random"
],
"object": [
"assign",
"assignIn",

View File

@ -0,0 +1,28 @@
# isJSONArray
与えられた値が有効なJSON配列かどうかを確認します。
有効なJSON配列は、すべての項目が[有効なJSON値](./isJSONValue.md)である配列として定義されます。
## インターフェース
```typescript
function isJSONArray(value: unknown): value is any[];
```
### パラメータ
- `value` (`unknown`): 確認する値。
### 戻り値
(`value is any[]`): 値が有効なJSON配列であれば`true`、それ以外の場合は`false`。
## 例
```typescript
console.log(isJSONArray([1, 2, 3])); // true
console.log(isJSONArray(['string', null, true])); // true
console.log(isJSONArray([1, 2, () => {}])); // false
console.log(isJSONArray('not an array')); // false
```

View File

@ -0,0 +1,27 @@
# isJSONObject
値がJSONオブジェクトかどうかを確認します。
有効なJSONオブジェクトとは、キーが文字列で、値が[有効なJSON値](./isJSONValue.md)を持つオブジェクトです。
## インターフェース
```typescript
function isJSONObject(obj: unknown): obj is Record<string, any>;
```
### パラメータ
- `obj` (`unknown`): 確認する値。
### 戻り値
(`obj is Record<string, any>`): `obj`がJSONオブジェクトである場合は`true`、それ以外の場合は`false`。
## 例
```typescript
isJSONObject({ nested: { boolean: true, array: [1, 2, 3], string: 'test', null: null } }); // true
isJSONObject({ regexp: /test/ }); // false
isJSONObject(123); // false
```

View File

@ -0,0 +1,39 @@
# isJSONValue
与えられた値が有効なJSON値かどうかを確認します。
有効なJSON値とは、次のいずれかを指します。
- [JSONオブジェクト](./isJSONObject.md)文字列キーと有効なJSON値を持つオブジェクト
- [JSON配列](./isJSONArray.md)有効なJSON値の配列
- 文字列(`string`
- 数字(`number`
- 真偽値(`boolean`
- `null`
## インターフェース
```typescript
function isJSONValue(value: unknown): value is Record<string, any> | any[] | string | number | boolean | null;
```
### パラメータ
- `value` (`unknown`): チェックする値。
### 戻り値
(`value is Record<string, any> | any[] | string | number | boolean | null`): 値が有効なJSON値であれば`true`、そうでなければ`false`。
## 例
```typescript
console.log(isJSONValue(null)); // true
console.log(isJSONValue({ key: 'value' })); // true
console.log(isJSONValue([1, 2, 3])); // true
console.log(isJSONValue('Hello')); // true
console.log(isJSONValue(42)); // true
console.log(isJSONValue(true)); // true
console.log(isJSONValue(undefined)); // false
console.log(isJSONValue(() => {})); // false
```

View File

@ -5,16 +5,16 @@
## インターフェース
```typescript
function isPlainObject(object: object): boolean;
function isPlainObject(value: unknown): value is Record<PropertyKey, any>;
```
### パラメータ
- `object` (`object`): 検査する値。
- `value` (`unknown`): 検査する値。
### 戻り値
(`boolean`): 値がプレーンオブジェクトの場合はtrue。
(`value is Record<PropertyKey, any>`): 値がプレーンオブジェクトの場合は`true`
## 例

View File

@ -0,0 +1,28 @@
# isJSONArray
주어진 값이 유효한 JSON 배열인지 확인해요.
유효한 JSON 배열이란, 모든 항목이 [유효한 JSON 값](./isJSONValue.md)인 배열이에요.
## 인터페이스
```typescript
function isJSONArray(value: unknown): value is any[];
```
### 파라미터
- `value` (`unknown`): 확인할 값.
### 반환 값
(`value is any[]`): 값이 유효한 JSON 배열이면 `true`, 그렇지 않으면 `false`.
## 예시
```typescript
console.log(isJSONArray([1, 2, 3])); // true
console.log(isJSONArray(['string', null, true])); // true
console.log(isJSONArray([1, 2, () => {}])); // false
console.log(isJSONArray('not an array')); // false
```

View File

@ -0,0 +1,27 @@
# isJSONObject
값이 JSON 객체인지 확인해요.
유효한 JSON 객체란, 키로 문자열을 가지고, 값으로 [유효한 JSON 값](./isJSONValue.md)을 가진 객체예요.
## 인터페이스
```typescript
function isJSONObject(obj: unknown): obj is Record<string, any>;
```
### 파라미터
- `obj` (`unknown`): 확인할 값.
### 반환 값
(`obj is Record<string, any>`): `obj`가 JSON 객체이면 `true`, 그렇지 않으면 `false`.
## 예시
```typescript
isJSONObject({ nested: { boolean: true, array: [1, 2, 3], string: 'test', null: null } }); // true
isJSONObject({ regexp: /test/ }); // false
isJSONObject(123); // false
```

View File

@ -0,0 +1,39 @@
# isJSONValue
주어진 값이 유효한 JSON 값인지 확인해요.
유효한 JSON 값이란, 다음 중 하나를 말해요.
- [JSON 객체](./isJSONObject.md) (문자열 키와 유효한 JSON 값을 가진 객체)
- [JSON 배열](./isJSONArray.md) (유효한 JSON 값의 배열)
- 문자열 (`string`)
- 숫자 (`number`)
- 참값 (`boolean`)
- `null`
## 인터페이스
```typescript
function isJSONValue(value: unknown): value is Record<string, any> | any[] | string | number | boolean | null;
```
### 파라미터
- `value` (`unknown`): 확인할 값.
### 반환 값
(`value is Record<string, any> | any[] | string | number | boolean | null`): 값이 유효한 JSON 값이면 `true`, 그렇지 않으면 `false`.
## 예시
```typescript
console.log(isJSONValue(null)); // true
console.log(isJSONValue({ key: 'value' })); // true
console.log(isJSONValue([1, 2, 3])); // true
console.log(isJSONValue('Hello')); // true
console.log(isJSONValue(42)); // true
console.log(isJSONValue(true)); // true
console.log(isJSONValue(undefined)); // false
console.log(isJSONValue(() => {})); // false
```

View File

@ -5,16 +5,16 @@
## 인터페이스
```typescript
function isPlainObject(object: object): boolean;
function isPlainObject(value: unknown): value is Record<PropertyKey, any>;
```
### 파라미터
- `object` (`object`): 검사할 값.
- `value` (`unknown`): 검사할 값.
### 반환 값
(`boolean`): 값이 순수 객체이면 true.
(`value is Record<PropertyKey, any>`): 값이 순수 객체이면 `true`.
## 예시

View File

@ -0,0 +1,28 @@
# isJSONArray
Checks if a given value is a valid JSON array.
A valid JSON array is defined as an array where all items are [valid JSON values](./isJSONValue.md).
## Signature
```typescript
function isJSONArray(value: unknown): value is any[];
```
### Parameters
- `value` (`unknown`): The value to check.
### Returns
(`value is any[]`): True if the value is a valid JSON array, otherwise false.
## Examples
```typescript
console.log(isJSONArray([1, 2, 3])); // true
console.log(isJSONArray(['string', null, true])); // true
console.log(isJSONArray([1, 2, () => {}])); // false
console.log(isJSONArray('not an array')); // false
```

View File

@ -0,0 +1,28 @@
# isJSONObject
Checks if a value is a JSON object.
A valid JSON object is defined as an object with string keys and valid [JSON values](./isJSONValue.md).
## Signature
```typescript
function isJSONObject(obj: unknown): obj is Record<string, any>;
```
### Parameters
- `value` (`unknown`): The value to check.
### Returns
(`obj is Record<string, any>`): True if the value is a JSON object, otherwise false.
## Examples
```typescript
console.log(isJSONObject({ nested: { boolean: true, array: [1, 2, 3], string: 'test', number: 1, null: null } })); // true
console.log(isJSONObject({})); // true
console.log(isJSONObject({ regexp: /test/ })); // false
console.log(isJSONObject(123)); // false
```

View File

@ -0,0 +1,39 @@
# isJSONValue
Checks if a given value is a valid JSON value.
A valid JSON value can be:
- [a JSON object](./isJSONObject.md) (an object with string keys and valid JSON values)
- [a JSON array](./isJSONArray.md) (an array of valid JSON values)
- a `string`
- a `number`
- a `boolean`
- `null`
## Signature
```typescript
function isJSONValue(value: unknown): value is Record<string, any> | any[] | string | number | boolean | null;
```
### Parameters
- `value` (`unknown`): The value to check.
### Returns
(`value is Record<string, any> | any[] | string | number | boolean | null`): True if the value is a valid JSON value, otherwise false.
## Examples
```typescript
console.log(isJSONValue(null)); // true
console.log(isJSONValue({ key: 'value' })); // true
console.log(isJSONValue([1, 2, 3])); // true
console.log(isJSONValue('Hello')); // true
console.log(isJSONValue(42)); // true
console.log(isJSONValue(true)); // true
console.log(isJSONValue(undefined)); // false
console.log(isJSONValue(() => {})); // false
```

View File

@ -5,16 +5,16 @@ Checks if a given value is a plain object.
## Signature
```typescript
function isPlainObject(object: object): boolean;
function isPlainObject(value: unknown): value is Record<PropertyKey, any>;
```
### Parameters
- `object` (`object`): The value to check.
- `value` (`unknown`): The value to check.
### Returns
(`boolean`): True if the value is a plain object, otherwise false.
(`value is Record<PropertyKey, any>`): True if the value is a plain object, otherwise false.
## Examples

View File

@ -0,0 +1,28 @@
# isJSONArray
检查给定值是否是有效的 JSON 数组。
有效的 JSON 数组定义为所有项都是[有效 JSON 值](./isJSONValue.md)的数组。
## 签名
```typescript
function isJSONArray(value: unknown): value is any[];
```
### 参数
- `value` (`unknown`): 要检查的值。
### 返回值
(`value is any[]`): 如果该值是有效的 JSON 数组则为 `true`,否则为 `false`
## 示例
```typescript
console.log(isJSONArray([1, 2, 3])); // true
console.log(isJSONArray(['string', null, true])); // true
console.log(isJSONArray([1, 2, () => {}])); // false
console.log(isJSONArray('not an array')); // false
```

View File

@ -0,0 +1,28 @@
# isJSONObject
检查一个值是否是合法的JSON对象。
一个有效的JSON对象是一个具有字符串键和[有效JSON值](./isJSONValue.md)的对象。
## 签名
```typescript
function isJSONObject(value: unknown): boolean;
```
### 参数
- `value` (`unknown`): 要检查的值。
### 返回值
(`boolean`): 如果该值是JSON对象则返回 `true`,否则返回 `false`
## 示例
```typescript
console.log(isJSONObject({ nested: { boolean: true, array: [1, 2, 3], string: 'test', null: null } })); // true
console.log(isJSONObject({})); // true
console.log(isJSONObject({ regexp: /test/ })); // false
console.log(isJSONObject(123)); // false
```

View File

@ -0,0 +1,39 @@
# isJSONValue
检查给定值是否为有效的JSON值。
一个有效的JSON值可以是
- [一个JSON对象](./isJSONObject.md) 一个具有字符串键和有效JSON值的对象
- [一个JSON数组](./isJSONArray.md) 一个有效JSON值的数组
- 字符串 (`string`)
- 数字 (`number`)
- 布尔值 (`boolean`)
- `null`
## 签名
```typescript
function isJSONValue(value: unknown): value is Record<string, any> | any[] | string | number | boolean | null;
```
### 参数
- `value` (`unknown`): 要检查的值。
### 返回值
(`value is Record<string, any> | any[] | string | number | boolean | null`): 如果值是有效的JSON值则为 `true`,否则为 `false`
## 示例
```typescript
console.log(isJSONValue(null)); // true
console.log(isJSONValue({ key: 'value' })); // true
console.log(isJSONValue([1, 2, 3])); // true
console.log(isJSONValue('Hello')); // true
console.log(isJSONValue(42)); // true
console.log(isJSONValue(true)); // true
console.log(isJSONValue(undefined)); // false
console.log(isJSONValue(() => {})); // false
```

View File

@ -5,16 +5,16 @@
## 签名
```typescript
function isPlainObject(object: object): boolean;
function isPlainObject(value: unknown): value is Record<PropertyKey, any>;
```
### 参数
- `object` (`object`): 要检查的值。
- `value` (`unknown`): 要检查的值。
### 返回值
(`boolean`): 如果该值是普通对象,则返回 `true`,否则返回 `false`
(`value is Record<PropertyKey, any>`): 如果该值是普通对象,则返回 `true`,否则返回 `false`
## 示例

View File

@ -15,6 +15,9 @@ export { isRegExp } from './isRegExp.ts';
export { isBoolean } from './isBoolean.ts';
export { isSymbol } from './isSymbol.ts';
export { isString } from './isString.ts';
export { isJSONObject } from './isJSONObject.ts';
export { isJSONValue } from './isJSONValue.ts';
export { isJSONArray } from './isJSONArray.ts';
export { isSet } from './isSet.ts';
export { isWeakMap } from './isWeakMap.ts';
export { isWeakSet } from './isWeakSet.ts';

View File

@ -0,0 +1,21 @@
import { isJSONArray } from './isJSONArray.ts';
import { describe, expect, it } from 'vitest';
describe('isJSONArray', () => {
it('should return true for valid JSON arrays', () => {
expect(isJSONArray([1, 2, 3])).toBe(true);
expect(isJSONArray(['string', null, true])).toBe(true);
expect(isJSONArray([{ key: 'value' }, [1, 2], null])).toBe(true);
expect(isJSONArray([])).toBe(true);
});
it('should return false for invalid JSON arrays', () => {
expect(isJSONArray('not an array')).toBe(false);
expect(isJSONArray(123)).toBe(false);
expect(isJSONArray(null)).toBe(false);
expect(isJSONArray(undefined)).toBe(false);
expect(isJSONArray({})).toBe(false);
expect(isJSONArray([1, 2, () => {}])).toBe(false);
expect(isJSONArray([1, 2, new Date()])).toBe(false);
});
});

View File

@ -0,0 +1,23 @@
import { isJSONValue } from './isJSONValue';
/**
* Checks if a given value is a valid JSON array.
*
* A valid JSON array is defined as an array where all items are valid JSON values.
*
* @param {unknown} value - The value to check.
* @returns {value is any[]} - True if the value is a valid JSON array, otherwise false.
*
* @example
* console.log(isJSONArray([1, 2, 3])); // true
* console.log(isJSONArray(["string", null, true])); // true
* console.log(isJSONArray([1, 2, () => {}])); // false
* console.log(isJSONArray("not an array")); // false
*/
export function isJSONArray(value: unknown): value is any[] {
if (!Array.isArray(value)) {
return false;
}
return value.every(item => isJSONValue(item));
}

View File

@ -0,0 +1,25 @@
import { isJSONObject } from './isJSONObject.ts';
import { describe, it, expect } from 'vitest';
describe('isJSONObject', () => {
it('isJSONObject should return true for valid JSON objects', () => {
expect(isJSONObject({ a: 1, b: 'es-toolkit' })).toBe(true);
expect(isJSONObject({})).toBe(true);
expect(isJSONObject({ nested: { boolean: true, array: [1, 2, 3], string: 'test', null: null } })).toBe(true);
});
it('isJSONObject should return false for not valid value', () => {
expect(isJSONObject(null)).toBe(false);
expect(isJSONObject(undefined)).toBe(false);
expect(isJSONObject('string')).toBe(false);
expect(isJSONObject(123)).toBe(false);
expect(isJSONObject(true)).toBe(false);
expect(isJSONObject([1, 2, 3])).toBe(false);
expect(isJSONObject({ date: new Date() })).toBe(false);
expect(isJSONObject({ func: () => {} })).toBe(false);
expect(isJSONObject({ regexp: /test/ })).toBe(false);
expect(isJSONObject({ undefinedProperty: undefined })).toBe(false);
expect(isJSONObject({ symbolProperty: Symbol('test') })).toBe(false);
expect(isJSONObject({ nested: { a: function* () {} } })).toBe(false);
});
});

View File

@ -0,0 +1,38 @@
import { isJSONValue } from './isJSONValue.ts';
import { isPlainObject } from './isPlainObject.ts';
/**
* Checks if a value is a JSON object.
*
* A valid JSON object is defined as an object with string keys and valid JSON values.
*
* @param {unknown} obj The value to check.
* @returns {obj is Record<string, any>} True if `obj` is a JSON object, false otherwise.
*
* @example
* isJSONObject({ nested: { boolean: true, array: [1, 2, 3], string: 'test', null: null } }); // true
* isJSONObject({ regexp: /test/ }); // false
* isJSONObject(123); // false
*/
export function isJSONObject(obj: unknown): obj is Record<string, any> {
if (!isPlainObject(obj)) {
return false;
}
const keys = Reflect.ownKeys(obj);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const value = obj[key];
if (typeof key !== 'string') {
return false;
}
if (!isJSONValue(value)) {
return false;
}
}
return true;
}

View File

@ -0,0 +1,36 @@
import { describe, expect, it } from 'vitest';
import { isJSONValue } from './isJSONValue.ts';
describe('isJSONValue', () => {
it('should return true for null', () => {
expect(isJSONValue(null)).toBe(true);
});
it('should return true for a valid JSON object', () => {
expect(isJSONValue({ key: 'value' })).toBe(true);
expect(
isJSONValue({
nested: { boolean: true, array: [1, 2, 3], string: 'test', null: null },
})
).toBe(true);
});
it('should return true for a valid JSON array', () => {
expect(isJSONValue([1, 2, 3])).toBe(true);
expect(isJSONValue(['string', 42, null, true])).toBe(true);
});
it('should return true for valid JSON primitive types', () => {
expect(isJSONValue('Hello')).toBe(true);
expect(isJSONValue(42)).toBe(true);
expect(isJSONValue(true)).toBe(true);
});
it('should return false for invalid JSON values', () => {
expect(isJSONValue(undefined)).toBe(false);
expect(isJSONValue(() => {})).toBe(false);
expect(isJSONValue(new Date())).toBe(false);
expect(isJSONValue(/regex/)).toBe(false);
expect(isJSONValue(Symbol('symbol'))).toBe(false);
});
});

View File

@ -0,0 +1,42 @@
import { isJSONArray } from './isJSONArray.ts';
import { isJSONObject } from './isJSONObject.ts';
/**
* Checks if a given value is a valid JSON value.
*
* A valid JSON value can be:
* - null
* - a JSON object (an object with string keys and valid JSON values)
* - a JSON array (an array of valid JSON values)
* - a string
* - a number
* - a boolean
*
* @param {unknown} value - The value to check.
* @returns {boolean} - True if the value is a valid JSON value, otherwise false.
*
* @example
* console.log(isJSONValue(null)); // true
* console.log(isJSONValue({ key: "value" })); // true
* console.log(isJSONValue([1, 2, 3])); // true
* console.log(isJSONValue("Hello")); // true
* console.log(isJSONValue(42)); // true
* console.log(isJSONValue(true)); // true
* console.log(isJSONValue(undefined)); // false
* console.log(isJSONValue(() => {})); // false
*/
export function isJSONValue(value: unknown): value is Record<string, any> | any[] | string | number | boolean | null {
switch (typeof value) {
case 'object': {
return value === null || isJSONArray(value) || isJSONObject(value);
}
case 'string':
case 'number':
case 'boolean': {
return true;
}
default: {
return false;
}
}
}

View File

@ -1,8 +1,8 @@
/**
* Checks if a given value is a plain object.
*
* @param {object} object - The value to check.
* @returns {boolean} - True if the value is a plain object, otherwise false.
* @param {object} value - The value to check.
* @returns {value is Record<PropertyKey, any>} - True if the value is a plain object, otherwise false.
*
* @example
* console.log(isPlainObject({})); // true
@ -11,28 +11,28 @@
* console.log(isPlainObject(Object.create(null))); // true
* console.log(Buffer.from('hello, world')); // false
*/
export function isPlainObject(object: object): boolean {
if (typeof object !== 'object') {
export function isPlainObject(value: unknown): value is Record<PropertyKey, any> {
if (typeof value !== 'object') {
return false;
}
if (object == null) {
if (value == null) {
return false;
}
if (Object.getPrototypeOf(object) === null) {
if (Object.getPrototypeOf(value) === null) {
return true;
}
if (object.toString() !== '[object Object]') {
if (value.toString() !== '[object Object]') {
return false;
}
let proto = object;
let proto = value;
while (Object.getPrototypeOf(proto) !== null) {
proto = Object.getPrototypeOf(proto);
}
return Object.getPrototypeOf(object) === proto;
return Object.getPrototypeOf(value) === proto;
}