diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 021a1da..4a408ce 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,21 +2,21 @@ name: CI on: push: - branches: [master] + branches: [master, v1] pull_request: - branches: [master] + branches: [master, v1] jobs: tests: runs-on: ubuntu-latest strategy: matrix: - php: ['8.2', '8.4'] + php: ['8.1', '8.5'] name: PHP ${{ matrix.php }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Setup PHP uses: shivammathur/setup-php@v2 @@ -40,7 +40,7 @@ jobs: name: Coding Standards steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Setup PHP uses: shivammathur/setup-php@v2 diff --git a/README.md b/README.md index fecb811..a3e327c 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![Latest Stable Version](https://img.shields.io/packagist/v/php-collective/toml?style=flat-square)](https://packagist.org/packages/php-collective/toml) [![Total Downloads](https://img.shields.io/packagist/dt/php-collective/toml?style=flat-square)](https://packagist.org/packages/php-collective/toml) [![PHPStan](https://img.shields.io/badge/PHPStan-level%208-brightgreen.svg?style=flat-square)](https://phpstan.org/) -[![PHP Version](https://img.shields.io/badge/php-%3E%3D8.2-8892BF.svg?style=flat-square)](https://php.net) +[![PHP Version](https://img.shields.io/badge/php-%3E%3D8.1-8892BF.svg?style=flat-square)](https://php.net) [![Software License](https://img.shields.io/badge/license-MIT-green.svg?style=flat-square)](LICENSE) A [TOML](https://toml.io/) (v1.0 and v1.1) parser and encoder for PHP with AST access and collected parse errors. @@ -22,7 +22,7 @@ A [TOML](https://toml.io/) (v1.0 and v1.1) parser and encoder for PHP with AST a ## Requirements -- PHP 8.2 or higher +- PHP 8.1 or higher ## Installation @@ -185,7 +185,7 @@ The library currently supports: See the [Support Matrix](https://php-collective.github.io/toml/reference/support-matrix) for current coverage and known gaps. -Versioned behavior is available through `TomlVersion` and `EncoderOptions(version: ...)`. The default remains TOML 1.1-compatible; use `TomlVersion::V10` when you need strict TOML 1.0 parsing or output rules. +Versioned behavior is available through `TomlVersion` and `EncoderOptions(version: ...)`. Parsing defaults to TOML 1.1-compatible input, while encoding defaults to TOML 1.0-compatible output for interoperability. Use `TomlVersion::V10` when you need strict TOML 1.0 parsing, or `EncoderOptions(version: TomlVersion::V11)` when you want TOML 1.1 output. For explicit local temporal encoding, use: diff --git a/composer.json b/composer.json index fc6adcd..63838b1 100644 --- a/composer.json +++ b/composer.json @@ -18,11 +18,11 @@ ], "homepage": "https://php-collective.github.io/toml/", "require": { - "php": ">=8.2", + "php": ">=8.1", "symfony/polyfill-mbstring": "^1.30" }, "require-dev": { - "phpunit/phpunit": "^11.5 || ^12.5 || ^13.0", + "phpunit/phpunit": "^10.5 || ^11.5 || ^12.5 || ^13.0", "phpstan/phpstan": "^2.0", "php-collective/code-sniffer": "dev-master" }, diff --git a/docs/guide/encoding.md b/docs/guide/encoding.md index 8734c52..05cec1f 100644 --- a/docs/guide/encoding.md +++ b/docs/guide/encoding.md @@ -429,6 +429,24 @@ message = "Hello\nWorld" path = "C:\\Users\\name" ``` +Literal or multiline string output can be enabled explicitly: + +```php +use PhpCollective\Toml\Encoder\StringStyle; + +$toml = Toml::encode([ + 'path' => 'C:\Users\name', +], new EncoderOptions(stringStyle: StringStyle::Literal)); +``` + +Output: + +```toml +path = 'C:\Users\name' +``` + +The default remains basic strings. Literal styles fall back to basic strings when a value cannot be represented safely in the requested style. + ## Re-encoding from AST ```php diff --git a/docs/guide/index.md b/docs/guide/index.md index 6938af9..e297134 100644 --- a/docs/guide/index.md +++ b/docs/guide/index.md @@ -10,7 +10,7 @@ Install via Composer: composer require php-collective/toml ``` -**Requirements:** PHP 8.2+ +**Requirements:** PHP 8.1+ ## Quick Start diff --git a/docs/index.md b/docs/index.md index 95a3f2e..ba5f218 100644 --- a/docs/index.md +++ b/docs/index.md @@ -4,7 +4,7 @@ layout: home hero: name: PHP Toml text: TOML 1.0/1.1 Parser - tagline: A modern PHP 8.2+ parser and encoder with AST access, trivia preservation, and error recovery + tagline: A modern PHP 8.1+ parser and encoder with AST access, trivia preservation, and error recovery image: src: /logo.svg alt: PHP Toml @@ -31,7 +31,7 @@ features: details: Full abstract syntax tree for analysis, transformation, or editor integrations - icon: ⚡ title: Zero Dependencies - details: No required extensions - pure PHP 8.2+ with optional php-ds for performance + details: No required extensions - pure PHP 8.1+ with optional php-ds for performance - icon: 🔄 title: Structured Re-Encode details: Parse TOML to an AST, modify nodes, and re-encode with partial trivia and layout preservation diff --git a/docs/reference/api.md b/docs/reference/api.md index 742da39..1908f13 100644 --- a/docs/reference/api.md +++ b/docs/reference/api.md @@ -42,7 +42,7 @@ $config = Toml::decodeFile('/path/to/config.toml'); public static function parse( string $input, bool $preserveTrivia = false, - TomlVersion $version = TomlVersion::V11, + TomlVersion $version = TomlVersion::V10, ): Document ``` @@ -91,9 +91,8 @@ Encodes a PHP array to a TOML string. $toml = Toml::encode(['key' => 'value']); // key = "value" -$strict = Toml::encode( +$toml = Toml::encode( ['time' => new \PhpCollective\Toml\Value\LocalTime('07:32')], - new EncoderOptions(version: TomlVersion::V10), ); // time = 07:32:00 ``` @@ -250,6 +249,7 @@ public function __construct( ?int $multilineThreshold = null, ?int $inlineTableThreshold = null, string $indent = ' ', + StringStyle $stringStyle = StringStyle::Basic, ) ``` @@ -275,7 +275,7 @@ $toml = Toml::encode($data, EncoderOptions::diffFriendly()); | `newline` | `string` | `"\n"` | Newline sequence to use (`"\n"` or `"\r\n"`) | | `documentFormatting` | `DocumentFormattingMode` | `Normalized` | `Normalized` or `SourceAware` for `encodeDocument()` | | `skipNulls` | `bool` | `false` | Omit `null` values instead of throwing `EncodeException` | -| `version` | `TomlVersion` | `V11` | TOML version for output rules | +| `version` | `TomlVersion` | `V10` | TOML version for output rules | | `integerGrouping` | `bool` | `false` | Add underscores to large integers (e.g., `1_000_000`) | | `integerBase` | `IntegerBase` | `Decimal` | Radix for integers in `encode()` output (`Hexadecimal`/`Octal`/`Binary` emit `0x`/`0o`/`0b`; negatives stay decimal) | | `trailingComma` | `bool` | `false` | Add trailing commas to inline arrays | @@ -285,6 +285,7 @@ $toml = Toml::encode($data, EncoderOptions::diffFriendly()); | `multilineThreshold` | `?int` | `null` | Opt-in string length threshold for multiline basic strings in `encode()` | | `inlineTableThreshold` | `?int` | `null` | Opt-in key count threshold for small flat nested arrays to encode as inline tables | | `indent` | `string` | `' '` | Indentation string for multiline arrays | +| `stringStyle` | `StringStyle` | `Basic` | String formatting style for plain PHP strings | ### ArrayStyle @@ -387,18 +388,43 @@ $toml = Toml::encode( // database.port = 5432 ``` -### TOML 1.0 Mode +### StringStyle + +Controls how plain PHP strings are formatted during `encode()`. + +```php +use PhpCollective\Toml\Encoder\StringStyle; +``` + +| Style | Description | +|-------|-------------| +| `StringStyle::Basic` | Basic double-quoted strings. This is the default and preserves current output behavior | +| `StringStyle::Literal` | Single-quoted literal strings when representable; falls back to basic strings when needed | +| `StringStyle::MultiLineBasic` | Multiline basic strings | +| `StringStyle::MultiLineLiteral` | Multiline literal strings when representable; falls back to multiline basic strings when needed | + +```php +$toml = Toml::encode( + ['path' => 'C:\Users\name'], + new EncoderOptions(stringStyle: StringStyle::Literal), +); +// path = 'C:\Users\name' +``` + +### TOML Version Modes + +Parsing and decoding default to TOML 1.1-compatible input. Encoding defaults to TOML 1.0-compatible output for interoperability and normalizes local times and local datetimes to include seconds where possible. -In strict TOML 1.0 mode, `encode()` normalizes local times and local datetimes to include seconds where possible. `encodeDocument()` in `DocumentFormattingMode::SourceAware` throws `EncodeException` if preserving the parsed source would keep TOML 1.1-only syntax. +`encodeDocument()` in `DocumentFormattingMode::SourceAware` throws `EncodeException` if preserving the parsed source would keep TOML 1.1-only syntax while `EncoderOptions(version: TomlVersion::V10)` is active. ## TomlVersion Controls version-specific parser and encoder behavior. - `TomlVersion::V11` - Default behavior. Accepts TOML 1.1 syntax and emits TOML 1.1-compatible output. + Default parser/decoder behavior. Accepts TOML 1.1 syntax and emits TOML 1.1-compatible output when passed to `EncoderOptions`. - `TomlVersion::V10` - Strict TOML 1.0 mode for parsing, decoding, and encoding. + Strict TOML 1.0 mode for parsing and decoding. Default encoder behavior. ## DocumentFormattingMode diff --git a/docs/reference/support-matrix.md b/docs/reference/support-matrix.md index 3d70fbf..728fcce 100644 --- a/docs/reference/support-matrix.md +++ b/docs/reference/support-matrix.md @@ -6,7 +6,7 @@ It is intentionally narrower than a blanket "full TOML support" claim. The goal The sections below intentionally separate parsing/decoding, encoding, and round-trip editing so support claims stay scoped to the actual surface being described. -The default API behavior is TOML 1.1-compatible. Strict TOML 1.0 parsing/decoding and encoding are available through `TomlVersion::V10` and `EncoderOptions(version: TomlVersion::V10)`. +The default parser/decoder behavior is TOML 1.1-compatible. The default encoder behavior is TOML 1.0-compatible for interoperability; TOML 1.1 output is available through `EncoderOptions(version: TomlVersion::V11)`. ## Status Legend @@ -68,7 +68,7 @@ The default API behavior is TOML 1.1-compatible. Strict TOML 1.0 parsing/decodin | Feature | Status | Notes | |---------|--------|-------| -| Strings | Supported | Encoded as basic strings; control characters are escaped (`\uXXXX` / shorthand) so output stays valid TOML | +| Strings | Supported | Encoded as basic strings by default; literal and multiline styles are opt-in via `EncoderOptions`. Control characters are escaped (`\uXXXX` / shorthand) so output stays valid TOML | | Integers | Supported | | | Floats | Supported | Round-tripped at full `double` precision (shortest exact representation) | | Booleans | Supported | | diff --git a/phpunit.xml b/phpunit.xml index b7abf16..c85a031 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -5,7 +5,6 @@ colors="true" cacheDirectory=".phpunit.cache" executionOrder="depends,defects" - shortenArraysForExportThreshold="10" displayDetailsOnTestsThatTriggerWarnings="true" displayDetailsOnTestsThatTriggerDeprecations="true" displayDetailsOnIncompleteTests="true" diff --git a/src/Encoder/Encoder.php b/src/Encoder/Encoder.php index 50ac18a..b0e8162 100644 --- a/src/Encoder/Encoder.php +++ b/src/Encoder/Encoder.php @@ -22,7 +22,7 @@ use PhpCollective\Toml\Ast\Value\LocalDateTime; use PhpCollective\Toml\Ast\Value\LocalTime; use PhpCollective\Toml\Ast\Value\OffsetDateTime; -use PhpCollective\Toml\Ast\Value\StringStyle; +use PhpCollective\Toml\Ast\Value\StringStyle as AstStringStyle; use PhpCollective\Toml\Ast\Value\StringValue; use PhpCollective\Toml\Ast\Value\Value; use PhpCollective\Toml\Exception\EncodeException; @@ -198,11 +198,7 @@ private function encodeValue(mixed $value): string } if (is_string($value)) { - if ($this->options->multilineThreshold !== null && mb_strlen($value) > $this->options->multilineThreshold) { - return $this->encodeMultilineBasicString($value); - } - - return $this->encodeString($value); + return $this->encodeStringValue($value); } if ($value instanceof DateTimeInterface) { @@ -372,10 +368,10 @@ private function encodeAstStringValue(StringValue $value): string } return match ($value->style) { - StringStyle::Basic => $this->encodeString($value->value), - StringStyle::Literal => "'" . $value->value . "'", - StringStyle::MultiLineBasic => $this->encodeMultilineBasicString($value->value), - StringStyle::MultiLineLiteral => "'''\n" . $value->value . "'''", + AstStringStyle::Basic => $this->encodeString($value->value), + AstStringStyle::Literal => "'" . $value->value . "'", + AstStringStyle::MultiLineBasic => $this->encodeMultilineBasicString($value->value), + AstStringStyle::MultiLineLiteral => "'''\n" . $value->value . "'''", }; } @@ -1356,6 +1352,64 @@ private function escapeControlChars(string $value): string ) ?? $value; } + private function encodeStringValue(string $value): string + { + $style = $this->options->stringStyle; + if ($this->options->multilineThreshold !== null && mb_strlen($value) > $this->options->multilineThreshold) { + $style = $style === StringStyle::Literal + ? StringStyle::MultiLineLiteral + : StringStyle::MultiLineBasic; + } + + return match ($style) { + StringStyle::Basic => $this->encodeString($value), + StringStyle::Literal => $this->encodeLiteralString($value), + StringStyle::MultiLineBasic => $this->encodeMultilineBasicString($value), + StringStyle::MultiLineLiteral => $this->encodeMultilineLiteralString($value), + }; + } + + private function encodeLiteralString(string $value): string + { + if (!$this->canUseSingleLineLiteralString($value)) { + return $this->encodeString($value); + } + + return "'" . $value . "'"; + } + + private function encodeMultilineLiteralString(string $value): string + { + if (!$this->canUseMultilineLiteralString($value)) { + return $this->encodeMultilineBasicString($value); + } + + return "'''\n" . $value . "'''"; + } + + private function canUseSingleLineLiteralString(string $value): bool + { + return !str_contains($value, "'") + && !str_contains($value, "\n") + && !str_contains($value, "\r") + && !$this->containsDisallowedControlCharacter($value); + } + + private function canUseMultilineLiteralString(string $value): bool + { + return !str_contains($value, "'''") + && !$this->containsDisallowedControlCharacter($value, allowNewline: true); + } + + private function containsDisallowedControlCharacter(string $value, bool $allowNewline = false): bool + { + if ($allowNewline) { + return preg_match('/[\x00-\x08\x0B-\x1F\x7F]/', $value) === 1; + } + + return preg_match('/[\x00-\x08\x0A-\x1F\x7F]/', $value) === 1; + } + /** * @param array $value */ diff --git a/src/Encoder/EncoderOptions.php b/src/Encoder/EncoderOptions.php index dd8ee21..ba20a19 100644 --- a/src/Encoder/EncoderOptions.php +++ b/src/Encoder/EncoderOptions.php @@ -7,23 +7,24 @@ use PhpCollective\Toml\Ast\Value\IntegerBase; use PhpCollective\Toml\TomlVersion; -final readonly class EncoderOptions +final class EncoderOptions { public function __construct( - public bool $sortKeys = false, - public string $newline = "\n", - public DocumentFormattingMode $documentFormatting = DocumentFormattingMode::Normalized, - public bool $skipNulls = false, - public TomlVersion $version = TomlVersion::V11, - public bool $integerGrouping = false, - public IntegerBase $integerBase = IntegerBase::Decimal, - public bool $trailingComma = false, - public bool $dottedKeys = false, - public ArrayStyle $arrayStyle = ArrayStyle::Inline, - public int $arrayAutoThreshold = 3, - public ?int $multilineThreshold = null, - public ?int $inlineTableThreshold = null, - public string $indent = ' ', + public readonly bool $sortKeys = false, + public readonly string $newline = "\n", + public readonly DocumentFormattingMode $documentFormatting = DocumentFormattingMode::Normalized, + public readonly bool $skipNulls = false, + public readonly TomlVersion $version = TomlVersion::V10, + public readonly bool $integerGrouping = false, + public readonly IntegerBase $integerBase = IntegerBase::Decimal, + public readonly bool $trailingComma = false, + public readonly bool $dottedKeys = false, + public readonly ArrayStyle $arrayStyle = ArrayStyle::Inline, + public readonly int $arrayAutoThreshold = 3, + public readonly ?int $multilineThreshold = null, + public readonly ?int $inlineTableThreshold = null, + public readonly string $indent = ' ', + public readonly StringStyle $stringStyle = StringStyle::Basic, ) { } diff --git a/src/Encoder/StringStyle.php b/src/Encoder/StringStyle.php new file mode 100644 index 0000000..35c71ff --- /dev/null +++ b/src/Encoder/StringStyle.php @@ -0,0 +1,13 @@ +code = $code ?? ParseErrorCode::fromMessage($message); diff --git a/src/Parser/ParseResult.php b/src/Parser/ParseResult.php index 7348700..469247c 100644 --- a/src/Parser/ParseResult.php +++ b/src/Parser/ParseResult.php @@ -6,7 +6,7 @@ use PhpCollective\Toml\Ast\Document; -final readonly class ParseResult +final class ParseResult { /** * @param \PhpCollective\Toml\Ast\Document|null $document @@ -14,9 +14,9 @@ * @param array|null $value */ public function __construct( - private ?Document $document, - private array $errors, - private ?array $value = null, + private readonly ?Document $document, + private readonly array $errors, + private readonly ?array $value = null, ) { } diff --git a/src/Value/LocalDate.php b/src/Value/LocalDate.php index bf61351..ea3bcd8 100644 --- a/src/Value/LocalDate.php +++ b/src/Value/LocalDate.php @@ -7,9 +7,9 @@ use InvalidArgumentException; use PhpCollective\Toml\Support\TemporalValidator; -final readonly class LocalDate implements TomlValue +final class LocalDate implements TomlValue { - public function __construct(public string $value) + public function __construct(public readonly string $value) { if (!TemporalValidator::isValidLocalDate($value)) { throw new InvalidArgumentException("Invalid TOML local date: `{$value}`"); diff --git a/src/Value/LocalDateTime.php b/src/Value/LocalDateTime.php index 190107f..f3a5fb4 100644 --- a/src/Value/LocalDateTime.php +++ b/src/Value/LocalDateTime.php @@ -7,9 +7,9 @@ use InvalidArgumentException; use PhpCollective\Toml\Support\TemporalValidator; -final readonly class LocalDateTime implements TomlValue +final class LocalDateTime implements TomlValue { - public function __construct(public string $value) + public function __construct(public readonly string $value) { if (!TemporalValidator::isValidLocalDateTime($value)) { throw new InvalidArgumentException("Invalid TOML local datetime: `{$value}`"); diff --git a/src/Value/LocalTime.php b/src/Value/LocalTime.php index 79a9fd3..8cf2aad 100644 --- a/src/Value/LocalTime.php +++ b/src/Value/LocalTime.php @@ -7,9 +7,9 @@ use InvalidArgumentException; use PhpCollective\Toml\Support\TemporalValidator; -final readonly class LocalTime implements TomlValue +final class LocalTime implements TomlValue { - public function __construct(public string $value) + public function __construct(public readonly string $value) { if (!TemporalValidator::isValidLocalTime($value)) { throw new InvalidArgumentException("Invalid TOML local time: `{$value}`"); diff --git a/src/Value/TomlInteger.php b/src/Value/TomlInteger.php index 3c16ef4..e7e5b49 100644 --- a/src/Value/TomlInteger.php +++ b/src/Value/TomlInteger.php @@ -6,11 +6,11 @@ use PhpCollective\Toml\Ast\Value\IntegerBase; -final readonly class TomlInteger implements TomlValue +final class TomlInteger implements TomlValue { public function __construct( - public int $value, - public IntegerBase $base = IntegerBase::Decimal, + public readonly int $value, + public readonly IntegerBase $base = IntegerBase::Decimal, ) { } diff --git a/tests/Encoder/EncoderTest.php b/tests/Encoder/EncoderTest.php index bd9a7b1..d320cf6 100644 --- a/tests/Encoder/EncoderTest.php +++ b/tests/Encoder/EncoderTest.php @@ -10,6 +10,7 @@ use PhpCollective\Toml\Encoder\DocumentFormattingMode; use PhpCollective\Toml\Encoder\Encoder; use PhpCollective\Toml\Encoder\EncoderOptions; +use PhpCollective\Toml\Encoder\StringStyle; use PhpCollective\Toml\Exception\EncodeException; use PhpCollective\Toml\Toml; use PhpCollective\Toml\Value\LocalDate; @@ -120,6 +121,63 @@ public function testEncodeStringWithEscapes(): void $this->assertStringContainsString('quote = "say \\"hello\\""', $result); } + public function testEncodeStringStyleLiteral(): void + { + $encoder = new Encoder(new EncoderOptions(stringStyle: StringStyle::Literal)); + + $result = $encoder->encode([ + 'path' => 'C:\Users\name', + ]); + + $this->assertStringContainsString("path = 'C:\\Users\\name'", $result); + } + + public function testEncodeStringStyleLiteralFallsBackToBasicWhenNeeded(): void + { + $encoder = new Encoder(new EncoderOptions(stringStyle: StringStyle::Literal)); + + $result = $encoder->encode([ + 'quote' => "it's fine", + 'line' => "hello\nworld", + ]); + + $this->assertStringContainsString('quote = "it\'s fine"', $result); + $this->assertStringContainsString('line = "hello\\nworld"', $result); + } + + public function testEncodeStringStyleMultilineBasic(): void + { + $encoder = new Encoder(new EncoderOptions(stringStyle: StringStyle::MultiLineBasic)); + + $result = $encoder->encode([ + 'message' => "hello\nworld", + ]); + + $this->assertStringContainsString("message = \"\"\"\nhello\nworld\"\"\"", $result); + } + + public function testEncodeStringStyleMultilineLiteral(): void + { + $encoder = new Encoder(new EncoderOptions(stringStyle: StringStyle::MultiLineLiteral)); + + $result = $encoder->encode([ + 'message' => "hello\nworld", + ]); + + $this->assertStringContainsString("message = '''\nhello\nworld'''", $result); + } + + public function testEncodeStringStyleDoesNotChangeKeyStyle(): void + { + $encoder = new Encoder(new EncoderOptions(stringStyle: StringStyle::Literal)); + + $result = $encoder->encode([ + 'key with spaces' => 'value', + ]); + + $this->assertStringContainsString('"key with spaces" = \'value\'', $result); + } + public function testEncodeDateTime(): void { $encoder = new Encoder(new EncoderOptions()); diff --git a/tests/Encoder/EncoderThresholdsTest.php b/tests/Encoder/EncoderThresholdsTest.php index a25bbc4..beef022 100644 --- a/tests/Encoder/EncoderThresholdsTest.php +++ b/tests/Encoder/EncoderThresholdsTest.php @@ -111,6 +111,7 @@ public function testInlineTableThresholdHonorsSortKeysAndTrailingComma(): void ], ], new EncoderOptions( + version: TomlVersion::V11, sortKeys: true, trailingComma: true, inlineTableThreshold: 3, diff --git a/tests/Integration/DocumentRoundTripTest.php b/tests/Integration/DocumentRoundTripTest.php index d44132d..37fc22a 100644 --- a/tests/Integration/DocumentRoundTripTest.php +++ b/tests/Integration/DocumentRoundTripTest.php @@ -7,6 +7,7 @@ use PhpCollective\Toml\Encoder\DocumentFormattingMode; use PhpCollective\Toml\Encoder\EncoderOptions; use PhpCollective\Toml\Toml; +use PhpCollective\Toml\TomlVersion; use PHPUnit\Framework\TestCase; final class DocumentRoundTripTest extends TestCase @@ -145,7 +146,13 @@ public function testEncodeDocumentPreservesTabIndentedMultilineInlineTable(): vo $input = "point = {\n\tx = 1,\n\ty = 2,\n}"; $doc = Toml::parse($input, true); - $encoded = Toml::encodeDocument($doc, new EncoderOptions(documentFormatting: DocumentFormattingMode::SourceAware)); + $encoded = Toml::encodeDocument( + $doc, + new EncoderOptions( + documentFormatting: DocumentFormattingMode::SourceAware, + version: TomlVersion::V11, + ), + ); $this->assertSame($input, $encoded); } diff --git a/tests/PublicApi/VersioningTest.php b/tests/PublicApi/VersioningTest.php index d98d9c7..f67f236 100644 --- a/tests/PublicApi/VersioningTest.php +++ b/tests/PublicApi/VersioningTest.php @@ -42,6 +42,15 @@ public function testDecodeRejectsOptionalSecondsInToml10Mode(): void Toml::decode("time = 07:32\n", TomlVersion::V10); } + public function testEncodeDefaultsToToml10Behavior(): void + { + $encoded = Toml::encode([ + 'time' => new LocalTime('07:32'), + ]); + + $this->assertSame('time = 07:32:00', $encoded); + } + public function testTryParseRejectsInlineTableTrailingCommaInToml10Mode(): void { $result = Toml::tryParse('point = { x = 1, }', TomlVersion::V10);