JavaScript Python PHP
import * as __biblioteca0 from "csv-stringify/browser/esm/sync";
import * as __biblioteca1 from "yaml";
function executar(input = '[{"nome":"João","codigo":"00123","ativo":false,"total":0}]', delimiter = ',') {
const stringify = __biblioteca0["stringify"];
const { parseJsonCompatible: parseJsonCompatible } = (() => {
const LineCounter = __biblioteca1["LineCounter"];
const parseDocument = __biblioteca1["parseDocument"];
const isAlias = __biblioteca1["isAlias"];
const isScalar = __biblioteca1["isScalar"];
const isSeq = __biblioteca1["isSeq"];
const isMap = __biblioteca1["isMap"];
const SAFE_TAGS = new Set(['str', 'bool', 'null', 'int', 'float', 'map', 'seq'].map(tag => `tag:yaml.org,2002:${tag}`));
function parseJsonCompatible(input, format, onObjectKeys) {
if (!input.trim())
throw new Error(`Informe um documento ${format}.`);
if (input.length > 1000000)
throw new Error('A entrada excede o limite de 1 milhão de caracteres.');
if (format === 'JSON') {
// Syntax check only: do not use the rounded numeric values from JSON.parse.
try {
JSON.parse(input);
}
catch (cause) {
throw new Error(`JSON inválido: ${cause instanceof Error ? cause.message : 'erro de sintaxe'}`);
}
}
const lines = new LineCounter();
const doc = parseDocument(input, { version: '1.2', schema: format === 'JSON' ? 'json' : 'core', intAsBigInt: true, uniqueKeys: true, lineCounter: lines, prettyErrors: true, resolveKnownTags: false });
const issue = doc.errors[0] ?? doc.warnings[0];
if (issue)
throw new Error(`${format} inválido (${issue.code}): ${issue.message}`);
if (doc.directives?.yaml.version !== '1.2')
throw new Error('Somente YAML 1.2 é aceito para preservar os tipos de JSON.');
let count = 0;
function fail(message, node) {
const offset = node?.range?.[0];
const position = offset === undefined ? '' : (() => { const { line, col } = lines.linePos(offset); return ` (linha ${line}, coluna ${col})`; })();
throw new Error(message + position);
}
function convert(node, depth = 0) {
if (++count > 100000 || depth > 100)
fail('Documento muito complexo: limite de 100 níveis ou 100 mil nós.', node);
if (!node)
return null;
if (isAlias(node))
fail('Aliases YAML não são aceitos: JSON não preserva referências ou ciclos.', node);
if (node.tag && !SAFE_TAGS.has(node.tag))
fail(`Tag não permitida: ${node.tag}.`, node);
if (isScalar(node)) {
const value = node.value;
if (typeof value === 'bigint') {
if (value === BigInt(0) && node.source?.startsWith('-'))
fail('JSON de saída não preserva o sinal de zero negativo. Use 0 ou uma string.', node);
if (value > BigInt(Number.MAX_SAFE_INTEGER) || value < BigInt(Number.MIN_SAFE_INTEGER))
fail('Inteiro fora do intervalo seguro de JSON/JavaScript. Use uma string entre aspas para preservar todos os dígitos.', node);
return Number(value);
}
if (typeof value === 'number') {
if (!Number.isFinite(value))
fail('JSON não representa NaN ou infinito.', node);
if (Number.isInteger(value) && !Number.isSafeInteger(value))
fail('Número inteiro fora do intervalo seguro. Use uma string entre aspas para preservar a precisão.', node);
if (value === 0 && /[1-9]/.test((node.source ?? '').split(/[eE]/)[0]))
fail('Número pequeno demais para a precisão de JavaScript. Use uma string entre aspas.', node);
if (Object.is(value, -0))
fail('JSON de saída não preserva o sinal de zero negativo. Use 0 ou uma string.', node);
return value;
}
if (value === null || typeof value === 'string' || typeof value === 'boolean')
return value;
fail('Valor não representável em JSON.', node);
}
if (isSeq(node))
return node.items.map(item => convert(item, depth + 1));
if (isMap(node)) {
const result = Object.create(null);
const keys = [];
for (const pair of node.items) {
if (!isScalar(pair.key) || typeof pair.key.value !== 'string')
fail('Chaves de objetos devem ser strings; chaves numéricas, booleanas ou complexas não são preservadas em JSON.', pair.key);
const key = pair.key.value;
if (format === 'YAML' && key === '<<' && pair.key.type === 'PLAIN')
fail('Chaves de merge YAML (<<) não são aceitas.', pair.key);
if (Object.hasOwn(result, key))
fail(`Chave duplicada: ${key}.`, pair.key);
keys.push(key);
result[key] = convert(pair.value, depth + 1);
}
onObjectKeys?.(result, keys);
return result;
}
fail('Estrutura não representável em JSON.', node);
}
if (!doc.contents)
throw new Error('Informe um documento com um valor; use null para um valor nulo.');
return convert(doc.contents);
}
return { parseJsonCompatible: parseJsonCompatible };
})();
function csvDelimiter(value) {
if (value === ',' || value === ';' || value === '\t')
return value;
if (value === 'Tabulação')
return '\t';
throw new Error('Escolha vírgula, ponto e vírgula ou tabulação.');
}
function jsonToCsv(input, delimiter = ',') {
const separator = csvDelimiter(delimiter);
const keyOrders = new WeakMap();
const value = parseJsonCompatible(input, 'JSON', (object, keys) => keyOrders.set(object, keys));
if (!Array.isArray(value) || value.length === 0)
throw new Error('Informe uma lista JSON não vazia de objetos simples.');
const columns = [];
const seen = new Set();
const objects = value.map((row, index) => {
if (row === null || typeof row !== 'object' || Array.isArray(row))
throw new Error(`Item ${index + 1}: deve ser um objeto simples.`);
for (const key of keyOrders.get(row) ?? Object.keys(row)) {
if (!key.trim())
throw new Error(`Item ${index + 1}: chave vazia não pode ser usada como cabeçalho CSV.`);
const cell = row[key];
if (cell !== null && typeof cell === 'object')
throw new Error(`Item ${index + 1}, propriedade "${key}": objetos e listas aninhados não são suportados em CSV.`);
if (!seen.has(key)) {
seen.add(key);
columns.push(key);
}
}
return row;
});
if (!columns.length)
throw new Error('A lista deve conter ao menos uma propriedade para gerar o cabeçalho CSV.');
const rows = objects.map(row => columns.map(key => !Object.hasOwn(row, key) || row[key] === null ? '' : String(row[key])));
// Quote empty cells so one-column empty records survive skip_empty_lines.
return stringify([columns, ...rows], { delimiter: separator, record_delimiter: '\r\n', quoted_empty: true, escape_formulas: false });
}
return jsonToCsv(input, delimiter);
}
import csv
import io
import json
import math
def executar(input='[{"nome":"João","codigo":"00123","ativo":false,"total":0}]', delimiter=","):
def read(text):
if not text.strip() or len(text.encode("utf-16-le", errors="surrogatepass")) // 2 > 1000000:
raise ValueError("Informe JSON com até 1 milhão de caracteres.")
def pairs(items):
result = {}
for key, value in items:
if key in result: raise ValueError("Chave duplicada: " + key)
result[key] = value
return result
def number(token):
value = float(token) if "." in token or "e" in token.lower() else int(token)
if not math.isfinite(value) or (value == 0 and (token.startswith("-") or any(c in "123456789" for c in token.lower().split("e")[0]))) or (value % 1 == 0 and abs(value) > 9007199254740991):
raise ValueError("Número não preservável; use uma string para preservar os dígitos.")
return value
def reject(token): raise ValueError("Constante JSON inválida: " + token)
value = json.loads(text, object_pairs_hook=pairs, parse_int=number, parse_float=number, parse_constant=reject)
count = 0
def walk(item, depth=0):
nonlocal count
count += 1
if count > 100000 or depth > 100: raise ValueError("Limite de 100 níveis ou 100 mil nós.")
if isinstance(item, dict):
for child in item.values(): walk(child, depth + 1)
elif isinstance(item, list):
for child in item: walk(child, depth + 1)
walk(value)
return value
def scalar(value):
if value is None: return "null"
if value is True: return "true"
if value is False: return "false"
if isinstance(value, float):
if value == int(value): return str(int(value))
text = repr(value)
if "e" in text:
coefficient, power = text.split("e")
exponent = int(power)
if -6 <= exponent < 21:
negative = coefficient.startswith("-")
coefficient = coefficient.lstrip("-")
digits = coefficient.replace(".", "")
point = coefficient.find(".") if "." in coefficient else len(coefficient)
point += exponent
return ("-" if negative else "") + ("0." + "0" * -point + digits if point <= 0 else digits + "0" * (point - len(digits)) if point >= len(digits) else digits[:point] + "." + digits[point:])
return coefficient + "e" + ("+" if exponent >= 0 else "-") + str(abs(exponent))
return text
return str(value)
delimiter = "\t" if delimiter == "Tabulação" else delimiter
if delimiter not in (",", ";", "\t"): raise ValueError("Delimitador inválido.")
data = read(input)
if not isinstance(data, list) or not data or any(not isinstance(row, dict) for row in data):
raise ValueError("Informe uma lista não vazia de objetos simples.")
columns = []
for row in data:
for key, value in row.items():
if not key.strip(): raise ValueError("Cabeçalho vazio.")
if isinstance(value, (dict, list)): raise ValueError("Objetos e listas aninhados não são suportados.")
if key not in columns: columns.append(key)
if not columns: raise ValueError("Informe ao menos uma propriedade.")
# Individual fields go through the CSV writer; explicit empty cells stay quoted.
def cell(value):
if value is None or value == "": return '""'
stream = io.StringIO(newline="")
csv.writer(stream, delimiter=delimiter, lineterminator="\r\n").writerow([scalar(value)])
return stream.getvalue()[:-2]
rows = [columns] + [[row.get(key) for key in columns] for row in data]
return "".join(delimiter.join(cell(value) for value in row) + "\r\n" for row in rows)
<?php
function executar($input = '[{"nome":"João","codigo":"00123","ativo":false,"total":0}]', $delimiter = ',') {
$read = function ($text) {
if (trim($text) === '' || !mb_check_encoding($text, 'UTF-8') || strlen(mb_convert_encoding($text, 'UTF-16LE', 'UTF-8')) / 2 > 1000000) throw new InvalidArgumentException('Informe JSON válido com até 1 milhão de caracteres.');
json_decode($text, false, 512, JSON_THROW_ON_ERROR | JSON_BIGINT_AS_STRING);
$stack = [];
for ($i = 0; $i < strlen($text); $i++) {
$ch = $text[$i];
if ($ch === '{' || $ch === '[') { $stack[] = ['keys'=>[]]; if (count($stack) > 101) throw new InvalidArgumentException('Limite de profundidade.'); }
elseif ($ch === '}' || $ch === ']') array_pop($stack);
elseif ($ch === '"') {
$start = $i;
while (++$i < strlen($text)) { if ($text[$i] === '\\') $i++; elseif ($text[$i] === '"') break; }
$look = $i + 1;
while ($look < strlen($text) && str_contains(" \r\n\t", $text[$look])) $look++;
if (($text[$look] ?? '') === ':') {
$key = json_decode(substr($text, $start, $i - $start + 1), false, 512, JSON_THROW_ON_ERROR);
$index = count($stack) - 1;
if (array_key_exists($key, $stack[$index]['keys'])) throw new InvalidArgumentException('Chave duplicada: '.$key);
$stack[$index]['keys'][$key] = true;
}
} elseif ($ch === '-' || ctype_digit($ch)) {
preg_match('/\G-?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?/', $text, $match, 0, $i);
$token = $match[0]; $value = (float)$token;
if (!is_finite($value) || ($value == 0 && (str_starts_with($token, '-') || preg_match('/[1-9]/', explode('e', strtolower($token))[0]))) || (floor($value) === $value && abs($value) > 9007199254740991)) throw new InvalidArgumentException('Número não preservável; use uma string.');
$i += strlen($token) - 1;
}
}
$value = json_decode($text, false, 512, JSON_THROW_ON_ERROR);
$count = 0;
$walk = function ($node, $depth = 0) use (&$walk, &$count) {
if (++$count > 100000 || $depth > 100) throw new InvalidArgumentException('Limite de 100 níveis ou 100 mil nós.');
if (is_object($node) || is_array($node)) foreach ($node as $child) $walk($child, $depth + 1);
};
$walk($value);
return $value;
};
$dump = fn($value) => preg_replace_callback('/^( +)/m', fn($match) => str_repeat(' ', strlen($match[1]) / 2), json_encode($value, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR));
$scalar = fn($value) => is_string($value) ? $value : json_encode($value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR);
$delimiter = $delimiter === 'Tabulação' ? "\t" : $delimiter;
if (!in_array($delimiter, [',', ';', "\t"], true)) throw new InvalidArgumentException('Delimitador inválido.');
$data = $read($input);
if (!is_array($data) || !$data) throw new InvalidArgumentException('Informe uma lista não vazia de objetos simples.');
$columns = [];
foreach ($data as $row) {
if (!$row instanceof stdClass) throw new InvalidArgumentException('Cada registro deve ser um objeto simples.');
foreach ($row as $key => $value) {
$key = (string)$key;
if (trim($key) === '') throw new InvalidArgumentException('Cabeçalho vazio.');
if (is_object($value) || is_array($value)) throw new InvalidArgumentException('Objetos e listas aninhados não são suportados.');
if (!in_array($key, $columns, true)) $columns[] = $key;
}
}
if (!$columns) throw new InvalidArgumentException('Informe ao menos uma propriedade.');
$cell = function ($value) use ($scalar, $delimiter) {
$text = $value === null ? '' : $scalar($value);
return $text === '' || strpbrk($text, $delimiter."\"\r\n") !== false ? '"'.str_replace('"', '""', $text).'"' : $text;
};
$output = implode($delimiter, array_map($cell, $columns))."\r\n";
foreach ($data as $row) $output .= implode($delimiter, array_map(fn($key) => $cell($row->{$key} ?? null), $columns))."\r\n";
return $output;
}