---
title: "@unikvs/utils"
description: "@unikvs/utils の使い方です。ファイル名の検証、バイト列操作、ストリーム変換を提供します。"
---

## 概要 [#overview]

`@unikvs/utils` は、ファイル名やディレクトリ名の検証、バイト列の変換や分割、反復可能オブジェクトから `ReadableStream` への変換などを提供するパッケージです。

プラグイン実装者向け

次のコマンドでインストールできます。

```package-install
npm install @unikvs/utils
```

```ts
import {
  assertValidFilename,
  assertValidDirname,
  bytesToHex,
  chunks,
  isValidFilename,
  isValidDirname,
  toReadableStream,
  withReadableStreamFrom,
  InvalidDirnameError,
  InvalidFilenameError,
} from "@unikvs/utils";
```

## ファイル名の検証 [#filename]

Windows・macOS・Linux で使えるファイル名か検証します。

### isValidFilename [#is-valid-filename]

```ts
function isValidFilename(filename: string): boolean;
```

使えない名前の場合は `false` を返します。例外は投げません。

```ts
import { isValidFilename } from "@unikvs/utils";

if (isValidFilename("report.txt")) {
  console.log("利用可能なファイル名です。");
}
```

### assertValidFilename [#assert-valid-filename]

```ts
function assertValidFilename(filename: string): void;
```

有効なら何もせずに戻り、無効なら `InvalidFilenameError` を投げます。

```ts
import { assertValidFilename } from "@unikvs/utils";

assertValidFilename("report.txt");
```

:::tip
真偽値で判定するなら `isValidFilename` を、無効時に止めるなら `assertValidFilename` を使います。
:::

## ディレクトリ名の検証 [#dirname]

Windows・macOS・Linux で使えるディレクトリ名か検証します。

### isValidDirname [#is-valid-dirname]

```ts
function isValidDirname(dirname: string): boolean;
```

有効なら `true` を、無効なら `false` を返します。例外は投げません。

```ts
import { isValidDirname } from "@unikvs/utils";

if (!isValidDirname("my-dir")) {
  console.log("利用できないディレクトリ名です。");
}
```

### assertValidDirname [#assert-valid-dirname]

```ts
function assertValidDirname(dirname: string): void;
```

有効なら何もせずに戻り、無効なら `InvalidDirnameError` を投げます。

```ts
import { assertValidDirname } from "@unikvs/utils";

assertValidDirname("my-dir");
```

## バイト列操作 [#bytes]

バイナリーデータの変換と分割を行います。

### bytesToHex [#bytes-to-hex]

```ts
function bytesToHex(bytes: Uint8Array): string;
```

`Uint8Array` を小文字の 16 進数文字列に変換します。

```ts
import { bytesToHex } from "@unikvs/utils";

const hex = bytesToHex(new Uint8Array([0, 255, 16]));
console.log(hex); // "00ff10"
```

### chunks [#chunks]

```ts
function chunks<TData extends DataView | ITypedArray>(
  data: TData,
  maxChunkByteSize: number,
): Generator<TData, void, unknown>;
```

データを指定バイト数ごとに分割し、順に返すジェネレーターを返します。

```ts
import { chunks } from "@unikvs/utils";

const data = new Uint8Array([1, 2, 3, 4, 5]);

for (const chunk of chunks(data, 2)) {
  console.log(chunk);
}
```

## ストリーム変換 [#streams]

反復可能オブジェクトを `ReadableStream` に変換します。

### toReadableStream [#to-readable-stream]

```ts
function toReadableStream<T>(
  iterable: Iterable<T> | AsyncIterable<T>,
): ReadableStream<T>;
```

同期・非同期の反復可能オブジェクトから `ReadableStream` を作ります。

```ts
import { toReadableStream } from "@unikvs/utils";

const stream = toReadableStream([1, 2, 3]);

for await (const value of stream) {
  console.log(value);
}
```

### withReadableStreamFrom [#with-readable-stream-from]

```ts
function withReadableStreamFrom<T>(
  cb: (ReadableStream: ReadableStreamWithFrom) => T,
): T;
```

`ReadableStream.from` を使った処理を、対応していない環境でも同じ書き方で実行できます。

```ts
import { withReadableStreamFrom } from "@unikvs/utils";

const stream = withReadableStreamFrom((ReadableStream) =>
  ReadableStream.from([1, 2, 3]),
);
```

## エラー [#errors]

ファイル名・ディレクトリ名の検証エラーです。使えない名前を指定すると投げられます。

| エラー | 発生条件 |
| --- | --- |
| `InvalidFilenameError` | 使えないファイル名を指定しました。 |
| `InvalidDirnameError` | 使えないディレクトリ名を指定しました。 |

```ts
import { InvalidFilenameError } from "@unikvs/utils";

throw new InvalidFilenameError({ filename: "../evil" });
```

## 使用例 [#examples]

ファイル名の検証・バイナリーの分割・ストリーム変換を組み合わせる例です。

```ts
import {
  assertValidFilename,
  chunks,
  InvalidFilenameError,
  toReadableStream,
} from "@unikvs/utils";

async function saveChunks(filename: string, data: Uint8Array): Promise<void> {
  try {
    assertValidFilename(filename);
  } catch (error) {
    if (error instanceof InvalidFilenameError) {
      console.error(`無効なファイル名です: ${error.meta.filename}`);
    }
    throw error;
  }

  const stream = toReadableStream(chunks(data, 64 * 1024));

  for await (const chunk of stream) {
    await writeChunk(filename, chunk);
  }
}

async function writeChunk(filename: string, chunk: Uint8Array): Promise<void> {
  console.log(`${filename}: ${chunk.byteLength} バイトを書き込みます。`);
}
```
