w

API リファレンス

JSON から CSV への変換機能を統合または拡張したい開発者向けの技術ドキュメントです。

ブラウザ API の使い方

Clipboard API

このツールは、コピー操作に最新の Clipboard API を使用します。

// Copy text to clipboard
async function copyToClipboard(text) {
  try {
    await navigator.clipboard.writeText(text);
    console.log("Text copied to clipboard");
  } catch (error) {
    console.error("Failed to copy text: ", error);
  }
}

ブラウザサポート:

  • Chrome 66+
  • Firefox 63+
  • Safari 13.1+
  • Edge 79+

ファイルダウンロード API

CSV ファイルは Blob API を使ってダウンロードされます。

// Download CSV file
function downloadCSV(csvContent, filename) {
  const blob = new Blob([csvContent], {
    type: "text/csv;charset=utf-8",
  });
  const url = URL.createObjectURL(blob);
  const link = document.createElement("a");
  link.href = url;
  link.download = filename;
  document.body.appendChild(link);
  link.click();
  document.body.removeChild(link);
  URL.revokeObjectURL(url);
}

データ処理関数

JSON 検証

// Validate JSON string
function validateJSON(jsonString) {
  try {
    const parsed = JSON.parse(jsonString);
    return { valid: true, data: parsed };
  } catch (error) {
    return { valid: false, error: error.message };
  }
}

CSV 変換ロジック

// Convert JSON array to CSV
function jsonToCSV(jsonData, options = {}) {
  const { delimiter = ",", includeHeaders = true, escapeQuotes = true } = options;

  if (!Array.isArray(jsonData) || jsonData.length === 0) {
    return "";
  }

  // Get all unique keys
  const allKeys = new Set();
  jsonData.forEach((item) => {
    if (typeof item === "object" && item !== null) {
      Object.keys(item).forEach((key) => allKeys.add(key));
    }
  });

  const keys = Array.from(allKeys);
  let csv = "";

  // Add headers
  if (includeHeaders) {
    csv += keys.map((key) => escapeCSVValue(key, delimiter, escapeQuotes)).join(delimiter) + "\n";
  }

  // Add data rows
  jsonData.forEach((item) => {
    if (typeof item === "object" && item !== null) {
      const row = keys.map((key) => {
        const value = item[key];
        return escapeCSVValue(value !== undefined ? String(value) : "", delimiter, escapeQuotes);
      });
      csv += row.join(delimiter) + "\n";
    }
  });

  return csv;
}

CSV 値のエスケープ

// Escape CSV values
function escapeCSVValue(value, delimiter, escapeQuotes) {
  if (!escapeQuotes) {
    return value;
  }

  // If value contains delimiter, newline, or quotes, wrap in quotes
  if (value.includes(delimiter) || value.includes("\n") || value.includes('"')) {
    // Escape quotes: replace " with ""
    return `"${value.replace(/"/g, '""')}"`;
  }

  return value;
}

設定オプション

変換オプションのインターフェース

interface ConversionOptions {
  delimiter: "," | ";" | "\t" | "|";
  encoding: "utf-8" | "utf-16" | "gbk";
  includeHeaders: boolean;
  escapeQuotes: boolean;
}

デフォルト設定

const defaultOptions = {
  delimiter: ",",
  encoding: "utf-8",
  includeHeaders: true,
  escapeQuotes: true,
};

データ構造

履歴レコードのインターフェース

interface HistoryRecord {
  id: string;
  input: string;
  inputPreview: string;
  output: string;
  delimiter: string;
  encoding: string;
  includeHeaders: boolean;
  escapeQuotes: boolean;
  rows: number;
  columns: number;
  timestamp: string;
  timestampMs: number;
}

統計情報のインターフェース

interface ConversionStats {
  rows: number;
  columns: number;
  size: string; // Formatted file size
}

エラーハンドリング

エラーの種類

enum ConversionError {
  INVALID_JSON = "INVALID_JSON",
  CONVERSION_FAILED = "CONVERSION_FAILED",
  EMPTY_DATA = "EMPTY_DATA",
  UNSUPPORTED_FORMAT = "UNSUPPORTED_FORMAT",
}

エラーハンドリング関数

// Handle conversion errors
function handleConversionError(error, jsonInput) {
  switch (error.type) {
    case "INVALID_JSON":
      return {
        message: "Invalid JSON format. Please check your input.",
        field: "input",
        severity: "error",
      };
    case "CONVERSION_FAILED":
      return {
        message: "Failed to convert JSON to CSV. Please check your data.",
        field: "output",
        severity: "error",
      };
    default:
      return {
        message: "An unexpected error occurred.",
        field: "general",
        severity: "error",
      };
  }
}

パフォーマンスに関する考慮事項

大規模データセットの処理

// Process large datasets in chunks
function processLargeDataset(jsonData, chunkSize = 1000) {
  const chunks = [];
  for (let i = 0; i < jsonData.length; i += chunkSize) {
    chunks.push(jsonData.slice(i, i + chunkSize));
  }

  return chunks.map((chunk) => jsonToCSV(chunk));
}

メモリ管理

// Monitor memory usage
function getMemoryUsage() {
  if (performance.memory) {
    return {
      used: performance.memory.usedJSHeapSize,
      total: performance.memory.totalJSHeapSize,
      limit: performance.memory.jsHeapSizeLimit,
    };
  }
  return null;
}

ブラウザ互換性

機能検出

// Check browser capabilities
function checkBrowserSupport() {
  return {
    clipboardAPI: !!navigator.clipboard,
    blobAPI: !!window.Blob,
    fileAPI: !!window.File,
    localStorage: !!window.localStorage,
    jsonSupport: !!JSON.parse,
  };
}

Polyfill

古いブラウザ向けには、以下の polyfill を検討してください。

// Clipboard API polyfill
if (!navigator.clipboard) {
  navigator.clipboard = {
    writeText: function (text) {
      return new Promise((resolve, reject) => {
        const textArea = document.createElement("textarea");
        textArea.value = text;
        document.body.appendChild(textArea);
        textArea.select();
        try {
          document.execCommand("copy");
          resolve();
        } catch (error) {
          reject(error);
        }
        document.body.removeChild(textArea);
      });
    },
  };
}

統合例

React コンポーネント統合

import React, { useState, useCallback } from "react";

function JSONToCSVConverter() {
  const [jsonInput, setJsonInput] = useState("");
  const [csvOutput, setCsvOutput] = useState("");
  const [options, setOptions] = useState(defaultOptions);

  const convertToCSV = useCallback(() => {
    try {
      const jsonData = JSON.parse(jsonInput);
      const csv = jsonToCSV(jsonData, options);
      setCsvOutput(csv);
    } catch (error) {
      console.error("Conversion failed:", error);
    }
  }, [jsonInput, options]);

  return (
    <div>
      <textarea
        value={jsonInput}
        onChange={(e) => setJsonInput(e.target.value)}
        placeholder="Enter JSON data..."
      />
      <button onClick={convertToCSV}>Convert</button>
      <textarea value={csvOutput} readOnly placeholder="CSV output will appear here..." />
    </div>
  );
}

Vue.js 統合

<template>
  <div class="json-to-csv-converter">
    <textarea v-model="jsonInput" placeholder="Enter JSON data..." @input="validateAndConvert" />
    <div class="options">
      <select v-model="options.delimiter">
        <option value=",">Comma (,)</option>
        <option value=";">Semicolon (;)</option>
        <option value="\t">Tab</option>
        <option value="|">Pipe (|)</option>
      </select>
    </div>
    <textarea :value="csvOutput" readonly placeholder="CSV output will appear here..." />
  </div>
</template>

<script>
export default {
  data() {
    return {
      jsonInput: "",
      csvOutput: "",
      options: {
        delimiter: ",",
        includeHeaders: true,
        escapeQuotes: true,
      },
    };
  },
  methods: {
    validateAndConvert() {
      try {
        const jsonData = JSON.parse(this.jsonInput);
        this.csvOutput = this.jsonToCSV(jsonData, this.options);
      } catch (error) {
        this.csvOutput = "";
      }
    },
    jsonToCSV(jsonData, options) {
      // Implementation here
    },
  },
};
</script>

テスト

単体テスト例

// Jest test examples
describe("JSON to CSV Converter", () => {
  test("converts simple array to CSV", () => {
    const input = [
      { name: "John", age: 30 },
      { name: "Jane", age: 25 },
    ];
    const expected = "name,age\nJohn,30\nJane,25\n";
    expect(jsonToCSV(input)).toBe(expected);
  });

  test("handles special characters", () => {
    const input = [{ name: "Smith, John", quote: 'He said "Hello"' }];
    const expected = 'name,quote\n"Smith, John","He said ""Hello"""\n';
    expect(jsonToCSV(input)).toBe(expected);
  });

  test("validates JSON input", () => {
    const invalidJson = '{ name: "John" }'; // Missing quotes
    const result = validateJSON(invalidJson);
    expect(result.valid).toBe(false);
  });
});
このページは役に立ちましたか?