見出し画像

tidyjsを使用した前後のデータを含むオブジェクトの生成~ナビゲーションデータを例に~

こんにちわ。nap5です。

tidyjsを使用したナビゲーションデータ生成の紹介です。

定義側になります。lag,leadがtidyjsから提供されていますが、型付けがやや苦しいです。ですが、d3のようにコールバックで配列データが下りてくるので、カスタマイズすると、型付けがうまくワークアラウンドできます。

import { Path } from 'dot-path-value'
import { mutateWithSummary, tidy } from '@tidyjs/tidy'

type Props<T extends Record<string, unknown>> = {
  key: Path<T>,
  n?: number
}

export const getDataWithPrevNext = <T extends Record<string, unknown>>(
  data: T[],
  options: Props<T>
) => {
  const { key, n = 1 } = options
  const outputData = tidy(
    data,
    mutateWithSummary({
      prev: (data) => data.map((d, i) => {
        const item = (i >= n ? data[i - n] : null)
        if (item == null) return
        return item[key]
      }),
      next: (data) =>
        data.map((d, i) => {
          const item = (i + n < data.length ? data[i + n] : null)
          if (item == null) return
          return item[key]
        }),
    })
  )
  return outputData
}


使用側になります。

import { describe, test, expect } from 'vitest'
import { getDataWithPrevNext } from '.'

describe('getDataWithPrevNext', () => {
  type Route = {
    href: string,
    title: string,
    description: string,
  }

  const routes: Route[] = [
    {
      href: 'prologue',
      title: 'プロローグ: 新たなる挑戦へ',
      description: '新たな挑戦が始まります。宇宙への夢と期待を胸に、壮大な冒険の序章が開かれます。'
    },
    {
      href: 'uchiage-junbi-engine-to-koko-system',
      title: '1章: 打ち上げ準備 - エンジンと航行システム',
      description: '打ち上げに向けての準備が進められます。エンジンと航行システムに焦点を当て、技術的な詳細を探求します。'
    },
    {
      href: 'uchu-e-no-tabidachi-tsuki-e-no-michinori',
      title: '2章: 宇宙への旅立ち - 月への道のり',
      description: '宇宙への旅が始まります。月への道のりと、宇宙船内での生活について詳しく探ります。'
    },
    {
      href: 'getsu-men-chakuriku-rekishiteki-shunkan',
      title: '3章: 月面着陸 - 歴史的瞬間',
      description: '月面着陸とその歴史的瞬間に焦点を当て、人類の偉大な成果を讃えます。'
    },
    {
      href: 'epilogue',
      title: 'エピローグ: 宇宙探査の未来へ',
      description: '宇宙探査の未来に思いを馳せ、この壮大な旅が私たちに何を教えてくれたのかを振り返ります。'
    }
  ]
  test('href -> windowSize=1', () => {
    const inputData = routes
    const outputData = getDataWithPrevNext(inputData, { key: 'href', n: 1 })
    expect(outputData).toStrictEqual([
      {
        href: 'prologue',
        title: 'プロローグ: 新たなる挑戦へ',
        description:
          '新たな挑戦が始まります。宇宙への夢と期待を胸に、壮大な冒険の序章が開かれます。',
        prev: undefined,
        next: 'uchiage-junbi-engine-to-koko-system',
      },
      {
        href: 'uchiage-junbi-engine-to-koko-system',
        title: '1章: 打ち上げ準備 - エンジンと航行システム',
        description:
          '打ち上げに向けての準備が進められます。エンジンと航行システムに焦点を当て、技術的な詳細を探求します。',
        prev: 'prologue',
        next: 'uchu-e-no-tabidachi-tsuki-e-no-michinori',
      },
      {
        href: 'uchu-e-no-tabidachi-tsuki-e-no-michinori',
        title: '2章: 宇宙への旅立ち - 月への道のり',
        description:
          '宇宙への旅が始まります。月への道のりと、宇宙船内での生活について詳しく探ります。',
        prev: 'uchiage-junbi-engine-to-koko-system',
        next: 'getsu-men-chakuriku-rekishiteki-shunkan',
      },
      {
        href: 'getsu-men-chakuriku-rekishiteki-shunkan',
        title: '3章: 月面着陸 - 歴史的瞬間',
        description:
          '月面着陸とその歴史的瞬間に焦点を当て、人類の偉大な成果を讃えます。',
        prev: 'uchu-e-no-tabidachi-tsuki-e-no-michinori',
        next: 'epilogue',
      },
      {
        href: 'epilogue',
        title: 'エピローグ: 宇宙探査の未来へ',
        description:
          '宇宙探査の未来に思いを馳せ、この壮大な旅が私たちに何を教えてくれたのかを振り返ります。',
        prev: 'getsu-men-chakuriku-rekishiteki-shunkan',
        next: undefined,
      },
    ])
  })
})


demo code.


簡単ですが、以上です。

いいなと思ったら応援しよう!