Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
# AI
.agents/
.claude/
.gemini/
plans/
GEMINI.md
CLAUDE.md

# VStudio stuff
/.vs
/.vscode
Expand Down
12 changes: 11 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.2.8] - 2026-09-13

### Changed
- Incremented version to 0.2.8.
- **Breaking Change**: Conformed empty and whitespace-only document parsing to RFC 4627, RFC 7159, RFC 8259, and JSON5 specifications. Parsing empty strings, whitespace-only content, or empty files now returns `nullptr` (or throws `TJParseException` when `throw_exception = true`) instead of fabricating an empty `TJValueString`.
- `TJ::is_valid("")` now correctly returns `false`.

### Fixed
- Fixed inconsistent behaviour where JSON5 returned `nullptr` on empty input while RFC 7159/8259 returned a `TJValueString`.

## [0.2.7] - 2026-06-27

### Added
Expand All @@ -22,7 +32,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added warning callback trigger when attempting to retrieve non-existent keys in `TJValueObject` using `try_get_string`, `get_*(..)`, or `get<>(..)` methods.

### Changed
- Incremented version to 0.3.0.
- Incremented version to 0.2.8.

## [0.2.4] - 2026-05-20

Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[![CI](https://github.com/FFMG/TinyJSON/actions/workflows/c-cpp.yml/badge.svg)](https://github.com/FFMG/TinyJSON/actions/workflows/c-cpp.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![Version](https://img.shields.io/badge/version-0.2.7-blue.svg)](src/TinyJSON.h)
[![Version](https://img.shields.io/badge/version-0.2.8-blue.svg)](src/TinyJSON.h)

A lightweight and lightning-fast C++ JSON & JSON5 parser designed for high performance and minimal footprint.

Expand Down Expand Up @@ -131,8 +131,8 @@ The version is set in the `TinyJSON.h` file.
```cpp
static const short TJ_VERSION_MAJOR = 0;
static const short TJ_VERSION_MINOR = 2;
static const short TJ_VERSION_PATCH = 7;
static const char TJ_VERSION_STRING[] = "0.2.7";
static const short TJ_VERSION_PATCH = 8;
static const char TJ_VERSION_STRING[] = "0.2.8";
```

### Simple Value Access
Expand Down
16 changes: 6 additions & 10 deletions src/TinyJSON.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4222,15 +4222,16 @@ namespace TinyJSON
return nullptr;
}

if (value_found == nullptr && parse_options.specification == parse_options::json5_1_0_0)
if (value_found == nullptr)
{
// JSON5 requires a value
return nullptr;
parse_result.assign_exception_message(TJCHARPREFIX("The JSON text is empty or contains no value."));
parse_result.throw_if_exception();
return nullptr;
}

if (parse_options.specification == parse_options::rfc4627 && !parse_result.has_exception_message())
{
if (value_found == nullptr || (!value_found->is_array() && !value_found->is_object()))
if (!value_found->is_array() && !value_found->is_object())
{
// error: RFC 4627: A JSON text must be either an object or an array.
parse_result.assign_exception_message("RFC 4627: A JSON text must be either an object or an array.");
Expand All @@ -4243,13 +4244,8 @@ namespace TinyJSON
}

// return if we found anything.
// if we found nothing ... then it is not an error, just an empty string
parse_result.throw_if_exception();
if (value_found == nullptr && parse_result.options().specification == parse_options::json5_1_0_0)
{
return nullptr;
}
return value_found != nullptr ? value_found : new TJValueString(TJCHARPREFIX(""));
return value_found;
}

/// <summary>
Expand Down
5 changes: 3 additions & 2 deletions src/TinyJSON.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,11 @@
// v0.2.5 - added raise warning when key is not found.
// v0.2.6 - fixed a bug in the resizing of string buffers.
// v0.2.7 - improved parse_file error reporting with specific system errors and file name.
// v0.2.8 - conformed empty input parsing to RFC specifications (returns nullptr / throws instead of empty string).
static const short TJ_VERSION_MAJOR = 0;
static const short TJ_VERSION_MINOR = 2;
static const short TJ_VERSION_PATCH = 7;
static const char TJ_VERSION_STRING[] = "0.2.7";
static const short TJ_VERSION_PATCH = 8;
static const char TJ_VERSION_STRING[] = "0.2.8";

#ifndef TJ_USE_CHAR
# define TJ_USE_CHAR 1
Expand Down
26 changes: 14 additions & 12 deletions tests/testtinyjson.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -352,29 +352,23 @@ TEST(TestBasic, NullInStringIsValid) {
delete json;
}

TEST(TestBasic, NothingIsJustAnEmptyString) {
TEST(TestBasic, EmptyStringReturnsNull) {
auto json = TinyJSON::TJ::parse("");
ASSERT_NE(nullptr, json);
ASSERT_TRUE(json->is_string());
ASSERT_STREQ("", json->dump_string());

delete json;
ASSERT_EQ(nullptr, json);
}

TEST(TestBasic, NothingIsJustAnEmptyStringWithSpaces) {
TEST(TestBasic, WhitespaceOnlyStringReturnsNull) {
auto json = TinyJSON::TJ::parse(R"(






)");
ASSERT_NE(nullptr, json);
ASSERT_TRUE(json->is_string());
ASSERT_STREQ("", json->dump_string());

delete json;

)");
ASSERT_EQ(nullptr, json);
}

TEST(TestBasic, StringValueIsValid) {
Expand Down Expand Up @@ -563,6 +557,14 @@ TEST(TestBasic, ArrayIsValid) {
ASSERT_TRUE(TinyJSON::TJ::is_valid("[12,13,14]"));
}

TEST(TestBasic, EmptyStringIsNotValid) {
ASSERT_FALSE(TinyJSON::TJ::is_valid(""));
}

TEST(TestBasic, WhitespaceOnlyIsNotValid) {
ASSERT_FALSE(TinyJSON::TJ::is_valid(" \t\r\n "));
}

TEST(TestBasic, UserLiteralsArray)
{
using namespace TinyJSON;
Expand Down
Loading
Loading