JavaScript Python PHP
import * as __biblioteca0 from "ajv";
import * as __biblioteca1 from "yaml";
function executar(schemaInput = '{"type":"object","properties":{"idade":{"type":"integer"}},"required":["idade"]}', input = '{"idade":25}') {
const Ajv = __biblioteca0["default"];
const { validateJson: validateJson } = (() => {
function validateJson(input) {
if (!input.trim())
throw new Error('Informe um documento JSON.');
if (input.length > 1000000)
throw new Error('Limite: 1 milhão de caracteres.');
try {
// Syntax only. Never use these parsed numbers to produce the formatted output.
JSON.parse(input);
}
catch (cause) {
const message = cause instanceof Error ? cause.message : 'Erro de sintaxe';
const offset = message.match(/position (\d+)/i);
const nativeLocation = message.match(/line (\d+) column (\d+)/i);
const position = offset ? Math.min(Number(offset[1]), input.length) : /end of JSON/i.test(message) ? input.length : undefined;
const before = position === undefined ? undefined : input.slice(0, position);
const line = before === undefined ? nativeLocation?.[1] : String(before.split('\n').length);
const column = before === undefined ? nativeLocation?.[2] : String(before.length - before.lastIndexOf('\n'));
const location = line && column ? ` (linha ${line}, coluna ${column})` : '';
throw new Error(`JSON inválido${location}: ${message}`);
}
const first = input.trim()[0];
const type = first === '{' ? 'objeto' : first === '[' ? 'lista' : first === '"' ? 'string' : first === 'n' ? 'null' : first === 't' || first === 'f' ? 'booleano' : 'número';
return { valid: true, type };
}
return { validateJson: validateJson };
})();
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 };
})();
const SCHEMA_DIALECT = 'http://json-schema.org/draft-07/schema#';
function read(input, label) {
try {
if (input.length > 100000)
throw new Error('Limite de 100 mil caracteres por entrada.');
validateJson(input);
return parseJsonCompatible(input, 'JSON');
}
catch (cause) {
throw new Error(`${label}: ${cause instanceof Error ? cause.message : 'entrada inválida'}`);
}
}
/** Visit schema locations, not example values or property names that resemble keywords. */
function checkPolicy(schema, depth = 0) {
if (typeof schema === 'boolean')
return;
if (!schema || Array.isArray(schema) || typeof schema !== 'object')
throw new Error('Cada schema deve ser um objeto ou booleano.');
if (depth > 50)
throw new Error('Limite de 50 níveis de subschemas.');
if (schema.$schema !== undefined && schema.$schema !== SCHEMA_DIALECT && schema.$schema !== SCHEMA_DIALECT.slice(0, -1))
throw new Error('Somente JSON Schema Draft-07 é suportado; use o URI mostrado no exemplo.');
if (schema.$id !== undefined || schema.id !== undefined)
throw new Error('$id/id não são suportados nesta ferramenta; use referências locais #/definitions/... sem identificadores de base.');
for (const key of ['properties', 'dependencies']) {
const map = schema[key];
if (map && typeof map === 'object' && Object.hasOwn(map, '__proto__'))
throw new Error(`A biblioteca não suporta __proto__ em ${key}. O schema foi rejeitado para não ignorar essa regra.`);
}
if (schema.$ref !== undefined) {
if (typeof schema.$ref !== 'string' || !(schema.$ref === '#' || schema.$ref.startsWith('#/')))
throw new Error('Somente $ref local (# ou #/...) é permitido. Referências externas não são carregadas.');
if (Object.keys(schema).some(key => key !== '$ref'))
throw new Error('$ref deve aparecer sozinho no subschema: Draft-07 ignora palavras-chave irmãs de $ref.');
}
for (const key of ['properties', 'patternProperties', 'definitions']) {
const map = schema[key];
if (map && typeof map === 'object' && !Array.isArray(map))
for (const child of Object.values(map))
checkPolicy(child, depth + 1);
}
const dependencies = schema.dependencies;
if (dependencies && typeof dependencies === 'object' && !Array.isArray(dependencies))
for (const child of Object.values(dependencies))
if (!Array.isArray(child))
checkPolicy(child, depth + 1);
for (const key of ['additionalProperties', 'additionalItems', 'contains', 'propertyNames', 'not', 'if', 'then', 'else'])
if (schema[key] !== undefined)
checkPolicy(schema[key], depth + 1);
if (schema.items !== undefined) {
if (Array.isArray(schema.items))
schema.items.forEach(child => checkPolicy(child, depth + 1));
else
checkPolicy(schema.items, depth + 1);
}
for (const key of ['allOf', 'anyOf', 'oneOf'])
if (Array.isArray(schema[key]))
schema[key].forEach(child => checkPolicy(child, depth + 1));
}
function validateJsonSchema(schemaInput, dataInput) {
const schema = read(schemaInput, 'JSON Schema');
checkPolicy(schema);
const ajv = new Ajv({ allErrors: true, jsonPointers: true, strictKeywords: true, ownProperties: true, format: 'full', coerceTypes: false, useDefaults: false, removeAdditional: false, logger: false });
let validate;
try {
validate = ajv.compile(schema);
}
catch (cause) {
throw new Error(`JSON Schema inválido ou não suportado: ${cause instanceof Error ? cause.message : 'não foi possível compilar'}`);
}
const data = read(dataInput, 'Documento JSON');
const valid = validate(data);
const errors = (validate.errors ?? []).slice(0, 50).map(error => ({
instancePath: error.dataPath || '/', schemaPath: error.schemaPath, keyword: error.keyword,
message: `${error.message ?? 'Restrição não atendida'}; detalhes: ${JSON.stringify(error.params)}`,
}));
return { valid, errors };
}
return validateJsonSchema(schemaInput, input);
}
import json
import math
from jsonschema import Draft7Validator, FormatChecker, RefResolver
def executar(schema_input='{"type":"object","properties":{"idade":{"type":"integer"}},"required":["idade"]}', input='{"idade":25}'):
def read(text):
if not text.strip(): raise ValueError('Informe um documento JSON')
if len(text.encode('utf-16-le',errors='surrogatepass'))//2>100000: raise ValueError('Limite de 100 mil caracteres')
def pairs(items):
output={}
for key,value in items:
if key in output: raise ValueError('Chave duplicada: '+key)
output[key]=value
return output
def number(token):
value=float(token) if '.' in token or 'e' in token.lower() else int(token)
if not math.isfinite(value): raise ValueError('Número não finito')
if value==0 and (token.startswith('-') or any(c in '123456789' for c in token.lower().split('e')[0])): raise ValueError('Zero negativo ou underflow')
if value%1==0 and abs(value)>9007199254740991: raise ValueError('Inteiro fora do intervalo seguro; use string')
return value
def reject(value): raise ValueError('Constante JSON inválida: '+value)
value=json.loads(text,object_pairs_hook=pairs,parse_int=number,parse_float=number,parse_constant=reject)
count=0
def walk(value,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(value,dict):
for child in value.values(): walk(child,depth+1)
elif isinstance(value,list):
for child in value: walk(child,depth+1)
walk(value)
return value
def reject(value): raise ValueError('Constante inválida: ' + value)
schema = read(schema_input)
allowed=['$comment', '$id', '$ref', '$schema', 'additionalItems', 'additionalProperties', 'allOf', 'anyOf', 'const', 'contains', 'contentEncoding', 'contentMediaType', 'default', 'definitions', 'dependencies', 'description', 'else', 'enum', 'examples', 'exclusiveMaximum', 'exclusiveMinimum', 'format', 'if', 'items', 'maxItems', 'maxLength', 'maxProperties', 'maximum', 'minItems', 'minLength', 'minProperties', 'minimum', 'multipleOf', 'not', 'oneOf', 'pattern', 'patternProperties', 'properties', 'propertyNames', 'readOnly', 'required', 'then', 'title', 'type', 'uniqueItems']
formats=['date', 'time', 'date-time', 'uri', 'uri-reference', 'uri-template', 'url', 'email', 'hostname', 'ipv4', 'ipv6', 'regex', 'uuid', 'json-pointer', 'json-pointer-uri-fragment', 'relative-json-pointer']
def policy(node,depth=0):
if isinstance(node, bool): return
if not isinstance(node, dict): raise ValueError('Schema deve ser objeto ou booleano')
if depth>50: raise ValueError('Limite de 50 níveis de subschemas')
if any(key not in allowed for key in node): raise ValueError('Palavra-chave desconhecida')
if 'format' in node and node['format'] not in formats: raise ValueError('Formato desconhecido')
if any(isinstance(node.get(key),dict) and '__proto__' in node[key] for key in ('properties','dependencies')): raise ValueError('__proto__ não suportado em properties/dependencies')
if '$id' in node or 'id' in node: raise ValueError('Identificadores de base não suportados')
if '$schema' in node and node['$schema'] not in ('http://json-schema.org/draft-07/schema#','http://json-schema.org/draft-07/schema'): raise ValueError('Somente Draft-07')
if '$ref' in node:
ref = node['$ref']
if not isinstance(ref, str) or not (ref == '#' or ref.startswith('#/')): raise ValueError('Somente referências locais')
if len(node) != 1: raise ValueError('$ref deve aparecer sozinho')
for key in ('properties','patternProperties','definitions'):
for child in node.get(key, {}).values(): policy(child,depth+1)
for child in node.get('dependencies', {}).values():
if not isinstance(child, list): policy(child,depth+1)
for key in ('additionalProperties','additionalItems','contains','propertyNames','not','if','then','else'):
if key in node: policy(node[key],depth+1)
if 'items' in node:
for child in node['items'] if isinstance(node['items'], list) else [node['items']]: policy(child,depth+1)
for key in ('allOf','anyOf','oneOf'):
for child in node.get(key, []): policy(child,depth+1)
Draft7Validator.check_schema(schema)
policy(schema)
data = read(input)
class LocalResolver(RefResolver):
def resolve_remote(self,uri): raise ValueError('Referências externas não são carregadas: '+uri)
validator = Draft7Validator(schema, format_checker=FormatChecker(),resolver=LocalResolver.from_schema(schema))
def pointer(parts): return '/' + '/'.join(str(part).replace('~','~0').replace('/','~1') for part in parts)
errors = [{'instancePath':pointer(error.absolute_path), 'schemaPath':'#'+pointer(error.absolute_schema_path), 'keyword':error.validator, 'message':error.message} for error in validator.iter_errors(data)]
return {'valid':not errors, 'errors':errors[:50]}
<?php
require 'vendor/autoload.php';
use Opis\JsonSchema\Validator;
use Opis\JsonSchema\Errors\ErrorFormatter;
function executar($schemaInput = '{"type":"object","properties":{"idade":{"type":"integer"}},"required":["idade"]}', $input = '{"idade":25}') {
$read = function ($text) {
if (trim($text)==='') throw new InvalidArgumentException('Informe um documento JSON');
if (!function_exists('iconv')) throw new RuntimeException('Requer extensão iconv');
$utf16=iconv('UTF-8','UTF-16LE',$text);
if ($utf16===false || strlen($utf16)/2>100000) throw new InvalidArgumentException('UTF-8 inválido ou limite de entrada excedido');
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[]=['object'=>$ch==='{','keys'=>[]]; continue; }
if ($ch==='}' || $ch===']') { array_pop($stack); continue; }
if ($ch==='"') {
$start=$i; $escaped=false;
while (++$i<strlen($text)) { $c=$text[$i]; if ($escaped) $escaped=false; elseif ($c==='\\') $escaped=true; elseif ($c==='"') break; }
$look=$i+1; while ($look<strlen($text) && str_contains(" \t\r\n",$text[$look])) $look++;
$index=count($stack)-1;
if ($index>=0 && $stack[$index]['object'] && ($text[$look] ?? '')===':') {
$key=json_decode(substr($text,$start,$i-$start+1),false,512,JSON_THROW_ON_ERROR);
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]; $number=(float)$token; $mantissa=explode('e',strtolower($token))[0];
if (!is_finite($number) || ($number==0 && (str_starts_with($token,'-') || preg_match('/[1-9]/',$mantissa))) || (floor($number)===$number && abs($number)>9007199254740991)) throw new InvalidArgumentException('Número não preservável; use string');
$i+=strlen($token)-1;
}
}
$value=json_decode($text,false,512,JSON_THROW_ON_ERROR);
$count=0;
$walk=function ($value,$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($value) || is_array($value)) foreach ($value as $child) $walk($child,$depth+1); };
$walk($value);
return $value;
};
$schema = $read($schemaInput);
$policy = function ($node,$depth=0) use (&$policy) {
if (is_bool($node)) return;
if (!is_object($node)) throw new InvalidArgumentException('Schema deve ser objeto ou booleano');
if ($depth>50) throw new InvalidArgumentException('Limite de 50 níveis de subschemas');
foreach (array_keys(get_object_vars($node)) as $key) if (!in_array($key,['$comment','$id','$ref','$schema','additionalItems','additionalProperties','allOf','anyOf','const','contains','contentEncoding','contentMediaType','default','definitions','dependencies','description','else','enum','examples','exclusiveMaximum','exclusiveMinimum','format','if','items','maxItems','maxLength','maxProperties','maximum','minItems','minLength','minProperties','minimum','multipleOf','not','oneOf','pattern','patternProperties','properties','propertyNames','readOnly','required','then','title','type','uniqueItems'],true)) throw new InvalidArgumentException('Palavra-chave desconhecida: '.$key);
if (property_exists($node,'format') && !in_array($node->format,['date','time','date-time','uri','uri-reference','uri-template','url','email','hostname','ipv4','ipv6','regex','uuid','json-pointer','json-pointer-uri-fragment','relative-json-pointer'],true)) throw new InvalidArgumentException('Formato desconhecido');
foreach (['properties','dependencies'] as $key) if (is_object($node->{$key} ?? null) && property_exists($node->{$key},'__proto__')) throw new InvalidArgumentException('__proto__ não suportado em properties/dependencies');
if (property_exists($node, '$id') || property_exists($node, 'id')) throw new InvalidArgumentException('Identificadores de base não suportados');
if (property_exists($node, '$schema') && !in_array($node->{'$schema'}, ['http://json-schema.org/draft-07/schema#','http://json-schema.org/draft-07/schema'], true)) throw new InvalidArgumentException('Somente Draft-07');
if (property_exists($node, '$ref')) {
$ref = $node->{'$ref'};
if (!is_string($ref) || !($ref === '#' || str_starts_with($ref, '#/'))) throw new InvalidArgumentException('Somente referências locais');
if (count(get_object_vars($node)) !== 1) throw new InvalidArgumentException('$ref deve aparecer sozinho');
}
foreach (['properties','patternProperties','definitions'] as $key) foreach (get_object_vars($node->{$key} ?? (object)[]) as $child) $policy($child,$depth+1);
foreach (get_object_vars($node->dependencies ?? (object)[]) as $child) if (!is_array($child)) $policy($child,$depth+1);
foreach (['additionalProperties','additionalItems','contains','propertyNames','not','if','then','else'] as $key) if (property_exists($node, $key)) $policy($node->{$key},$depth+1);
if (property_exists($node, 'items')) foreach (is_array($node->items) ? $node->items : [$node->items] as $child) $policy($child,$depth+1);
foreach (['allOf','anyOf','oneOf'] as $key) foreach ($node->{$key} ?? [] as $child) $policy($child,$depth+1);
};
$policy($schema);
$data = $read($input);
$validator = new Validator();
$result = $validator->validate($data, $schema, null, ['defaultDraft'=>'07']);
$errors=[]; $formatter=new ErrorFormatter();
$pointer=function ($parts) { return '/'.implode('/',array_map(fn($part)=>str_replace(['~','/'],['~0','~1'],(string)$part),$parts)); };
$collect=function ($error) use (&$collect,&$errors,$formatter,$pointer) {
if (count($errors)>=50) return;
if ($error->subErrors()) { foreach ($error->subErrors() as $child) $collect($child); return; }
$errors[]=['instancePath'=>$pointer($error->data()->fullPath()),'schemaPath'=>'#'.$pointer(array_merge($error->schema()->info()->path(),[$error->keyword()])),'keyword'=>$error->keyword(),'message'=>$formatter->formatErrorMessage($error)];
};
if ($result->hasError()) $collect($result->error());
return ['valid'=>$result->isValid(),'errors'=>$errors];
}