技術 約5分で読めます

ラボツール拡張計画: テキスト処理系ツールの追加候補

導入

Geminiにlilting.ch/labを見てもらったところ、DevToysとの比較分析をもらった。

DevToysが「プログラマの道具箱」なら、あなたのサイトは「クリエイター(特に画像・AI・Web制作)のための工房」という印象で、かなり方向性が違って面白いです。

確かにその通りで、現状のLabは画像処理系が充実している一方、テキストデータ処理系が手薄になっている。

現状のツール分布(全31個):

カテゴリツール数
画像変換4
画像変形4
画像編集4
画像エフェクト3
ビューワー6
自然言語処理4
汎用ツール6

テキスト処理系は「マークダウンエディター」「形態素解析」「OCR」など自然言語処理寄りのものはあるが、JSONフォーマッターやBase64変換といった開発者向けツールがない。

追加候補一覧

優先度付きで追加候補をリストアップした。

優先度ツール用途
JSONフォーマッターJSON整形・検証・minify
Base64変換テキスト/画像のエンコード・デコード
YAMLフォーマッターYAML整形・検証・JSON相互変換
テキスト差分比較2つのテキストのDiff表示
URLエンコード/デコード日本語URLなどの変換
タイムスタンプ変換UNIX時間 ↔ 日時の相互変換
HTMLエンティティ変換<&lt; などの相互変換
UUID生成ランダムID生成
ハッシュ生成MD5/SHA256計算
JWTデコーダー認証トークン解析
.envエディター環境変数ファイルの整形・検証
INIエディターINIファイルの整形・検証

各ツールの実装仕様

JSONフォーマッター(優先度: 高)

機能概要:

  • JSON文字列の整形(pretty print)
  • minify(圧縮)
  • バリデーション(構文エラー検出)
  • シンタックスハイライト

UI構成案:

  • 左: 入力テキストエリア
  • 右: 出力テキストエリア(ハイライト付き)
  • 上部: インデント設定(2/4スペース、タブ)、整形/minifyボタン
  • エラー時: エラー位置と内容を表示

使用ライブラリ候補:

  • シンタックスハイライト: Prism.jsまたはカスタムCSS
  • JSON処理: ブラウザ標準のJSON.parse()/JSON.stringify()で十分

実装メモ:

  • JSON.stringify(obj, null, indent)でインデント付き整形
  • JSON.stringify(obj)でminify
  • try-catchでバリデーション、エラーメッセージから行番号を抽出

Base64変換(優先度: 高)

機能概要:

  • テキスト → Base64エンコード
  • Base64 → テキストデコード
  • 画像 → Base64(data URI形式)
  • Base64 → 画像プレビュー

UI構成案:

  • タブ切り替え: 「テキスト」「画像」
  • テキストモード: 入力/出力テキストエリア + エンコード/デコードボタン
  • 画像モード: ドラッグ&ドロップエリア + Base64出力 + プレビュー

使用ライブラリ候補:

  • ブラウザ標準API: btoa()/atob()(ASCII)、TextEncoder/TextDecoder(UTF-8対応)
  • 画像処理: FileReader API

実装メモ:

  • UTF-8対応のエンコード:
    const base64 = btoa(unescape(encodeURIComponent(text)));
  • UTF-8対応のデコード:
    const text = decodeURIComponent(escape(atob(base64)));
  • 画像のdata URI: data:image/png;base64,${base64}

YAMLフォーマッター(優先度: 中)

機能概要:

  • YAML文字列の整形
  • バリデーション(構文エラー検出)
  • JSON ↔ YAML 相互変換

UI構成案:

  • 左: 入力テキストエリア
  • 右: 出力テキストエリア
  • 上部: 整形ボタン、JSON変換ボタン、YAML変換ボタン
  • エラー時: エラー位置と内容を表示

使用ライブラリ候補:

  • js-yaml: YAMLパーサーの定番
  • yaml: より新しい選択肢

実装メモ:

  • js-yamlの場合:
    import yaml from 'js-yaml';
    // YAML → JSON
    const obj = yaml.load(yamlString);
    const json = JSON.stringify(obj, null, 2);
    // JSON → YAML
    const yamlOutput = yaml.dump(JSON.parse(jsonString));
  • YAMLはインデントが意味を持つので、整形時の設定(インデント幅)をオプションで提供

テキスト差分比較(優先度: 中)

機能概要:

  • 2つのテキストを並べて表示
  • 差分箇所をハイライト(追加=緑、削除=赤)
  • 行単位/文字単位の切り替え
  • 統合ビュー/分割ビューの切り替え

UI構成案:

  • 上部: 2つの入力テキストエリア(横並びまたは縦並び)
  • 下部: 差分表示エリア
  • オプション: 空白無視、大文字小文字無視

使用ライブラリ候補:

  • diff: 軽量なdiffライブラリ
  • monaco-editor: VSCodeのエディタ(diffビュー内蔵だが重い)

実装メモ:

  • diffライブラリのdiffLines()/diffChars()を使用
  • 結果をHTMLに変換してハイライト表示
  • monaco-editorはバンドルサイズが大きいので、シンプルな用途なら避ける

URLエンコード/デコード(優先度: 中)

機能概要:

  • テキスト → URLエンコード
  • URLエンコード → テキストデコード
  • 全体エンコード/コンポーネントエンコードの切り替え

UI構成案:

  • 入力テキストエリア
  • 出力テキストエリア
  • ボタン: エンコード/デコード
  • オプション: encodeURI/encodeURIComponentの切り替え

使用ライブラリ候補:

  • ブラウザ標準API: encodeURI()/decodeURI()encodeURIComponent()/decodeURIComponent()

実装メモ:

  • encodeURI: URL全体をエンコード(/?&などは保持)
  • encodeURIComponent: クエリパラメータなど部分的にエンコード(すべての特殊文字を変換)
  • 違いをUIで説明すると親切

タイムスタンプ変換(優先度: 中)

機能概要:

  • UNIXタイムスタンプ → 人間が読める日時
  • 日時 → UNIXタイムスタンプ
  • ミリ秒/秒の切り替え
  • タイムゾーン対応(UTC/ローカル/任意)

UI構成案:

  • 上部: UNIXタイムスタンプ入力 + 「現在時刻」ボタン
  • 下部: 日時表示(複数フォーマット)
  • 逆変換: 日時入力 → タイムスタンプ出力
  • タイムゾーン選択ドロップダウン

使用ライブラリ候補:

  • ブラウザ標準: Dateオブジェクトで十分
  • フォーマット: date-fns(軽量)、dayjs(Moment.js代替)

実装メモ:

  • 基本変換:
    // タイムスタンプ → 日時
    const date = new Date(timestamp * 1000); // 秒の場合
    const date = new Date(timestamp);        // ミリ秒の場合
    
    // 日時 → タイムスタンプ
    const timestamp = Math.floor(date.getTime() / 1000); // 秒
    const timestampMs = date.getTime();                   // ミリ秒
  • ISO 8601形式: date.toISOString()
  • ローカル形式: date.toLocaleString('ja-JP')
  • 桁数で秒/ミリ秒を自動判定(10桁=秒、13桁=ミリ秒)

HTMLエンティティ変換(優先度: 中)

機能概要:

  • HTML特殊文字 → エンティティ(エスケープ)
  • エンティティ → HTML特殊文字(アンエスケープ)
  • 数値参照(&#60;)と名前参照(&lt;)の両対応

UI構成案:

  • 入力テキストエリア
  • 出力テキストエリア
  • ボタン: エンコード/デコード
  • オプション: 全文字変換/最小限変換

使用ライブラリ候補:

  • he: HTMLエンティティの定番ライブラリ
  • 自前実装: 基本的な文字(<>&"')だけなら簡単

実装メモ:

  • 基本的なエスケープ:
    function escapeHtml(text) {
      const map = { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' };
      return text.replace(/[&<>"']/g, c => map[c]);
    }
  • アンエスケープ(ブラウザAPIを利用):
    function unescapeHtml(text) {
      const doc = new DOMParser().parseFromString(text, 'text/html');
      return doc.documentElement.textContent;
    }
  • 全文字を数値参照に変換する場合: &#${char.charCodeAt(0)};

UUID生成(優先度: 低)

機能概要:

  • UUID v4(ランダム)の生成
  • 複数個を一括生成
  • 大文字/小文字の切り替え
  • ハイフンあり/なしの切り替え

UI構成案:

  • 生成ボタン
  • 生成数の入力(1〜100)
  • 出力テキストエリア(コピーボタン付き)
  • オプション: 大文字/小文字、ハイフン有無

使用ライブラリ候補:

  • uuid: 定番ライブラリ
  • ブラウザ標準: crypto.randomUUID()(モダンブラウザ対応)

実装メモ:

  • crypto.randomUUID()が使えるならライブラリ不要
  • ハイフン除去: uuid.replace(/-/g, '')
  • 大文字化: uuid.toUpperCase()

ハッシュ生成(優先度: 低)

機能概要:

  • テキストからハッシュ値を計算
  • 対応アルゴリズム: MD5, SHA-1, SHA-256, SHA-512
  • ファイルからのハッシュ計算

UI構成案:

  • 入力テキストエリア または ファイルドロップエリア
  • アルゴリズム選択(ラジオボタンまたはドロップダウン)
  • 出力: ハッシュ値(コピーボタン付き)

使用ライブラリ候補:

  • Web Crypto API: crypto.subtle.digest()(SHA系)
  • js-md5: MD5用(Web Crypto APIにMD5はない)
  • crypto-js: 複数アルゴリズム対応

実装メモ:

  • Web Crypto APIの例:
    const buffer = new TextEncoder().encode(text);
    const hashBuffer = await crypto.subtle.digest('SHA-256', buffer);
    const hashArray = Array.from(new Uint8Array(hashBuffer));
    const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
  • MD5は非推奨だが需要はあるので一応対応

JWTデコーダー(優先度: 低)

機能概要:

  • JWTトークンをデコードして中身を表示
  • ヘッダー、ペイロード、署名を分けて表示
  • 有効期限(exp)のタイムスタンプを人間が読める形式に変換
  • 署名の検証はしない(秘密鍵がないため)

UI構成案:

  • 入力: JWTトークン(テキストエリア)
  • 出力: ヘッダー(JSON)、ペイロード(JSON)、署名(Base64)
  • 有効期限があれば「期限切れ」「あと○日」などを表示

使用ライブラリ候補:

  • ライブラリ不要: Base64デコードのみで可能

実装メモ:

  • JWTはheader.payload.signatureの形式(ドット区切り)
  • ヘッダーとペイロードはBase64URLエンコード
  • Base64URLのデコード:
    function base64UrlDecode(str) {
      const base64 = str.replace(/-/g, '+').replace(/_/g, '/');
      return decodeURIComponent(escape(atob(base64)));
    }
  • expフィールドはUNIXタイムスタンプ(秒)

.envエディター(優先度: 低)

機能概要:

  • .envファイルの整形(KEY=value形式)
  • 重複キーの検出
  • コメント行の保持
  • 値のクォート有無の統一

UI構成案:

  • 入力テキストエリア(.env形式)
  • 出力: テーブル表示(キー/値の一覧)
  • オプション: ソート(アルファベット順)、クォート統一

使用ライブラリ候補:

  • dotenv: 定番だがNode.js向け
  • 自前パース: ブラウザで使うなら簡易パーサーで十分

実装メモ:

  • 基本的なパース:
    function parseEnv(text) {
      const result = {};
      for (const line of text.split('\n')) {
        if (line.startsWith('#') || !line.includes('=')) continue;
        const [key, ...valueParts] = line.split('=');
        result[key.trim()] = valueParts.join('=').trim();
      }
      return result;
    }
  • クォートの除去: value.replace(/^["']|["']$/g, '')
  • 複数行の値(heredoc形式)は対応しない方がシンプル

INIエディター(優先度: 低)

機能概要:

  • INIファイルの整形
  • セクション[section]とキー=値のパース
  • バリデーション(構文エラー検出)
  • コメント行の保持

UI構成案:

  • 入力テキストエリア(INI形式)
  • 出力: ツリー表示(セクション > キー/値)
  • オプション: ソート、JSON変換

使用ライブラリ候補:

  • ini: Node.js向けだがブラウザでも使える
  • 自前パース: セクションとキー=値の単純な構造なので自前でも可

実装メモ:

  • 基本的なパース:
    function parseIni(text) {
      const result = {};
      let currentSection = '';
      for (const line of text.split('\n')) {
        const trimmed = line.trim();
        if (trimmed.startsWith(';') || trimmed.startsWith('#')) continue;
        if (trimmed.startsWith('[') && trimmed.endsWith(']')) {
          currentSection = trimmed.slice(1, -1);
          result[currentSection] = {};
        } else if (trimmed.includes('=')) {
          const [key, ...valueParts] = trimmed.split('=');
          const target = currentSection ? result[currentSection] : result;
          target[key.trim()] = valueParts.join('=').trim();
        }
      }
      return result;
    }
  • セクションなしのキーも許容(ルートレベル)

実装方針

カテゴリの追加

現在のカテゴリ定義(src/lib/lab-tools.ts):

export type LabToolCategory =
  | 'image-convert'
  | 'image-transform'
  | 'image-edit'
  | 'image-effect'
  | 'viewer'
  | 'nlp'
  | 'utility';

テキスト処理専用のカテゴリを追加する案:

  • text-process: テキスト処理(JSON, Base64, URL, ハッシュなど)
  • developer: 開発者ツール(より広い範囲)

あるいは、既存のutilityに含めてしまう案もある。ツールが増えてきたらカテゴリを分ける。

ツール登録の手順

  1. src/pages/lab/に新しいAstroファイルを作成
  2. src/lib/lab-tools.tsのtools配列にエントリを追加
  3. 一覧ページ(src/pages/lab/index.astro)に自動反映される

共通コンポーネント

テキスト処理系ツールは似たUIになるため、共通コンポーネントを作ると効率的:

  • TextArea: コピーボタン付きテキストエリア
  • ConvertButton: 変換ボタン
  • OptionToggle: オプション切り替え

とはいえ実装するのもまあまあ暇がないと……気が向いたらって感じで