Skip to content

Commit

Permalink
feat: key-prefix 機能を追加 (#5)
Browse files Browse the repository at this point in the history
* feat: key-prefix 機能を追加

* Create empty-eagles-argue.md

* Update README.md
  • Loading branch information
mew-ton authored Sep 13, 2023
1 parent b975f83 commit 0ebd4f5
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 23 deletions.
5 changes: 5 additions & 0 deletions .changeset/empty-eagles-argue.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"json-origami": minor
---

feat: key-prefix 機能を追加
13 changes: 11 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ console.log(result)
### arrayIndex

**Type**: `'dot' | 'bracket'`
**Default**: 'bracket'
**Default**: `'bracket'`

Determines the formatting of array indexes when keys are compressed. Choose between dot notation (.0) or bracket notation ([0]).

Expand All @@ -106,10 +106,19 @@ conole.log(result)
/// { a: 1, 'b.c': 2, 'b.d.0': 3, 'b.d.1.e': 4 }
```

### keyPrefix

Options for 'fold'

**Type**: `string`
**Default**: `''` (empty string)

Adds a specified prefix to the keys in the output.

## License

[MIT](./LICENSE)

## Contributing

see [CONTRIBUTING.md}(./CONTRIBUTING.md)
see [CONTRIBUTING.md](./CONTRIBUTING.md)
7 changes: 5 additions & 2 deletions src/fold.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {
defaultFoldOption,
defaultCommonOption,
type Dictionary,
type FoldOption,
type Folded,
Expand Down Expand Up @@ -34,7 +34,10 @@ import {
*/
export function fold<D extends Dictionary>(obj: D, option?: FoldOption): Folded<D> {
return Object.fromEntries(
flatEntries('', obj, { ...defaultFoldOption, ...option } as FixedFoldOption)
flatEntries(option?.keyPrefix ?? '', obj, {
...defaultCommonOption,
...option
} as FixedFoldOption)
) as Folded<D>
}

Expand Down
4 changes: 2 additions & 2 deletions src/twist.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { fold, unfold } from '.'
import type { Dictionary, MoveMap, Twist, FoldOption } from './type'
import type { Dictionary, MoveMap, Twist, TwistOption } from './type'

/**
*
Expand All @@ -9,7 +9,7 @@ import type { Dictionary, MoveMap, Twist, FoldOption } from './type'
export function twist<D extends Dictionary, M extends MoveMap>(
obj: D,
moveMap: M,
option?: FoldOption
option?: TwistOption
): Twist<D, M> {
const folded = fold(obj, option)

Expand Down
33 changes: 27 additions & 6 deletions src/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,39 @@ export type Twist<_D extends Dictionary, _M extends MoveMap> = object
*/
export type ArrayIndex = 'dot' | 'bracket'

interface CommonOption {
/**
* @default 'bracet'
*/
arrayIndex?: 'dot' | 'bracket'
}

/**
*
*/
export interface FoldOption {
export interface FoldOption extends CommonOption {
/**
* @default 'bracet'
*
*/
arrayIndex?: 'dot' | 'bracket'
keyPrefix?: string
}

export const defaultFoldOption = {
arrayIndex: 'bracket'
export const defaultCommonOption = {
arrayIndex: 'bracket' as ArrayIndex
} satisfies FoldOption

export type FixedFoldOption = Readonly<Required<FoldOption>>
export type FixedFoldOption = Readonly<FoldOption & typeof defaultCommonOption>

/**
*
*/
export interface UnfoldOption extends CommonOption {}

export type FixedUnfoldOption = Readonly<UnfoldOption & typeof defaultCommonOption>

/**
*
*/
export interface TwistOption extends CommonOption {}

export type FixedTwistOption = Readonly<TwistOption & typeof defaultCommonOption>
22 changes: 11 additions & 11 deletions src/unfold.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import {
defaultFoldOption,
defaultCommonOption,
type ArrayIndex,
type FixedFoldOption,
type FoldOption,
type FixedUnfoldOption,
type UnfoldOption,
type Folded,
type Unfolded
} from './type'
Expand Down Expand Up @@ -32,11 +32,11 @@ import {
* // }
* ```
*/
export function unfold<KV extends Folded<any>>(kv: KV, option?: FoldOption): Unfolded<KV> {
export function unfold<KV extends Folded<any>>(kv: KV, option?: UnfoldOption): Unfolded<KV> {
const fixedOpion = {
...defaultFoldOption,
...defaultCommonOption,
...option
} as FixedFoldOption
} as FixedUnfoldOption
validateKeys(kv, fixedOpion)

return unfoldInternal(Object.entries(kv), fixedOpion) as Unfolded<KV>
Expand All @@ -47,7 +47,7 @@ const validateIndexMap = {
bracket: (k) => /\[\d+\]/.test(k)
} satisfies Record<ArrayIndex, (key: string) => boolean>

function validateKeys(kv: Folded<any>, opt: FixedFoldOption) {
function validateKeys(kv: Folded<any>, opt: FixedUnfoldOption) {
for (const key in kv) {
if (/\d+/.test(key)) {
validateNumberKey(key, opt)
Expand All @@ -59,7 +59,7 @@ function validateKeys(kv: Folded<any>, opt: FixedFoldOption) {
}
}

function validateNumberKey(key: string, { arrayIndex }: FixedFoldOption) {
function validateNumberKey(key: string, { arrayIndex }: FixedUnfoldOption) {
if (!validateIndexMap[arrayIndex](key)) {
throw new Error(`Invalid key ${key}`)
}
Expand All @@ -70,7 +70,7 @@ const extractHeadIndexMap = {
bracket: (k) => (k.match(/^\[(\d+)\]/) ?? [])[1]
} satisfies Record<ArrayIndex, (key: string) => string | undefined>

function extractHeadKey(key: string, { arrayIndex }: FixedFoldOption): string | number {
function extractHeadKey(key: string, { arrayIndex }: FixedUnfoldOption): string | number {
const indexHead = extractHeadIndexMap[arrayIndex](key)

if (indexHead !== undefined) {
Expand All @@ -83,7 +83,7 @@ function extractHeadKey(key: string, { arrayIndex }: FixedFoldOption): string |
return match
}

function omitHeadKey(key: string, opt: FixedFoldOption): string {
function omitHeadKey(key: string, opt: FixedUnfoldOption): string {
const headKey = (() => {
const k = extractHeadKey(key, opt)
if (typeof k === 'number') {
Expand All @@ -95,7 +95,7 @@ function omitHeadKey(key: string, opt: FixedFoldOption): string {
return key.replace(headKey === undefined ? '' : new RegExp(`^${headKey}\\.?`), '')
}

function unfoldInternal(entries: Array<[string, unknown]>, opt: FixedFoldOption): unknown {
function unfoldInternal(entries: Array<[string, unknown]>, opt: FixedUnfoldOption): unknown {
if (entries.length <= 0) {
return {}
}
Expand Down
47 changes: 47 additions & 0 deletions test/fold.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,51 @@ describe('fold', () => {
'1.f.h.1': 8
})
})

it('nested object with key prefix', () => {
const target = {
a: 1,
b: {
c: 2,
d: [3, 4]
}
}

expect(fold(target, { keyPrefix: 'root' })).toEqual({
'root.a': 1,
'root.b.c': 2,
'root.b.d[0]': 3,
'root.b.d[1]': 4
})
})

it('nested object with root array with key prefix', () => {
const target = [
{
a: 1,
b: {
c: 2,
d: [3, 4]
}
},
{
e: 5,
f: {
g: 6,
h: [7, 8]
}
}
] as const

expect(fold(target, { keyPrefix: 'root' })).toEqual({
'root[0].a': 1,
'root[0].b.c': 2,
'root[0].b.d[0]': 3,
'root[0].b.d[1]': 4,
'root[1].e': 5,
'root[1].f.g': 6,
'root[1].f.h[0]': 7,
'root[1].f.h[1]': 8
})
})
})

0 comments on commit 0ebd4f5

Please sign in to comment.